Ret2Libc 练习(1) -- ZwSetInformationProcess
花了两个小半晚上的时间将0day安全这本书的绕过DEP的第一个实验做了,这里做些笔记。
Ret2libc 我现在自己的理解就是在开启DEP保护的情况下,在程序的其他的可执行位置找到可以满足我利用要求的指令,形成一个可执行的指令序列,达到成功执行shellcode的目的。
那么利用Ret2libc的第一个方法就是通过ZwSetInformationProcess函数,这个API可以直接将进程中的DEP保护关闭,执行shellcode。
首先需要了解的是一个进程的DEP标识是在KPROCESS结构中的_KEXECUTE_OPTIONS中,_KEXECUTE_OPTIONS的具体结构是这样子的:
标识位的前4bit和DEP相关,当DEP开启Pos0置1,DEP关闭Pos1置1,Pos3置1表示标识位都不能修改,所以影响DEP状态的是前2位,只需要设置成00000010就可以。
接下来是ZwSetInformationProcess函数:
ZwSetInformationProcess函数的第一个参数显而易见是进程的句柄,设置为-1的时候标识当前进程,第3个参数是用来设置_KEXECUTE_OPTIONS的,只需要这个参数二进制值最后两位是01即可,第四个参数是第三个参数的长度。
接下来是具体的实验步骤:
根据书上的指导,用了OllyFindAddr这个插件,Disable DEP -> Disable DEP<==XP SP3搜索,不太清楚为什么是从这里开始而不是直接跳到ZwSetInformationProcess函数的入口,这里留个疑问,用了这个插件OD搜索到的地址同样是0x7c93cd24, 指向的汇编指令是CMP AL,1,所以为了满足这个判断条件,第一步是找到将AL赋值为1的指令,所有 的MOV EAX,0x1 ; MOV AL,1 理论上都可以,这里我用了ID的mona插件,查找到相应的指令的地址就ok,为了稳妥,选用了和书上一样的地址,所以我的ROP链现在是这样 :
"\x52\xe2\x92\x7c" // MOV AL,1 "\x24\xcd\x93\x7c" // 关闭DEP的起始地址
当然ROP链会根据出现的情况进行调整,接下来正如同书上写的情况同样,运行到对EBP-4这个地址写数据的时候出现异常了,原因是之前的字节覆盖了EBP-4这个地址内容,所以程序写入了一个无效的地址,需要修正EBP,然后运行到此查看各个寄存器的值,发现ESP的值适合赋给EBP,所以查找PUSH ESP; POP EBP; RETN的指令,修正ROP是这样:
"\x52\xe2\x92\x7c" "\x85\x8b\x1d\x5d" //修正EBP "\x24\xcd\x93\x7c"
继续运行,在CALL ZwSetInformationProcess处下断点,观察ZwSetInformationProcess的参数情况,也就是注意ZwSetInformationProcess用来设置_KEXECUTE_OPTIONS的第三个参数,这里刚刚好是0x22(00100010),最末两位是01,不需要对其进行修改。继续往下走,走到0x7c93cd6f, RETN 4 这个地方,此时ESP的值指向的地址是0x00000004, 这是之前ZwSetInformationProcess函数的参数压栈的结果,所以在修正EBP以后,要对ESP进行修正,防止影响ROP。
然后根据书上的方法找到RETN 0x28这个指令的地址,所以现在的ROP是这样:
"\x52\xe2\x92\x7c" "\x85\x8b\x1d\x5d" "\x19\x4a\x97\x7c" // 增大ESP "\x24\xcd\x93\x7c"
但是这样的问题是由于RETN 0x4的偏移的原因导致堆栈是这样的:
ESP应该指向0x7c93cd24跳到关闭DEP的代码但是指向了堆栈的下一个,所以ROP修改为:
"\x52\xe2\x92\x7c" "\x85\x8b\x1d\x5d" "\x19\x4a\x97\x7c" "\x90\x90\x90\x90" "\x24\xcd\x93\x7c"
这样就可以保证在增大ESP以后,程序进入关闭DEP代码的流程。
接下来程序会顺利进入到关闭DEP代码,然后一直往下走,走到0x7c93cd6f这个地方,这时候发现ESP指向了之前用4个90填充的堆栈,这时候很显然,在执行0x0013febc这个指令地址以后,ESP会跳到0x0013fec4这个堆栈地址,显然,0x0013febc我们就可以放入jmp esp的指令地址,然后代码跳到0x0013fec4,这时候仔细观察堆栈我们可以发现有176个字节的shellcode离0x0013fec4这个地方有200个字节远,所以最后在0x0013fec4这个地方放上回跳200个字节的指令就可以了,因为此时DEP已经被关闭,所以堆栈可以放上可执行的代码。
最后的ROP链:
"\x52\xe2\x92\x7c" "\x85\x8b\x1d\x5d" "\x19\x4a\x97\x7c" "\xc7\x31\x5a\x7d" "\x24\xcd\x93\x7c" "\xe9\x33\xff\xff" "\xff\x90\x90\x90"
几个小tips:
1. 汇编中LEAVE指令相当于 mov esp,ebp ; pop ebp
2. 最后的回跳指令在VC6中提取出回跳200字节的机器码
2015/9/21
23:41
posted on 2015-09-21 23:42 bongbongbong 阅读(753) 评论(0) 编辑 收藏 举报