MiddleOut
MiddleOut
Platform: spbctf | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: Windows | Author: XESXOR | Date: 2026-06-24 | Status: Solved Techniques: constraint_inversion, custom_hash_reimplementation, static_analysis, xor_validation
Summary
Task: 32-bit PE crackme that validates a username (scanf %s) and integer password (scanf %d); flag is admin's password. Solution: static analysis in radare2 shows validation reduces to password = hash(username) ^ 0xFF; reimplement the custom multiplicative-XOR hash for 'admin' to recover REDACTED.
MiddleOut — spbctf
Description
Flag is the password for admin user.
A 32-bit Windows console binary (MiddleOut.exe, PE32, Intel 80386, ~9.7 KB) prompts
for a username (scanf %s) and a password (scanf %d, signed integer). On valid input
it prints You are welcome! Now you can use this app., otherwise Go out of here!.
The goal is to recover the password that is accepted for the username admin — that
password is the flag.
Analysis
Static analysis with radare2 reveals two key routines.
main @ 0x401100
- Constant checksum loop:
esi = 0xFF; forecxin0..0x5b:eax = ecx + 0x76; esi ^= eax. This is independent of any input. XOR-folding a fixed arithmetic sequence cancels out, and the result is exactly0xFF. eax = hash(username)— calls the custom hash atfcn.00401080.esi ^= password— XOR the running value (0xFF) with the user-entered integer.cmp eax, esi— success iffhash(username) == 0xFF ^ password.
This collapses the whole check into a single algebraic constraint:
password = hash(username) ^ 0xFF
Username hash @ 0x401080
- Computes
strlen(username). - If
strlen(username) > 6→ returns0(thecmp edx, 6; jbebranch sends lengths<= 6to the hashing code; longer strings fall through toxor eax,eax; ret). - Otherwise (
len <= 6):- seed
h = 0x124B mult = 1- for each character
c(loaded withmovsx, i.e. signed char):h ^= (signed char)c * multmult = mult*16 + mult = mult*17(assembled asshl edx,4; add edx,eax)
- returns
h
- seed
The ×17 multiplicative mixing of each successive character is the "Middle-Out" theme
(a nod to Silicon Valley's "middle-out compression").
Solution
admin has length 5 (<= 6), so it is hashed. Tracing the loop:
| char | code | mult | contribution | running h |
|---|---|---|---|---|
| seed | 0x124b | |||
| a | 97 | 1 | 0x61 | 0x122a |
| d | 100 | 17 | 0x6a4 | 0x148e |
| m | 109 | 289 | 0x7b0d | 0x6f83 |
| i | 105 | 4913 | 0x7df19 | 0x7b09a |
| n | 110 | 83521 | 0x8c2fee | 0x8b9f74 |
| |
So hash("admin") = 0x8b9f74, and:
password = 0x8b9f74 ^ 0xFF = 0x8b9f8b = REDACTED
Python solver
python read-only • copy allowed#!/usr/bin/env python3 def uname_hash(s): if len(s) > 6: return 0 h = 0x124b mult = 1 for ch in s: c = ord(ch) if c >= 128: c -= 256 # movsx = signed char h ^= (c * mult) & 0xFFFFFFFF h &= 0xFFFFFFFF mult = (mult * 17) & 0xFFFFFFFF # shl 4 + add = *17 return h h = uname_hash("admin") # 0x8b9f74 password = h ^ 0xff # 0x8b9f8b print(password) # REDACTED
Entering username admin and password REDACTED yields
You are welcome! Now you can use this app.