<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/binary/5831

                    又一期的wargame來了,這一期的wargame主要側重于逆向,基本上在gdb下把程序的思路弄清楚了,再利用一些簡單的滲透溢出技巧,就可以成功了。 Let's go!

                    依然是老方法,在游戲behemoth首頁可以找到登陸的服務器的賬號和密碼。ssh登陸上去,開始我們的wargame之旅。

                    level 0


                    登陸服務器,在游戲文件夾/behemoth下可以看到全部的可執行程序,首先執行./behemoth0,這是這一關待解決的程序。

                    behemoth_level0_login

                    程序讓我們輸入一個密碼,估計是將我們輸入的密碼和某個固定的密碼做匹配,可能是加密后最匹配,誰知道它怎么做。gdb走起。

                    behemoth_level0_disassemble

                    從反匯編的代碼可能看到兩個令人激動的函數,一個是memfrob(),通過找男人(man)知道,這個函數是將輸入的指定長度的字符串中的字符與數字42做異或,既然是異或操作,就是可逆的。另一個函數是strcmp(),這個函數才是最令人激動的,從整個程序流程大概看到,程序通過scanf()獲取用戶輸入,然后通過memfrob()做異或處理,然后再送入strcmp()做匹配,所以,我們只要在strcmp()函數調用處下斷點,然后查看棧內容就可以得到真正的密碼了。

                    behemoth_level0_passwd

                    程序需要輸入的密碼是eatmyshorts,執行程序,這一關就過去了。

                    behemoth_level0_crack

                    level 1


                    這一關程序也是要求輸入一個密碼,無法得到準備密碼,還是要gdb走起。

                    behemoth_level1_login

                    behemoth_level1_disassemble

                    好吧,從逆向出來的匯編代碼看,程序很簡單,使用gets()得到用戶輸入,然后puts()輸出"Authentication failure.\nSorry."提示結束就可以了,沒有匹配,也就是沒有正確的密碼。不過從gets()這是一個不安全的函數,這里也沒有邊界檢查,說明存在緩沖區溢出漏洞,這是可以利用的。

                    behemoth_level1_overflow

                    通過驗證,確實存在緩沖區溢出漏洞,下面就是如何利用這個漏洞了,這個溢出利用前面的wargame已經玩得很多了。

                    behemoth_level1_crack

                    level 2


                    這里程序執行似乎是要創建某個文件,多次執行發現,每次創建的文件名似乎都不相同,應該是跟pid相關。

                    behemoth_level2_login

                    還是看匯編代碼比較容易理解程序的執行意圖。

                    behemoth_level2_disassemble

                    對反匯編代碼做個大概解釋,執行的流程如下

                    #!c
                    id = getpid()
                    s = lstat("touch " + str(id))
                    if(s & 0xf000 == 0x8000){
                        unlink(str(id);
                        system("touch " + ID);
                    }
                    sleep(0x7d0);
                    system("cat  " + str(id));
                    

                    程序在當前目錄下嘗試查找以自己pid為名的文件,如果不存在的話,就建立該文件,然后執行一個很長時間的sleep(),然后再打開文件。這里沒有輸入,不存在溢出,也沒有其它很明顯的漏洞。sleep(a_long_time)這個函數調用似乎沒有辦法越過,也沒法通過修改.got.plt來嘗試將sleep()替換成其它的函數。后來再參考了網上的類似writeup,發現這里在調用system()的時候使用的是相對路徑,既然是相對路徑,那么這個路徑就是我們可以控制的,通過修改PATH環境變量,這樣就可以使程序在路徑搜索的時候,先搜索我們指定的路徑,這樣就可以將touch程序替換成我們想要執行的程序,比如執行生成一個*shell*。這樣就順利通過這一關了。

                    behemoth_level2_crack

                    這里需要注意路徑和偽 touch 程序的權限問題,開始我一直失敗就是因為權限配置的不對,浪費了不少時間按。

                    level 3


                    這里還是有一個輸入,既然有輸入就有可能有溢出點。

                    behemoth_level3_login

                    從程序執行的結果來看,程序打印了我們的輸入,猜測可能有緩沖區溢出,或者是格式化字符串漏洞,經過驗證,確實有格式化字符串漏洞,這樣就很容易了,基本上不需要看匯編代碼就可以搞定了。

                    behemoth_level3_test_offset

                    從上面的測試我們發現,字符串存儲地址是在當前棧的第六個偏移的地方,即0x18(%esp),這個值在gdb中也是可以看到的。接下來就是構造攻擊程序了。我將shellcode放在環境變量中。

                    behemoth_level3_gdb_test

                    如上圖所示,環境變量即shellcode保存在0xffffd78c中,可能存在一點偏移,不過我們有Nop sledReturn Address處保存著程序原來的返回地址,我們需要將它修改為shellcode

                    behemoth_level3_crack_attack

                    這里執行的cat是為了防止管道關閉,在前面的wargame也使用了這個方法。其中需要注意的是,管道的右邊,一開始我使用的是相對路徑,導致總是沒法得到正確的結果,也不知道問題出現在哪里,后來無意中使用了絕對路徑,才搞定的。這里不知道為什么,等我之后看看管道的具體原理再做記錄。

                    behemoth_level3_crack_ret

                    level 4


                    這里執行的結果就給了一個提示,PID not found!,看樣子程序又是跟PID相關了。

                    behemoth_level4_login

                    從反匯編出來的代碼可以大概了解到程序的執行流程。

                    behemoth_level4_disassemble

                    behemoth_level4_disassemble_2

                    程序首先打開/tmp/pid文件,然后sleep(1)一秒,然后將文件內容輸出,這樣我們只要將文件軟鏈接到密碼文件,就可以讓程序打開密碼文件,同時輸出文件內容了。難點在于,我們如何知道程序的pid,雖然linux 下 pid 是遞增的,但是這也無法保證每次增加的就是 1 個單位。于是,我想到了一個不優雅的方法,我們先建立大量的可能的pid軟鏈接文件,然后一直執行程序,執行程序的pid會落到我們建立的文件范圍內的。

                    behemoth4.py

                    #!python
                    #!/usr/bin/env python
                    #coding=utf-8
                    
                    import sys, os
                    passwd_file = "/etc/behemoth_pass/behemoth5"
                    
                    if len(sys.argv) < 2:
                            print "usage %s [start pid num]"
                            sys.exit(-1)
                    try:
                            start_pid = int(sys.argv[1])
                    except ValueError:
                            print "usage %s [start pid num]"
                            sys.exit(-1)
                    
                    # 建立 50 個符號鏈接文件
                    for i in range(50):
                            os.popen("ln -s " + passwd_file + " /tmp/" + str(i+start_pid))
                    
                    # 執行 1000 次程序
                    for i in range(1000):
                            ret = os.popen("/behemoth/behemoth4")
                            ret = ret.read()
                            if not "not" in ret:
                                    print ret
                                    break
                    
                    # 刪除所有建立的文件
                    for i in range(50):
                            os.popen("rm /tmp/" + str(i+start_pid))
                    

                    主要是python下獲取子進程的pid太麻煩了,要不然這個爆破的代碼可以寫得更優雅一點。不過不影響結果,依然爆破出來了。這里需要注意的是,start pid即程序的參數應該要選得大一點,因為程序里面建立符號鏈接文件啟動了不少子進程,我這里在原來的基礎上增加了500個數,否則容易越過。

                    behemoth_level4_crack

                    level 5


                    這一關執行程序沒有任何輸出,沒有提示,還是直接看反匯編出來的代碼吧。代碼

                    behemoth_level5_disassemble_0

                    behemoth_level5_disassemble_1

                    behemoth_level5_disassemble_2

                    behemoth_level5_disassemble_3

                    behemoth_level5_disassemble_4

                    可以看到,程序首先打開了密碼文件/etc/behemoth_pass/behemoth6,然后建立了localhost:1337socket,再用sendto函數將文件內容發送出去。程序的流程很明顯了,接下來我們只要監聽本地端口1337就可以收到密碼了。需要注意的是sendto是用UDP協議發送的,需要監聽該端口的UDP數據包。

                    使用瑞士軍刀nc進行監聽,然后在另外一個shell中執行程序,nc就會輸出收到的UDP數據包內容了。

                    shell 1 behemoth_level5_listen

                    shell 2 behemoth_level5_sendto

                    shell 1 behemoth_level5_crack

                    level 6


                    這一關有兩個可執行程序,執行程序都沒有得到任何有意義的結果,還是直接看反匯編出來的代碼吧。

                    behemoth_level6_disassemble

                    behemoth_level6_memory

                    第一個主程序與第二個程序/behemoth/behemoth6_reader建立一個管道,然后通過管道讀取,如果讀到的內容等于HelloKitty,這樣就會執行execl(),建立一個shell。我們再看看第二個程序。第二個程序,執行就會輸出Couldn't open shellcode.txt!,看樣子是要建立一個名為shellcode.txt的文件,具體還是看看匯編代碼吧。

                    behemoth_level6_reader

                    程序首先打開一個名為shellcode.txt的文件,然后將文件內容讀取到動態申請的存儲區,最后跳轉到動態存儲區,執行讀取到的內容。這樣就很容易理解了,我們在shellcode.txt文件中存放一段shellcode,這段shellcode只執行一個任務,就是向標準輸出stdout打印一段字符串HelloKitty就可以了。

                    section .text
                    global _start
                    _start:
                            mov ax, 0x7974          ; ty
                            movzx eax, ax           ; zero-extend ax to 32bits
                            push eax
                            push 0x74694b6f         ; oKit
                            push 0x6c6c6548         ; Hell
                            mov ecx, esp
                            xor ebx, ebx
                            inc ebx
                            xor edx, edx
                            mov dl, 10
                            xor eax, eax
                            mov al, 4
                            int 80h
                    
                            ; exit(0)
                            xor ebx, ebx
                            xor eax, eax
                            mov al, 1
                            int 80h
                    

                    上面就是我寫的輸出HelloKittyshellcode程序,匯編之后就可以得到可用的shellcode程序了。需要注意的是,behemoth6_reader程序使用的也是相對路徑,既然是相對路徑,就是我們可以控制的。在/tmp下建立文件夾behemoth6,將當前文件夾設置為/tmp/behemoth6,在該目錄下操作就可以了。

                    behemoth_level6_crack

                    level 7


                    這一關的程序也是執行沒有任何輸出,所以說這次的wargame主要還是看逆向能力,基本上能逆向出來程序流程,后面的問題都很容易就可以解決了。匯編出來的程序很長,就不貼了。

                    唯一可能有點難度的是,在匯編代碼中有兩次調用call 0x8048420 <[email protected]>這一個函數,男人(man)告訴說,這個函數一般是<ctype.h>中的函數如isspace()isalpha()等調用的,也就是在程序里執行的是類似的檢測,再加上從其它的代碼總體來看,得到結論。該程序檢測argv[1]中是否有Non-alpha字符存在,如果有的話那么就有可能是shellcode,這樣就提示錯誤。如圖所示,

                    behemoth_level7_login

                    如上圖所示,第一次執行時,argv[1]中有字符,存在,于是程序報錯,提示可能有shellcode存在。

                    不過程序只是檢測argv[1]中前256個字符,這樣我們只需要用alpha字符填充前面256個位置就可以了,后面可以進行緩沖區溢出利用。不過程序中將全部的環境變量都清空了,這就意味著我們不能將shellcode放置在環境變量中,需要找其它的地方存放,同時一開始,我將shellcode放在argv[1]字符串中的尾部,加上Nop sled,執行的時候提示Illegal Struction,猜測可能棧不可執行。最終我使用return-to-libc,將返回地址修改成system()函數的地址,同時將參數/bin/sh放置在argv[2]中,加上一定的猜測,最終搞定了。

                    behemoth_level7_crack

                    end of the game


                    又完成一期wargame了,現在的難度不是很大,都是一些很基礎的逆向、溢出的知識,不過作為一個新手,我深深地知道打好基礎才是最重要的,后面依然有很多好玩的。盡請期待~

                    想了解更多關于wargame的內容,請參考這里

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频