mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/ios-exploiting/ios-physical-uaf-ios
This commit is contained in:
parent
ef24e38b3b
commit
8f7b523bbf
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@ book
|
||||
book/*
|
||||
hacktricks-preprocessor.log
|
||||
hacktricks-preprocessor-error.log
|
||||
searchindex.js
|
||||
|
@ -1,97 +1,111 @@
|
||||
# iOS Physical Use After Free via IOSurface
|
||||
# iOS 物理 Use After Free 通过 IOSurface
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## iOS Exploit Mitigations
|
||||
|
||||
- **Code Signing** in iOS works by requiring every piece of executable code (apps, libraries, extensions, etc.) to be cryptographically signed with a certificate issued by Apple. When code is loaded, iOS verifies the digital signature against Apple’s trusted root. If the signature is invalid, missing, or modified, the OS refuses to run it. This prevents attackers from injecting malicious code into legitimate apps or running unsigned binaries, effectively stopping most exploit chains that rely on executing arbitrary or tampered code.
|
||||
- **CoreTrust** is the iOS subsystem responsible for enforcing code signing at runtime. It directly verifies signatures using Apple’s root certificate without relying on cached trust stores, meaning only binaries signed by Apple (or with valid entitlements) can execute. CoreTrust ensures that even if an attacker tampers with an app after installation, modifies system libraries, or tries to load unsigned code, the system will block execution unless the code is still properly signed. This strict enforcement closes many post-exploitation vectors that older iOS versions allowed through weaker or bypassable signature checks.
|
||||
- **Data Execution Prevention (DEP)** marks memory regions as non-executable unless they explicitly contain code. This stops attackers from injecting shellcode into data regions (like the stack or heap) and running it, forcing them to rely on more complex techniques like ROP (Return-Oriented Programming).
|
||||
- **ASLR (Address Space Layout Randomization)** randomizes the memory addresses of code, libraries, stack, and heap every time the system runs. This makes it much harder for attackers to predict where useful instructions or gadgets are, breaking many exploit chains that depend on fixed memory layouts.
|
||||
- **KASLR (Kernel ASLR)** applies the same randomization concept to the iOS kernel. By shuffling the kernel’s base address at each boot, it prevents attackers from reliably locating kernel functions or structures, raising the difficulty of kernel-level exploits that would otherwise gain full system control.
|
||||
- **Kernel Patch Protection (KPP)** also known as **AMCC (Apple Mobile File Integrity)** in iOS, continuously monitors the kernel’s code pages to ensure they haven’t been modified. If any tampering is detected—such as an exploit trying to patch kernel functions or insert malicious code—the device will immediately panic and reboot. This protection makes persistent kernel exploits far harder, as attackers can’t simply hook or patch kernel instructions without triggering a system crash.
|
||||
- **Kernel Text Readonly Region (KTRR)** is a hardware-based security feature introduced on iOS devices. It uses the CPU’s memory controller to mark the kernel’s code (text) section as permanently read-only after boot. Once locked, even the kernel itself cannot modify this memory region. This prevents attackers—and even privileged code—from patching kernel instructions at runtime, closing off a major class of exploits that relied on modifying kernel code directly.
|
||||
- **Pointer Authentication Codes (PAC)** use cryptographic signatures embedded into unused bits of pointers to verify their integrity before use. When a pointer (like a return address or function pointer) is created, the CPU signs it with a secret key; before dereferencing, the CPU checks the signature. If the pointer was tampered with, the check fails and execution stops. This prevents attackers from forging or reusing corrupted pointers in memory corruption exploits, making techniques like ROP or JOP much harder to pull off reliably.
|
||||
- **Privilege Access never (PAN)** is a hardware feature that prevents the kernel (privileged mode) from directly accessing user-space memory unless it explicitly enables access. This stops attackers who gained kernel code execution from easily reading or writing user memory to escalate exploits or steal sensitive data. By enforcing strict separation, PAN reduces the impact of kernel exploits and blocks many common privilege-escalation techniques.
|
||||
- **Page Protection Layer (PPL)** is an iOS security mechanism that protects critical kernel-managed memory regions, especially those related to code signing and entitlements. It enforces strict write protections using the MMU (Memory Management Unit) and additional checks, ensuring that even privileged kernel code cannot arbitrarily modify sensitive pages. This prevents attackers who gain kernel-level execution from tampering with security-critical structures, making persistence and code-signing bypasses significantly harder.
|
||||
|
||||
|
||||
## Physical use-after-free
|
||||
|
||||
这是对帖子 [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) 的摘要,更多关于使用该技术的利用细节可见 [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
|
||||
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
用户进程在 iOS 上的虚拟内存地址空间范围为 0x0 到 0x8000000000。但这些地址并不直接映射到物理内存。相反,内核使用页表将虚拟地址翻译为实际的物理地址。
|
||||
The **virtual memory address space** for user processes on iOS spans from **0x0 to 0x8000000000**. However, these addresses don’t directly map to physical memory. Instead, the **kernel** uses **page tables** to translate virtual addresses into actual **physical addresses**.
|
||||
|
||||
#### Levels of Page Tables in iOS
|
||||
|
||||
页表在 iOS 中按层次组织为三层:
|
||||
Page tables are organized hierarchically in three levels:
|
||||
|
||||
1. **L1 Page Table (Level 1)**:
|
||||
* 此层的每个条目表示一大段虚拟内存。
|
||||
* 它覆盖 **0x1000000000 bytes**(或 **256 GB**)的虚拟内存。
|
||||
* Each entry here represents a large range of virtual memory.
|
||||
* It covers **0x1000000000 bytes** (or **256 GB**) of virtual memory.
|
||||
2. **L2 Page Table (Level 2)**:
|
||||
* 这里的每个条目表示更小的虚拟内存区域,具体为 **0x2000000 bytes**(32 MB)。
|
||||
* 如果 L1 条目无法自身映射整个区域,它可能指向一个 L2 表。
|
||||
* An entry here represents a smaller region of virtual memory, specifically **0x2000000 bytes** (32 MB).
|
||||
* An L1 entry may point to an L2 table if it can't map the entire region itself.
|
||||
3. **L3 Page Table (Level 3)**:
|
||||
* 这是最细的级别,每个条目映射一个 **4 KB** 的内存页。
|
||||
* 如果需要更精细的控制,L2 条目可能指向一个 L3 表。
|
||||
* This is the finest level, where each entry maps a single **4 KB** memory page.
|
||||
* An L2 entry may point to an L3 table if more granular control is needed.
|
||||
|
||||
#### Mapping Virtual to Physical Memory
|
||||
|
||||
* **Direct Mapping (Block Mapping)**:
|
||||
* 页表中的某些条目直接将一段虚拟地址范围映射到连续的物理地址范围(类似捷径)。
|
||||
* Some entries in a page table directly **map a range of virtual addresses** to a contiguous range of physical addresses (like a shortcut).
|
||||
* **Pointer to Child Page Table**:
|
||||
* 如果需要更精细的控制,某一层(例如 L1)中的条目可以指向下一层的子页表(例如 L2)。
|
||||
* If finer control is needed, an entry in one level (e.g., L1) can point to a **child page table** at the next level (e.g., L2).
|
||||
|
||||
#### Example: Mapping a Virtual Address
|
||||
|
||||
假设你尝试访问虚拟地址 **0x1000000000**:
|
||||
Let’s say you try to access the virtual address **0x1000000000**:
|
||||
|
||||
1. **L1 Table**:
|
||||
* 内核检查对应该虚拟地址的 L1 页表条目。如果它包含指向 L2 页表的指针,则转到该 L2 表。
|
||||
* The kernel checks the L1 page table entry corresponding to this virtual address. If it has a **pointer to an L2 page table**, it goes to that L2 table.
|
||||
2. **L2 Table**:
|
||||
* 内核在 L2 页表中查找更详细的映射。如果该条目指向 L3 页表,则继续到 L3。
|
||||
* The kernel checks the L2 page table for a more detailed mapping. If this entry points to an **L3 page table**, it proceeds there.
|
||||
3. **L3 Table**:
|
||||
* 内核查找最终的 L3 条目,该条目指向实际内存页的物理地址。
|
||||
* The kernel looks up the final L3 entry, which points to the **physical address** of the actual memory page.
|
||||
|
||||
#### Example of Address Mapping
|
||||
|
||||
如果你在 L2 表的第一个索引写入物理地址 **0x800004000**,那么:
|
||||
If you write the physical address **0x800004000** into the first index of the L2 table, then:
|
||||
|
||||
* 虚拟地址从 **0x1000000000** 到 **0x1002000000** 将映射到物理地址从 **0x800004000** 到 **0x802004000**。
|
||||
* 这是 L2 级别的 **block mapping**。
|
||||
* Virtual addresses from **0x1000000000** to **0x1002000000** map to physical addresses from **0x800004000** to **0x802004000**.
|
||||
* This is a **block mapping** at the L2 level.
|
||||
|
||||
或者,如果 L2 条目指向 L3 表:
|
||||
Alternatively, if the L2 entry points to an L3 table:
|
||||
|
||||
* 虚拟地址范围 **0x1000000000 -> 0x1002000000** 中的每个 4 KB 页面将由 L3 表中的单独条目映射。
|
||||
* Each 4 KB page in the virtual address range **0x1000000000 -> 0x1002000000** would be mapped by individual entries in the L3 table.
|
||||
|
||||
### Physical use-after-free
|
||||
|
||||
当发生 **physical use-after-free (UAF)** 时,流程通常为:
|
||||
A **physical use-after-free** (UAF) occurs when:
|
||||
|
||||
1. 进程分配了一块可读写的内存。
|
||||
2. 页表被更新以将这块内存映射到进程可访问的特定物理地址。
|
||||
3. 进程释放(deallocate)了该内存。
|
||||
4. 但是,由于一个 bug,内核忘记从页表中移除该映射,即便内核将对应的物理内存标记为已释放。
|
||||
5. 内核随后可能将这块“已释放”的物理内存重新分配给其他用途,例如内核数据结构。
|
||||
6. 由于映射未被移除,进程仍然可以对这块物理内存进行读写。
|
||||
1. A process **allocates** some memory as **readable and writable**.
|
||||
2. The **page tables** are updated to map this memory to a specific physical address that the process can access.
|
||||
3. The process **deallocates** (frees) the memory.
|
||||
4. However, due to a **bug**, the kernel **forgets to remove the mapping** from the page tables, even though it marks the corresponding physical memory as free.
|
||||
5. The kernel can then **reallocate this "freed" physical memory** for other purposes, like **kernel data**.
|
||||
6. Since the mapping wasn’t removed, the process can still **read and write** to this physical memory.
|
||||
|
||||
这意味着进程可以访问到内核内存页,这些页可能包含敏感数据或结构,从而可能允许攻击者操纵内核内存。
|
||||
This means the process can access **pages of kernel memory**, which could contain sensitive data or structures, potentially allowing an attacker to **manipulate kernel memory**.
|
||||
|
||||
### IOSurface Heap Spray
|
||||
|
||||
因为攻击者无法控制哪些具体的内核页会被分配给被释放的内存,他们使用一种称为 **heap spray** 的技术:
|
||||
Since the attacker can’t control which specific kernel pages will be allocated to freed memory, they use a technique called **heap spray**:
|
||||
|
||||
1. 攻击者在内核内存中创建大量的 IOSurface 对象。
|
||||
2. 每个 IOSurface 对象在其某个字段中包含一个用于识别的 **magic value**,便于定位。
|
||||
3. 他们扫描被释放的页以查看是否有任何这些 IOSurface 对象被分配到了被释放的页上。
|
||||
4. 一旦发现某个 IOSurface 对象落在被释放的页上,就可以利用它来读写内核内存。
|
||||
1. The attacker **creates a large number of IOSurface objects** in kernel memory.
|
||||
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
|
||||
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
|
||||
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
|
||||
|
||||
更多信息参见 [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
> [!TIP]
|
||||
> 注意,iOS 16+(A12+)设备引入了硬件缓解措施(如 PPL 或 SPTM),这使得 physical UAF 技术变得远不那么可行。
|
||||
> PPL 在与代码签名、权限以及敏感内核数据相关的页面上强制执行严格的 MMU 保护,因此即便某个页面被重用,来自 userland 或被攻破的内核代码对 PPL 保护页面的写入也会被阻止。
|
||||
> Secure Page Table Monitor (SPTM) 通过强化页表更新本身来扩展 PPL。它确保即便是特权内核代码也不能在不经过安全检查的情况下悄然重新映射已释放页面或篡改映射。
|
||||
> KTRR (Kernel Text Read-Only Region) 在引导后将内核的代码段锁为只读。这阻止了对内核代码的任何运行时修改,封堵了许多 physical UAF 利用常依赖的攻击向量。
|
||||
> 此外,`IOSurface` 的分配变得不那么可预测,也更难映射到用户可访问的区域,这使得“magic value 扫描”策略的可靠性大幅下降。并且 `IOSurface` 现在受到权限(entitlements)和沙箱限制的保护。
|
||||
> Be aware that iOS 16+ (A12+) devices bring hardware mitigations (like PPL or SPTM) that make physical UAF techniques far less viable.
|
||||
> PPL enforces strict MMU protections on pages related to code signing, entitlements, and sensitive kernel data, so, even if a page gets reused, writes from userland or compromised kernel code to PPL-protected pages are blocked.
|
||||
> Secure Page Table Monitor (SPTM) extends PPL by hardening page table updates themselves. It ensures that even privileged kernel code cannot silently remap freed pages or tamper with mappings without going through secure checks.
|
||||
> KTRR (Kernel Text Read-Only Region), which locks down the kernel’s code section as read-only after boot. This prevents any runtime modifications to kernel code, closing off a major attack vector that physical UAF exploits often rely on.
|
||||
> Moreover, `IOSurface` allocations are less predictable and harder to map into user-accessible regions, which makes the “magic value scanning” trick much less reliable. And `IOSurface` is now guarded by entitlements and sandbox restrictions.
|
||||
|
||||
### Step-by-Step Heap Spray Process
|
||||
|
||||
1. **Spray IOSurface Objects**: 攻击者创建大量包含特殊标识(“magic value”)的 IOSurface 对象。
|
||||
2. **Scan Freed Pages**: 检查这些对象是否有被分配到被释放的页面上。
|
||||
3. **Read/Write Kernel Memory**: 通过操纵 IOSurface 对象中的字段,他们获得了在内核内存中进行**任意读写**的能力。这使得他们可以:
|
||||
* 使用一个字段来**读取内核内存中的任意 32 位值**。
|
||||
* 使用另一个字段来**写入 64 位值**,从而实现稳定的**内核读/写原语**。
|
||||
1. **Spray IOSurface Objects**: The attacker creates many IOSurface objects with a special identifier ("magic value").
|
||||
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
|
||||
3. **Read/Write Kernel Memory**: By manipulating fields in the IOSurface object, they gain the ability to perform **arbitrary reads and writes** in kernel memory. This lets them:
|
||||
* Use one field to **read any 32-bit value** in kernel memory.
|
||||
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
|
||||
|
||||
Generate IOSurface objects with the magic value IOSURFACE\_MAGIC to later search for:
|
||||
```c
|
||||
@ -148,24 +162,24 @@ free(surfaceIDs);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### 使用 IOSurface 实现 Kernel Read/Write
|
||||
### 使用 IOSurface 实现内核读/写
|
||||
|
||||
在对 kernel memory 中的 IOSurface 对象取得控制(映射到可从 userspace 访问的已释放物理页面)之后,我们可以使用它进行 **arbitrary kernel read and write operations**。
|
||||
在内核内存中获得对一个 IOSurface 对象的控制之后(该对象映射到一个已释放的物理页并可从用户态访问),我们可以利用它进行 **任意内核读写操作**。
|
||||
|
||||
**IOSurface 的关键字段**
|
||||
|
||||
IOSurface 对象有两个关键字段:
|
||||
|
||||
1. **Use Count Pointer**:允许 **32-bit read**。
|
||||
2. **Indexed Timestamp Pointer**:允许 **64-bit write**。
|
||||
1. **Use Count Pointer**:允许 **32 位读取**。
|
||||
2. **Indexed Timestamp Pointer**:允许 **64 位写入**。
|
||||
|
||||
通过覆盖这些指针,我们可以将它们重定向到 kernel memory 中的任意地址,从而实现读/写能力。
|
||||
通过覆盖这些指针,将它们重定向到内核内存中的任意地址,从而实现读/写能力。
|
||||
|
||||
#### 32-Bit Kernel Read
|
||||
#### 32 位内核读取
|
||||
|
||||
要执行读取:
|
||||
|
||||
1. 覆盖 **use count pointer**,使其指向目标地址减去 0x14 字节的偏移。
|
||||
1. 覆写 **use count pointer**,使其指向目标地址减去 0x14 字节的偏移处。
|
||||
2. 使用 `get_use_count` 方法读取该地址处的值。
|
||||
```c
|
||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||
@ -184,9 +198,9 @@ iosurface_set_use_count_pointer(info.object, orig);
|
||||
return value;
|
||||
}
|
||||
```
|
||||
#### 64 位内核写入
|
||||
#### 64 位 内核写入
|
||||
|
||||
要执行写入操作:
|
||||
要执行写入:
|
||||
|
||||
1. 将 **indexed timestamp pointer** 覆盖为目标地址。
|
||||
2. 使用 `set_indexed_timestamp` 方法写入一个 64 位值。
|
||||
@ -205,11 +219,11 @@ iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||
```
|
||||
#### 利用流程回顾
|
||||
|
||||
1. **Trigger Physical Use-After-Free**: 已释放的页面可被重新使用。
|
||||
2. **Spray IOSurface Objects**: 在 kernel memory 中分配大量带有唯一 "magic value" 的 IOSurface 对象。
|
||||
1. **Trigger Physical Use-After-Free**: 释放的页面可供重用。
|
||||
2. **Spray IOSurface Objects**: 在内核内存中分配大量带有唯一 "magic value" 的 IOSurface 对象。
|
||||
3. **Identify Accessible IOSurface**: 在你控制的已释放页面上定位一个 IOSurface。
|
||||
4. **Abuse Use-After-Free**: 修改 IOSurface 对象中的指针,通过 IOSurface 方法实现任意 **kernel read/write**。
|
||||
|
||||
利用这些原语,漏洞利用可以对 kernel memory 进行受控的 **32-bit reads** 和 **64-bit writes**。后续的 jailbreak 步骤可能涉及更稳定的 read/write primitives,这可能需要绕过额外的保护(例如针对较新的 arm64e 设备的 PPL)。
|
||||
使用这些原语,利用程序可对内核内存进行受控的 **32-bit reads** 和 **64-bit writes**。后续的 jailbreak 步骤可能需要更稳定的读/写原语,这可能要求绕过额外的防护(例如在更新的 arm64e 设备上绕过 PPL)。
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -1,69 +1,147 @@
|
||||
# 检测钓鱼
|
||||
# Detecting Phishing
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## 介绍
|
||||
|
||||
要检测钓鱼尝试,重要的是**了解当前使用的钓鱼技术**。在此帖子的父页面上,您可以找到这些信息,因此如果您不知道今天使用了哪些技术,我建议您访问父页面并至少阅读该部分。
|
||||
要检测一次 phishing 尝试,重要的是要**了解当今正在使用的 phishing 技术**。在本帖的父页面里你可以找到这些信息,所以如果你不知道现在都有哪些技术在被使用,建议你先去父页面至少阅读那一节。
|
||||
|
||||
这篇文章基于这样的想法:**攻击者会试图以某种方式模仿或使用受害者的域名**。如果您的域名是`example.com`,而您被使用完全不同的域名钓鱼,例如`youwonthelottery.com`,这些技术将无法揭示它。
|
||||
本帖基于一个假设:**攻击者会尝试以某种方式模仿或使用受害者的域名**。如果你的域名是 `example.com`,而你遭到钓鱼却使用了一个完全不同的域名,例如 `youwonthelottery.com`,这些技术就不会发现它。
|
||||
|
||||
## 域名变体
|
||||
|
||||
揭露那些在电子邮件中使用**相似域名**的**钓鱼**尝试是相对**简单**的。\
|
||||
只需**生成攻击者可能使用的最可能的钓鱼名称列表**,并**检查**它是否**已注册**,或者检查是否有任何**IP**在使用它。
|
||||
对于那些在邮件中使用**相似域名**的 phishing 尝试,**发现它们相对比较容易**。\
|
||||
只需**生成一份攻击者可能使用的最可能的 phishing 名称列表**,并**检查**这些域名是否已经**被注册**,或者仅检查是否有任何**IP**在使用它们。
|
||||
|
||||
### 查找可疑域名
|
||||
|
||||
为此,您可以使用以下任何工具。请注意,这些工具还会自动执行DNS请求,以检查域名是否有任何IP分配给它:
|
||||
为此,你可以使用以下任意工具。注意这些工具也会自动执行 DNS 请求以检查域名是否被分配了 IP:
|
||||
|
||||
- [**dnstwist**](https://github.com/elceef/dnstwist)
|
||||
- [**urlcrazy**](https://github.com/urbanadventurer/urlcrazy)
|
||||
|
||||
### 位翻转
|
||||
提示:如果你生成了候选列表,也把它送入你的 DNS resolver logs 以检测来自组织内部的 **NXDOMAIN lookups**(用户在攻击者实际注册之前尝试访问的拼写错误)。如果策略允许,Sinkhole 或预先屏蔽这些域名。
|
||||
|
||||
**您可以在父页面找到此技术的简短解释。或者阅读原始研究** [**https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/**](https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/)
|
||||
### Bitflipping
|
||||
|
||||
例如,对域名microsoft.com进行1位修改可以将其转换为_windnws.com._\
|
||||
**攻击者可能会注册尽可能多的与受害者相关的位翻转域名,以将合法用户重定向到他们的基础设施**。
|
||||
**你可以在父页面找到该技术的简短说明。或者阅读原始研究:** [**https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/**](https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/)
|
||||
|
||||
**所有可能的位翻转域名也应进行监控。**
|
||||
例如,对域名 microsoft.com 做 1 bit 的修改可以把它变成 _windnws.com._\
|
||||
**攻击者可能会尽可能注册与受害者相关的许多 bit-flipping 域名,以便把合法用户重定向到他们的基础设施**。
|
||||
|
||||
**所有可能的 bit-flipping 域名也都应该被监控。**
|
||||
|
||||
如果你还需要考虑 homoglyph/IDN 类似域名(例如混用 Latin/Cyrillic 字符),请查看:
|
||||
|
||||
{{#ref}}
|
||||
homograph-attacks.md
|
||||
{{#endref}}
|
||||
|
||||
### 基本检查
|
||||
|
||||
一旦您有了一份潜在可疑域名的列表,您应该**检查**它们(主要是HTTP和HTTPS端口),以**查看它们是否使用与受害者域名相似的登录表单**。\
|
||||
您还可以检查端口3333,以查看它是否开放并运行`gophish`实例。\
|
||||
了解**每个发现的可疑域名的年龄**也很有趣,越年轻的域名风险越大。\
|
||||
您还可以获取可疑网页的**截图**,以查看它是否可疑,如果是,则**访问它以进行更深入的查看**。
|
||||
一旦你有了一份潜在可疑域名的列表,你应该**检查**它们(主要是 HTTP 和 HTTPS 端口)以**查看它们是否使用了类似于受害者域名的登录表单**。\
|
||||
你也可以检查端口 3333 是否开放并运行着 `gophish` 的实例。\
|
||||
了解每个发现的可疑域名的**年龄**也很有趣,域名越新风险越高。\
|
||||
你还可以获取可疑 HTTP 和/或 HTTPS 网页的**截图**,来判断它是否可疑,如果可疑则**访问它以做更深入的查看**。
|
||||
|
||||
### 高级检查
|
||||
|
||||
如果您想更进一步,我建议您**监控这些可疑域名,并不时搜索更多**(每天?只需几秒钟/分钟)。您还应该**检查**相关IP的开放**端口**,并**搜索`gophish`或类似工具的实例**(是的,攻击者也会犯错误),并**监控可疑域名和子域名的HTTP和HTTPS网页**,以查看它们是否复制了受害者网页的任何登录表单。\
|
||||
为了**自动化这一过程**,我建议您拥有一份受害者域名的登录表单列表,爬取可疑网页,并使用类似`ssdeep`的工具将可疑域名中的每个登录表单与受害者域名的每个登录表单进行比较。\
|
||||
如果您找到了可疑域名的登录表单,您可以尝试**发送垃圾凭据**并**检查它是否将您重定向到受害者的域名**。
|
||||
如果你想更进一步,我建议你**持续监控这些可疑域名并定期(比如每天?)搜索更多**(这只需几秒/分钟)。你还应该**检查相关 IP 的开放端口**并**搜索 `gophish` 或类似工具的实例**(是的,攻击者也会犯错),并**监控可疑域名和子域名的 HTTP 和 HTTPS 网页**以查看它们是否复制了受害者网页的任何登录表单。\
|
||||
为了**自动化**这一过程,我建议维护一份受害者域名的登录表单列表,对可疑网页进行爬取,然后使用类似 `ssdeep` 的工具把可疑域名中找到的每个登录表单与受害者域名的每个登录表单进行比较。\
|
||||
如果你已经定位到了可疑域名的登录表单,你可以尝试**发送垃圾凭证**并**检查它是否把你重定向到受害者的域名**。
|
||||
|
||||
## 使用关键字的域名
|
||||
---
|
||||
|
||||
父页面还提到了一种域名变体技术,即将**受害者的域名放入更大的域名中**(例如paypal-financial.com用于paypal.com)。
|
||||
### 通过 favicon 和 web 指纹进行狩猎(Shodan/ZoomEye/Censys)
|
||||
|
||||
### 证书透明度
|
||||
许多钓鱼套件会重用其冒充品牌的 favicon。Internet-wide 扫描器会对 base64 编码的 favicon 计算 MurmurHash3。你可以生成该 hash 并据此 pivot:
|
||||
|
||||
无法采用之前的“暴力破解”方法,但实际上**也可以通过证书透明度揭露此类钓鱼尝试**。每当CA发出证书时,详细信息会公开。这意味着通过阅读证书透明度或甚至监控它,**可以找到在其名称中使用关键字的域名**。例如,如果攻击者生成了[https://paypal-financial.com](https://paypal-financial.com)的证书,通过查看证书可以找到关键字“paypal”,并知道正在使用可疑电子邮件。
|
||||
Python 示例(mmh3):
|
||||
```python
|
||||
import base64, requests, mmh3
|
||||
url = "https://www.paypal.com/favicon.ico" # change to your brand icon
|
||||
b64 = base64.encodebytes(requests.get(url, timeout=10).content)
|
||||
print(mmh3.hash(b64)) # e.g., 309020573
|
||||
```
|
||||
- 查询 Shodan: `http.favicon.hash:309020573`
|
||||
- 使用工具:查看社区工具,如 favfreak,用于为 Shodan/ZoomEye/Censys 生成 hashes 和 dorks。
|
||||
|
||||
帖子[https://0xpatrik.com/phishing-domains/](https://0xpatrik.com/phishing-domains/)建议您可以使用Censys搜索影响特定关键字的证书,并按日期(仅“新”证书)和CA发行者“Let's Encrypt”进行过滤:
|
||||
注意
|
||||
- Favicons 经常被重用;将匹配视为线索,在采取行动前验证内容和 certs。
|
||||
- 结合 domain-age 和 keyword heuristics 可提高准确性。
|
||||
|
||||
### URL 遥测搜寻 (urlscan.io)
|
||||
|
||||
`urlscan.io` 存储已提交 URL 的历史截图、DOM、requests 和 TLS 元数据。你可以用它来搜索品牌滥用和克隆站点:
|
||||
|
||||
示例查询(UI 或 API):
|
||||
- 查找类似站点,排除你的合法域:`page.domain:(/.*yourbrand.*/ AND NOT yourbrand.com AND NOT www.yourbrand.com)`
|
||||
- 查找热链接你资源的网站:`domain:yourbrand.com AND NOT page.domain:yourbrand.com`
|
||||
- 限制为最近结果:追加 `AND date:>now-7d`
|
||||
|
||||
API 示例:
|
||||
```bash
|
||||
# Search recent scans mentioning your brand
|
||||
curl -s 'https://urlscan.io/api/v1/search/?q=page.domain:(/.*yourbrand.*/%20AND%20NOT%20yourbrand.com)%20AND%20date:>now-7d' \
|
||||
-H 'API-Key: <YOUR_URLSCAN_KEY>' | jq '.results[].page.url'
|
||||
```
|
||||
从 JSON 中着眼于:
|
||||
- `page.tlsIssuer`, `page.tlsValidFrom`, `page.tlsAgeDays` 用于发现用于仿冒/相似域名的非常新的证书
|
||||
- `task.source` 的值(例如 `certstream-suspicious`)用于将发现与 CT 监控关联
|
||||
|
||||
### 通过 RDAP 获取域名年龄(可脚本化)
|
||||
|
||||
RDAP 返回机器可读的创建事件。可用于标记 **新注册域名 (NRDs)**。
|
||||
```bash
|
||||
# .com/.net RDAP (Verisign)
|
||||
curl -s https://rdap.verisign.com/com/v1/domain/suspicious-example.com | \
|
||||
jq -r '.events[] | select(.eventAction=="registration") | .eventDate'
|
||||
|
||||
# Generic helper using rdap.net redirector
|
||||
curl -s https://www.rdap.net/domain/suspicious-example.com | jq
|
||||
```
|
||||
Enrich your pipeline by tagging domains with registration age buckets (e.g., <7 days, <30 days) and prioritise triage accordingly.
|
||||
|
||||
### TLS/JAx fingerprints to spot AiTM infrastructure
|
||||
|
||||
现代的 credential-phishing 越来越多地使用 **Adversary-in-the-Middle (AiTM)** reverse proxies(例如 Evilginx)来窃取会话令牌。你可以增加网络侧的检测:
|
||||
|
||||
- 在出口处记录 TLS/HTTP fingerprints (JA3/JA4/JA4S/JA4H)。一些 Evilginx 构建被观察到具有稳定的 JA4 客户端/服务器值。仅将已知恶意指纹作为弱信号触发告警,并始终通过内容和域名情报确认。
|
||||
- 主动记录 TLS 证书元数据(签发者、SAN count、通配符使用、有效期)用于通过 CT 或 urlscan 发现的相似域名,并与 DNS age 和地理位置进行关联。
|
||||
|
||||
> Note: Treat fingerprints as enrichment, not as sole blockers; frameworks evolve and may randomise or obfuscate.
|
||||
|
||||
### Domain names using keywords
|
||||
|
||||
父页面还提到一种域名变体技术,即将 **受害者的域名嵌入到更大的域名中**(例如 paypal-financial.com 对应 paypal.com)。
|
||||
|
||||
#### Certificate Transparency
|
||||
|
||||
无法使用之前的“Brute-Force”方法,但实际上也可以通过 certificate transparency 发现此类钓鱼尝试。每次 CA 颁发证书时,细节都会被公开。这意味着通过读取 certificate transparency 或监控它,**可以找到在其名称中使用特定关键词的域名**。例如,如果攻击者生成了 [https://paypal-financial.com](https://paypal-financial.com) 的证书,通过查看证书可以发现关键字 "paypal",从而知道存在可疑使用。
|
||||
|
||||
帖子 [https://0xpatrik.com/phishing-domains/](https://0xpatrik.com/phishing-domains/) 建议你可以使用 Censys 搜索包含特定关键字的证书,并按日期筛选(仅“new”证书)以及按 CA 签发者 "Let's Encrypt" 过滤:
|
||||
|
||||
.png>)
|
||||
|
||||
然而,您可以使用免费的网页[**crt.sh**](https://crt.sh)做“同样的事情”。您可以**搜索关键字**,并根据需要**按日期和CA过滤**结果。
|
||||
不过,你也可以使用免费的网页 [**crt.sh**](https://crt.sh) 做“同样的事”。你可以 **搜索关键字**,并且如需可以 **按日期和 CA 筛选** 结果。
|
||||
|
||||
.png>)
|
||||
|
||||
使用最后一个选项,您甚至可以使用匹配身份字段查看真实域名的任何身份是否与任何可疑域名匹配(请注意,可疑域名可能是误报)。
|
||||
使用此选项你甚至可以使用 Matching Identities 字段来查看真实域名的任何 identity 是否与可疑域名匹配(注意可疑域名可能是误报)。
|
||||
|
||||
**另一个替代方案**是名为[**CertStream**](https://medium.com/cali-dog-security/introducing-certstream-3fc13bb98067)的精彩项目。CertStream提供新生成证书的实时流,您可以使用它来实时检测指定关键字。实际上,有一个名为[**phishing_catcher**](https://github.com/x0rz/phishing_catcher)的项目就是这样做的。
|
||||
**Another alternative** 是一个很棒的项目 [**CertStream**](https://medium.com/cali-dog-security/introducing-certstream-3fc13bb98067)。CertStream 提供新生成证书的实时流,你可以用它在(近)实时检测指定关键字。事实上,有一个名为 [**phishing_catcher**](https://github.com/x0rz/phishing_catcher) 的项目正是这么做的。
|
||||
|
||||
### **新域名**
|
||||
Practical tip: when triaging CT hits, prioritise NRDs, untrusted/unknown registrars, privacy-proxy WHOIS, and certs with very recent `NotBefore` times. Maintain an allowlist of your owned domains/brands to reduce noise.
|
||||
|
||||
**最后一个替代方案**是收集一些TLD的新注册域名列表([Whoxy](https://www.whoxy.com/newly-registered-domains/)提供此服务),并**检查这些域名中的关键字**。然而,长域名通常使用一个或多个子域,因此关键字不会出现在FLD中,您将无法找到钓鱼子域。
|
||||
#### **New domains**
|
||||
|
||||
**One last alternative** 是收集某些 TLD 的 **newly registered domains** 列表([Whoxy](https://www.whoxy.com/newly-registered-domains/) 提供此类服务),并 **检查这些域名中的关键字**。然而,较长的域名通常使用一个或多个子域,因此关键字不会出现在 FLD 中,你将无法找到钓鱼子域。
|
||||
|
||||
附加启发式方法:在告警时对某些 **file-extension TLDs**(例如 `.zip`, `.mov`)提高警惕。这些 TLD 常被诱饵中的文件名混淆;将 TLD 信号与品牌关键字和 NRD age 结合可以提高精确度。
|
||||
|
||||
## References
|
||||
|
||||
- urlscan.io – Search API reference: https://urlscan.io/docs/search/
|
||||
- APNIC Blog – JA4+ network fingerprinting (includes Evilginx example): https://blog.apnic.net/2023/11/22/ja4-network-fingerprinting/
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -24,13 +24,15 @@
|
||||
/* 2 — load a single index (remote → local) */
|
||||
async function loadIndex(remote, local, isCloud=false){
|
||||
let rawLoaded = false;
|
||||
try {
|
||||
const r = await fetch(remote,{mode:'cors'});
|
||||
if (!r.ok) throw new Error('HTTP '+r.status);
|
||||
importScripts(URL.createObjectURL(new Blob([await r.text()],{type:'application/javascript'})));
|
||||
rawLoaded = true;
|
||||
} catch(e){ console.warn('remote',remote,'failed →',e); }
|
||||
if(!rawLoaded){
|
||||
if(remote){
|
||||
try {
|
||||
const r = await fetch(remote,{mode:'cors'});
|
||||
if (!r.ok) throw new Error('HTTP '+r.status);
|
||||
importScripts(URL.createObjectURL(new Blob([await r.text()],{type:'application/javascript'})));
|
||||
rawLoaded = true;
|
||||
} catch(e){ console.warn('remote',remote,'failed →',e); }
|
||||
}
|
||||
if(!rawLoaded && local){
|
||||
try { importScripts(abs(local)); rawLoaded = true; }
|
||||
catch(e){ console.error('local',local,'failed →',e); }
|
||||
}
|
||||
@ -40,13 +42,41 @@
|
||||
return data;
|
||||
}
|
||||
|
||||
async function loadWithFallback(remotes, local, isCloud=false){
|
||||
if(remotes.length){
|
||||
const [primary, ...secondary] = remotes;
|
||||
const primaryData = await loadIndex(primary, null, isCloud);
|
||||
if(primaryData) return primaryData;
|
||||
|
||||
if(local){
|
||||
const localData = await loadIndex(null, local, isCloud);
|
||||
if(localData) return localData;
|
||||
}
|
||||
|
||||
for (const remote of secondary){
|
||||
const data = await loadIndex(remote, null, isCloud);
|
||||
if(data) return data;
|
||||
}
|
||||
}
|
||||
|
||||
return local ? loadIndex(null, local, isCloud) : null;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const MAIN_RAW = 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js';
|
||||
const CLOUD_RAW = 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/refs/heads/master/searchindex.js';
|
||||
const htmlLang = (document.documentElement.lang || 'en').toLowerCase();
|
||||
const lang = htmlLang.split('-')[0];
|
||||
const mainReleaseBase = 'https://github.com/HackTricks-wiki/hacktricks/releases/download';
|
||||
const cloudReleaseBase = 'https://github.com/HackTricks-wiki/hacktricks-cloud/releases/download';
|
||||
|
||||
const mainTags = Array.from(new Set([`searchindex-${lang}`, 'searchindex-en', 'searchindex-master']));
|
||||
const cloudTags = Array.from(new Set([`searchindex-${lang}`, 'searchindex-en', 'searchindex-master']));
|
||||
|
||||
const MAIN_REMOTE_SOURCES = mainTags.map(tag => `${mainReleaseBase}/${tag}/searchindex.js`);
|
||||
const CLOUD_REMOTE_SOURCES = cloudTags.map(tag => `${cloudReleaseBase}/${tag}/searchindex.js`);
|
||||
|
||||
const indices = [];
|
||||
const main = await loadIndex(MAIN_RAW , '/searchindex.js', false); if(main) indices.push(main);
|
||||
const cloud= await loadIndex(CLOUD_RAW, '/searchindex-cloud.js', true ); if(cloud) indices.push(cloud);
|
||||
const main = await loadWithFallback(MAIN_REMOTE_SOURCES , '/searchindex.js', false); if(main) indices.push(main);
|
||||
const cloud= await loadWithFallback(CLOUD_REMOTE_SOURCES, '/searchindex-cloud.js', true ); if(cloud) indices.push(cloud);
|
||||
|
||||
if(!indices.length){ postMessage({ready:false, error:'no-index'}); return; }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user