论野生技术&二次元

某某管家:从错误堆栈到root shell

发了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(&quot;request&quot;).toString();
46: String requestStr = AESCoder.decrypt(requestStr0, &quot;一个base64&quot;);
47: System.out.println(&quot;requerst======&quot;+requestStr);
48: JSONObject object = JSONObject.parseObject(requestStr);
49: String hgUserid= &quot;&quot;;

我好像看到了一个密钥一个base64,解开是16个字节,因为没看到IV,盲猜了AES-128-ECB。在python中尝试后,发现成功解密之前的迷之request

果然request中并没有存储完整的登陆信息,只有一个登陆手机号;因此可以任意构造手机号,完成整个流程。

一键脚本就这样搞定惹。

root shell

有了AES密钥之后,脑子里奇怪的想法就变多了。

通过构造可以正确AES解密,但是不合法的JSON字符串,我们可以使服务端返回下几行的代码。

47: System.out.println(&quot;requerst======&quot;+requestStr);
48: JSONObject object = JSONObject.parseObject(requestStr);
49: String hgUserid= &quot;&quot;;
50: if(object.containsKey(&quot;account&quot;)
51:   StringUtils.isNotBlank(object.getString(&quot;account&quot;))){
52:     hgUserid = object.getString(&quot;account&quot;);
53: System.out.println(&quot;hgUserid======&quot;+hgUserid);

查阅各种文档后,没有发现其他行会有丢出异常的条件,所以看不到其他行的代码了。但是48行引起了我的注意,从(忘记截图的)堆栈中,我们可以知道这个JSON库是阿里爸爸的fastjson。

一说到fastjson我们就想到反序列化漏洞,今年下半年,中美合拍的……但是仍然要赌一把运维小哥有没有升级库和关闭AutoType。在网上随便找了一个POC之后,返回了新的错误堆栈(还是没截图),异常为”className not found”。说明确实有打开AutoType。

一顿Google之后,使用marshalsec 搭建RMI/LDCP reference server的方式利用。

  1. 起一个nginx,放入编译的反射到的类文件,需要编译成class文件,我们这里用了一个反弹shell
  2. 运行marshalsec的RMI服务器,这个服务器的作用是将来自受害主机的JNDI请求重定向到受我们控制的url。在这个例子里,我们重定向到第一步中的class
  3. 起一个nc等反弹shell

发现nc虽然接收到连接,却对命令没有回显。

查看nginx日志,发现Java版本是8u181。

通过一顿Google了解到,RMI方式在8u113之后被Java屏蔽,所以改用LDAP方式。

这次成功了,而且记得截了个图。

20202年了,为什么还要用root跑web服务。

结末的教训

退出移动版