發了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 觀察到已關閉