这是一种技术,并非漏洞本身。可以用于大部分的二进制漏洞当中的技术,举个例子,写入shellcode的偏移量可能会因为系统原因而产生一些不同,但是漏洞确实存在,这个时候传统的通过偏移跳转shellcode的方式就不再稳定,或者,如之前我在SEH溢出当中提到的部分,也许数据发送成功了,但是数据位置,距离当前位置很远,传统模式我们就需要先手动去查找计算这个部分。EggHunter这个技术就是解决上述这类问题的。假设有一个程序的代码如下:这个溢出发生在LogError ,但是由于 B区域缓冲区大小只有64,但是strcpy不管不顾的把 A*10000都写入这个部分,能不能写入不重要,重要的是,这个部分一定会崩溃。此时,首先要确认,这个部分崩溃以后,到底溢出了多少。假设这里溢出过后,发现B区域后续有1000字节的空间,那么就不用egg hunter技术了,直接写shellcode即可。但是更多的情况是,这10000个A只有很少一部分在溢出过后在区域B当中,比如只有100个A写进来了,后续的空间会因为权限或是其他原因根本没办法动,如何在这100个A的空间内想办法精准的跳到Full_Requests_Store当中的shellcode部分,就是egg hunter解决的问题。内存图大概是这样简单总结下原理,就是在shellcode之前放一串特定字符串,然后在内存当中搜索这个字符串,找到这个字符串以后,跳转到这里,就能够实现精准跳转shellcode了。Egg Hunter 的精髓在于:它利用系统调用 (Syscall) 或 异常处理机制 (SEH) 来判断一个内存地址是否可读。这个在接下来这个漏洞分析当中会详细说明。详细原理可以参考这个论文:egghunt-shellcode.pdf由于 Egghunter 通常用于可用空间受限的场景,所以它的代码设计得尽可能小巧精炼。此外,扫描速度非常关键 —— Egghunter 越快找到目标标签,应用程序就越不容易出现长时间挂起或崩溃的现象。因为手动读未映射的内存会直接崩溃程序,而系统调用访问时:漏洞链接:CVE-2002-1120:Savant Web Server 3.1 及更早版本中的缓冲区溢出允许远程攻击者Savant Web Server 3.1 及更早版本中的缓冲区溢出允许远程攻击者通过较长的 HTTP GET 请求执行任意代码。这个漏洞的溢出,不是单纯的溢出,Savant Web Server 3.1 的这个漏洞只有在进行 URL 解码(%xx 解码)时才会触发栈溢出。当 HTTP 请求的路径中出现 % 字符时,服务器会尝试对后面的两个十六进制数字进行解码,并把解码后的字节写入一个固定大小的栈缓冲区,这个过程没有边界检查,才导致了溢出。非常符合我们对于当前技术的研究背景。OK,来写一个初始的Poc程序加载windbg,可以很清楚的看到此时eip被A覆盖,但是查看栈顶(esp)会发现,溢出的位置并不像是常规的溢出
继续分析这个情况,查看esp,首先eip目前被A覆盖,然后发现esp + 4的位置实际上就是指向 Payload的指针(地址),可以清楚的看到这个地址当中存放了完整的发送的数据。
这个输出就是在概念部分举的例子,回顾伪代码接下来,我们需要找到eip的位置加载到windbg当中会发现,坏字符引发崩溃二分法解决这个问题加载windbg,可以看到在B的部分
然后循环往复找到这个位置,在253这里加载windbg验证
这里我想到的处理逻辑比较简单,既然esp + 4存放的地址指向的是我整个发送的payload那么我先测试坏字符,测试完坏字符以后,再利用有序字符串查找位置。然后修改exp逐行测试坏字符,建议先注释一半,然后循环查找。程序应该会在第一行就“滑过去”,因为是Web服务,所以\x0a大多数情况下都会是坏字符,再排除一个\x0d这两个都是换行,\x0d是回车,基本上大部分的web服务对这两个字符都会敏感的。稍微提一下,在一些特定环境当中\x0a甚至可以当作sql注入的注释符平替。然后还有之前就遇到过的\x25百分号,这个符号在web服务当中也极其危险,所以手动先把这些排除掉。修改坏字符测试然后加载windbg,可以观察到,所有字符显示正常,说明除了手动排除的那几个字符,其他字符都安全
再次验证eip位置,生成一个字符串。基于对漏洞原理的理解,所以我们需要在生成的字符串前面加一个\x25来让漏洞触发加载到windbg,然后查询35694134查看位置,254 减去 手动添加的一个 \x25还是253 重复验证了eip的位置加载narly可以看到,这个程序几乎没有自带的dll,所以一切就只能从这个程序本身想办法解决。
程序本身的地址范围当中包含\x00 ,常规情况下,应该寻找安全地址的dll来利用,但是分析这个程序的崩溃,可以发现一个很巧妙的事情,eip之后的部分,默认就是\x00。可以通过只写入3个字节的地址,然后让程序本身自动补齐\x00的方式解决这个问题。加载到windbg查看,eip和预期一样变成了00424242,那也就是说可以构造eip让他指向程序本身当中的某个可用的地址。
到此为止,剩下要解决的就是如何跳转到esp + 4的位置,这个位置存放着一个地址,这个地址里面放着发送过去的完整payload,那么首先最好的选择肯定是jmp这样的跳转指令需要一个jmp [esp + 4]。可惜这样的指令本身就特别罕见,尤其是目前的程序并不大,只是一个小程序就更不太可能有这样的指令了。所以,还是需要PR系列的指令,选择一个其余三位不包含坏字符的地址比如0x00418674这个就可以。修改代码加载windbg验证,eip成功指向esp + 4的位置,成功跳转
分析windbg的输出,\x47对应字符G也就是请求方法的部分(GET),尝试修改这个部分,可以观察到这中间有24字节的可写部分。必须要保持这个结构,GET / 或者 xxxx /简而言之就是,/这个字符必须存在。修改代码加载windbg,可以看到,这个部分,是可以写一部分指令进去的。
接下来需要让执行流顺利的走到inputBuffer处,修改一下代码查看windbg,重点在于,完全没有在预期当中看到写入的跳转指令,跳转指令被替换成了\x3f 也就是aas指令。在较老的系统版本当中EB会被换成retf,这是字符编码的问题,是一个关于坏字符的问题。Savant这个程序的内部处理逻辑是分裂的:结论:\xeb 在“URL路径”里是好人,但在“HTTP Method”里就是坏人。这就是所谓的上下文相关坏字符。这就是为什么不同版本的 Windows 表现不同是默认的语言包/代码页设置不同,最终会导致这里的jmp被转换成不同的东西。既然知道了无法跳转的原因,处理这个问题也很简单,用条件跳转即可,jz/je之类的跳转。空间上有24字节左右的大小,足够写一个条件跳转。把上述这个条件跳转放进HTTP请求方法的部分当中去加载windbg,一切符合预期,成功跳转到预想的部分。
开始之前,首先需要知道shellcode在什么位置,因为很显然,剩下的这些空间肯定不够写入shellc
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289666.htm
[原创] Egg Hunter 技术详解
444 浏览
8 回复
感谢分享
感谢分享
感谢分享
为你点赞!
为你点赞!
为你点赞!
感谢分享
感谢分享