从笔记中随机抽取一篇文章发一下,现在网上应该是没有qiling的fuzz资料的,我来一个成功的例子示范。
环境是tenda ac15
搭建环境 启动http服务后会在这里卡住,check一下二进制程序。
1 2 3 4 5 6 7 8 9 10 11 12 /bin # ./httpd init_core_dump 1816: rlim_cur = 0, rlim_max = -1 init_core_dump 1825: open core dump success sh: can't create /proc/sys/kernel/core_pattern: nonexistent directory init_core_dump 1834: rlim_cur = 5242880, rlim_max = 5242880 Yes: ****** WeLoveLinux****** Welcome to ...
跟踪字符串,猜测是这里的check_network函数的问题
1 2 3 4 5 v3 = puts("\n\nYes:\n\n ****** WeLoveLinux****** \n\n Welcome to ..."); sub_30A5C(v3); while ( check_network(v21) <= 0 ) sleep(1u); v4 = sleep(1u);
patch源文件 把r0寄存器改成#1即可
patch完会变成这样
1 2 3 4 Welcome to ... connect: No such file or directory Connect to server failed. connect cfm failed!
我们定位connect cfm failed!
字符串,然后继续patch。
patch完发现ip不对
我们可以找一下check_network
这个函数,可以发现在lib/libcommon.so
中
1 2 3 4 5 6 7 8 bool __fastcall check_network (int a1) { int LanIfName; LanIfName = j_getLanIfName(); return j_getIfIp(LanIfName, a1) >= 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const char *__fastcall get_eth_name (int a1) { const char *v1; switch ( a1 ) { case 0 : v1 = "br0" ; break ; case 1 : v1 = "br1" ; break ; ... case 55 : v1 = "br20" ; break ; default : v1 = (const char *)&unk_66C8; break ; } return v1; }
所以我们需要一张网卡是br0的,不然就会出现服务启动,但是无法连接的状况。
1 2 3 4 ip link add name br0 type veth peer name br0-peer ip addr add 192.168.3.3/24 dev br0 ip link set dev br0 up
此时ip正确了,但是看不到网站。去读启动项文件rcS可以看见cp -rf /webroot_ro/* /webroot/
,照做即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #! /bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin/ export PATH mount -t ramfs none /var/ mkdir -p /var/etc mkdir -p /var/media mkdir -p /var/webroot mkdir -p /var/etc/iproute mkdir -p /var/run cp -rf /etc_ro/* /etc/ cp -rf /webroot_ro/* /webroot/ mkdir -p /var/etc/upan mount -a ...
成功复现
qiling patch
诉苦:鬼知道我为了调试这个东西用了多久,最后鉴定为未来战士,现在底层写的太不完善了。为了调试这个东西真的把网上所有跟qiling相关的文章都看了一遍了,各种报错,各种出问题。
最后在不断的patch中,翻遍了qiling github上所有的issue,顺便找到了一个调完的师傅,终于把这个摸明白了。(找到的时候我已经把所有的坑都踩完了QAQ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 import os, socket, threadingimport syssys.path.append(".." ) from qiling import Qilingfrom qiling.const import QL_VERBOSEdef patcher (ql: Qiling ): br0_addr = ql.mem.search("br0" .encode() + b'\x00' ) for addr in br0_addr: ql.mem.write(addr, b'lo\x00' ) def nvram_listener (): server_address = 'rootfs/var/cfm_socket' data = "" try : os.unlink(server_address) except OSError: if os.path.exists(server_address): raise sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) sock.bind(server_address) sock.listen(1 ) while True : connection, _ = sock.accept() try : while True : data += str (connection.recv(1024 )) if "lan.webiplansslen" in data: connection.send('10.211.55.7' .encode()) else : break data = "" finally : connection.close() def myvfork (ql: Qiling ): regreturn = 0 ql.log.info("vfork() = %d" % regreturn) return regreturn def my_sandbox (path, rootfs ): ql = Qiling(path, rootfs,verbose=QL_VERBOSE.OFF) ql.add_fs_mapper("/dev/urandom" ,"/dev/urandom" ) ql.hook_address(patcher, ql.loader.elf_entry) ql.debugger = False if ql.debugger == True : ql.os.set_syscall("vfork" , myvfork) ql.run() if __name__ == "__main__" : nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True ) nvram_listener_therad.start() my_sandbox(["rootfs/bin/httpd" ], "rootfs" )
运行成功,其实我觉得这个东西还挺巧妙的,你从它patch的时候就能看出来(和我们手动patch不一样),但是我觉得这个多少有点给自己增加工作量,我可以用qeme+ida把固件基本上patch明白,用这个多少有点增加工作量。
打开web页面就看见程序崩溃了,原因是打开之后请求资源太多,虚拟的环境崩溃了
加一下内存也许就能跑了。
其余fuzz其实网上有很多资料了,麻烦的只有如何使用qiling将固件模拟起来,这里不过多赘述了。