使用GDB调试软路由
Monitor
选项中输入gdbserver
,默认情况下即可开启gdbserver,监听服务器的1234端口。extract-vmlinux boot/vmlinuz > /tmp/vmlinux
。gdb /tmp/vmlinux
。target remote x.x.x.x:1234
。0xFFFFFFFFxxxxxxxx
,该地址为内核地址,然后在gdb界面输入continue
,让其继续运行。execve("/bin/sh", ["/bin/sh","-c","/usr/sbin/telnetd -l /bin/sh -p xxxxx"], 0)
命令(当然已经确定了存在telnetd
,和其路径)。0x00: /bin/sh\x00
0x08: -c\x00
0x10: cmd
0x100: 0x00
0x108: 0x08
0x110: 0x10
0x118: 0
mov rdi, 0x00
mov rsi, 0x100
xor rdx, rdx
xor rax, rax
mov al, 59
syscall
set *0x00=xxxx
set *0x04=xxxx
......
set $rdi=0x00
set $rsi=0x100
set $rdx=0
set $rax=59
set *((int *)$rip)=0x050F(syscall)
ping
),然后按ctrl+c
,中断程序运行,重复N次,如果不是运气不好的情况下,会很快断在一个地址开头不是0xffffffff
的地址,这就是用户态程序的地址空间了。pc
值为syscall
指令,再输入contiune
,系统就会运行你想执行的命令了。/bin/bash
的程序段,或者是libc
的程序段,当修改代码段的代码时,不会像平常调试普通程序那样,修改的只是映射的内存代码,当程序退出后,修改的代码随同映射的内存一起释放了。当一个新的bash
程序运行时,内存重新进行了映射,所以使用gdb修改当前程序的上下文,并不会影响到之后运行的程序。但是在调试内核的时候,进入用户态后,访问到的是该程序的真正内存区域,代码一经修改,除非系统重启,不然每次运行相同的程序,都将会运行修改后的代码。/bin/bash
代码段的指令,执行了/bin/sh -c "/usr/sbin/telnetd -l /bin/bash"
命令之后,bash
这个程序实际的代码已经被破坏了,所以在该命令成功开启了telnet
服务后,每当有用户连接这个telnet
服务,根据bash
程序代码被破坏的程度,程序将会有不同的异常(运气好,破坏的代码不重要,则不会影响到后续使用。运气不好,破坏的代码很重要,则可能无法再运行bash
程序)。? ~ telnet 10.11.33.115 33333
Trying 10.11.33.115...
Connected to 10.11.33.115.
Escape character is '^]'.
bash-4.4# id
Connection closed by foreign host.
telnet
服务,服务的banner正常显示,但是当执行id
命令时,telnet
服务却断开了连接,按照上述的分析,猜测是bash
程序被修改的代码段位于bash
程序处理用户输入的命令的函数中,所以当用户想执行id
命令时,程序将会奔溃,导致telnet
服务断开连接。libc
的程序段,那将会造成更严重的后果,不仅是telnet
服务甚至是操作系统的其他服务,运行到该libc
的代码时,都会崩溃导致程序异常。telnetd -l /bin/sh
,用户连接到telnetd
服务,执行命令时,将不会出现异常导致连接断开。不过这种方法治标不治本,只作为应急使用。一键操作
arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes
──────────────────────────────────────────────────────────────────
arm/OABI a1 a2 a3 a4 v1 v2 v3
arm/EABI r0 r1 r2 r3 r4 r5 r6
arm64 x0 x1 x2 x3 x4 x5 -
blackfin R0 R1 R2 R3 R4 R5 -
i386 ebx ecx edx esi edi ebp -
ia64 out0 out1 out2 out3 out4 out5 -
mips/o32 a0 a1 a2 a3 - - - See below
mips/n32,64 a0 a1 a2 a3 a4 a5 -
parisc r26 r25 r24 r23 r22 r21 -
s390 r2 r3 r4 r5 r6 r7 -
s390x r2 r3 r4 r5 r6 r7 -
sparc/32 o0 o1 o2 o3 o4 o5 -
sparc/64 o0 o1 o2 o3 o4 o5 -
x86_64 rdi rsi rdx r10 r8 r9 -
x32 rdi rsi rdx r10 r8 r9 -
arm/OABI swi NR - a1 NR is syscall #
arm/EABI swi 0x0 r7 r0
arm64 svc #0 x8 x0
blackfin excpt 0x0 P0 R0
i386 int $0x80 eax eax. 0x80CD
ia64 break 0x100000 r15 r8 See below
mips syscall v0 v0 See below
parisc ble 0x100(%sr2, %r0) r20 r28
s390 svc 0 r1 r2 See below
s390x svc 0 r1 r2 See below
sparc/32 t 0x10 g1 o0
sparc/64 t 0x6d g1 o0
x86_64 syscall rax rax See below 0x050F
x32 syscall rax rax See below
execve
的系统调用号:execve:
arm64/h8300/hexagon/ia64/m68k/nds32/nios2/openrisc/riscv32/riscv64/c6x/tile/tile64/unicore32/score/metag: 221
arm/i386/powerpc64/powerpc/s390x/s390/arc/csky/parisc/sh/xtensa/avr32/blackfin/cris/frv/sh64/mn10300/m32r: 11
armoabi: 9437195
x86_64/alpha/sparc/sparc64: 59
x32: 1073742344
mips64: 5057
mips64n32: 6057
mipso32: 4011
microblaze: 1033
xtensa: 117
@register_commandclass 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_) _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()] # 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 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 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) if "patterns found." not in res: err("can't find syscall. Please break in libc.") return newpc = res.splitlines()[0] endian_symbol = endian_str() endian = "little" if endian_symbol == "<" else "big" 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) 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 endian = "little" if endian_str() == "<" else "big" 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 dofunc("set %s=%s"%(sysreg, sysreg_value)) # set $pc=$sp dofunc("set $pc=%s"%newpc) # set *$pc # dofunc("set *(int *)$pc=%s"%hex(syscall_instr)) # show context # dofunc("context") # continue dofunc("c") return
总 结
往 期 热 门
(点击图片跳转)
开发 Kunyu(坤舆) 的心路旅程
Kunyu(坤舆)-基于 ZoomEye API 的高效信息收集工具
Rocket.Chat 远程命令执行漏洞分析