HTB – debugging with GDB/pwntools

>LC_ALL=en_US.UTF-8 gdb -q [elf]
>gdb -q [linux exec]
>break main
>break *0x565564e3
>attach [pid]
>sudo gdb -q --args php -a
Debug with php interactive shell
>r
(r means run)
Starting program: /usr/bin/php -a
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Interactive shell

php > dl('lverifier');
Debug the php extension so file

Crtl-c can pass the control back to gdb
(gdb)....

Set the break point at function or at the specific address. Use attach to debug the existing process, then nexti to find a good place to start the debugging.

>run
>continue
>nexti
>stepi
>fin

fin →step out. nexti runs the call(). stepi dives into call() →able to check each opcode
run →start the code. continute → continue the debugging

>set $ps=$ps|0x40
>set $ps=$ps & ~0x40
>print $ps

set $ps=$ps|0x40 → set Zero Flag bit(to alter the flow)
set $ps=$ps & ~0x40→ reset Zero Flag bit. use print to check the status of $ps

>set $eax=0
>set *[addr] = 0x90
>set *[addr] = 0x88

alter the value in register by set. We can also alter the flow by set the next instruction to
0x90 = NOP
0x88 = JS
0x85 = JNE

>info registers $EAX
>info registers
>info breakpoints
>info functions
>i b
>del [# of breakpoint]

Inspect the value in registers. List the breakpoints you set. Delete the breakpoint.
“i b” is the short representation of “info breakpoints”

>x/s [reg/address]
>x/32xb [reg/address]
>x/64xb [reg/address]

x/s [address] → Check value at the address
32xb means show the first 32 bytes. x/s means show the values by string.

difference between x/s and x/32xb

CyberChef can help on decode hex values to readable strings

>watch *[addr]
>rwatch *[addr]
>awatch *[addr]

watch only breaks on write(and only if the value changes)
rwatch breaks on read
awatch breaks on read/write

Basic Ideas when debugging

  • Online tools can help. For example https://dogbolt.org can provide decompiled source code by BinaryNinja, Ghidra, Hex-Rays, angr
  • Spy on the standard functions. For example the buffer parameter in write(), read() or recv() can find something interesting.
  • accept() is waiting for socket connection

More GDB info. https://reverse.put.as/wp-content/uploads/2011/03/gdbreferencecard.html

Spot the pos that buffer overflow

>pattern_create 500
>pattern_offset AAdAA3AA

Use pattern_create to locate the offset of buffer overflow

input the created pattern then observe the registry

>x/100x $sp

Show stack memory

Pwntools

>ulimit -S -c unlimited
>ulimit -c 
unlimited
>sudo sysctl -w kernel.core_pattern=core
>cat /proc/sys/kernel/core_pattern
core

setup core dump when application crashed in linux

#! /usr/bin/python3
from pwn import *
binary_file = './leak'
context(arch='amd64')

elf = ELF(binary_file)
p = process(binary_file)

print(p.recvline())
pattern = cyclic(1024)
p.sendline(pattern)

time.sleep(1)

core = Coredump("./core")
seg_addr = int("0x" + hex(core.fault_addr)[10:], 16)
log.success(f"Coer fault address at: {hex(core.fault_addr)}")
log.info(f"Finding offset for: {hex(seg_addr)}")
offset = cyclic_find(seg_addr)
log.success(f"Offset found at: {offset}")

Run the script to get the offset that trigger the buffer overflow

>cyclic 50
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama

Create pattern to spot the offset

Decode the hex values in stack

#!/usr/bin/env python3

from pwn import *
import re

#Have to process it by reverse manner. e.g. fc 0a a9 ff f4 0a a9 ff.....
raw_flag = "0x57e021c0 0x170 0x56648dfa 0x33 0x7 0x26 0x2 0x1 0x5664996c 0x57e021c0 0x57e02340 0x7b425448 0x5f796877 0x5f643164 0x34735f31 0x745f3376 0x665f3368 0x5f67346c 0x745f6e30 0x355f3368 0x6b633474 0x7d213f 0x1247c600 0xf7f003fc 0x5664bf8c 0xffa90a48 0x56649441 0x1 0xffa90af4 0xffa90afc"

#raw_flag = input("Enter the raw data: ")

#reversed copy of the array
raw_flag = raw_flag.split()[::-1]
print(raw_flag)

for i in range(len(raw_flag)):
    #. means any single char so .. means pick up any 2 char 
    raw_flag[i] = re.findall('..', raw_flag[i])
print("===========================================")
print(raw_flag)

flag = []
for chars in raw_flag:
    word = ""
    #read the item in array reversely
    for char in chars[::-1]:
        if char != '0x':
            word += chr(int(char, 16))
    flag.append(word)
#print(flag)
flag.reverse()
print("===========================================")
print(flag)

GDB Server + pwntools

>sudo apt-get install gdbserver

Install gdb server for the remote debugging

#! /usr/bin/python3
from pwn import *
binary_path = './leak'
context(arch='amd64')

elf = context.binary = ELF(binary_path)

#elf = ELF(binary_file)
#p = process(binary_file)

address_of_main = elf.symbols['main']

offset = 72
#print(hex(address_of_main))

io = gdb.debug(binary_path, '''
   break main
''')

payload = [
    b"1"*offset,
    p64(address_of_main)
]
print(payload)
print(io.recvuntil("> ").decode().rstrip())

io.sendline(b"".join(payload))

Call gdb.debug to use the remote gdb server to debug the crafted payoad

Common cmds

>readelf -s elf

Check symbol table in elf

Registers

EIP: next instruction
RSP: stack pointer, keep the lowest stack address

關於作者

Nelley,乃力。
就是一個村民。