Windows下堆栈溢出入门

二进制的学习首先从《黑手缓冲区溢出教程》一书开始,由于自己基础差,学习起来极其慢,这儿就先简单整理下本书第一章的一些重点知识。

一、缓冲区溢出

1. 缓冲区溢出原理

(1)缓冲区
计算机内部用于存放输入数据的临时空间。
(2)缓冲区溢出
缓冲区内填充数据,如果数据的长度很长,超过了缓冲区本身的容量,那么数据就会溢出存储空间,装不下的数据就会覆盖在合法数据上,这就是缓冲区溢出的道理。
(3)缓冲区溢出的利用
引导溢出的数据,使计算机执行我们想要的命令。

    注:理想情况下,程序检查每个数据的长度,并且不允许超过缓冲区的长度,但有些程序会假设数据长度总是与所分配的存储空间相匹配,而不去检查,从而为缓冲区溢出埋下隐患。

2. windows系统缓冲区溢出例子--报错对话框


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

    char name[] = "ww0830";
    int main(){
        char output[8];
        strcpy(output,name);

        for(int i=0; i < 8 && output[i]; i++)
	        printf("\\0x%x",output[i])

        return 0; 
    }

    分析:对于上述这个打印字符串"ww0830"的十六进制的程序,核心是strcpy函数,它的目的是将name变量的值复制给output变量,只给output变量分配了8个字节的空间,因此会出现隐患:当变量name的长度大于output的长度8时,复制后就会出现溢出情况,如下图所示:

    注:此报错信息只能在xp以及之前的系统出现,win7之后的系统报错的情况如下图所示(二者报错的具体原因都一样,只是表现形式不同):

3. 初识堆栈

(1)堆栈
计算机为了能回头继续处理原来的事情,需要把原来指令的指针EIP保存在堆栈中,当要回去原来的地方时,就把保存在堆栈中的EIP恢复即可。并且各个函数的局部变量的分配也是在堆栈中。
(2)中断
指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。
(3)堆栈规则
堆栈是一种数据结构,遵循 “先进后出,后进先出”的规则。操作系统中,存和取的动作是Push和Pop,Push放一个数据到堆栈中去,Pop取一个堆栈中的数据出来。

4. 缓冲区溢出的简单利用

缓冲区溢出利用的步骤:
(1)找到返回点定位
(2)ShellCode的编写
(3)把返回点覆盖成ShellCode的地址

5. 返回点覆盖方法

(1)NNNNNSSSSSRRRRR 型
此种方法适合于大缓冲区,"N"代表空指令,也就是0x90。在实际运行中,程序将什么也不做,而是一直沿着这些Nop运行下去,直到遇到不是Nop的指令再执行之;"S"代表ShellCode;"R"代表覆盖的返回地址,思路就是把返回地址R覆盖为Nop的大概位置,这样就会跳到Nop中,然后继续执行,直到ShellCode。
(2)RRRRRNNNNNSSSSS 型
此种方法是用大量的"R"填满整个缓冲区,然后大量的Nop,最后是ShellCode。这里“R”往后跳到Nops中,再顺着往下执行就会到ShellCode中。但在Windows下,“R”中必定会含有0,这样,整个构造就会被截断,只能用于Unix中。

    注:直观理解----方法(1)原理:这种是指在buffer区放置Nop和shellcode代码以及部分ret值,然后直到在EIP处被ret值所覆盖掉,这个ret值就指向buffer中的Nop区域,这样可以一直执行直到执行了shellcode,弹窗成功!(由buffer区到EIP处,然后又回到buffer区);方法(2)原理:这种就是在buffer区放置比shellcode地址高一些的某个固定地址值ret(这个固定值会指向Nop),直到覆盖掉EIP处,那个固定地址被Nop所覆盖,然后会一直读取直到读到shellcode,然后执行,弹窗!(由buffer区到EIP处,然后跳出到shellcode之前的Nop处)

6. 小知识

(1)ESP:栈指针(Extended stack pointer),用于指向栈的栈顶(下一个压入栈的活动记录的顶部)。
(2)EBP:扩展基址指针寄存器(extended base pointer) 其内存放一个指针,该指针指向系统栈最上面一个栈帧的底部。
(3)EIP: 用来存储CPU要读取指令的地址,CPU通过EIP寄存器读取即将要执行的指令。
(4)Windows 通过动态链接库(dll)来提供系统函数。
(5)Windows下堆栈的分配是从高地址往低地址分配的。
(6)二进制漏洞:二进制文件(如PE文件、ELF文件等)中存在的漏洞。

二、漏洞认识及利用

1. 漏洞认识及利用的一般步骤

(1)查看漏洞公告
① 首先要注意是什么程序、它的什么版本有漏洞。找出有问题的的版本,就安装上相应的版本,写出对它的溢出攻击程序;
② 给出大概的问题分析,查看有问题的是某个PE文件(如punylib.dll)。在安装目录的子目录下发现它;
③ 给出漏洞的解决办法或补丁下载。
(2)查看漏洞分析报告
漏洞公告是不会给我们说如何利用漏洞的。所以除了查看漏洞公告,我们还要查找其他人或安全组织的相关漏洞分析报告。
(3)写漏洞利用程序(如缓冲区溢出漏洞)(标准缓冲区堆栈溢出利用的标准方法)
要成功利用缓冲区溢出需要的三个条件:
① 有问题程序返回点的精确位置――我们可以把它覆盖成任意地址;
② ShellCode――一个提供给我们想要的功能的代码;
③ JMP ESP的地址――把返回点覆盖JMP ESP的地址,这样可跳入ShellCode。

2. 通用的JMP ESP地址

中文版Win2000、XP、Win2003的JMP ESP通用跳转地址(lion给出的0x7ffa4512)

3. 精确定位有问题程序返回点的方法

(1)先用大字段的字符串覆盖buffer区,使出现read或者write错误,当出现write错误时,意味着覆盖的过多,导致一些参量地址被覆盖;
(2)再采用二分法,直到错误类型改为read类型,接下来定位返回点的位置;
(3)使用缓冲区字符串的填入方法:
① buffer[i] = "A" + i % 10 取余数,字符串会在 A-J (0x41-0x50)之间循环;
② buffer[i] = "A" + i / 10 取整除的数, 字符串会以 AAAAAAAAAABBBBBBBBBBCC...这种形式存在,每10个后出现下一个字母。
这样结合两种就可以定位到程序返回点的位置。比如:① 报错 4A494847,② 报错 5A5A5A5A,那么返回点的位置就是:(0x5A-0x41)*10+(0x47-0x41) = 256 那么从第257个字段开始的位置为返回点位置。

4. 小知识

(1)EAX : "累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
(2)EBX : "基地址"(base)寄存器, 在内存寻址时存放基地址。
(3)ECX : "计数器"(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
(4)EDX : 用来放整数除法产生的余数。
(5)EBP : "基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer)。

三、总结

本书的第一章利用几天时间看完了,主要讲的是windows下缓冲区溢出漏洞的原理、利用方法以及漏洞利用返回点的定位等。通过几天的学习,自己对于二进制漏洞的基本知识有了初步认识,并且知道了什么是缓冲区漏洞,简单认识了汇编语言、基本指令、几个基本寄存器等。这算是给二进制学习打了个头,有了个直观的认识。但是在学习的过程发现一些问题:
(1)第一次接触二进制,第一次接触这本书,发现书中的知识点多而且杂,看了一遍之后发现并没有记住多少,后续学习需要反复看,经常回头复习;
(2)文章中给到很多漏洞实例,例如Foxmaiil,Printer,IIS等的早期漏洞,只看书本上讲的理论认识不够充分,确实需要实践来发现问题,目前因为一些设备原因无法实践,后期有条件了都需要动手操作,复现漏洞;
(3)自己底子差,对于很多不理解的知识需要多百度,多花时间去学习。
学习二进制知识有几天时间了,希望在后面的日子里自己能脚踏实地,一步一个脚印,不气馁,不浮躁,争取学到肚子里......

posted @ 2018-08-04 23:55  ma_nu  阅读(1853)  评论(0编辑  收藏  举报