reversefreemedium

Wayback

HackTheBox

Two files are provided: - `V1` — ELF 64-bit LSB PIE executable (password generator, compiled from Wayback.cpp with GCC 14.2.1, not stripped) - `decrypt.py` — Python script for AES-CBC decryption with user-provided key

$ ls tags/ techniques/
static_reverse_engineeringaes_cbc_decryptionprng_seed_bruteforceinteger_overflow_arithmetic

$ cat /etc/rate-limit

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

Wayback — HackTheBox

Description

A man named Michael Tanz bought 30 bitcoin in 2013 and stored it in his hardware wallet. He set the password for his hardware wallet through a password generator named "V1". He remembers that his password is 20 characters long, and consisted of only alphanumeric characters and symbols. Michael however is not exactly sure of the date he generated the password - he knows it was between the 10th and the 11th of December 2013. Can you crack the password and help him recover his bitcoin?

Two files are provided:

  • V1 — ELF 64-bit LSB PIE executable (password generator, compiled from Wayback.cpp with GCC 14.2.1, not stripped)
  • decrypt.py — Python script for AES-CBC decryption with user-provided key

Analysis

decrypt.py

The script performs AES-256-CBC decryption:

  • Key — user input, left-padded with null bytes to 32 bytes
  • IV — first 16 bytes of the encrypted blob
  • Ciphertext — remaining part after IV
  • PKCS7 padding
  • Encrypted hex:
ad24426047b0ffb03b679773664838462a6f00bdcaf0589dd1748e9ed5c568601edc87d974894f9dd9b98cc35535145c494eb0af84c8f78d440a033c91c7de62d506d8cabdc2a10138b95139bbe60e89

Reversing the V1 binary

Static analysis of the ELF binary revealed a password generator with the following algorithm:

Function: generate_password(int length, bool include_sym, bool include_num)

Character set (72 characters):

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*_+0123456789

Formed by concatenation: lowercase + uppercase + symbols (if enabled) + digits (if enabled).

Seed calculation — from time(NULL)localtime(), then a custom formula with 32-bit arithmetic and overflow:

struct tm* tm = localtime(&t); int seed = tm->tm_mday * 1000000 + tm->tm_min * 100 + tm->tm_sec + tm->tm_hour * 10000 + (tm->tm_year + 1900) * 0x540BE400 // year * 1,410,065,408 + (tm->tm_mon + 1) * 0x5F5E100; // month(1-12) * 100,000,000 srand((unsigned)seed);

...

$ grep --similar

Similar writeups