Don't Panic!
Don't Panic!
Platform: HackTheBox | Category: Reversing | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-01-28 | Status: Solved Techniques: character_validation_reverse, function_pointer_tracing, rust_binary_analysis
Summary
Task: Reverse engineer a Rust ELF binary with custom panic handling. Solution: Traced function pointer array in check_flag function to reconstruct the flag character by character.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
hackthebox| ID:20260128_hackthebox_dontpanic - Tags: static_analysis, elf, rust, function_pointers
- Indicators: Rust binary, panic messages, function pointer array, character-by-character validation
- Source:
20260128_hackthebox_dontpanic.md
Foothold
Vulnerability / Misconfiguration
- Character_validation_reverse
- Function_pointer_tracing
- Rust_binary_analysis
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- character_validation_reverse
- function_pointer_tracing
- rust_binary_analysis
- Tags: static_analysis, elf, rust, function_pointers
Original Writeup
<details><summary>Click to expand original content</summary>Description
"Don't Panic! You've cut a deal with the Brotherhood; if you can locate and retrieve their stolen weapons cache, they'll provide you with the kerosene needed for your makeshift explosives for the underground tunnel excavation. The team has tracked the unique energy signature of the weapons to a small vault, currently being occupied by a gang of raiders who infiltrated the outpost by impersonating commonwealth traders. Using experimental stealth technology, you've slipped by the guards and arrive at the inner sanctum. Now, you must find a way past the highly sensitive heat-signature detection robot. Can you disable the security robot without setting off the alarm?"
Analysis
Initial Reconnaissance
Downloaded and extracted the challenge file, revealing a Rust ELF 64-bit binary called dontpanic.
$ file dontpanic dontpanic: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked
String Analysis
Found interesting strings that hint at the challenge theme:
$ strings dontpanic | grep -i rust RUST_BACH $ strings dontpanic | grep -i panic You made me panic! $ strings dontpanic | grep -i message Have you got a message for me?
The "RUST_BACH" and panic-related strings confirm this is a Rust binary with custom panic handling.
Symbol Analysis
Using nm to find key functions:
$ nm dontpanic | grep -E "(check|main)" 0000000000009060 t _ZN3src10check_flag17h397d174e03dc8c74E 0000000000009230 t _ZN3src4main17hf9bc229851763ab9E
Key functions identified:
check_flagat 0x9060 — the flag validation functionmainat 0x9230 — program entry point
Disassembly of check_flag
The check_flag function implements a clever validation scheme:
- Length Check: Expects input of exactly 31 characters (0x1f)
- Function Pointer Array: Creates an array of 31 function pointers on the stack
- Iteration: For each input character, calls the corresponding function pointer
- Validation: Each function checks if the character matches a specific expected value
; Length check cmp rsi, 0x1f ; Compare length with 31 jne fail_label ; Jump if not equal ; Function pointer setup (example) lea rax, [rip+0x8b80] ; Load address of check function for 'H' mov [rsp+0x10], rax ; Store at first position
Character Check Functions
Found 19 unique check functions, each comparing against a specific byte value:
| Address | Character | Hex Value |
|---|---|---|
| 0x8b80 | 'H' | 0x48 |
| 0x8d80 | 'T' | 0x54 |
| 0x8d40 | 'B' | 0x42 |
| 0x8e00 | '{' | 0x7b |
| 0x8e40 | 'd' | 0x64 |
| 0x8c00 | '0' | 0x30 |
| 0x8c80 | 'n' | 0x6e |
| 0x8ac0 | 't' | 0x74 |
| 0x8b00 | '_' | 0x5f |
| 0x8a80 | 'p' | 0x70 |
| 0x8d00 | '4' | 0x34 |
| 0x8cc0 | '1' | 0x31 |
| 0x8b40 | 'c' | 0x63 |
| 0x8a40 | 'h' | 0x68 |
| 0x8dc0 | 'e' | 0x65 |
| 0x8e80 | '3' | 0x33 |
| 0x8c40 | 'r' | 0x72 |
| 0x8bc0 | 'o' | 0x6f |
| 0x8ec0 | '}' | 0x7d |
Solution
Flag Reconstruction
Traced through the assembly to determine the order of function pointers stored at stack offsets 0x10 through 0x100. Each offset maps to a position in the flag, and the function pointer at that offset determines the expected character.
#!/usr/bin/env python3
"""
Don't Panic! - Flag Reconstruction
Traces function pointer array to reconstruct the flag
"""
# Mapping of function addresses to characters
func_to_char = {
0x8b80: 'H',
0x8d80: 'T',
0x8d40: 'B',
0x8e00: '{',
0x8e40: 'd',
0x8c00: '0',
0x8c80: 'n',
0x8ac0: 't',
0x8b00: '_',
0x8a80: 'p',
0x8d00: '4',
0x8cc0: '1',
0x8b40: 'c',
0x8a40: 'h',
0x8dc0: 'e',
0x8e80: '3',
0x8c40: 'r',
0x8bc0: 'o',
0x8ec0: '}'
}
# Order of function pointers from stack analysis
# (extracted from disassembly of check_flag)
func_order = [
0x8b80, # H
0x8d80, # T
0x8d40, # B
0x8e00, # {
0x8e40, # d
0x8c00, # 0
0x8c80, # n
0x8ac0, # t
0x8b00, # _
0x8a80, # p
0x8d00, # 4
0x8c80, # n
0x8cc0, # 1
0x8b40, # c
0x8b00, # _
0x8b40, # c
0x8d00, # 4
0x8ac0, # t
0x8b40, # c
0x8a40, # h
0x8b00, # _
0x8ac0, # t
0x8a40, # h
0x8dc0, # e
0x8b00, # _
0x8e80, # 3
0x8c40, # r
0x8c40, # r
0x8bc0, # o
0x8c40, # r
0x8ec0 # }
]
# Reconstruct flag
flag = ''.join(func_to_char[addr] for addr in func_order)
print(f"Flag: {flag}")
Verification
$ ./dontpanic
Have you got a message for me?
HTB{REDACTED}
[Success message]
Notes
The challenge title is a reference to "The Hitchhiker's Guide to the Galaxy" ("Don't Panic!"), and the flag plays on Rust's error handling philosophy: instead of panicking (panic!) it's better to catch errors (catch the error). This is also a hint at catch_unwind in Rust, which allows catching panics.
Rust binaries are often harder to reverse due to:
- Mangled symbol names
- Extensive use of generics and monomorphization
- Complex error handling system (Result/Option)
- Built-in bounds checks and panic handlers
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR