← Back to Writeups
CUSTOMEasyReversing

Uzzi

XESXOR9/2/20262 min read
#reversing#custom#easy#call_count_analysis#prng_state_recovery#static_analysis

Uzzi

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

Summary

Walkthrough of the CUSTOM Reversing Uzzi. Task: a 32-bit Linux ELF asks for one integer serial and validates it against a pseudo-random value. Solution: reverse the main routine, note the fixed srand(0) seed and exactly 127 discarded rand() c

Description

Flag is the valid serial.

We are given a 32-bit i386 ELF that asks for a single integer serial key. The goal is to recover the exact value accepted by the check routine.

Analysis

Initial recon shows a dynamically linked, non-stripped ELF, so the validation logic is easy to inspect in a disassembler. main prints Input valid serial key: >, reads one integer with scanf("%d"), and then performs a deterministic PRNG check.

The important code path is:

c
scanf("%d", &user_value);
srand(0);
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

for (int i = 0; i < 127; i++)
    rand();

if (user_value == rand())
    puts("You are welcome! Now you can use this app.");
else
    puts("Go out of here!");

So this is not a real secret-based serial scheme. The program uses a fixed seed, discards exactly 127 rand() outputs, and compares the input with the 128th generated value. The earlier hypothesis about 128 discarded calls was incorrect; the correct count is 127 discarded calls and then one checked call.

Solution

The solve is just reproducing the same PRNG sequence under glibc: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

  1. Seed with srand(0).
  2. Call rand() 127 times and ignore the results.
  3. Call rand() once more.
  4. Use that integer as the serial.

On Linux glibc, that final value is REDACTED, which matches dynamic verification in an i386 Linux container and prints the success message.

Minimal reproduction script:

python
#!/usr/bin/env python3
import ctypes

libc = ctypes.CDLL("libc.so.6")
libc.srand(0)

for _ in range(127):
    libc.rand()

print(libc.rand())

Output:

text
REDACTED

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

Key Takeaways / Lessons

  • Mastering call_count_analysis, prng_state_recovery, static_analysis was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-04-03 • CUSTOM • Uzzi • Difficulty: Easy