Python "sandbox" escape (last update: 2022-07-31, created: 2013-05-06) back to the list ↑
|
|||
So as I've recently learnt Python "sandbox" (as in removing _builtins_, and similar tricks) doesn't work. And it seems this is sometimes useful since different projects tend to use a Python "sandbox" anyway. So I decided to put some links / notes here.
(btw, this is about Python 2.6/2.7, not 3.X) # Trick 1 If __builtins__ are removed, and import doesn't work, you can use this: classes = {}.__class__.__base__.__subclasses__() The 49 there is the index of warnings.catch_warnings class, however do note that the index might be totally different in your environment (and might change depending on what code was executed. I somewhat recall that on a different python version there was another warning-related class which has the same _module thing. This basically solves the problem of missing import. # Trick 2 Quite similar to Trick 1 actually, just a different class. classes = {}.__class__.__base__.__subclasses__() The 80 in this case is _frozen_importlib.BuiltinImporter (the index may vary of course). # Trick 2 In this we get __builtins__ back by walking through the exception traceback information. The problem is that you need to be able to catch a named exception (unless you can send in bytecode instead of Python code, then this isn't a problem), and that in some cases the f_back is not defined for some reason. try: # See also Bypass Python sandboxes @ HackTricks. And basically any CTF writeup about python jail/sandbox escape. http://blog.pnuts.tk/2013/04/plaidctf-pyjail-story-of-pythons-escape.html http://ctftime.org/task/377/ http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html http://www.reddit.com/r/Python/comments/hftnp/ask_rpython_recovering_cleared_globals/ https://nedbatchelder.com/blog/201302/looking_for_python_3_builtins.html https://www.floyd.ch/?p=584 And also this semi-on-topic post: https://gynvael.coldwind.pl/?id=739 The PlaidCTF 2014 had a _nightmare_ task where you could execute any code, but there was nothing in the environment except stdout. It was solvable by accessing /proc/self/mem of the Python process and overwriting something. In our case we overwritten the fopen64 address in the .got/.plt with the address of system, and were able to run any command by just using type(stdout)("command"). Write-ups: https://docs.google.com/document/d/1pgl19sRdNGH1mYNdjoZSRtkAFTn0TQYR7bhUDw99sew/edit#bookmark=id.hub6v8dj4caa (by q3k and me) http://blog.mheistermann.de/2014/04/14/plaidctf-2014-nightmares-pwnables-375-writeup/ On the 0x3004 CTF recently there was a different kind of task, which looked like this:
I played with the task quite a lot but in the end didn't manage to solve it. The organizers said there were two solutions, both really sweet: *Solution 1*: max(open([list(vars())[5]for(password)in[0]][0])) It basically creates a new local variable called "password" (it's the newly defined iterator in the for loop), and then uses the name of this variable (that's the list(vars())[5] - the number here might vary; on the CTF server it was 8) as the name to open the ./password file. The max() there is used to read the data from the file; list(open(...))[0] would work as well, but max is shorter. Lesson: you actually could create new variables here *Solution 2*: [chr(53)for(vars()[list(vars())[0]])in[1]] This one works by replacing the LEN_PASS variable with 1 (this is done by using the the LEN_PASS variable (hint: reference) - that's the vars()[list(vars())[0]] part - as a value-iterator for the [1] array; which basically means it sets it to 1) and then returning always a given character - in this case it was "5" (of course, you had to brute-force this character on the server). Lesson: list-for can be used to set existing variables, even if they are access in a really strange way Python's ASTWhile writing an article on how "Hello World" actually works in Python (written with j00ru and Adam Sawicki, and published in 100th issue of the Polish Programista magazine; we'll publish the English translation on our blogs around September/October 2022) I've played a bit with Python's ast module (as in Abstract Syntax Tree), and decided it would make a cool CTF challenge if I would make some restrictions on AST level and have folks try to bypass it.Note: This wasn't the first challenge using AST on a CTF of course (though I did think to check only after I've already implemented it). Thankfully other challenges use different restrictions, so there was no collisions. Here are some of them though (send me an e-mail if I've missed some): - pysandbox @ TokyoWesterns CTF 4th 2018 (example write-up by hawkcurry), - Tree of danger @ HTB Uni CTF 2021 - Quals (example write-up by Ratman), - Finance Calculat0r 2021 @ CyberSecurityRumble CTF 2021 (example write-up by Zeyu). The challenge was published in Google CTF 2022 in the Sandbox category under the name of Treebox and was solved 268 times, making it the easiest (or most popular? ;>) challenge of the CTF. There were only 3 AST-level restrictions: - you can't call a function, - you can't use import, - and you can't use import from. What was wonderful about the way players solved it, was that every solution was unique in some way. There were of course clusters of solutions converging around this or that feature, but at the end of the day the solutions were pretty different. Below are some links to write-ups, as well as ones published by folks on the CTF's discord server after the competition. # Challenge author's (gynvael's) solution: Write-ups: - Multiple on CTFTime.org (also linked individually below) - write-up by Ajmal - write-up by radl97 - write-up by Om3rR3ich - write-up by nikosChalk - write-up by officialaimm - write-up by Robin Jadoul - write-up by kusano_k (JP) - write-up by DomDom (KR) - write-up by nop Video write-ups: - How to solve Python Sandbox Capture The Flag challenges? by CTF School Solutions posted on #sandbox and #writeups channel after the CTF was over. They are chronologically in reverse order: Note that since these where also heavily discussed it was at times a bit hard to figure out whether the solution was made by the person posting it, or whether that was an iteration/improvement on someone else's solution. Given the above, if I misattributed someone's solution, please let me know and I will correct it. # 温柔小🐖's solution | |||
|