gdb固件提取插件

修了个小bug,方便提取固件使用

iot类一键获取shell

gef插件代码

原作者的插件代码并没有完全公开,缺少了很多,也可能是由于版本适配问题,以下是修改过的最新代码。

底层原理见参考资料,使用时注意吧断点全部清除。如果gef用不习惯可以移植pwndbg,只需要更改gdbinit即可

1
2
source /home/pisanbao/pwndbg/gdbinit.py
source ~/gef.py

这样就能在gef中使用一些pwndbg定义的命令了后面在source一下插件代码正常使用即可,其中patterns found可能会出现小bug在只找到一个pattern的时候就不是patterns是pattern

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
class ExecveCommand(GenericCommand):
"""use execve do anything cmd"""
_cmdline_ = "execve"
_syntax_ = "{:s} [cmd]|set addr [address]".format(_cmdline_)
_example_ = "{:s} /usr/sbin/telnetd -l /bin/bash -p 23333\n{:s} set addr 0x7fb4360748ae".format(_cmdline_, _cmdline_)

_aliases_ = ["exec",]
def __init__(self):
super().__init__(complete=gdb.COMPLETE_FILENAME)
self.findAddr = None
return

@only_if_gdb_running
def do_invoke(self, argv):
'''
mips/arm todo
'''
if len(argv) > 0:
if argv[0] == "debug":
# debug = 1
dofunc = print
argv = argv[1:]
elif argv[0] == "set":
if argv[1] == "addr":
self.findAddr = int(argv[2], 16)
info("set success")
return
else:
# debug = 0
dofunc = gdb.execute
else:
err("The lack of argv.")
return
cmd = " ".join(argv)
cmd = [b"/bin/sh", b"-c", cmd.encode()]
current_arch = gef.arch
# print(current_arch.sp)
# print(current_arch.pc)
# print(current_arch.ptrsize)
# print(endian_str())
# print(current_arch.syscall_instructions)
# print(current_arch.syscall_register)
# print(current_arch.special_registers)
# print(current_arch.function_parameters)
# print(current_arch.arch)
# print(current_arch.get_ith_parameter)
# print(current_arch.gpr_registers)
# print(current_arch.get_ra)
# write_memory

inferior = gdb.selected_inferior()
write_memory = inferior.write_memory

try:
rsp = current_arch.sp
nowpc = self.findAddr or current_arch.pc
except gdb.error as e:
err("%s Please start first."%e)
return
bit = current_arch.ptrsize
print(f"current_arch.ptrsize={current_arch.ptrsize}")
if current_arch.arch == "X86":
arg0 = "$rdi" if bit == 8 else "$ebx"
arg1 = "$rsi" if bit == 8 else "$ecx"
arg2 = "$rdx" if bit == 8 else "$edx"
sysreg = current_arch.syscall_register
sysreg_value = 59 if bit == 8 else 11
syscall_instr = 0x050F if bit == 8 else 0x80CD
else:
err("%s can't implementation." % current_arch.arch)
return
spc = nowpc & (~0xFFF)
res = gdb.execute("find /h %s,%s,%s"%(spc, spc+0x10000, syscall_instr), to_string=True)
print(f"syscall addr={res}")
if "patterns found." not in res:
err("can't find syscall. Please break in libc.")
return
newpc = res.splitlines()[0].split(' ')[0]
print(f"newpc addr={newpc}")
endian_symbol = endian_str()
endian = "little" if endian_symbol == "<" else "big"
print(f"endian_symbol={endian_symbol}")
startaddr = rsp + 0x100
args_list = []
# cmd write to stack
for cstr in cmd:
args_list.append(startaddr)
cstr += b"\x00" * (4 - (len(cstr) % 4))
length = len(cstr)
#print(f"i am here~~~{cstr}")
write_memory(startaddr, cstr, length)
startaddr += length
# for i in range(0, len(cstr), 4):
# t = hex(struct.unpack(endian_symbol+'I', cstr[i:i+4])[0])
# dofunc("set *(%s)=%s"%(hex(startaddr), t))
# startaddr += 4
args_list.append(0)
# set cmd point (rsi)
rsiAddr = rsp + 0x50
addrvalue = b""
for addr in args_list:
addrvalue += addr.to_bytes(bit, endian)

write_memory(rsiAddr, addrvalue, len(addrvalue))
# for i in range(0, len(addr), 4):
# t = hex(struct.unpack(endian_symbol+'I', addr[i:i+4])[0])
# dofunc("set *(%s+%d)=%s"%(hex(rsiAddr), i, t))
# rsiAddr += bit

# set first arguments.
dofunc("set %s=%s"%(arg0, hex(args_list[0])))
# set second arguments
dofunc("set %s=%s"%(arg1, hex(rsp + 0x50)))
# set third arguments
dofunc("set %s=0"%arg2)
# set syscall register
print(f"i am here now~~~")
dofunc("set %s=%s"%(sysreg, sysreg_value))
# set $pc=$sp
print(f"i am here~~~{newpc}")
dofunc("set $pc=%s"%newpc)
print(f"i am here~~~")
# set *$pc
# dofunc("set *(int *)$pc=%s"%hex(syscall_instr))
# show context
# dofunc("context")
# continue
dofunc("c")
return

register_external_command(ExecveCommand())

最终效果如下,注意调试时要gdb aaa,aaa是vmlinuz转换成的文件

可以使用vmlinux-to-elf或者extract-vmlinux或者binwalk强行提取

image-20230526193258763

参考资料

https://paper.seebug.org/1660/


gdb固件提取插件
http://www.psbazx.com/2023/06/12/gdb固件提取插件/
Beitragsautor
皮三宝
Veröffentlicht am
June 12, 2023
Urheberrechtshinweis