發了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服務。

結末的教訓

  • 別用root別用root別用root別用root別用root
  • 出站流量規則同樣很重要,可以擋住一些任意端口的反彈shell
  • 使用fastjson如無必要,請關閉AutoType;反射一時爽,運維火x場
  • 生產環境關閉錯誤回顯,這次能成功利用到fastjson的洞,根本原因還是AES密鑰的泄漏
    • 2020/02/28 觀察到已關閉