$ cat writeup.md…
$ cat writeup.md…
TJCTF 2026
Task: Python pickle deserialization server with RestrictedUnpickler using a strict allowlist of 14 builtins, plus regex output filter stripping flag pattern. Solution: getattr(getattr, '__self__') returns the builtins module, enabling __import__ → os.popen chain; list() wrapping bypasses the regex filter.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Rick's Mind Blows are now protected by a blacklist! You won't be able to hack this one!
Connection:
nc tjc.tf 31420Attachment:server.py
A Python server accepts base64-encoded pickle data and deserializes it using a RestrictedUnpickler with a strict allowlist of only 14 builtins. The deserialized result is converted to a string and returned, but any flag pattern matching tjctf{...} is redacted before output. The goal is to achieve RCE and exfiltrate the flag despite both restrictions.
Unlike the companion challenge "mind blowers" (which uses a blocklist), this challenge uses a strict allowlist. The find_class method only permits loading names from the builtins module that appear in the ALLOWED set:
ALLOWED = { 'type', 'getattr', 'len', 'range', 'str', 'int', 'bytes', 'list', 'dict', 'tuple', 'bool', 'set', 'frozenset', 'bytearray', } class RestrictedUnpickler(pickle.Unpickler): def find_class(self, module, name): if module == 'builtins' and name in ALLOWED: return getattr(builtins, name) raise pickle.UnpicklingError('not allowed')
This means:
builtins module is accessible — no os, subprocess, importlib, etc.eval, exec, __import__, open, license, help, etc.GLOBAL/STACK_GLOBAL opcodes raises UnpicklingErrorAfter deserialization, the server applies a regex to strip the flag:
result_str = re.sub(r'tjctf\{[^}]*\}', '[REDACTED]', result_str)
Even if we achieve RCE and read the flag file, the output will be redacted if it contains the continuous tjctf{...} pattern.
getattr.__self__The key insight is that getattr is in the allowed set. In CPython, built-in functions (builtin_function_or_method type) have a __self__ attribute that points to the module they belong to:
...
$ grep --similar