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

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

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

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

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

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
Tenda-Router-VR-and-Exploit — Tenda AC15 राउटर फर्मवेयर पुनः होस्टिंग और दूरस्थ कमांड निष्पादन (CVE-2020-10987) शोषण प्रतिकृति के लिए लेख | Kitploit
उपकरण/GitHubGitHub/jaden-bowers/tenda-router-vr-and-exploit
एम्बेडेड सिस्टम सुरक्षाIoT सुरक्षाभेद्यता विश्लेषणशोषणरिवर्स इंजीनियरिंगपेनिट्रेशन टेस्टिंगहार्डवेयर सुरक्षालर्निंग और शिक्षाफर्मवेयर विश्लेषण

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

सभी देखें →

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

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

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

सभी उपकरण देखें →
साझा करें
बाइनरी शोषण
लैब और अभ्यास
GitHubjaden-bowers/tenda-router-vr-and-exploit

Tenda-Router-VR-and-Exploit

Tenda AC15 राउटर फर्मवेयर पुनः होस्टिंग और दूरस्थ कमांड निष्पादन (CVE-2020-10987) शोषण प्रतिकृति के लिए लेख

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

Tenda-Router-VR-and-Exploit

यह लेख दिखाता है कि कैसे मैंने AC15 (V15.03.05.19) फर्मवेयर के वेबसर्वर को QEMU के साथ एमुलेट किया, इसे होस्ट ब्राउज़र से पहुंच योग्य बनाया, और कमांड निष्पादन प्राप्त करने के लिए एमुलेटेड rootfs के अंदर /goform/setUsbUnload हैंडलर (CVE-2020-10987) का उपयोग किया।


अवलोकन

  • फर्मवेयर इमेज से squashfs फाइलसिस्टम निकालें (या हमारे मामले में प्राप्त करें) और रिवर्सिंग शुरू करें
  • qemu-system-arm के तहत चलने वाला एक Debian armhf गेस्ट बनाएं
  • गेस्ट के नेटवर्किंग और एमुलेटेड राउटर के लिए पोर्ट-फ़ॉरवर्डिंग पथ सेट अप करें
  • हमारा बूट स्क्रिप्ट बनाएं
  • एमुलेटेड राउटर का शोषण करें

फाइलसिस्टम निकालना

पहले हमें अपनी फर्मवेयर इमेज प्राप्त करनी होगी। मैं AC15 V15.03.05.19 के लिए इमेज डाउनलोड नहीं ढूंढ पाया, हालांकि मुझे पहले से निकाले गए squashfs फाइलसिस्टम के साथ एक github रेपो मिल गया। यदि हमारे पास सही इमेज फ़ाइल होती, तो हम इसे binwalk का उपयोग करके निकाल सकते थे, जैसे,``` user@computer $ binwalk -e AC15_V15.03.05.19.bin

DECIMAL HEXADECIMAL DESCRIPTION

64 0x40 TRX firmware header, little endian, image size: 6778880 bytes, CRC32: 0x80AD82D6, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x1A488C, rootfs offset: 0x0 92 0x5C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4177792 bytes 1722572 0x1A48CC Squashfs filesystem, little endian, version 4.0, compression:xz, size: 5052332 bytes, 848 inodes, blocksize: 131072 bytes, created: 2017-04-19 16:18:08

user@computer $ cd _AC15_V15.03.05.19.bin.extracted

चूंकि हमारे पास सही इमेज फ़ाइल नहीं है, लेकिन पहले से निकाली गई फाइलसिस्टम वाला एक रेपो है, हम बस रेपो को क्लोन कर सकते हैं।```
git clone https://github.com/lapinpt/Tenda-AC15-Firmware-V15.03.05.19-9061

मैंने VR नामक एक डायरेक्टरी बनाई है और इस रिपॉजिटरी को इसके अंदर क्लोन किया है। मेरा rootfs $HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs पर है।

बढ़िया, अब हमारे पास हमारा AC15 V15.03.05.19 फर्मवेयर है। चलिए कुछ रिवर्सिंग करते हैं ताकि देख सकें कि क्या हो रहा है।

रिवर्स इंजीनियरिंग

मैं अपने रिवर्सिंग के लिए Ghidra 11.4.2 का उपयोग करूंगा। चलिए अपने टार्गेट बाइनरी rootfs/bin/httpd पर जाते हैं और इसे Ghidra में लोड करते हैं। अगर हम formsetUsbUnload फंक्शन पर जाते हैं, तो हम देख सकते हैं,```C uVar1 = FUN_0002bd4c(param_1,"deviceName",&DAT_000f4bdc); doSystemCmd("cfm post netctrl %d?op=%d,string_info=%s",0x33,3,uVar1); FUN_0002c6cc(param_1,"HTTP/1.0 200 OK\r\n\r\n"); FUN_0002c6cc(param_1,"{"errCode":0}"); FUN_0002cc14(param_1,200); return;

यह कमज़ोरी है। `deviceName` पैरामीटर सीधे `doSystemCmd` में पास किया जाता है जिससे हम जो चाहें कमांड भेज सकते हैं।

अब चूँकि हम इस फर्मवेयर को qemu का उपयोग करके रीहोस्ट करने जा रहे हैं, न कि मूल राउटर हार्डवेयर से, कुछ प्रोग्राम उन डिवाइसों तक पहुँचने का प्रयास करेंगे जो वहाँ नहीं हैं और हमारे स्टार्टअप को क्रैश कर देंगे।
चूँकि हमारा लक्ष्य वेबसर्वर (`httpd`) का शोषण करना है, मैंने केवल उस बाइनरी को रीहोस्ट करने पर ध्यान केंद्रित किया, न कि पूरे स्टार्टअप (`/rootfs/etc_ro/init.d/rcS`) पर। _पीछे मुड़कर देखने पर मुझे यकीन नहीं है कि यह सही कदम था_

इसलिए `rcS` को देखते समय मैं कुछ ऐसा खोजना चाहता था जो `rcS` कर सकता है और `httpd` को इसकी आवश्यकता होगी। फ़ाइल के अंत की ओर हम देख सकते हैं:```bash
cfmd &
echo '' > /proc/sys/kernel/hotplug
udevd &
logserver &

rcS शेष स्टैक के शुरू होने से ठीक पहले पृष्ठभूमि में cfmd प्रारंभ करता है। कुछ और शोध करने और यह देखने के बाद कि कमजोर फ़ंक्शन कमांड कैसे भेजता है, मैं इस निष्कर्ष पर पहुंचा कि,

  • httpd एक cfm post बनाता है
  • फिर cfm क्लाइंट एक UNIX डोमेन सॉकेट (जैसे /var/cfm_socket) के माध्यम से cfmd से संवाद करता है।

cfmd में InitServer रूटीन में हम देख सकते हैं```C unlink("/var/cfm_socket"); strncpy(sa_unix.sun_path, "/var/cfm_socket", ...); bind(fd, (sockaddr*)&sa_unix, 0x6e); listen(fd, 5);

यह एक UIX socket बनाता है और सुनता है।
कुल मिलाकर यह कैसे काम करता है कि handler प्रत्येक क्लाइंट से एक निश्चित 0x7e0-बाइट frame पढ़ता है (`RecvMsg`/`SendMsg`)। पहले 4 बाइट एक command code होते हैं; फिर एक 512-बाइट key buffer और एक 1500-बाइट value buffer होता है (आप handler में stack object sizes देख सकते हैं)। यह opcode पर switch करता है और एक ACK code के साथ उत्तर देता है:
- `2` -> Get: `GetCfmValue(key, value)` फिर reply code `3`
- `0` -> Set: `SetCfmValue(key, value)` फिर reply code `1`
- `0x11` -> Unset: `UnSetCfmValue(key)` फिर reply code `0x12`
- `10` -> Commit: `SaveCfm2Flash()` फिर उत्तर `0x10` (ठीक) या `0xB` (त्रुटि) देता है

इसलिए `cfmd` का अनुकरण करने के लिए मैंने एक छोटी स्क्रिप्ट `cfm_stub` बनाई।```C
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define SOCK_PATH "/var/cfm_socket"

// minimal UNIX-domain server that httpd expects.
// Replies with an IP string when it sees the key it asks for.
int main(void) {
  int s = socket(AF_UNIX, SOCK_STREAM, 0);
  struct sockaddr_un addr = {0};
  if (s < 0) { perror("socket"); return 1; }
  unlink(SOCK_PATH);
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path)-1);
  if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; }
  if (listen(s, 5) < 0) { perror("listen"); return 1; }

  for (;;) {
    int c = accept(s, NULL, NULL);
    if (c < 0) { if (errno==EINTR) continue; perror("accept"); break; }
    char buf[1024]; ssize_t n = read(c, buf, sizeof(buf));
    if (n > 0) {
      // In some builds httpd asks for "lan.webiplansslen" etc.
      // Any non-empty reply that looks like an IP keeps init happy.
      const char *reply = "192.168.0.1";
      write(c, reply, strlen(reply));
    }
    close(c);
  }
  close(s);
  return 0;
}

अगले भाग के बाद मैं इसे संकलित करने का तरीका दिखाऊंगा।

अगली सहायक फ़ाइल hooks.so है। httpd और cfm में कुछ फ़ंक्शन हैं जो गैर-मौजूद हार्डवेयर के साथ बातचीत करने का प्रयास करते हैं। हमारा प्रोग्राम शुरू होने पर निम्नलिखित मान लेता है।

  • फ्लैश + MTD विभाजन मौजूद हैं और माउंट किए जा सकते हैं।
  • एक NVRAM डिवाइस (/dev/nvram) मौजूद है और सामान्य डिफ़ॉल्ट मान लौटाता है।
  • विभिन्न प्लेटफ़ॉर्म रूटीन सफल होते हैं (Layer-7 सेटिंग्स लोडर, RF पावर रिस्टोर, आदि)।

निम्नलिखित फ़ंक्शन एक समस्या बन जाते हैं और इसलिए हमें LD_PRELOAD=/hooks.so के साथ पैच करना होगा।

  • get_flash_type() -> यदि यह 4 लौटाता है, तो कोड फ़ाइल-आधारित पथ (cfm_file_init) लेता है, अन्यथा यह MTD से बात करने का प्रयास करता है (जो हमारे पास नहीं है)।
  • कॉन्फ़िग ब्लॉक आकार के लिए get_cfm_blk_size_from_cache() (और/या वैरिएंट j_get_cfm_blk_size_from_cache) से परामर्श लिया जाता है।
  • Broadcom NVRAM शिम (bcm_nvram_get) के लिए कॉल विफल नहीं होनी चाहिए अन्यथा स्टैक मानता है कि "NVRAM नष्ट हो गया" और रिस्टोर/रीबूट लॉजिक में चला जाता है।
  • इसके अतिरिक्त load_l7setting_file() और restore_power() जैसी रूटीन से सफल होने की उम्मीद है लेकिन वे गैर-मौजूद हार्डवेयर/फ़ाइलों को छूती हैं।

यहाँ हमारा hooks.c है। मूल के लिए azeria-labs को श्रेय।```C #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <dlfcn.h> #include <string.h>

int j_get_cfm_blk_size_from_cache(const int i) { puts("j_get_cfm_blk_size_from_cache called....\n"); return 0x20000; // 128 KiB block — what the file path expects }

int get_flash_type() { puts("get_flash_type called....\n"); return 4; // force file-backed CFM init, not MTD }

int load_l7setting_file() { puts("load_l7setting_file called....\n"); return 1; // pretend Layer-7 settings loaded OK }

int restore_power(int a, int b) { puts("restore_power called....\n"); return 0; // success (don’t touch RF/power hardware) }

char *bcm_nvram_get(char *key) { char *value = NULL;

टूल डाउनलोड करें