← Back to Writeups
CUSTOMEasyReversing

structurize

XESXOR9/2/20263 min read
#reversing#custom#easy#in_place_data_mutation_trackin#md5_flag_computation#static_analysis#struct_of_pointers_recovery

structurize

Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: in_place_data_mutation_tracking, md5_flag_computation, static_analysis, struct_of_pointers_recovery

Summary

Walkthrough of the CUSTOM Reversing structurize. Task: 64-bit ELF crackme reads a name and password into a malloc'd struct of two char* and validates both with strcmp. Solution: name must equal .rodata SeCrEtUsEr; password must equal the .data globa

Description

RE4_structurize / "structurize" Pass all checks, and app will tell you how to get the flag.

We are given a 64-bit ELF structurize.elf (x86-64, non-PIE base 0x400000, not stripped). The program prompts:

Enter your name:
Enter your password:

On passing both checks it prints md5(password) is a flag. The flag is the MD5 hex digest of the password that satisfies the checks, submitted via POST flag to rev-kids20.forkbomb.ru.

Analysis

The program is small and built from three relevant functions. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

read_user()

Allocates a struct of two char* fields and fills them with fgets:

  • field0 = name (fgets, up to 0x80 bytes), trailing newline stripped.
  • field1 = password (fgets, up to 0x80 bytes), trailing newline stripped.

So the struct is simply two heap pointers built by malloc — recognizing this struct-of-pointers layout is the first reading step.

main() — the in-place mutation (the crux)

Before calling check, main runs a loop that calls toupper() over every character of the global string at 0x601070, writing the result back in place. The .data global originally contains: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

0x601070: "sOmEeL33TpAss\0"

After the loop it becomes:

0x601070: "SOMEEL33TPASS"

This is the trap: the value check later compares against is the uppercased version, not the raw .data bytes.

check(struct*)

c
if (strcmp(name, "SeCrEtUsEr") != 0) { puts("Nope!"); return; }   // 0x40099c
if (strcmp(password, global@0x601070) != 0) { puts("Nope!"); return; }
puts("md5(password) is a flag");                                  // 0x4009ad
  • name must equal the .rodata constant at 0x40099c = SeCrEtUsEr.
  • password must equal the now-uppercased global = SOMEEL33TPASS. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Relevant constants:

AddressSectionValue
0x40099c.rodataSeCrEtUsEr
0x4009a7.rodataNope!
0x4009ad.rodatamd5(password) is a flag
0x601070.datasOmEeL33TpAss (→ SOMEEL33TPASS after toupper)

Solution

  1. Name = SeCrEtUsEr (exact .rodata constant).
  2. Password = SOMEEL33TPASS — the .data global after the in-place toupper transform. Using the raw mixed-case sOmEeL33TpAss fails the strcmp.
  3. Flag = MD5 of the password you actually type, i.e. md5("SOMEEL33TPASS"). ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍
python
#!/usr/bin/env python3
import hashlib

name = "SeCrEtUsEr"
password = "SOMEEL33TPASS"   # .data global AFTER in-place toupper

print("name    :", name)
print("password:", password)
print("flag    :", hashlib.md5(password.encode()).hexdigest())
# -> REDACTED

Verification by running the binary (the success branch prints the hint string):

bash
printf 'SeCrEtUsEr\nSOMEEL33TPASS\n' | \
  docker run --rm -i --platform linux/amd64 -v "$PWD:/w" -w /w ubuntu:22.04 \
  ./structurize.elf
# ... -> "md5(password) is a flag"

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

Trap note: md5("sOmEeL33TpAss") = df89e7cd604cd74621ae1d219a4e2681 was not accepted. Only the post-toupper password SOMEEL33TPASS gives the correct flag. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Takeaways / Lessons

  • Mastering in_place_data_mutation_tracking, md5_flag_computation, static_analysis, struct_of_pointers_recovery was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-06-15 • CUSTOM • structurize • Difficulty: Easy