rotated
rotated
Platform: Tjctf | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-16 | Status: Solved Techniques: base64_gzip_decoding, bash_parameter_expansion_deobfuscation, byte_frequency_analysis, caesar_byte_rotation, upx_unpacking
Summary
Task: a 6480-byte file identified as 'data' — each byte was shifted by +0x1d (ROT-29), hiding a UPX-packed ELF with an obfuscated bash script containing a multi-layer encoded flag. Solution: byte frequency analysis to find the rotation offset, UPX unpacking, bash deobfuscation, then base64+gzip+base64 decoding to recover the flag.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
tjctf| ID:20260516_tjctf_rotated - Tags: base64, multi_layer_encoding, elf, caesar_cipher, upx, gzip, frequency_analysis, bash_obfuscation, byte_rotation
- Indicators: file command reports 'data' for what should be an executable, most common byte is non-zero (0x1d) suggesting byte-level shift from null, challenge title hints at rotation/Caesar cipher on bytes, UPX signature strings in decoded binary, bash parameter expansion noise like ${*
- Source:
20260516_tjctf_rotated.md
Foothold
Vulnerability / Misconfiguration
- Base64_gzip_decoding
- Bash_parameter_expansion_deobfuscation
- Byte_frequency_analysis
- Caesar_byte_rotation
- Upx_unpacking
<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
- base64_gzip_decoding
- bash_parameter_expansion_deobfuscation
- byte_frequency_analysis
- caesar_byte_rotation
- upx_unpacking
- Tags: base64, multi_layer_encoding, elf, caesar_cipher, upx, gzip, frequency_analysis, bash_obfuscation, byte_rotation
Original Writeup
<details><summary>Click to expand original content</summary>Description
this file isn't making any sense to me. can you discover what it means?
Hint 1: "look at the title" Hint 2: "consider each byte separately"
English summary: a single binary file chall (6480 bytes) is provided. The file command identifies it only as "data" — not a recognized format. The goal is to reverse the obfuscation and find the flag.
Analysis
Initial recon
$ file chall chall: data $ wc -c chall 6480 chall
The file is not recognized as any known format. A hex dump of the first bytes shows no recognizable magic number.
Byte frequency analysis
The most common byte in the file is 0x1d, appearing 644 times out of 6480 bytes. In a typical ELF binary, the most common byte is 0x00 (null). This suggests each byte was shifted by adding 0x1d (decimal 29) modulo 256.
Verification against the expected ELF magic header \x7fELF:
| File byte | - 0x1d | Expected |
|---|---|---|
0x9c | 0x7f | \x7f ✓ |
0x62 | 0x45 | E ✓ |
0x69 | 0x4c | L ✓ |
0x63 | 0x46 | F ✓ |
The "rotation" in the title refers to a Caesar/ROT cipher applied to raw bytes: each byte had 0x1d (29) added to it modulo 256.
Decoded binary analysis
After subtracting 0x1d from every byte, the result is a valid ELF binary — but UPX-packed:
$ file chall_decoded
chall_decoded: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, no section header
$ strings chall_decoded | grep UPX
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 4.24 Copyright (C) 1996-2024 the UPX Team. All Rights Reserved. $
Embedded bash script
After UPX unpacking (6480 → 16152 bytes), strings reveals an embedded obfuscated bash script using heavy bash parameter expansion tricks:
#!/bin/bash
${*,} ${@//nj2p#@$\!/^Bis\X} e\val "$( ${*#+*=\`gr4#} ${*~~} 'p'r\i"n"tf 'H4sIAEDAzmkC/...' ${!*} | ${*%b:d\)} b""'a'''s"e"6"${@^^}"4 -d ${*} | ${*//\`FsXY^F} ${*#0ms7JMci} \gu${*//.Km\`1B/vmdvatBX}n$'\172''i'p -c ${*,,} )" ${*%TB.h}
All ${*,}, ${@//...}, ${*~~}, ${*#+*=...} etc. are bash parameter expansions that resolve to empty strings when there are no positional arguments. The obfuscated command names decode as:
e\val→eval'p'r\i"n"tf→printfb""'a'''s"e"6"${@^^}"4→base64\gu...n$'\172''i'p→gunzip(where$'\172'=z)
Clean command: eval "$(printf '<base64_string>' | base64 -d | gunzip -c)"
Solution
Step 1: Reverse the byte rotation (ROT-29)
#!/usr/bin/env python3
data = open('chall', 'rb').read()
decoded = bytes([(b - 0x1d) & 0xFF for b in data])
open('chall_decoded', 'wb').write(decoded)
Step 2: UPX unpack
upx -d chall_decoded -o chall_unpacked # 6480 -> 16152 bytes (40.12% ratio)
Step 3: Extract and decode the bash payload
echo 'H4sIAEDAzmkC/0tNzshXUPLJz8/OzEtXSMsvUkhUSMtJTLdXUlBWSHEvyEpxjzKPzAo0THSzzPY18jL0y7Es8XMJNfY19rJ0Tre1BQCGqZA9QQAAAA==' | base64 -d | gunzip -c
Output:
echo "Looking for a flag?" # dGpjdGZ7YjQ1aF9kM2J1Nl9tNDU3M3J9Cg==
Step 4: Decode the final base64 from the comment
echo 'dGpjdGZ7YjQ1aF9kM2J1Nl9tNDU3M3J9Cg==' | base64 -d
Output: tjctf{REDACTED}
Full solve script
#!/usr/bin/env python3
"""TJCTF 2026 - rotated: ROT-29 byte shift → UPX → bash obfuscation → base64+gzip → base64 flag"""
import base64
import gzip
# Step 1: Reverse byte rotation
data = open('chall', 'rb').read()
decoded = bytes([(b - 0x1d) & 0xFF for b in data])
# Step 2: Extract base64 payload from strings (found in unpacked binary)
b64_payload = 'H4sIAEDAzmkC/0tNzshXUPLJz8/OzEtXSMsvUkhUSMtJTLdXUlBWSHEvyEpxjzKPzAo0THSzzPY18jL0y7Es8XMJNfY19rJ0Tre1BQCGqZA9QQAAAA=='
# Step 3: Decode base64 → gunzip
bash_script = gzip.decompress(base64.b64decode(b64_payload)).decode()
print(f"Bash script: {bash_script}")
# Step 4: Extract and decode the hidden base64 from the comment
hidden_b64 = bash_script.split('# ')[1].strip()
flag = base64.b64decode(hidden_b64).decode().strip()
print(f"Flag: {flag}")
</details>
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR