Highway
Highway
Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: base64_index_reversal, control_flow_recovery_from_trace, instruction_trace_analysis, loop_iteration_counting
Summary
Walkthrough of the CUSTOM Reversing Highway. Task: recover a flag passed as argv[1] from a captured instruction trace of main in an i386 ELF that produces no output. Solution: disassemble main to find a nested loop that finds each input char's b
Description
Мы сняли трассу функции main этого бинаря. Вроде, этого достаточно чтобы получить флаг, который был передан ему аргументом.
English summary: We are given an i386 ELF binary and a plain-text instruction trace of its main function (a list of executed instruction addresses). The binary takes the flag as its command-line argument argv[1] and produces no visible output. The goal is to recover that argument from the trace alone.
Provided files:
highway_wow.elf— ELF 32-bit LSB, Intel 80386, dynamically linked, not stripped.highway_itrace.out— instruction trace ofmain, 13203 lines, each line one executed instruction address (e.g.0x8048426).
Recon
bash read-only • copy allowedfile highway_wow.elf # ELF 32-bit LSB executable, Intel 80386, dynamically linked, not stripped head highway_itrace.out # 0x8048426 # 0x804842a # ... wc -l highway_itrace.out # 13203
The trace is just a sequential list of the addresses main executed. Since the binary
prints nothing, the flag is never written anywhere — but the control flow recorded in
the trace depends on the input, so the trace itself leaks the flag.
Disassembly analysis
objdump -d -M intel highway_wow.elf, structure of main (base ~0x8048426):
- Requires
argc > 1, otherwiseputs("not enough args!")and exit. - Loop A (body at
0x8048475): copiesargv[1]byte-by-byte into a buffer at0x804a040; input length saved in[ebp-0x18]. Terminates on NUL (test dl,dl; jne 0x8048475). - Nested Loop B: outer index
iin[ebp-0x10], inner indexjin[ebp-0xc]from0to0x40(64). Inner body at0x80484baloadstable[j]and compares it toinput[i]. The table address is computed aslea ecx,[eax-0x1a40]witheax = 0x804a000(viaget_pc_thunk+add 0x1bc3) → table at0x80485c0. On a match (cmp ecx,edx; jne 0x80484f4not taken → falls through to0x80484e0), it storesjinto an output buffer at0x804a140[i].
So for each input character the program finds its index in a 64-entry table.
The table
objdump -s highway_wow.elf at 0x80485c0 dumps the standard Base64 alphabet:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
Loop B therefore computes the base64-alphabet index of every input character.
Key insight
The program yields no output, but the instruction trace encodes the argument:
- The number of Loop A body executions (
0x8048475) equals the flag length: 21. - For each character, the inner search loop body (
0x80484ba) executes once per candidate indexj. When the match is found, thejneat0x80484deis not taken and control reaches0x80484e0. Counting inner-body executions up to each match marker givesj= the base64 index of that character.
So walking the trace, incrementing a counter on every 0x80484ba and reading it off at
each 0x80484e0, reconstructs the base64 indices of all characters — and thus the flag.
Trace-based recovery
python read-only • copy allowed#!/usr/bin/env python3 alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' lines = [l.strip() for l in open('highway_itrace.out') if l.strip()] inner = '0x80484ba' # each inner-loop iteration (candidate j) match = '0x80484e0' # jne not taken -> match found, j = current count - 1 result, count = [], 0 for l in lines: if l == inner: count += 1 elif l == match: result.append(count - 1) count = 0 print('indices:', result) print('flag:', ''.join(alpha[i] for i in result))
Output:
indices: [26, 39, 32, 43, 62, 28, 26, 39, 62, 29, 40, 62, 44, 40, 38, 30, 45, 33, 34, 39, 32]
flag: REDACTED
21 recovered indices, matching the Loop A count. The + characters are base64 index 62
and stand in for spaces — the phrase reads "angr can do something", a nod to the fact
that a symbolic-execution engine (angr) could also have solved this from the binary/trace.
Key Takeaways / Lessons
- Mastering base64_index_reversal, control_flow_recovery_from_trace, instruction_trace_analysis, loop_iteration_counting was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-07-02 • CUSTOM • Highway • Difficulty: Easy