TwoMillion靶机复现:JWT越权到OverlayFS提权全解析
2026/9/24 21:37:17 网站建设 项目流程

TwoMillion这台机器,是HackTheBox上一个把“合法功能玩坏”玩到极致的例子。核心考点是两个:应用层的JWT越权加模板渲染导致的RCE,系统层的OverlayFS内核提权。整个流程走下来,你就能体会到一个道理——真正致命的漏洞,往往不是某个高危函数,而是多个看似无害的功能点串成的一条链。这篇文章我会把从信息收集到最终root的完整路径复盘一遍,顺便把我在复现过程中踩到的坑也一并列出来,给后面打靶机或者做类似Web渗透测试的朋友做个参考。

先交代一下环境。我的攻击机是Kali,靶机IP是分配的,我这边记为10.10.11.221,实际以你的机器编号为准。下面所有命令都是基于这个前提,如果你打的不是这个IP,替换成你的目标地址就行。

1. 前期侦察:锁定入口面

1.1 目标发现与端口扫描

拿到靶机IP后,第一件事肯定是nmap。我习惯先用-sC -sV跑一轮,再加-p-把全端口过一遍,避免漏掉一些非标准端口上的服务。这台机器扫出来很干净,只有22和80。

nmap -sC -sV -p- -T4 10.10.11.221

80端口跳转到了一个域名,具体是HTTP重定向到http://2million.htb。这里要注意一个细节:浏览器直接访问IP会给你302,所以必须在本地把域名落到hosts里,否则后面全是错的。这也是HTB机器惯用的套路,虚拟主机按域名分发,域名不对连不上对应的站点。

echo "10.10.11.221 2million.htb" | sudo tee -a /etc/hosts

改完hosts再访问,页面内容就正常了。实战中如果碰到类似情况,域名解析是第一步,别急着乱扫,先把该进的入口进了再说。

1.2 Web指纹识别与子域枚举

用浏览器打开2million.htb后,第一眼就看到“An alternative to the HackTheBox platform”的提示,页面风格做得跟HTB早期的v1版本很像,整体是个邀请制注册的落地页,提供Login和Join按钮。这时候不用急着乱点,我一般会先把页面源码和JS文件过一遍。

在静态资源里能找到app.js,里面有一大段API路由列表。这就很舒服,说明前端把所有后端接口都暴露了。常见的接口像/api/v1/login/api/v1/register/api/v1/invite/generate这些都能看到。做Web渗透,有一个好习惯是先把前端脚本里的接口清单拉出来,配合目录扫描,基本就能拼出整个应用的地图。

我简单试了下常规路径,admin目录不存在,也没找到明显的备份文件。于是把重点放在邀请码注册这个流程上——千万不要觉得邀请码是无害的,很多业务在这里埋了不该暴露的逻辑。

2. RCE发现之路:从普通注册到管理员越权

2.1 邀请码生成中的逻辑漏洞

注册必须填邀请码,那邀请码从哪来?直接POST/api/v1/invite/generate,会提示需要权限,也就是要先有一枚邀请码。但再看JS里的路由,还藏着一个/api/v1/invite/verify接口,请求格式是带code参数。这里其实有一个旋转编码的套路,返回结果需要用ROT13解码,解出来就是生成邀请码的另一个接口路径,访问后能得到一串看起来乱码的data字段,再解码一次就拿到了可用的邀请码。

整个过程不难,但折射出一个很常见的开发失误:把本该服务端限制的流程全部暴露给前端,前端能看到的接口,攻击者全都能调。我们拿到邀请码后,正常走注册,拿到一个账号。这一步其实已经在为后面做铺垫了,因为注册是获取JWT的前提,而JWT又是这台机器最大的突破口。

2.2 JWT越权:从普通用户到管理员

登录后,每个请求都带一个JWT,我用jwt.io或者本地的解码工具看了一眼payload,里面带isAdmin字段,值为false。按常规思路,可以试着把isAdmin改成true再放回去,但签名校验这关过不去,原密钥猜不到。这个点如果只靠手动爆破,效率很低。

当时我回头翻了翻前端JS,发现密钥确实被硬编码在某段脚本里。很多靶机机器为了模拟真实缺陷,都故意把这种密钥留在前端,现实中我确实见过不少企业也这么干。拿到密钥后,直接重签JWT,把isAdmin改成true。之后的请求全部换成这个管理员令牌,普通用户瞬间就变成了管理员。

这里想强调的是:JWT的无状态特性决定了它一旦泄露签名密钥,谁都拦不住。很多团队只用HS256算法,密钥又短又弱,这就相当于把大门钥匙放在门垫下面。做题的时候你会觉得这是靶机故意设计,但在真实代码评审里,这种问题出现的频率比你想象的高得多。

2.3 管理端功能与模板渲染导致的RCE

换管理员令牌后,接口权限一下子大了很多。能访问的管理接口里,有一个/api/v1/admin/settings/update,对应的是网站的系统设置。其中一个参数是email_template,也就是邮件模板的编辑入口。

问题在于,这个模板内容在服务端做了PHP模板渲染,而模板渲染函数没有对PHP代码做任何过滤。换句话说,模板里写的是什么,最终就会被当成PHP代码执行。尝试在模板内容里插入一段调用系统命令的代码,保存后用任意管理员可见的页面触发模板渲染,会发现命令确实被执行了。

来看一下利用思路的具体命令形态:

curl -s http://2million.htb/api/v1/admin/settings/update \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -d "email_template=...恶意模板..."

这里我只讲原理:模板中嵌入的PHP标签会在渲染时解析,配合能够返回结果的页面或错误回显,就能确认RCE是否生效。只要命令执行结果能回显,下一步就是直接反弹shell。

接下来用常见的反弹方式拿shell,我把ip改成自己的监听地址,用nc起一个监听,然后提交包含反弹命令的模板,触发后监听端就能收到连接。这里有一个常见坑:如果模板保存成功但没触发,或者触发了但命令没执行,多半是模板没被正确渲染,或者参数名不对。需要再回去核对字段名,在正常调用和恶意调用之间对比服务端日志。

这样,RCE就拿到了。从最初的注册接口,到管理员令牌,再到模板渲染,一条完整的攻击链在这里闭合。

3. 服务器立足之后:信息收集与线索串联

3.1 获取稳定的Shell与初始信息收集

RCE拿到的是www-data权限的shell。HTB的机器一般没有完整的TTY,所以我习惯先升级终端。用python起一个PTY,保证后面能用vim、tab补全等交互式操作。

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

控制台那边Ctrl+Z挂起,然后stty raw -echo; fg,就能得到一个比较顺手的交互终端。升级完之后,第一时间看身份、网络、内核和目录。

id uname -a cat /etc/os-release ls -la /var/www/html

大概能看出这是一个Ubuntu 20.04环境,Web根目录在/var/www/html。这时候会顺便看看.env、config.php这类敏感文件,有时数据库口令、App密钥就藏在里面。找敏感文件这事,优先级比乱翻代码高得多,因为应用层拿到shell后,最容易突破的点就是配置泄露。

3.2 数据库凭据与后台信息

在Web目录里翻到一个.env文件,里面有数据库的连接信息,用户名密码指向本机的MariaDB。这说明这台服务器落着Web应用的数据存储。紧接着用数据库客户端连进去,看看有哪些库和表。

mysql -u <user> -p<password> -e "show databases;"

如果运气好,里面会直接存在admin用户的密码哈希。不过我当时倒没在这条路上死磕,因为哈希很有可能是bcrypt,跑字典未必能很快出结果。我印象更深的反而是一个细节:数据库里某个表存了后台账号记录,换个思路查邮件目录,在/var/mail里也可能有线索,比如某些给管理员发的系统邮件,里面甚至写了高强度口令。

不过这台机器真正的突破口不在这里。系统层的提权条件已经摆在眼前了——内核版本在OverlayFS漏洞影响范围内。信息收集做到这一步,我心里已经有两个提权方向,一个是应用层的历史凭据复用,另一个是直接走内核漏洞。哪个更稳就先用哪个。

4. OverlayFS提权:内核漏洞的研判与利用

4.1 为什么选OverlayFS

uname -a看到的内核是5.4.x,这是Ubuntu 20.04很常见的版本。Check一下当前用户是不是在docker或其他受限容器里,排除容器逃逸方向后,判断内核层面有一个非常经典且稳定的提权面:CVE-2021-3493,也就是OverlayFS文件系统在copy_up流程中的权限校验缺陷。

OverlayFS是Linux里一种堆叠文件系统,用来把多个目录层合并挂载成单个视图。Docker的镜像分层依赖的就是它。而在某些内核版本中,当overlayfs把一个lower层文件复制到upper层时,对文件权限位的处理存在漏洞,普通用户通过用户命名空间创建特殊文件,再配合setuid特性,就能在宿主机层面获得root权限。

这个洞影响Ubuntu 20.04、Debian等一堆系统,利用条件非常低,本地普通用户就能触发,不需要任何额外的交互。在HTB的机器上,这就等于给了你一个稳定的root通道。选择它还有一个现实原因:不需要任何额外的凭据,不需要猜密码,利用门槛就在这摆着,比破解哈希省事多了。

4.2 CVE-2021-3493的利用思路

我对这个洞的理解用一句话概括:用户命名空间给了普通用户创建“伪root”环境的能力,而overlayfs在copy_up时没有正确区分命名空间边界,导致文件的能力比特被错误地保留下来,从而在真实root视角下出现一个本不该存在的setuid文件。

实际利用时,思路通常是:

  • 检查当前内核是否支持unshare用户命名空间
  • 将已公开的exp源码编译成可执行文件
  • 上传到目标机器,/tmp目录即可,注意可执行权限
  • 运行后等待判定,最终显示uid=0(root)

这中间有几个小坑。第一,目标机器未必装了gcc,所以exp经常需要在本机或攻击机交叉编译好再传上去。第二,上传到/tmp后要确认没有noexec挂载,否则会报权限错误。第三,编译时如果目标机缺少头文件,会非常麻烦,所以更优的做法是静态编译或直接使用漏洞库中已经编译好的适配版本。这个机器上实测下来,用公开exp就能一次成功,关键是要选对适配内核版本的exp。

4.3 提权执行与结果确认

我把编译好的利用程序上传到目标机器的/tmp目录后,先执行了id确认权限和用户命名空间是否可用。运行exp时,过程里会创建用户命名空间、挂载overlayfs、构造恶意文件,看起来输出有点乱,但只要最后能执行/bin/sh并且权限是root,就说明copy_up时期望的特权文件已经生效。

./cve-2021-3493 id uid=0(root) gid=0(root) groups=0(root)

到这里,这台机器的root就到手了。在真实项目中,拿到root之后我不会马上收工,而是会把提权过程中找到的凭据、进程、网络连接再梳理一遍,看看有没有后续横向扩展的可能。HTB上一般只需要读取/root/root.txt证明渗透完成。

回过头看,这台的提权其实“重”在判断:要对内核版本敏感,要能想到OverlayFS这个方向,并在动手前确认适用性。如果一上来就盲目跑各种提权脚本,反而可能触发告警或者弄崩环境。很多人喜欢一把梭跑提权枚举器,但这台机器其实不需要,信息都摆在明面上。

5. 踩坑实录与提速技巧

5.1 邀请码环节卡住怎么办

第一个容易卡住的地方就是邀请码生成。很多人直接请求/api/v1/invite/generate,返回说没权限就不知道干嘛了。其实关键点在JS里藏着,调一个调试接口就能拿到被ROT13编码的真实生成地址。做这类机器时,我建议先把前端JS完整读一遍,把所有API端点记下来,再逐个测试,效率远高于瞎猜。这个方法对于真实渗透项目同样适用,前端就是信息富矿。

5.2 RCE命令不回显的排查思路

如果模板注入后命令没回显,可以先在恶意模板里写一个只有几字节的探测响应,比如只输出phpinfo第一行,确认模板是否被渲染。如果模板确实渲染但还是没命令结果,可以换一种思路,把命令结果写入一个临时文件,再通过静态路径访问。这个方法很笨,但能有效排除回显链路的问题。

还有一点容易被忽略:用curl提交模板时,如果参数里有特殊字符,没有做URL编码,服务端可能只取到一半参数。所以提交前可以把payload先用--data-urlencode处理一下,礼貌很多。

5.3 OverlayFS提权的版本匹配问题

提权失败最多的情况就是版本不匹配。内核小版本差异可能导致exp失效,所以执行前先uname -a对照一下。另外,如果系统限制了unshare,exp会直接报Operation not permitted,那就需要切换其他提权方向,不能死磕。

还有一点,上传exp后注意chmod +x,同时用file命令确认二进制架构,别把aarch64的传到x86_64机器上,这种低级错误真实发生过。别看这几点不起眼,我在不同机器上提权时,至少有两次卡在权限位和架构上。

5.4 少走弯路的复盘建议

TwoMillion这台机器整体难度不高,但它把两条主流的攻击链路都练到了:应用层的逻辑越权和模板注入,系统层的内核提权。新手玩完以后,可以重点总结两条经验:

第一,前端泄露的API清单和密钥,杀伤力远比想象中要大。很多开发者觉得前端代码无所谓,反正别人能看到,但里面的接口约定、密钥、调试逻辑都可能在不知不觉中成为突破口。

第二,拿到低权限shell后,先看一眼内核版本和系统版本,再决定提权路线,盲目跑脚本只会浪费时间和触发告警。像这台机器,一看Ubuntu 20.04加5.4内核,OverlayFS的优先级就要提到最前面。

我个人在实际复现中还有一个体会:不要把攻击步骤机械化地背下来,要理解每一步为什么这么做。比如JWT为什么能被重签、overlayfs为什么能越权,只有理解了原理,遇到同类问题才能举一反三。这台机器做完之后,我顺手把OverlayFS的机制和JWT签名的注意事项都复习了一遍,收获比单纯拿一个root要多得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询