ProFTPd Local pr_ctrls_connect Vulnerability - ftpdctl 漏洞及攻擊代碼分析

攻擊代碼網址:http://www.exploit-db.com/exploits/394/


1、運行環境:
1、ProFTPD 1.3.0/1.3.0a
2、編譯ProFTPD時,--enable-ctrls選項必須打開
./configure --enable-ctrls
2、運行參數:
root@kali:~# gcc 394.c -o 394
root@kali:~# ./394 –s <option> [-p <option_path>] [-o <option_offset>]
參數-s後的值是攻擊的兩種不同的方式,值有1和2可以選擇。第1種方式使用當前環境,第2種方式是使用ret-to-libc的方式。
注:return-to-libc 攻擊中,其堆棧中的返回地址被替換爲另一條指令的地址,並且堆棧的一部分被覆蓋以提供其參數。這允許攻擊者調用現有函數而無需注入惡意代碼到程序中。
參數 -o參數-p無太大意義。僅僅是幫助使用該攻擊代碼。
3、代碼分析
代碼執行命令爲:root@kali:~# ./394 –s 1
3.1分析程序參數

程序的第236行,是對394.c程序運行時的參數進行分析。getopt(int argc, char * const argv[ ], const char * optstring)用來分析命令行參數。參數argc和argv是由main()傳遞的參數個數和內容。參數optstring 則代表欲處理的選項字符串。選項字符串裏的字母后接着冒號“:”,則表示還有相關的參數,全域變量optarg 即會指向此額外參數。然後下面就是針對不同的參數進行處理,由於最終起作用的只有-s一個參數,下面將着重的分析-s參數。
getopt處理到-s參數後,由於optstring中冒號“:”的存在,optarg會指向-s的下一個參數,也就是1。然後程序在246行將該參數值賦值給變量wybor,等待下一步處理。

3.2確定參數的有效性
由於394.c程序只提供了2種漏洞攻擊方式,所以程序中241行會將-s後的參數值限定爲1或2,其他的任何值都視爲非法,將導致程序直接退出。

此外,程序中的另一個變量path,用於指定漏洞程序的絕對路徑,值默認爲/usr/local/bin/ftpdctl。也正是ProFTPD服務器的ftpdctl中調用了ctrls.c中的pr_ctrls_connect()函數,而該函數中的一個strncpy()是該漏洞的緩衝區溢出點。在394.c的267行通過fopen()打開文件的方式確定,該路徑下的文件是否有效。

3.3構造溢出數據並執行攻擊
最終實施攻擊的語句是298行和324行的execle(path,path,"-s",buf,0,sh);
int execle(const char *path, const char *arg, ..., char * const envp[]);
用execle函數可以把當前進程替換爲一個新進程,path參數表示你要啓動程序的名稱包括路徑名,arg參數表示啓動程序所帶的參數,一般第一個參數爲要執行命令名。將環境變量傳遞給需要替換的進程envp保存環境信息的數據
變量buf用於存放溢出數據,除了大量的無意義數據,最重要的是有/bin/sh的入口地址。當緩衝區溢出後,程序會被引導,跳轉到/bin/sh,從而能執行任意指令。
構造溢出數據主要涉及到兩個變量:buf[229]和sh[2],由於-s後的參數(1或2)決定了利用漏洞的兩種不同方式,下面將針對這兩種方式分開描述:
方式1也就是wybor=1時,buf中除了前兩個字節數據”/A”,其餘227個字節全部爲/bin/sh的入口地址,如圖。

envp[]則是使用0x90作爲填充字符,並在末尾寫入事先構造好的shellcode。shellcode的主要作用是執行: setuid(0)、setgid(0)、/bin/sh和exit(0)。

方式2也就是wybor=2時,由於使用ret-to-libc的方式,buf中的數據除了第一個字節爲‘/’,最後3字節依次爲LIBC_SYSTEM地址、LIBC_NEXT__地址和/BIN/SH地址以外,其餘225個字節均爲填充字符0x41。

envp[]是使用‘’’作爲填充字符並在結尾寫入字符串”/bin/sh”。

3、分析結果
由上面的分析,可以看出,394.c程序主要是通過直接調用ProFTPD服務器的命令ftpdctl -s來對漏洞實施攻擊。之所以是這樣,那是因爲,命令ftpdctl中需要與服務器建立本地socket連接來進行進程間的通信,建立socket連接的時候,ftpdctl.c調用了在ctrls.c中874行定義的函數pr_ctrls_connect(char *socket_file)。
pr_ctrls_connect(char *socket_file)的主要作用是,創建AF_UNIX類型的流式套接字,並連接到服務器,用於連接的本地套接字地址爲ctrl_sock。而ctrl_sock是struct sockaddr_un結構,它有兩個參數sun_family、sun_path。sun_family是協議族,賦值爲AF_UNIX,用於本地進程間通信。sun_path是本地文件的路徑,在程序中使用socket_file對sun_path賦值。不幸的是在進行賦值時,使用了沒有檢查數據邊界的strncpy(),可以看到在程序的923行寫入內存的函數爲strncpy(ctrl_sock.sun_path,socket_file,strlen(socket_file)),很顯然這個函數並沒有對寫入的數據進行邊界檢查,也就是說可以向大小爲sizeof(ctrl_sock)的內存區域寫入任意長度的數據。ctrl_sock是在函數pr_ctrls_connect()中定義的局部變量,發生函數調用時計算機會在動態存儲區爲之開闢大小爲sizeof(ctrl_sock)的內存存儲區,與此同時動態存儲區也會用於保存函數調用時的現場信息和函數返回地址,這就爲緩衝區溢出攻擊創造了條件。也正如394.c源碼註釋中所說,我們可以通過控制socket_file的長度來使緩衝區發生溢出。
的確394.c正是利用這個漏洞,構造了含有/bin/sh返回地址的超長數據,在調用ftpdctrl時使用參數-s來替換正常的socket_file路徑。當ctrls.c執行strncpy()時,這個超長的shellcode使得緩衝區溢出,從而轉去執行/bin/sh,以此來達到攻擊的目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章