以如下程序为例子
通过gdb调试,我们可以看到buf的存储地址在0xffffd5d6处,push eax来入栈。 当程序继续向下运行的时候,会有返回点,由于gets未对输入的字符串长度进行限制,所以我们可以通过覆盖返回点来控制程序走向。 以攻防世界level1的一个题目为例,程序的溢出点在vulnerable_function中 通过执行add esp,0x10, leave可以达到返回点
xman攻防世界的level1题目在远程环境和本地环境中,有所区别,本地可以直接拿到buf泄露的地址,但是在远程环境中,则是先接受输入,然后拿到输出的,在后来的出题过程中发现,是由于没有在题目中置空缓冲区造成的。在这里用到DynELF来泄露出其libc中system的地址,其大概原理,是不间断的重复执行程序的前两部分,直到得到system字符串,有些类似暴力破解(此处仅个人理解),此也为泄露libc中system的一个template
未开启NX保护,堆栈可执行
如果堆栈可以执行,通过pattern来找到覆盖地址,直接通过shellcode来覆盖,程序运行跳转到shellcode 即可实现getshell
开启NX保护,使用ROP来跳转
有system('/bin/sh')直接跳转调用
没有system('/bin/sh')则可以通过系统调用来实现,满足系统调用,需要通过ropgadgetl来找到合适的gadgets。
程序中没有给出system,可以通过泄露libc中的system地址,进一步getshell
打开DEP防护,aslr是关闭的情况下,此时堆栈不可执行
在通过printf来输出的时候,我们往往会通过printf("%s",s);来进行输出,有的时候,为了偷懒,我们也可以通过printf(s);来进行输出,当我们通过printf(s)来进行输出的时候,如果我们输入的字符串为"%s",那么printf会将字符串解析为格式化字符串参数,然后将堆栈上的内容输出。
我们以先知上的一道总结题目为例
在先知的总结上,该题目类型是编译为64为程序,此处,我们编译为32位程序,通过
printf堆栈图如下 首先是将"%s"来入栈,然后将解析其为特定的格式化字符串参数。我们通过%n$x来输出特定的字符串。当我们用"%1$x"时,输出为0xffffd59c
通过计算我们可以知道此处应该为%20$lld
在上一小节中,我们能够泄露出在栈中,指定位置的数据,本节中,我们将通过格式化字符串来泄露任意地址位置的值。这里我们需要首先调试出printf的第一个参数在堆栈中存储的位置,确认其存在与第几个参数位置。然后在此处写入要读取的位置的地址,然后通过该地址将其值泄露出来,从而我们可以泄露scanf的地址
覆盖C的地址
我们以CTF-wiki中pwn的栈内存覆盖为例来进行指定栈位置写。题目原型
通过peda我们可以看到栈中的实际的情况,s3anapwned是输入的字符串的位置,其偏移相对是6。我们要覆盖栈中的变量的时候,我们通过"%6$x"即可实现覆盖,由于%n的覆盖是覆盖为输出的字符的个数,故在"%6$x"前我们仍然要加上输出的指定的字符格式。
printf("addr%6$xs"),任意地址写分为两种情况,一种情况是写入的数值是一个小的数值,比如写入2,在之前我们往往是通过地址+偏移来写,而一个地址的偏移往往会大于等于4字节,这个时候,我们便不能将格式化字符串的地址放入到串首的位置,%n是将其前面已经输出的字符的个数写入对应的位置,这个时候,我们可以将地址后移,但是任然要找到其对应的位置,比如"aa%n$xaa(addr)"这个时候的addr将是第八个位置,(aa%n)是第七个位置,($xaa)将是第六个位置。从而可以实现将指定位置的数值写为2。
如果想要在指定的位置输出1或者 3,则调换a的相应的位置即可。 在分析完对较小的数值,可以继续看较大的数值的覆盖,此处引用CTF-wiki模板,先给出一个基本的payload构造
其构造模板如下(源自CTF-Wiki)
其中每个参数的含义基本如下
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-9-22 18:58
被seana编辑
,原因: