课程链接:https://www.bilibili.com/video/BV1854y1y7Ro/?vd_source=7b06bd7a9dd90c45c5c9c44d12e7b4e6
课程附件: https://pan.baidu.com/s/1vRCd4bMkqnqqY1nT2uhSYw 提取码: 5rx6
局部变量肯定会发生溢出,一直输入0x64字节打满,再输入一个字节到0x68覆盖ebp指向上一个函数的地址,最后再加上一个字节覆盖返回地址
用gdb调试的主要目的还是找到正常情况下(即输入8个A后)字符串所在的位置(即ebp与esp的位置)
在最开始的寄存器也可以看到,如果隔得太远就需要把stack后面的项数调大一些
这里esp存放的是一个指针,gdb会自动把指针指向的数据打印出来
从字符串所在的地址到ebp所在的地址是我们关心的位置,用来填充适量的垃圾数据
我们可用python来计算需要填充多少垃圾数据,即计算二者的差值
但是我们会发现,这与IDA告诉我们的值(0x64)不同
当两者发生冲突肯定是动态调试是准确的,因为IDA是静态的
由于没有直接的后门程序,我们应该将shellcode写入缓冲区,这里不用考虑栈了(可能被远程地址随机化了),考虑Bss的缓冲区位置,我们可以发现在strncpy(buf2,s,0x64u)提供了位置【将第二个参数(s)中的指定长度(0x64个字节)拷入第一个参数(buf2)中】
由于我们没有在main函数中看到buf2的定义,由此可判定其为全局变量
其在Bss位置(804A080)
此时我们拥有了shellcode以及远程服务器所保存shellcode的目标地址
我们首先应填充shellcode的地址再向后补充垃圾数据,这是因为这一部分数据被拷贝到buf2中后首先执行前面的数据(shellcode),最后把buf2的起始地址填充之前的返回地址进行跳转即可。
值得注意的是,我们可利用.ljust(num,b’X’)以补全字符X到固定长度num;以及最后的地址记得转p32
最后发送并交互来打通
防御者提前放一个canary(金丝雀)以保护,当s覆盖掉后,防御者会检测新的canary和旧的是否保持一致
值得注意的是,在64位下时,需要在脚本中提前写context.arch = “amd64”
以及shellcraft.amd64.sh()
后续加上ebp的字节是8而不是4
以及是p64不是p32
gdb默认是关闭ASLR的
ldd 可查看一个程序所用到的所有动态链接库
libc.so.6是一个软链接,即快捷方式
eax永远存的是系统调用号,后续的寄存器保存系统调用的参数,最后通过int 0x80这样一个指令来执行,这里的int是中断的意思,不同的中断号表示的系统调用不同
ROP的意思是,组合分离的这些指令变成系统调用【现实情况下是没有这些连续的代码的】
之前的溢出覆盖return address已经不足以完成攻击,从红色框可见形成了一个链
我们可使用ROPgadget找到文件中大量的制定代码段,也就是gadget
我们随机选取一个地址,在IDA中按G输入这样的地址
可以看到这段代码的位置,也就是说我直接跳转到这个位置可以直接执行这段代码
text段存在过多的pop ret这样的指令
此时已成功实现栈溢出。stack overflow;ret;为溢出的第一行返回地址
在返回地址之后又接着溢出了一些内容
栈中的内容和text中的内容对应
ret 在x86中对应 pop eip,就会把0x08052318指向的值pop到eip中,即对应的 pop edx; ret;那么就需要执行这段代码
值得注意的是此时esp往上走指向了数据0x0c0c0c
根据pop edx; ret;以及esp之前指向的是值value,那么先把值value存放在edx中,同时esp继续向高地址移动,指向0x0809951f
紧接着执行ret,那么esp继续向高地址移动,并且把0x0809951f指向的代码放入eip,等效于pop eip,就需要执行xor eax, eax; ret;
xor eax, eax; ret;
xor eax, eax;表示清空eax,为eax赋值为0
ret;表示pop eip,同理
mov eax, edx; ret;
mov eax, edx;表示把eax中的值给edx对应的位置【注意这是AT&T不是intel,二者是反过来的】
我们可以发现,这要代码段的结尾是ret,这样的情况就能无限循环下去
先checksec目标程序
用IDA进行反编译,先尝试在functions window中ctrl+f找后门函数(system)【这里是没有的】
还可以在汇编窗口按shift+f12再来搜索/bin/sh,这里是有的,可以跳转看看
找一下引用它的位置;此时我们程序中有/bin/sh字符串但是没有system函数,没有后门函数;虽然有后门函数对应的参数,但是也没用
回到main函数回到汇编窗口【在函数窗口双击即可】,再按f5到c语言程序
找一下对应的gadget,根据我们的目标,先找到pop eax以及pop ebx,对于ecx和ebx我们运气好的话在调用时默认为0
这里老师为了简单说明,直接看写好的文件了。
这里没有直接pop ebx的gadget,只有可替代的
以上是整个函数调用栈的构造