← Back to Writeups
CUSTOMMediumReversing

По дороге к Замку Капибар (On the Road to Capybara Castle)

XESXOR9/2/20265 min read
#reversing#custom#medium#cryptographic-operation-revers#reverse-engineering-of-obfusca#static-binary-analysis-with-ob#upx-header-repair-(anti-unpack#linux

По дороге к Замку Капибар (On the Road to Capybara Castle)

Platform: hackerlab | Category: Reversing | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2025-12-27 | Status: Solved Techniques: Cryptographic operation reversal, Reverse engineering of obfuscation algorithm, Static binary analysis with objdump, UPX header repair (anti-unpacking bypass)

Summary

Task: UPX-packed ELF binary with corrupted magic bytes and sequential arithmetic/XOR obfuscation. Solution: Repair UPX header by replacing CDB! with UPX!, unpack, extract target bytes from .data section, and reverse 25 sequential operations.

По дороге к Замку Капибар — hackerlab

Description

На пути к флагу!

Analysis

1. Initial Examination

The downloaded archive contains:

  • ELF binary packed with UPX
  • AES-encrypted ZIP archive with images ("Рисунки.zip")

2. Detecting Anti-Unpacking Protection

When attempting to unpack the binary with standard upx -d, we get an error. Hex dump analysis shows that the l_info header is corrupted:

Offset 0xec: 43 44 42 21 (CDB!)  # Should be UPX!

This is a typical anti-unpacking technique — replacing UPX magic bytes with custom ones. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

3. Analyzing the Flag Verification Algorithm

After unpacking, disassembly reveals the flag verification function at address 0x129c. The function applies 25 sequential operations to each input character:

#OperationValue
1SUB0x16
2ADD0x6e
3XOR0xa0
4XOR0x5c
5XOR0x62
6SUB0x71
7SUB0x14
8ADD0x15
9SUB0x49
10XOR0x4c
11XOR0x97
12XOR0x38
13ADD0x66
14ADD0x35
15ADD0x56
16SUB0x63
17ADD0x5d
18SUB0x3a
19XOR0xe9
20ADD0x6d
21ADD0x1c
22XOR0xd4
23ADD0x61
24XOR0xfc
25XOR0x49
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Target bytes are located in the .data section at address 0x5010.

Solution

Step 1: Fixing the UPX Header

python
#!/usr/bin/env python3
# fix_upx.py - Repair corrupted UPX header

with open('task', 'rb') as f:
    data = bytearray(f.read())

# Replace "CDB!" with "UPX!" at offset 0xec
data[0xec:0xf0] = b'UPX!'

with open('task_fixed', 'wb') as f:
    f.write(data)

print("[+] UPX header fixed: task_fixed")

Step 2: Unpacking the Binary

bash
upx -d task_fixed -o task_unpacked

Step 3: Extracting Target Bytes

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

From the .data section at address 0x5010:

9206e5fcfbf84a92f949f85bf94ba0f6d54b9049f690a2f69289896d5443

Step 4: Reverse Transformation

python
#!/usr/bin/env python3
# solve.py - Reverse the obfuscation algorithm

def reverse_transform(b):
    """Apply all 25 operations in reverse order"""
    # Reverse of XOR 0x49 (operation 25)
    b = b ^ 0x49
    # Reverse of XOR 0xfc (operation 24)
    b = b ^ 0xfc
    # Reverse of ADD 0x61 (operation 23)
    b = (b - 0x61) & 0xff
    # Reverse of XOR 0xd4 (operation 22)
    b = b ^ 0xd4
    # Reverse of ADD 0x1c (operation 21)
    b = (b - 0x1c) & 0xff
    # Reverse of ADD 0x6d (operation 20)
    b = (b - 0x6d) & 0xff
    # Reverse of XOR 0xe9 (operation 19)
    b = b ^ 0xe9
    # Reverse of SUB 0x3a (operation 18)
    b = (b + 0x3a) & 0xff
    # Reverse of ADD 0x5d (operation 17)
    b = (b - 0x5d) & 0xff
    # Reverse of SUB 0x63 (operation 16)
    b = (b + 0x63) & 0xff
    # Reverse of ADD 0x56 (operation 15)
    b = (b - 0x56) & 0xff
    # Reverse of ADD 0x35 (operation 14)
    b = (b - 0x35) & 0xff
    # Reverse of ADD 0x66 (operation 13)
    b = (b - 0x66) & 0xff
    # Reverse of XOR 0x38 (operation 12)
    b = b ^ 0x38
    # Reverse of XOR 0x97 (operation 11)
    b = b ^ 0x97
    # Reverse of XOR 0x4c (operation 10)
    b = b ^ 0x4c
    # Reverse of SUB 0x49 (operation 9)
    b = (b + 0x49) & 0xff
    # Reverse of ADD 0x15 (operation 8)
    b = (b - 0x15) & 0xff
    # Reverse of SUB 0x14 (operation 7)
    b = (b + 0x14) & 0xff
    # Reverse of SUB 0x71 (operation 6)
    b = (b + 0x71) & 0xff
    # Reverse of XOR 0x62 (operation 5)
    b = b ^ 0x62
    # Reverse of XOR 0x5c (operation 4)
    b = b ^ 0x5c
    # Reverse of XOR 0xa0 (operation 3)
    b = b ^ 0xa0
    # Reverse of ADD 0x6e (operation 2)
    b = (b - 0x6e) & 0xff
    # Reverse of SUB 0x16 (operation 1)
    b = (b + 0x16) & 0xff
    
    return b
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Target bytes from .data section at 0x5010
target_hex = '9206e5fcfbf84a92f949f85bf94ba0f6d54b9049f690a2f69289896d5443'
target = bytes.fromhex(target_hex)

# Reverse transform each byte
flag = ''.join(chr(reverse_transform(b)) for b in target)
print(f"Flag: {flag}")

Notes

  • Anti-unpacking bypass: Replacing magic bytes is the simplest protection against automatic unpacking. Just find and fix the signature.
  • Reverse operations: ADD ↔ SUB, XOR ↔ XOR (XOR is self-inverse)
  • Order: When reversing, operations are applied in reverse order (from last to first)
  • Modular arithmetic: All arithmetic operations are performed modulo 256 (& 0xff) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍