zoukankan      html  css  js  c++  java
  • Linux (x86) Exploit 开发系列教程之三(Off-By-One 漏洞 (基于栈))

    (1)原理:

    将源字符串复制到目标缓冲区可能会导致off by one。当源字符串长度等于目标缓冲区长度时,单个NULL字节将被复制到目标缓冲区上方。这里由于目标缓冲区位于堆栈中,所以单个NULL字节可以覆盖存储在堆栈中的调用者的EBP的最低有效位(LSB),这可能导致任意的代码执行。

    (2)漏洞代码

    #include <stdio.h>
    #include <string.h>
    void foo(char* arg);
    void bar(char* arg);
    void foo(char* arg) {
     bar(arg); /* [1] */
    }
    void bar(char* arg) {
     char buf[256];
     strcpy(buf, arg); /* [2] */
    }
    int main(int argc, char *argv[]) {
     if(strlen(argv[1])>256) { /* [3] */
      printf("Attempted Buffer Overflow
    ");
      fflush(stdout);
      return -1;
     }
     foo(argv[1]); /* [4] */
     return 0;
    }
    

     编译文件

    (2)漏洞代码的第[2]行是可能发生off by one溢出的地方。目标缓冲区长度为256,因此长度为256字节的源字符串可能导致任意代码执行。如果调用者的EBP位于目标缓冲区之上,则在strcpy之后,单个NULL字节将覆盖调用者EBP的LSB。反汇编漏洞代码并绘制它的堆栈布局

    gdb-peda$ disassemble main
    Dump of assembler code for function main:
       0x08048497 <+0>:	push   ebp
       0x08048498 <+1>:	mov    ebp,esp
       0x0804849a <+3>:	push   edi
       0x0804849b <+4>:	sub    esp,0x8
       0x0804849e <+7>:	mov    eax,DWORD PTR [ebp+0xc]
       0x080484a1 <+10>:	add    eax,0x4
       0x080484a4 <+13>:	mov    eax,DWORD PTR [eax]
       0x080484a6 <+15>:	mov    DWORD PTR [ebp-0x8],0xffffffff
       0x080484ad <+22>:	mov    edx,eax
       0x080484af <+24>:	mov    eax,0x0
       0x080484b4 <+29>:	mov    ecx,DWORD PTR [ebp-0x8]
       0x080484b7 <+32>:	mov    edi,edx
       0x080484b9 <+34>:	repnz scas al,BYTE PTR es:[edi]
       0x080484bb <+36>:	mov    eax,ecx
       0x080484bd <+38>:	not    eax
       0x080484bf <+40>:	sub    eax,0x1
       0x080484c2 <+43>:	cmp    eax,0x100
       0x080484c7 <+48>:	jbe    0x80484e9 <main+82>
       0x080484c9 <+50>:	mov    DWORD PTR [esp],0x80485e0
       0x080484d0 <+57>:	call   0x8048380 <puts@plt>
       0x080484d5 <+62>:	mov    eax,ds:0x804a020
       0x080484da <+67>:	mov    DWORD PTR [esp],eax
       0x080484dd <+70>:	call   0x8048360 <fflush@plt>
       0x080484e2 <+75>:	mov    eax,0xffffffff
       0x080484e7 <+80>:	jmp    0x80484fe <main+103>
       0x080484e9 <+82>:	mov    eax,DWORD PTR [ebp+0xc]
       0x080484ec <+85>:	add    eax,0x4
       0x080484ef <+88>:	mov    eax,DWORD PTR [eax]
       0x080484f1 <+90>:	mov    DWORD PTR [esp],eax
       0x080484f4 <+93>:	call   0x8048464 <foo>
       0x080484f9 <+98>:	mov    eax,0x0
       0x080484fe <+103>:	add    esp,0x8
       0x08048501 <+106>:	pop    edi
       0x08048502 <+107>:	pop    ebp
       0x08048503 <+108>:	ret    
    End of assembler dump.
    gdb-peda$ disassemble foo
    Dump of assembler code for function foo:
       0x08048464 <+0>:    push   ebp
       0x08048465 <+1>:    mov    ebp,esp
       0x08048467 <+3>:    sub    esp,0x4
       0x0804846a <+6>:    mov    eax,DWORD PTR [ebp+0x8]
       0x0804846d <+9>:    mov    DWORD PTR [esp],eax
       0x08048470 <+12>:    call   0x8048477 <bar>
       0x08048475 <+17>:    leave  
       0x08048476 <+18>:    ret    
    End of assembler dump.
    gdb-peda$ disassemble bar
    Dump of assembler code for function bar:
       0x08048477 <+0>:    push   ebp
       0x08048478 <+1>:    mov    ebp,esp
       0x0804847a <+3>:    sub    esp,0x108
       0x08048480 <+9>:    mov    eax,DWORD PTR [ebp+0x8]
       0x08048483 <+12>:    mov    DWORD PTR [esp+0x4],eax
       0x08048487 <+16>:    lea    eax,[ebp-0x100]
       0x0804848d <+22>:    mov    DWORD PTR [esp],eax
       0x08048490 <+25>:    call   0x8048370 <strcpy@plt>
       0x08048495 <+30>:    leave  
       0x08048496 <+31>:    ret    
    End of assembler dump.

     

    (3)256字节的用户输入,用空字节可以覆盖foo的EBP的LSB。所以当foo的存储在目标缓冲区“buf”之上的EBP被一个NULL字节所覆盖时,ebp从0xbffff2d8变为0xbffff200。从堆栈布局我们可以看到堆栈位置0xbffff200是目标缓冲区“buf”的一部分,由于用户输入被复制到该目标缓冲区,攻击者可以控制这个堆栈位置(0xbffff200),因此他控制指令指针(eip )使用他可以实现任意代码执行。

    测试:可覆盖返回地址。

    (4)尝试找出ret_addr的值。

    将断点下在Breakpoint 2, 0x08048495 in bar ()处。运行查看内存情况

    可以看到EBP 的值从0xbffff158被覆盖成0xbffff100。EIP指向的是0xbffff104地址。EIP所指地址与buf之间需要填充172个A。

    尝试找出ret_addr的地址。

    (5)攻击代码

    不知道为何,尝试运行攻击代码失败了。但是直接在调试界面输入,可以获得普通用户的shell权限。

    由于无法解释的神圣旨意,我们徒然地到处找你;你就是孤独,你就是神秘,比恒河或者日落还要遥远。。。。。。
  • 相关阅读:
    IDEA 'Error:java: 无效的源发行版: 12' 解决方案
    E Golang语言之网络编程
    E 04 Golang语言之运算符
    ie表单提交提示下载文件
    日期初始化兼容
    IE8兼容问题总结---trim()方法
    es6变量声明和解构赋值
    js的call和apply拾遗
    prop&attr区别和用法,以多选框为例
    es6的箭头函数
  • 原文地址:https://www.cnblogs.com/momoli/p/10865324.html
Copyright © 2011-2022 走看看