• 这里感谢一位学长的答疑

栈溢出相关疑问

关于栈迁移

疑问1:ret到之前使用过的程序代码

  • 在栈溢出ret2libc的时候通常要先构造ROP链,泄露libc地址后才能ret2libc,但是当程序栈溢出ret之后,没有了栈溢出点,这时就要返回到程序开头重新执行一遍程序。在做这类pwn题的时候,之前我会ret到子程序半中间,然后会出现段错误
  • 例如下图:我会返回到call_puts这个指令的地址这边,然后就栈溢出的时候就出现了段错误

image-20240618013114306

原因

  • 注意到在程序执行的末尾,出现了 leave retn这一串指令
1
2
3
leave的指令进行的隐含操作是
mov esp,ebp
pop ebp
  • 这个指令的隐含操作,导致了如果栈溢出不输入合适的ebp的地址就会出现ebp乱跑的结果,导致再返回到之前程序执行过的指令,再次进行栈溢出就会发生栈迁移,从而出现段错误
  • 还有就是如果栈溢出时不输入合适的栈地址使得ebp乱跑,这时需要返回到程序的开头,因为在程序的开头中有出现push ebp,mov esp,ebp这套指令,会使得已经乱指的ebp指针,回到栈上

疑问2:面向返回编程不需要执行权限

  • 之前在做pwn题的时候会出现构造ROP链需要执行权限的段,但是有一次在做栈迁移的时候,迁移到.bss段上,但是.bss段上没有执行权限,这就出现了此问题
  • 对于ROP链,这个面向返回编程只需要的是地址,而不是ret2shellcode那样要先把shellcode写入可写可执行的段中,然后再ret到shellcode

疑问3:在栈迁移到.bss段

  • 在写栈题,有时候栈迁移到.bss段,在.bss段上写入ROP链,在调用system函数时,会出现段错误,原因是栈迁移所迁移的地址距离代码段或者不可写段太近了,在子函数调用降低栈地址的时候,栈跑不可读或不可写的段去了
  • 这时用vmmap指令查看哪一寻找合适的可写段去写就行了

关于栈对齐

疑问1:栈对齐需要对齐几次

  • 对齐问题,只会在调用system的时候遇到。因为libc 2.27以后的system指令里,有一个涉及xmm寄存器的操作,xmm寄存器的数据类型要符合SSE指令集标准,也就是要满足0x10对齐(64位)。

  • 对于栈对齐,在之前没怎么接触过,前面也只有在格式化字符串漏洞那块接触过栈对齐

  • 在写这道题的时候:[CISCN 2019东北]PWN2 | NSSCTF,出现了一个疑问,在栈对齐的时候需要对齐几次。当我在发送payload1时不需要栈对齐,而发送payload2的时候却需要栈对齐,为什么不是两个payload都需要栈对齐呢

image-20240618111733495

  • 这时候就需要进行动态调试去查看程序运行时的栈布局了,在0x400AE8处打下断点,然后ni执行到ret前一个指令

image-20240618114137426

  • 这时会看到第一次输入后如下的栈布局,这时会发现栈是没有对齐的(栈对齐rsp指针必须指向末尾是0的栈地址而不是末尾是8的栈地址),但是此时的ROP链构造后是可以正常返回的

image-20240618114348339

  • 然后再查看第二次payload后的栈布局,栈没有对齐导致了所构造的ROP链没有办法正常返回。这就需要再添加ret,使得栈对齐才能正常运行,注意:这里一定是要ret的地址,如果不是ret的地址就没办法与右边的汇编指令配合,右边的指令会ret到你所控制对齐的那个地方。

image-20240618114931199

  • 其实在第一次payload的时候就先栈对齐,然后第二次payload时不进行栈对齐也可以打通,所以在有时候ROP链构造正确但是打不通的时候,需要动态调试看看栈是否对齐。没对齐使用ret指令进行对齐
  • 下图是第一次payload的时候栈对齐的结果

image-20240618120742059

image-20240618120812218