← Back to Writeups
CUSTOMEasyReversing

task1.out (re2)

XESXOR9/2/20263 min read
#reversing#custom#easy#decoy_detection#hash_collision#static_disassembly#xor_decryption

task1.out (re2)

Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: decoy_detection, hash_collision, static_disassembly, xor_decryption

Summary

Walkthrough of the CUSTOM Reversing task1.out (re2). A 32-bit ELF binary with a decoy flag string. The program validates input through a custom XOR-based hash function and decrypts the real flag when the correct hash is provided.

Description

Language: C. Download binary: task1.out (ELF 32-bit) / task1.exe (PE32). The task expects a string as command line argument, and checks it. Complete the checks, and app will print the flag.

A 32-bit ELF binary with a decoy flag string. The program validates input through a custom XOR-based hash function and decrypts the real flag when the correct hash is provided.

Analysis

Step 1 - Reconnaissance

bash
$ file task1.out
task1.out: ELF 32-bit LSB executable, Intel 80386, dynamically linked, not stripped
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

$ strings task1.out
FLAG{123REALFLAG!!!}   # Decoy!
What?
Ok, you are wrong
Not enough!

Symbol table reveals 4 custom functions: main, decode, hashf, dwords_count.

Step 2 - Function Analysis

dwords_count(str): Returns strlen(str) / 4 — number of 32-bit dwords in the string.

hashf(str): Custom XOR hash function:

  • Starts with seed hash = 0xCAFEDEAD
  • XORs each 4-byte dword of the string into the accumulator
  • hash = 0xCAFEDEAD ^ dword[0] ^ dword[1] ^ ... ^ dword[n-1] ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

decode(buf, key): XOR-decodes each dword of buf with the 32-bit key value in-place.

main(argc, argv):

  1. Checks argc > 1, otherwise prints "Not enough!" and exits
  2. Checks strlen(argv[1]) % 4 == 0, otherwise prints "What?" and exits
  3. Compares argv[1] with decoy string "FLAG{123REALFLAG!!!}" using strcmp
    • If equal: prints "Ok, you are wrong" and exits (trap!)
  4. If input is not equal to decoy, computes hashf(input) and hashf("FLAG{123REALFLAG!!!")
  5. If hashes match: loads encrypted flag bytes, calls decode(), prints result ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 3 - The Decoy Trap

The key insight is that the obvious answer "FLAG{123REALFLAG!!!}" is explicitly rejected! The program wants an input that:

  1. Has length divisible by 4
  2. Is NOT equal to the decoy string
  3. Has the SAME XOR hash as the decoy

Since XOR is commutative and associative, swapping any two 4-byte chunks produces the same hash.

Solution

Static Decryption

Compute hashf("FLAG{123REALFLAG!!!"):

ChunkBytesDword (LE)
"FLAG"46 4C 41 470x47414C46
"{123"7B 31 32 330x3332317B
"REAL"52 45 41 4C0x4C414552
"FLAG"46 4C 41 470x47414C46
"!!!}"21 21 21 7D0x7D212121
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍
hash = 0xCAFEDEAD ^ 0x47414C46 ^ 0x3332317B ^ 0x4C414552 ^ 0x47414C46 ^ 0x7D212121
hash = 0xC8AC8BA5

XOR encrypted dwords with hash to get flag:

EncryptedXOR 0xC8AC8BA5ASCII
0x8FEDC7E30x47414C46"FLAG"
0x81E4DFDE0x4948547B"{THI"
0x9BE5D4F60x53495F53"S_IS"
0x97F5C6FA0x5F594D5F"MY"
0xB5F5CEEE0x7D59454B"KEY}"
python
#!/usr/bin/env python3
import struct

# hashf("FLAG{123REALFLAG!!!}")
reference = b"FLAG{123REALFLAG!!!}"
hash_val = 0xCAFEDEAD
for i in range(len(reference) // 4):
    dword = struct.unpack('<I', reference[i*4:(i+1)*4])[0]
    hash_val ^= dword
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

print(f"Hash: 0x{hash_val:08X}")  # 0xC8AC8BA5

# Encrypted flag dwords from binary
encrypted_dwords = [0x8FEDC7E3, 0x81E4DFDE, 0x9BE5D4F6, 0x97F5C6FA, 0xB5F5CEEE]

# Decode by XORing with hash
flag_bytes = b''
for d in encrypted_dwords:
    flag_bytes += struct.pack('<I', d ^ hash_val)

print(f"Flag: {flag_bytes.decode()}")
# FLAG{REDACTED}

Dynamic Verification (Alternative)

To run the binary and get the flag dynamically, provide an input with the same hash but different string. Swap two dwords: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

bash
# Swap "FLAG" and "{123" chunks
./task1.out '{123FLAGREALFLAG!!!}'
# Prints: FLAG{REDACTED}

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Takeaways / Lessons

  • Mastering decoy_detection, hash_collision, static_disassembly, xor_decryption was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-03-09 • CUSTOM • task1.out (re2) • Difficulty: Easy