← Back to Writeups
CUSTOMEasyReversing

s4.out

XESXOR9/10/20262 min read
#reversing#custom#easy#address_offset_calculation#character_by_character_validat#static_disassembly

s4.out

Platform: spbctf | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-03-25 | Status: Solved Techniques: address_offset_calculation, character_by_character_validation, static_disassembly

Summary

A 32-bit ELF executable compiled from C++. Classic serial number validation crackme where the goal is to find the correct serial that passes all validation checks.

s4.out — SPbCTF Reverse Kids 2.0

Description

Language: C. Download binary: s4.out (ELF 32-bit) or s4.exe (PE32). Flag is the correct serial number.

A 32-bit ELF executable compiled from C++. Classic serial number validation crackme where the goal is to find the correct serial that passes all validation checks.

Analysis

  1. File reconnaissance:

    • file s4.out shows: ELF 32-bit LSB executable, Intel 80386, dynamically linked, not stripped
    • strings s4.out reveals:
      • "Enter serial number:"
      • "Serial number is correct!"
      • "Error! Serial number is wrong!"
    • Key symbols from nm: main at 0x080484eb, _Z5Checkv (Check()) at 0x08048546 ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍
  2. main() function analysis:

    • Prints "Enter serial number: "
    • Reads up to 11 bytes via fgets() into a global buffer at 0x804a048
    • Calls Check() function
    • If Check() returns true → prints "Serial number is correct!"
    • If Check() returns false → prints "Error! Serial number is wrong!"
  3. Check() function disassembly: The validation function performs character-by-character comparison in scrambled order:

c
bool Check() {
    if (strlen(Buf) <= 5) return false;
    
    if (Buf[3] != 'a') return false;  // 0x61
    if (Buf[1] != '1') return false;  // 0x31
    if (Buf[5] != 'B') return false;  // 0x42
    if (Buf[0] != 'c') return false;  // 0x63
    if (Buf[2] != '4') return false;  // 0x34
    if (Buf[4] != 'e') return false;  // 0x65
    
    return true;
}

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

  1. Validation logic:
    • Length must be > 5 (at least 6 characters)
    • Six character comparisons with early-exit on mismatch:
      • Buf[0] == 'c' (0x63)
      • Buf[1] == '1' (0x31)
      • Buf[2] == '4' (0x34)
      • Buf[3] == 'a' (0x61)
      • Buf[4] == 'e' (0x65)
      • Buf[5] == 'B' (0x42)

Solution

Reconstructing the serial by mapping each character to its position:

python
#!/usr/bin/env python3
# Reconstruct serial from Check() comparisons

checks = {
    0: 'c',  # 0x63
    1: '1',  # 0x31
    2: '4',  # 0x34
    3: 'a',  # 0x61
    4: 'e',  # 0x65
    5: 'B',  # 0x42
}
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

serial = ''.join(checks[i] for i in range(6))
print(f"Serial: {serial}")
# Output: REDACTED

Verification:

$ echo "REDACTED" | ./s4.out
Enter serial number: Serial number is correct!

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