magic words
magic words
Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: magic_byte_replacement, upx_magic_repair, upx_unpack
Summary
Walkthrough of the CUSTOM Reversing magic words. Task: statically-linked ELF packed with UPX 3.96 that refuses to unpack (NotPackedException). Solution: the UPX! magic bytes were replaced with the ASCII 'magic word' 2021; restore all occurrences (l_
Description
Only one magic word and the flag is yours!
English summary: A single file upx1.upx is given. It is a statically-linked
x86-64 ELF that is clearly UPX-packed, but the standard upx -d refuses to
unpack it. The goal is to repair the packed file, unpack it, and read the flag.
Analysis
Recon:
bash read-only • copy allowedfile upx1.upx # ELF 64-bit LSB executable, x86-64, statically linked, no section header strings upx1.upx | grep -i upx # $Info: This file is packed with the UPX executable packer ...$ # $Id: UPX 3.96 Copyright ...$ strings upx1.upx | grep -i magic # Feel the magic in
So the binary was packed with UPX 3.96, yet:
bash read-only • copy allowedupx -d upx1.upx # NotPackedException: not packed by UPX
This is the classic UPX anti-unpacking trick: the UPX! magic bytes
(hex 55 50 58 21) were overwritten so the loader no longer recognizes the
file as UPX-packed.
The task title "magic words" and hint "Only one magic word and the flag is
yours!" point directly at the UPX magic bytes. A healthy UPX ELF carries
the UPX! magic in two places:
- the
l_infoheader near the ELF header, and - the tail PackHeader (repeated twice at the end).
Scanning the file, the only literal UPX! present (offset 0x45481) is
coincidental data inside the compressed stream (its version byte 0x75 is
invalid). The real magics had been replaced with the ASCII string 2021
(hex 32 30 32 31) — a thematic "magic word" (the year replaced UPX!).
Effective magic locations to repair:
| Location | Offset |
|---|---|
l_info magic | 0xec |
| tail PackHeader magic #1 | 0x4be7a |
| tail PackHeader magic #2 | 0x4be84 |
After restoring the l_info magic, the following fields become valid, confirming
the repair: at 0xf0 l_lsize=0x0968, l_version=0x0d (13),
l_format=0x16 (22 = linux/amd64 elf64); p_info filesize/blocksize = 0xd5340.
Important: fixing only the
l_infomagic at0xecis NOT enough. UPX still refuses until the two tail PackHeader magics at0x4be7a/0x4be84are also restored.
Solution
Replace every occurrence of 2021 with UPX!, then unpack:
python read-only • copy allowed#!/usr/bin/env python3 # repair.py — restore corrupted UPX magic bytes data = open('upx1.upx', 'rb').read().replace(b'2021', b'UPX!') open('upx1_fixed2', 'wb').write(data)
bash read-only • copy allowedpython3 repair.py upx -d upx1_fixed2 -o upx1.unpacked # 873280 <- 310952 35.61% linux/amd64 Unpacked 1 file.
The unpacked binary is not stripped, so the flag sits in .rodata right next to
the teaser string:
bash read-only • copy allowedstrings upx1.unpacked | grep -i -A1 'magic' # Feel the magic in the air # spbctf{REDACTED} # flag1.c
Key Takeaways / Lessons
- Mastering magic_byte_replacement, upx_magic_repair, upx_unpack was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-07-05 • CUSTOM • magic words • Difficulty: Easy