0x01 暴力破解
朴实无华的弱口令,我都怀疑是不是撞上了交互式蜜罐。

0x02 文件上传
目标系统里所有的文件上传功能,都共用同一套处理逻辑。

从文件列表里能看出来,文件上传之后,存放路径由 FileDir 加上 FilePath 拼成,文件名实际上是 GUID 去掉短横线后的结果。系统加载文件的时候,靠的是 FileGUID 这个参数,并且这个参数不存在注入。


0x03 SQL注入
把各个功能点挨个儿测了一遍,最后在投票模块的“修改参与人”那里,发现有注入。确认了用户表叫 t_userinfo,而且看返回的信息,这地方很可能支持堆叠注入。

因为请求里同时涉及 DELETE 和 INSERT 操作,就直接放弃了 SQLMAP。先试了试报错注入,结果发现它会“吞”字符串,用 substr 分割虽然能绕过去,可实在太慢了,完全不是我的风格。

有意思的是测试过程中发现,在堆叠注入里能直接把数据返回到响应中。心里不禁想问:这开发到底是怎么写的代码?

哟呵,居然还有 WAF 拦着。前面我搞那么多敏感操作你都没动静,现在才跳出来?估计不会太强。

果然,最后在注入语句前后加上左右括号,就轻松绕过去了。

就这样拿到了管理员的账号密码。进到后台仔仔细细翻了一圈,却什么有价值的东西都没发现。回过头来再研究这个注入点吧——MySQL 拿权限的路子本身就不多,何况这里还是普通用户权限。

0x04 组合漏洞
难道就这么结束了?灵光一闪:既然这里能堆叠,前面文件加载又是靠 FileGUID 从数据库里查路径来读文件的,那是不是能通过堆叠注入去改文件路径,从而实现任意文件读取?


那么下一个问题来了:Web 路径在哪?目标中间件会不会是 Tomcat?用 ~ 试试看。


只能说,运气还不错。

0x05 读取源码
先读 web.xml,发现里面还有一个 /admin/login.jsp。划个重点,后面会考到——可当时我并没有太在意这个路径。

接下来开始读源码。比如 com.xxx.core.filter.SecurityFilter 这个类,它在 Tomcat 里的文件位置应该是 /webapps/ROOT/WEB-INF/classes/com/xxx/core/filter/SecurityFilter.class。当然,如果开发把核心代码打成了 jar 包扔到 /lib/ 目录下,那就没法读了——猜包名实在太难了。

真见鬼,FileDir 这个字段居然有长度限制。不过问题不大,因为文件读取的路径是 FileDir 和 FilePath 拼起来的,超出长度的部分直接写到 FilePath 里就行了。


靠着这个办法,再加上源码内部引用的类,我陆续拿到了不少源码。审计下来确实发现了一些漏洞,比如认证权限绕过、新的注入点等等。但依然没法 Getshell——因为这个网站的开发方式实在有点神奇,后面会细说。
0x06 后台登录
事情开始有点让人烦躁了。后续又折腾了一大堆:读 Tomcat 日志、log4j 日志(没发现 log4j 漏洞)、配置文件、猜 jar 包名、试备份文件(像 webapps/ROOT.压缩文件后缀 或者绝对路径 tomcat.压缩文件后缀 之类)。虽说没什么突破性进展,但也攒下了一些信息,后来证明这些都帮了大忙。
回到 web.xml,访问 /admin/login.jsp,页面大概长这样(自己画的):

用之前从数据库里读出来的前台管理员账号密码登录,居然进不去。难道账号密码存在另一张表里?查看之前从 log4j 的 debug 日志里抠出来的 SQL 语句,想着干脆去读那张表,结果发现根本读不到。
???这可真是见了鬼了。不,有一万分的不对劲。再仔细回想一下:数据库配置文件里,明明用的是 root 用户,可刚才那个注入点执行的时候,身份却是普通用户。

沉下心来仔细审了一下已经拿到的那部分源码,才恍然大悟——这狗东西跟我玩这一套。

这套系统的大致设计是:前台通过 SourceCode 和 ROOT 数据库连接,获取数据库里预先配置好的连接信息,再动态设置一个新的数据源。前台的所有数据操作,实际上都是从这个新数据源走的。这就解释了为什么注入点拿到的只是普通用户权限,而不是 ROOT。
不过,获取配置源的那个地方本身也存在注入。也就是说,我们依然能利用 ROOT 权限去执行语句,只不过这次是 selectOne 而不是堆叠注入。问题不大,我的主要目标只是拿后台密码。

0x07 JDBC 反序列化
登录后台后,第一时间就注意到了数据源配置的功能点,这和我之前的推测完全吻合。当时第一个念头就是打 JDBC 反序列化,可惜目标不出网。

0x08 RCE
后台功能点其实不算多,能测的基本都测过了。不过有个地方能用来调试 SQL 语句。至于为什么会有这个功能?因为它本身就是通过后台配置功能来动态控制网站接口的。我之前拿到的那些源码,基本上都是公共类的实现。
翻了一阵子,总算找到了一个能用 ROOT 权限执行语句的功能点。

先查询一下 secure_file_priv。

准备用日志写入来 Getshell。
……这开发脑子是不是有坑?SQL 语句居然还用 XML 解析。服了,不用想就知道,是 <> 这两个符号惹的祸。

用 XML 实体转换一下就解决了:
< 转换为 <
> 转换为 >

访问一下文件,打完收工。

0x09 总结
这是一次很有意思的渗透测试,整条利用链走得相当曲折:
从暴力破解开始 → 拿到普通用户权限的注入点 → 堆叠注入配合文件下载实现任意文件读取 → 读取配置文件与源码 → 审计出 ROOT 权限的 SELECT 注入 → 读出后台账号密码 → JDBC 反序列化因不出网失败 → 发现后台 ROOT 权限执行 SQL 语句的功能 → 利用日志文件写 Shell → 中途被 XML 格式的坑绊了一脚
你在实际的渗透测试项目中,是否也遇到过类似这种环环相扣、靠组合拳才能打通的案例?如果有难忘的经历,欢迎到云栈社区分享交流,说不定你的思路能帮到下一个卡在某个环节的兄弟。