147 words
1 minutes
BITSCTF 2026 - El Diablo - Reverse Engineering Writeup

Category: Reverse Engineering
Flag: BITSCTF{l4y3r_by_l4y3r_y0u_unr4v3l_my_53cr375}

Challenge Description#

Given challenge. UPX-packed binary expecting license file.

Analysis#

After unpacking: binary requires LICENSE-<hex> format. Has anti-debug (ptrace, /proc/self/status), SIGILL handler for VM execution.

VM logic recovered:

out[i] = CONST[i] XOR license[i mod 10]   for i = 0..45

Recovered 46-byte constant: dbbc3342678166ae9a08e0c6154e46ac7fb9c245aa87386814a07fa0984ead83547d7bb8598ac30ffa87542611a8

Only the first 10 license bytes matter for the transformed output.

Solution#

Derive first 8 key bytes from BITSCTF{ prefix, brute-force remaining 2 bytes:

#!/usr/bin/env python3
import re

CONST = bytes.fromhex(
    "dbbc3342678166ae9a08e0c6154e46ac7fb9c245aa873868"
    "14a07fa0984ead83547d7bb8598ac30ffa87542611a8"
)

PREFIX = b"BITSCTF{"


def decode_with_key10(key10: bytes) -> bytes:
    return bytes(CONST[i] ^ key10[i % 10] for i in range(len(CONST)))


def main():
    key = [None] * 10
    for i, ch in enumerate(PREFIX):
        key[i] = CONST[i] ^ ch

    pattern = re.compile(r"^BITSCTF\{[A-Za-z0-9_]+\}$")

    for k8 in range(256):
        for k9 in range(256):
            key[8] = k8
            key[9] = k9
            key10 = bytes(key)
            pt = decode_with_key10(key10)

            try:
                s = pt.decode("ascii")
            except UnicodeDecodeError:
                continue

            if pattern.fullmatch(s):
                print(f"key10_hex={key10.hex()}  flag={s}")


if __name__ == "__main__":
    main()

Output:

key10_hex=99f5671124d520d5f63c
flag=BITSCTF{l4y3r_by_l4y3r_y0u_unr4v3l_my_53cr375}

Valid license: LICENSE-99f5671124d520d5f63c

BITSCTF 2026 - El Diablo - Reverse Engineering Writeup
https://blog.rei.my.id/posts/46/bitsctf-2026-el-diablo-reverse-engineering-writeup/
Author
Reidho Satria
Published at
2026-02-22
License
CC BY-NC-SA 4.0