发了CNVD,来来回回让我修改也不知道到底想让我写什么。估计他们也不在意,直接公开了。
一天晚上看到了某某管家的某活动,想做个一键脚本,于是打开Quantumult抓包。
跟踪请求发现关键参数来源于一个base64编码的迷之字符串request。
解码后发现是无意义的字符。猜想这个参数来自于app中用户的登陆,但是又不想重新实现整个登陆流程,所以开始研(xia)究(gao)这个request参数。
错误堆栈
尝试构造request,发现服务端竟然返回了错误堆栈
堆栈忘记截图了,我们来看看这个错误回显的开头部分:
<!doctype html><html lang=”zh”><head><title>HTTP Status 500 – Internal Server Error</title><style type=”text/css”>body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 500 – Internal Server Error</h1><hr class=”line” /><p><b>Type</b> 异常报告</p><p><b>消息</b> 在 [46] 行处理 [/xxxxx/index.jsp] 时发生异常</p><p><b>描述</b> 服务器遇到一个意外的情况,阻止它完成请求。</p><p><b>Exception</b> <pre>org.apache.jasper.JasperException: 在 [46] 行处理 [/xxxxx/index.jsp] 时发生异常
43: return;
44: }
45: String requestStr0 = request.getParameter("request").toString();
46: String requestStr = AESCoder.decrypt(requestStr0, "一个base64");
47: System.out.println("requerst======"+requestStr);
48: JSONObject object = JSONObject.parseObject(requestStr);
49: String hgUserid= "";
我好像看到了一个密钥一个base64,解开是16个字节,因为没看到IV,盲猜了AES-128-ECB。在python中尝试后,发现成功解密之前的迷之request。
1 2 |
>>> cipher.decrypt(cc.decode('base64')) '{"account":"一个手机号","area_no":"430074","timestamp":1582631414314}\n\n\n\n\n\n\n\n\n\n' |
果然request中并没有存储完整的登陆信息,只有一个登陆手机号;因此可以任意构造手机号,完成整个流程。
一键脚本就这样搞定惹。
root shell
有了AES密钥之后,脑子里奇怪的想法就变多了。
通过构造可以正确AES解密,但是不合法的JSON字符串,我们可以使服务端返回下几行的代码。
47: System.out.println("requerst======"+requestStr);
48: JSONObject object = JSONObject.parseObject(requestStr);
49: String hgUserid= "";
50: if(object.containsKey("account")
51: StringUtils.isNotBlank(object.getString("account"))){
52: hgUserid = object.getString("account");
53: System.out.println("hgUserid======"+hgUserid);
查阅各种文档后,没有发现其他行会有丢出异常的条件,所以看不到其他行的代码了。但是48行引起了我的注意,从(忘记截图的)堆栈中,我们可以知道这个JSON库是阿里爸爸的fastjson。
一说到fastjson我们就想到反序列化漏洞,今年下半年,中美合拍的……但是仍然要赌一把运维小哥有没有升级库和关闭AutoType。在网上随便找了一个POC之后,返回了新的错误堆栈(还是没截图),异常为”className not found”。说明确实有打开AutoType。
一顿Google之后,使用marshalsec 搭建RMI/LDCP reference server的方式利用。
- 起一个nginx,放入编译的反射到的类文件,需要编译成class文件,我们这里用了一个反弹shell
- 运行marshalsec的RMI服务器,这个服务器的作用是将来自受害主机的JNDI请求重定向到受我们控制的url。在这个例子里,我们重定向到第一步中的class
- 起一个nc等反弹shell
发现nc虽然接收到连接,却对命令没有回显。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Connection from xx.xx.xx.xx xxxxx received! id ls as ^C |
查看nginx日志,发现Java版本是8u181。
1 |
xx.xx.xx.xx - - [26/Feb/2020:08:43:19 -0800] "GET /xx.class HTTP/1.1" 200 655 "-" "Java/1.8.0_181" |
通过一顿Google了解到,RMI方式在8u113之后被Java屏蔽,所以改用LDAP方式。
这次成功了,而且记得截了个图。
20202年了,为什么还要用root跑web服务。
结末的教训
- 别用root别用root别用root别用root别用root
- 出站流量规则同样很重要,可以挡住一些任意端口的反弹shell
- 使用fastjson如无必要,请关闭AutoType;反射一时爽,运维火x场
- 生产环境关闭错误回显,这次能成功利用到fastjson的洞,根本原因还是AES密钥的泄漏
- 2020/02/28 观察到已关闭