Back to Defense Log
.NETReverse EngineeringILSpyCryptographyAESHMACMedium

Activation

2025-10-09rwx4m@vault

🚩 CTF Writeup: Activation Challenge

📋 Informasi Challenge

  • Kategori: Reverse Engineering
  • Tingkat Kesulitan: Medium
  • Format File: PE32 .NET Executable
  • Nama File: aktivasi.exe
  • Platform: FGTE CTF
  • Objective: Temukan username dan license yang valid.

1. Reconnaissance & Initial Analysis

1.1 Eksekusi Awal Program

Pertama-tama, saya menjalankan binary untuk memahami perilakunya:

$ chmod +x ./aktivasi.exe
$ ./aktivasi.exe
> aktivasi v1.0
> Usage: aktivasi.exe <username> <license>

Temuan Awal:

  • Program memerlukan 2 argumen: username dan license.
  • Aplikasi command-line sederhana.

1.2 Testing dengan Input Random

$ ./aktivasi.exe RANI salt_part_1_from_cre
> aktivasi v1.0
> Invalid license.

Analisis: Program memvalidasi username dan license. Pesan "Invalid license" menunjukkan bahwa mungkin username sudah benar (atau belum divalidasi), namun license salah.


2. Identifikasi Tipe Binary

Menggunakan command file untuk melihat arsitektur:

$ file aktivasi.exe
aktivasi.exe: PE32 executable for MS Windows 4.00 (console), Intel i386 Mono/.Net assembly, 4 sections

Implikasi:

  • Mono/.Net assembly: KUNCI PENTING. Ini adalah aplikasi .NET.
  • Kita bisa menggunakan ILSpy atau dnSpy untuk melakukan Decompile (mendapatkan source code asli), bukan sekadar Disassemble.

3. String Analysis

Ekstraksi string untuk mencari petunjuk awal:

$ strings aktivasi.exe | grep -i "salt\|flag\|license\|key" | head -10
saltChunks
license
set_KeySize
set_Key
GetSalt
ExpectedLicense
DeriveKeyFromLicense

Analisis String:

  • ExpectedLicense: Kemungkinan fungsi validasi utama.
  • DeriveKeyFromLicense: Mengindikasikan license digunakan untuk membuat kunci (KDF).
  • saltChunks: Array yang menyimpan potongan-potongan salt.

4. Decompilation dengan ILSpy

Karena ini file .NET, saya menggunakan ilspycmd untuk mendapatkan kode sumbernya.

ilspycmd aktivasi.exe > source.cs

Berikut adalah hasil decompile yang telah dibersihkan:

🔻 Klik untuk melihat Solver Code
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ActivatorApp;

internal class Program
{
    // [DATA HARDCODED]
    private static readonly string[] userChunks = new string[1] { "UkFOSQ==" };
    private static readonly string[] saltChunks = new string[4] { 
        "c2FsdF9w", "YXJ0XzFf", "ZnJvbV9j", "cmU=" 
    };
    
    // Encrypted Blob (Flag) - 64 Bytes
    private static readonly byte[] encryptedBlob = new byte[64] { ... };

    // [FUNGSI UTAMA]
    private static string GetEmbeddedUsername() { ... }
    private static byte[] GetSalt() { ... }
    
    // Core Logic
    private static string ExpectedLicense(string username) { ... }
    private static byte[] DeriveKeyFromLicense(string license) { ... }
    private static string DecryptBlob(byte[] key) { ... }
    
    private static void Main(string[] args) { 
        // Logic validasi argumen ada di sini
    }
}

5. Analisis Source Code

5.1 Static Data Extraction

Dari kode di atas, kita bisa mendekode data penting:

A. Username

"UkFOSQ=="
  • Decode: Base64("UkFOSQ==") → RANI

B. Salt

"c2FsdF9w" + "YXJ0XzFf" + "ZnJvbV9j" + "cmU="
  • Gabungan: c2FsdF9wYXJ0XzFfZnJvbV9jcmU=
  • Decode: salt_part_1_from_cre

6. Reverse Engineering Algoritma

Mari kita bedah fungsi kriptografinya.

A. Pembuatan License (ExpectedLicense)

Algoritma validasi license adalah sebagai berikut:

  1. Ambil Salt (salt_part_1_from_cre).
  2. Hitung HMAC-SHA256 dari username ("RANI") menggunakan key Salt.
  3. Ambil 8 Byte pertama dari hash.
  4. Konversi ke Hex String (Uppercase).

Simulasi Manual:

Key     = "salt_part_1_from_cre"
Message = "RANI"
HMAC    = HMAC-SHA256(Key, Message)
Result  = 0905E413DDF6D48B... (panjang)
License = 0905E413DDF6D48B (16 char pertama)

B. Derivasi Kunci AES (DeriveKeyFromLicense)

Setelah license valid, kunci enkripsi dibuat dengan cara:

  1. Gabungkan string: License + Base64(Salt).
  2. Hash menggunakan SHA256.
  3. Ambil 16 Byte pertama sebagai AES-128 Key.

C. Dekripsi Flag (DecryptBlob)

  1. Ambil 16 byte pertama dari encryptedBlob sebagai IV.
  2. Sisanya adalah Ciphertext.
  3. Dekripsi menggunakan AES-128-CBC (PKCS7 Padding).

7. Implementasi Solver Script

Saya membuat script Python untuk menghitung license dan mendekripsi flag secara otomatis.

🔻 Klik untuk melihat Solver.py
#!/usr/bin/env python3
"""
CTF Solver: Activation Challenge
Author: rwx4m
"""
import hmac
import hashlib
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

# 1. SETUP DATA
USER_B64 = "UkFOSQ=="
SALT_CHUNKS = ["c2FsdF9w", "YXJ0XzFf", "ZnJvbV9j", "cmU="]
ENCRYPTED_BLOB = bytes([
    167, 164, 179, 68, 122, 43, 220, 205, 221, 237,
    252, 140, 94, 60, 228, 168, 158, 24, 12, 211,
    42, 196, 123, 129, 112, 31, 108, 142, 85, 169,
    138, 71, 23, 244, 193, 140, 102, 155, 201, 244,
    183, 5, 176, 49, 163, 24, 215, 196, 212, 215,
    159, 80, 85, 221, 12, 234, 16, 7, 169, 163,
    172, 218, 85, 246
])

# 2. DECODE STATIC DATA
username = base64.b64decode(USER_B64).decode('utf-8')
salt_b64 = "".join(SALT_CHUNKS)
salt = base64.b64decode(salt_b64)

print(f"[+] Username : {username}")
print(f"[+] Salt     : {salt.decode('utf-8')}")

# 3. GENERATE LICENSE (HMAC-SHA256)
hmac_obj = hmac.new(salt, username.encode('utf-8'), hashlib.sha256)
hmac_digest = hmac_obj.digest()
license_key = "".join([f"{b:02X}" for b in hmac_digest[:8]]) 

print(f"[+] License  : {license_key}")

# 4. DERIVE AES KEY
# Logic: SHA256(License + Base64Salt) -> Take 16 bytes
combined = license_key + salt_b64
key_hash = hashlib.sha256(combined.encode('utf-8')).digest()
aes_key = key_hash[:16]

print(f"[+] AES Key  : {aes_key.hex()}")

# 5. DECRYPT FLAG (AES-CBC)
iv = ENCRYPTED_BLOB[:16]
ciphertext = ENCRYPTED_BLOB[16:]

cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
plaintext_padded = decryptor.update(ciphertext) + decryptor.finalize()

# Remove PKCS7 Padding manually for display
padding_len = plaintext_padded[-1]
flag = plaintext_padded[:-padding_len].decode('utf-8')

print(f"\n[SUCCESS] FLAG: {flag}")

Hasil Eksekusi Solver

🔻 Klik untuk melihat Output Solver
[+] Username : RANI
[+] Salt     : salt_part_1_from_cre
[+] License  : 0905E413DDF6D48B
[+] AES Key  : ab5ca2c49a6e6f4425eb73d97f603242

[SUCCESS] FLAG: FGTE{REDACTED_FOR_SECURITY}

8. Verifikasi Akhir

Untuk memastikan temuan benar, saya jalankan binary asli dengan kredensial yang didapat.

$ ./aktivasi.exe RANI 0905E413DDF6D48B
aktivasi v1.0
Activation OK. Here is your secret:
FGTE{REDACTED_FOR_SECURITY}

9. Key Takeaways:

  1. .NET is Open Book: Aplikasi .NET tanpa obfuscation sangat mudah dibaca source code-nya.
  2. Hardcoded Secrets: Memecah string salt (saltChunks) tidak menambah keamanan signifikan.
  3. Kriptografi: Implementasi teknis benar, namun lemah di manajemen kunci (key derivation dari data statis).