miscfreemedium

ShinyHunter

hackthebox

A Pokémon-themed challenge where you connect to a remote service that simulates a "Poketmon" game. You need to obtain a shiny Pokémon to get the flag. The title "ShinyHunter" hints at Pokémon shiny hunting and PRNG manipulation.

$ ls tags/ techniques/
prng_seed_recoverylcg_predictiontiming_calibrationreconnection_bruteforce

$ cat /etc/rate-limit

Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.

ShinyHunter — HackTheBox

Description

A Pokémon-themed challenge where you connect to a remote service that simulates a "Poketmon" game. You need to obtain a shiny Pokémon to get the flag. The title "ShinyHunter" hints at Pokémon shiny hunting and PRNG manipulation.

Remote: 154.57.164.78:32331

Files

  • chall.py — Python challenge server (runs via socat on port 1337 inside Docker)

Analysis

Source Code Structure

The challenge implements a Pokémon starter selection game with a shiny check:

  1. Random MAC generation: get_mac() generates a random MAC address displayed in the boot logo
  2. Battery died: system_time is reset to 0, eliminating real-world clock entropy
  3. Seed computation:
    time_passed = time.time() - boot_time dialog_time = system_time + time_passed # = 0 + time_passed formatted_time = int(dialog_time) initial_seed = int(formatted_time + int(device_mac.replace(":", ""), 16)) seed = lcg(initial_seed)
  4. Trainer IDs from seed:
    def generate_ids(seed): random.seed(seed) tid = random.randint(0, 65535) sid = random.randint(0, 65535) return tid, sid
  5. Shiny check: shiny_value = ((tid ^ sid) ^ (pid & 0xFFFF) ^ (pid >> 16)) — shiny if < 8
  6. LCG: lcg(seed, a=1664525, c=1013904223, m=2**32) — standard Numerical Recipes LCG
  7. 3 starters generated with seed+0, seed+1, seed+2

Vulnerability: Fully Deterministic PRNG

The PRNG seed is completely predictable:

ComponentStatusWhy
MAC addressKnownDisplayed in the ASCII art logo output
system_timeZerobattery_died = True resets it to 0
time_passedControllableWe control when we send input (name), which triggers seed computation
formatted_timePredictableint(time_passed) — integer seconds since boot

Given the seed, all random values (tid, sid, pid) are fully predictable, so we can determine which starters will be shiny before choosing.

...

$ grep --similar

Similar writeups