首先看一下保护机制
然后我们拖入IDA,发现是一个很简单的程序。
然而,最后的那个**printf(&s);**存在格式化字符串漏洞,可以造成任意地址的读写。
首先,我们需要确定我们输入的数据的相对位置。
经过测试,我们需要在前面填充2个字符,然后接下来我们的数据会位于第12个位置
那么,我们的payload = ‘aa’ + p32(address) + ‘%10c%12$n’
,我们就能把address处的数据写为(10+4+2+strlen(“Nice to meet you,”))这个值
原理请见https://www.cnblogs.com/ichunqiu/p/9329387.html
那么,我们可以用这种方式来修改GOT表
我们可以修改strlen的GOT表内容为system的PLT,然后我们想办法让程序程序回到main,执行strlen,我们输入/bin/sh,即可get shell
我们发现,程序结束时,会调用这个地方,我们利用printf把这里也一起修改为main的地址
以上两个地方的修改必须在一次完成,并且,我们的payload长度不能大于64,因为程序最多读取64个字符,因此,我们精心布置payload。并且,我们应该拆分4字节,分开写,不要,printf()需要输出很多字符,假如我们要让目标地址存入main_addr,如果我们是
payload = ‘aa’ + p32(fini_got) + “%” + str(main_addr -4 -2 – strlen(“Nice to meet you,”)) + ‘c%12$n’,那么printf需要输出main_addr这么多个字符,也就是
0x80485ED / 1024 / 1024 = 128MB,这是非常低效的。因此,我们有另一种方法。在printf的格式化修饰符中,hn 为WORD(字),hhn为BYTE(字节),n为DWORD(双字)
fini_got = 0x8049934
main_addr = 0x80485ED
strlen_got = 0x8049A54
system_plt = 0x8048490
此处的数据,只有后2字节与main_addr不一样,因此,我们只需要修改后两字节
然后就是strlen的GOT表内容,四个字节我们都需要修改,我们拆分为2个2字节写。
1 | arr = [ |
由于因特尔处理器小端存储,因此,我们要在fini_got写入2字节数据arr[0]
在strlen_got写入2字节数据arr[2],在strlen_got+2处写入2字节数据arr[1]
我们应该按照数据的大小,从小到大的顺序写。
那么,我们需要先写0x804这个数据,再写0x8490,再写0x85ED(想想为什么?),这样,printf总共输出了0x85ED个字符,也就是33KB大小的数据,效率提升了近4000倍
1 | #coding:utf8 |