s3.out
s3.out
Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: brute_force, disassembly, modular_arithmetic_solving, static_analysis
Summary
Walkthrough of the CUSTOM Reversing s3.out. A 32-bit ELF binary (also provided as PE32 for Windows). Password checker that uses modular arithmetic to validate input. Unlike simple byte-by-byte comparisons, this challenge requires understanding
Description
Download binary: s3.out / s3.exe. Flag is the correct password that satisfies the formula. There are many valid flags.
A 32-bit ELF binary (also provided as PE32 for Windows). Password checker that uses modular arithmetic to validate input. Unlike simple byte-by-byte comparisons, this challenge requires understanding the mathematical constraint.
Analysis
-
File reconnaissance:
file s3.outshows it's a 32-bit ELF, not stripped- Compiled from s3.cpp (C++ source)
stringsreveals standard password prompt messages
-
Disassembly of main(): The password validation algorithm:
c read-only • copy allowedacc = 0x75; // 117 for (i = 0; i < strlen(password); i++) { acc = (acc * (password[i] + 1)) % 256; } if (acc == 0x76) { // 118 puts("You are welcome! Now you can use this app."); } else { puts("Go out of here!"); } -
Mathematical constraint:
- Initial value: acc = 117
- Target value: acc = 118
- Formula: 117 × ∏(c_i + 1) ≡ 118 (mod 256)
-
Key insight: The modulo 256 operation creates many valid solutions. Any password where the product of (char + 1) values, multiplied by 117, equals 118 mod 256 is valid.
Solution
python read-only • copy allowed#!/usr/bin/env python3 """ s3.out password solver Constraint: 117 * product((c+1) for c in password) ≡ 118 (mod 256) """ def check_password(password): """Verify if password satisfies the constraint""" acc = 117 for c in password: acc = (acc * (ord(c) + 1)) % 256 return acc == 118 def find_2char_passwords(): """Find all 2-character printable passwords""" solutions = [] for c1 in range(32, 127): # printable ASCII for c2 in range(32, 127): acc = 117 acc = (acc * (c1 + 1)) % 256 acc = (acc * (c2 + 1)) % 256 if acc == 118: solutions.append(chr(c1) + chr(c2)) return solutions # Find solutions passwords = find_2char_passwords() print(f"Found {len(passwords)} 2-character solutions:") print(passwords[:10]) # First 10 # Verify one solution password = "REDACTED" print(f"\nVerification for '{password}':") print(f" '!' (ASCII 33): 117 * 34 mod 256 = {(117 * 34) % 256}") print(f" '~' (ASCII 126): 138 * 127 mod 256 = {(138 * 127) % 256}") print(f" Valid: {check_password(password)}")
Output:
Found 34 2-character solutions:
['REDACTED', '%4', ')r', '-h', '0=', '1F', '4%', '5<', '9z', '<5']
Verification for 'REDACTED':
'!' (ASCII 33): 117 * 34 mod 256 = 138
'~' (ASCII 126): 138 * 127 mod 256 = 118
Valid: True
Manual verification for REDACTED:
- Initial acc = 117
- char '!' (ASCII 33): acc = 117 × 34 mod 256 = 3978 mod 256 = 138
- char '~' (ASCII 126): acc = 138 × 127 mod 256 = 17526 mod 256 = 118
- Final acc = 118 = target ✓
Key Takeaways / Lessons
- Mastering brute_force, disassembly, modular_arithmetic_solving, static_analysis was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-03-25 • CUSTOM • s3.out • Difficulty: Easy