
قم بتكوين Pi Zero 2W الخاص بك ليكون BadUSB
منصة هجوم BadUSB / HID قابلة للبرمجة مبنية على Raspberry Pi Zero 2 W. يتعرف Pi على أنه جهاز USB مركب (لوحة مفاتيح بالإضافة إلى وحدة تخزين كبيرة للقراءة فقط اختيارية) وينفذ حمولات على غرار Ducky-Script ضد المضيف الذي يتم توصيله به. مصممة لاستخدامات الفريق الأحمر المصرح بها، واختبارات الاختراق، ومسابقات CTF.
⚠️ إشعار قانوني. استخدم فقط على الأنظمة التي تمتلكها أو لديك إذن كتابي صريح لاختبارها. الوصول غير المصرح به غير قانوني في معظم الدول، والتظاهر بعدم المعرفة لن يفيد.
configured لـ UDC — لا يتم إطلاق حمولات خاطئة عند الإقلاع.LAYOUT.IF / ELSE، WHILE، HOLD / RELEASE، INJECT_MOD، مولدات RANDOM_*، STRING_BLOCK / STRINGLN_BLOCK، .+----------------+ كابل USB +-------------+
| Raspberry Pi | ===================>>> | المضيف |
| Zero 2 W | (Pi يحاكي HID + | (الهدف) |
| (هذا الجهاز) | محرك اختياري) | |
+----------------+ +-------------+
|
| /home/pi/pi-badusb/
|
+-- badusb.service ----> monitor_and_run.py
|
| عند `state == configured`:
v
run_payload.py
|
v
/dev/hidg0 (أداة USB HID)
badusb.service بتشغيل gadget_setup.sh، الذي يستخدم configfs/libcomposite لتكوين أداة USB مع وظيفة لوحة مفاتيح HID و (اختياريًا) LUN تخزين كبير مدعوم بملف صورة مسطح في /var/badusb/storage.img.monitor_and_run.py. يستطلع حالة /sys/class/udc/<udc>/state وينتظر configured — حالة USB-Spec التي تعني أن المضيف قد عدّد الأداة بنجاح. (نحن لا نستخدم وجود /dev/hidg0 كإشارة: هذا صحيح منذ اللحظة التي ترتبط فيها الأداة بـ UDC عند الإقلاع، بغض النظر عما إذا كان أي شيء موصولاً.)run_payload.py، الذي يوزع payload.txt ويكتب تقارير HID إلى /dev/hidg0.| المكون | ملاحظة |
|---|---|
| Raspberry Pi Zero 2 W | تم اختباره على مراجعة الأجهزة 2026-05. يعمل Pi Zero W الأقدم مع برنامج تشغيل BCM2835 dwc_otg من حيث المبدأ أيضًا، لكن هذا README يفترض 2 W مع dwc2. |
| كابل micro-USB إلى USB-A | أو محول على شكل "محرك أقراص USB" يسمح للPi بالتوصيل مباشرة بمنفذ مضيف. |
| اختياري: شاحن منفصل | إذا كنت ترغب في تشغيل Pi من مصدر غير المضيف حتى يتمكن المستمع من الإقلاع قبل توصيله بهدف (وإلا فإن منفذ المضيف يوفر الطاقة). |
يحتوي Pi Zero 2 W على منفذي micro-USB:
PWR IN — الطاقة فقط، لا يعرض خطوط بيانات USB لكتلة dwc2 OTG.USB — منفذ بيانات OTG؛ هذا هو المكان الذي توصل به إلى الهدف.انسخ المستودع أو استنسخه إلى Pi، ثم قم بتشغيل المثبِّت:
git clone http://your-gitea/admin/Pi-Zero-2W-Bad-USB.git /home/pi/pi-badusb
cd /home/pi/pi-badusb
sudo ./install.sh
sudo reboot
بعد إعادة الإقلاع، قم بتمكين الخدمة وتشغيلها:
sudo systemctl enable --now badusb.service
journalctl -u badusb -f
install.sh غير مؤثرة — أعد تشغيلها كلما غيرت ملفات المشروع. تقوم بـ:
/boot/firmware (Bookworm+) مقابل /boot (الأقدم).dtoverlay=dwc2,dr_mode=otg نشط تحت كتلة [all] في config.txt. الإعدادات الافتراضية لـ Raspberry Pi Imager تضع هذا السطر داخل مرشح [cm5] الذي لا ينطبق على Pi Zero 2 W؛ يضيف المثبِّت تجاوزًا مُوسومًا بحيث لا تكرره عمليات إعادة التشغيل.modules-load=dwc2 موجود في cmdline.txt.g_ether لا يزال موجودًا في cmdline.txt (يسرق UDC من libcomposite ويكسر وضع الأداة)./etc/systemd/system/badusb.service./etc/udev/rules.d/99-badusb-hidg.rules بحيث يكون قابلًا للكتابة للمجموعة بواسطة .# بدء / إيقاف / إعادة تشغيل
sudo systemctl start badusb
sudo systemctl stop badusb
sudo systemctl restart badusb # آمن أثناء التوصيل
# مراقبة مباشرة
journalctl -u badusb -f
# تعطيل التشغيل التلقائي عند الإقلاع
sudo systemctl disable badusb
# ضبط التوقيتات (ينشئ إدراج تجاوز)
sudo systemctl edit badusb
# (الصق كتلة [Service] مع Environment="BADUSB_REARM_COOLDOWN_S=8" إلخ)
sudo systemctl restart badusb
تعتمد الخدمة على sys-kernel-config.mount ووجود UDC، لذا لا يمكنها إطلاق الحمولات قبل أن تكون الأداة جاهزة فعليًا.
تحرير الحمولة لا يتطلب إعادة تشغيل — تتم قراءة payload.txt من جديد عند كل توصيل.
payload.txt موجود في دليل التثبيت. مرجع الأوامر الكامل موجود في payload_commands.md.
REM افتح مربع حوار التشغيل واكتب تحية عبر Notepad
LAYOUT US
GUI r
DELAY 1500
STRING notepad
ENTER
DELAY 2500
STRINGLN مرحبًا من Pi Zero 2 W
VAR $USER="alice"
VAR $COUNT=0
WHILE $COUNT < 3
STRINGLN مرحبًا $USER (التكرار $COUNT)
VAR $COUNT = $COUNT + 1
END_WHILE
IF $USER == "alice"
STRINGLN تم المطابقة
ELSE
STRINGLN لم يتم المطابقة
END_IF
تمر التعبيرات الرياضية في VAR عبر مقيم آمن يعمل على ast — لا أسماء، لا استدعاءات، لا وصول إلى سمات، فقط القيم الرقمية و + - * / // % **.
HOLD SHIFT
STRINGLN هذا السطر مكتوب بأحرف كبيرة
RELEASE SHIFT
REM أمسك Ctrl+Shift (0x01 + 0x02) واضغط A
INJECT_MOD 0x03
STRING a
REM تحرير جميع المعدِّلات
INJECT_MOD 0x00
RANDOM_LETTER 12 # 12 حرفًا عشوائيًا مختلط الأحرف
RANDOM_NUMBER 6 # 6 أرقام عشوائية
RANDOM_SPECIAL 4 # 4 رموز ASCII عشوائية
LAYOUT UK # التبديل إلى تعيينات UK ISO لـ STRING/STRINGLN اللاحقة
STRING @ " # ~ £ \ | # يكتب بشكل صحيح على مضيف محلي بريطاني
أسقط ملفًا آخر في keymaps/ (بجانب us.py و uk.py) وسيلتقط التوجيه LAYOUT <name> من خلال importlib.
gadget_setup.sh)يمكن تجاوزها لكل استدعاء عن طريق تعيينها في البيئة عند تشغيل gadget_setup.sh يدويًا، أو عالميًا عبر توجيهات Environment= الخاصة بالوحدة.
monitor_and_run.py)تجاوز مع:
sudo systemctl edit badusb
# في المحرر:
# [Service]
# Environment="BADUSB_REARM_COOLDOWN_S=8"
# Environment="BADUSB_MIN_INTER_FIRE_S=20"
sudo systemctl restart badusb
/dev/hidg0اختبر التنفيذ السابق وجود /dev/hidg0 + قابلية الكتابة كإشارة "المضيف متصل". يتم إنشاء عقدة الجهاز هذه في اللحظة التي ترتبط فيها الأداة بـ UDC عند الإقلاع — قبل وقت طويل من قيام أي مضيف بعدها. لذا تم إطلاق الحمولات فور التشغيل بغض النظر عن مكان توصيل Pi.
الإشارة الموثوقة هي /sys/class/udc/<udc>/state، التي تبلغ عن حالة جهاز USB وفقًا للمواصفات. فقط configured تعني أن المضيف قد أصدر SetConfiguration(1) — الجهاز مؤهل الآن لإرسال تقارير HID.
كشف الانفصال الفعلي على Pi Zero 2 W مستحيل من البرنامج: لا تقوم اللوحة بتوصيل إحساس VBUS بكتلة dwc2 OTG في SoC. بعد الفصل الفعلي:
/sys/class/udc/<udc>/state يظل عند configured.current_speed يظل عند high-speed.GOTGCTL يظل عند 0x000d0000 (بت BSesVld مضبوط).لذا بدلاً من انتظار إشارة لن تأتي أبدًا، يقوم المستمع بالتسبب بنشاط في الانفصال: بعد كل حمولة، يكتب "" إلى ملف UDC configfs للأداة (الذي يفسره النواة كإلغاء ربط)، ينام لمدة BADUSB_REARM_COOLDOWN_S، ثم يكتب اسم UDC مرة أخرى لإعادة الربط. يؤدي توصيل المضيف التالي إلى إنتاج انتقال configured نظيف يمكن للمستمع اكتشافه.
إذا ترك المشغل Pi موصولاً بعد حمولة، تتسبب إعادة الربط في قيام المضيف بإعادة عد الأداة. لمنع حلقة إطلاق هاربة، يتم تفعيل ضمانين:
BADUSB_MIN_INTER_FIRE_S — إذا حدث انتقال configured ضمن هذه النافذة الزمنية بعد الإطلاق السابق، قم بإلغائه وإلغاء الربط مرة أخرى. تدور الأداة بصمت في الخلفية.BADUSB_MAX_FIRES_PER_MINUTE — حد أقصى صارم بنافذة منزلقة. فوق الحد، يتوقف المستمع لمدة BADUSB_RATELIMIT_PAUSE_S ويسجل تحذيرًا.rm -rf على configfs أبدًالا يمكن إزالة ملفات السمات المدارة من kernel في configfs (bcdUSB، idVendor، webusb/*، os_desc/*، …) بواسطة rm(2) — يعيد kernel EPERM. يتم تحريرها فقط عندما يتم rmdir للدليل الأب. يقوم كل من gadget_setup.sh و teardown_gadget.sh بجولة في شجرة configfs بترتيب libcomposite القياسي — rmdir فقط، أبدًا rm على ملفات السمات — وينظف kernel الباقي تلقائيًا.
os.write وليس file.writeكتابة سلسلة فارغة عبر open(path, "w").write("") لا تستدعي write(2) بصفر بايت — يتجاهلها TextIOWrapper في CPython. بالنسبة لإلغاء ربط configfs (الذي يفسره kernel من كتابة طول صفر بعد إزالة السطر الجديد)، نستخدم os.write(fd, b"\n") مباشرة بحيث يتم دائمًا إصدار استدعاء النظام ببايت واحد على الأقل.
يحتوي محلل Ducky على مجموعة اختبارات pytest مكونة من 34 اختبارًا تعمل مقابل MockHIDEngine (بديل في الذاكرة لكاتب HID الحقيقي)، لذا لا تحتاج إلى Pi ولا أجهزة USB.
cd /home/pi/pi-badusb
python3 -m pytest tests/
تغطية الاختبارات تشمل:
safe_eval_math يقبل العمليات الحسابية، ويرفض الأسماء / الاستدعاءات / وصول السمات / ثوابت السلسلة.evaluate_condition للمقارنات الرقمية ومقارنات السلاسل الحساسة لحالة الأحرف.VAR مع =، +=، -=، *=، /= .IF / ELSE / END_IF يأخذ الفرع الصحيح.WHILE / END_WHILE عدد التكرارات لـ < و <=.cat /sys/class/udc/*/state — يجب أن يصل إلى configured عندما يعدّد المضيف الجهاز. إذا ظل عند not attached، فإن المضيف لا يتحدث: جرب كابلًا مختلفًا (بعضها للشحن فقط) أو منفذ مضيف مختلف.lsmod | grep dwc2 — يجب أن يكون محملاً. إذا كان dwc_otg فقط موجودًا، فإن dtoverlay=dwc2,dr_mode=otg لا يُطبق؛ أعد تشغيل install.sh وأعد الإقلاع.journalctl -u badusb -f أثناء التوصيل — يجب أن يظهر Host attached. Running payload. خلال ~2 ثانية من تعداد المضيف.كان هذا خطأ حقيقيًا تم إصلاحه الآن. إذا حدث ذلك، فقد عدت إلى بنية قديمة قبل os.write. تأكد من أن monitor_and_run.py يتطابق مع الفرع الرئيسي الحالي (ابحث عن os.write(fd, payload)).
Operation not permitted"قبل الإصلاح، كان gadget_setup.sh يستخدم rm -rf على configfs. النسخة الحالية تستخدم teardown_gadget() — إذا رأيت هذه الأخطاء، فلديك نسخة قديمة. أعد النشر من الرئيسي.
/dev/hidg0"تحتاج قاعدة udev إلى توصيل ساخن لتطبق، أو sudo udevadm trigger وإعادة تسجيل الدخول حتى يلتقط المستخدم pi مجموعة plugdev.
g_ether أثناء التثبيت"أزل g_ether من cmdline.txt؛ فهو يطالب بـ UDC قبل أن يتمكن libcomposite من الربط.
يتم تعيين حجم التخزين الكبير بواسطة BACKING_SIZE_MB ولا يسري إلا في التشغيل الأول عند إنشاء الصورة الخلفية. لتغيير الحجم:
sudo systemctl stop badusb
sudo rm /var/badusb/storage.img
sudo BACKING_SIZE_MB=256 /home/pi/pi-badusb/gadget_setup.sh
sudo systemctl start badusb
هذا هو الغرض من BADUSB_MIN_INTER_FIRE_S و BADUSB_MAX_FIRES_PER_MINUTE. اضبطهما أعلى عبر systemctl edit badusb. مع الإعدادات الافتراضية، يعيد Pi الموصول إطلاق الحمولة كل ~15 ثانية لأول دقيقة، ثم يتوقف لمدة 60 ثانية، ثم يستأنف.
.
├── README.md هذا الملف
├── LICENSE MIT
├── install.sh مثبِّت غير مؤثر (تكوين البرامج الثابتة، systemd، udev، plugdev)
├── gadget_setup.sh يؤلف أداة USB عبر configfs/libcomposite
├── teardown_gadget.sh إلغاء تكوين configfs القياسي (مرتبط كـ ExecStop)
├── reload_gadget.sh مساعد يدوي لإلغاء ربط UDC / إعادة الربط
├── autorun.sh غلاف تشغيل يدوي قديم (systemd هو المفضل)
├── monitor_and_run.py المستمع: ينتظر توصيل المضيف، يشغل الحمولة، يفرض إعادة التسليح
├── run_payload.py مترجم على غرار Ducky-Script
├── payload.txt حمولتك — حرر بحرية؛ يُعاد قراءتها عند كل توصيل
├── payload_commands.md مرجع الأوامر الكامل
├── etc/
│ ├── badusb.service وحدة systemd
│ └── 99-badusb-hidg.rules قاعدة udev لـ /dev/hidg0 ملكية
├── keymaps/
│ ├── __init__.py محمل التخطيط الديناميكي
│ ├── us.py US ANSI (الافتراضي)
│ └── uk.py UK ISO
└── tests/
├── __init__.py
├── conftest.py إعداد مسار pytest
└── test_parser.py 34 اختبارًا للمحلل مقابل MockHIDEngine
libcomposite، برنامج تشغيل dwc2 kernel.MIT — انظر LICENSE.
DEFINEExecStop الذي يفك الأداة بشكل نظيف. لا توجد حالة متبقية من configfs، وإعادة التشغيل تعمل دون إعادة إقلاع./dev/hidg0 — لا توجد عُقد جهاز قابلة للكتابة للجميع.configured| المتطلب | لماذا |
|---|
| Raspberry Pi OS (Debian Bookworm أو Trixie، 64 بت Lite موصى به) | يكتب البرنامج النصي للتثبيت /boot/firmware/... على Bookworm+ ويعود إلى /boot/... على الصور الأقدم. |
| Python 3 | يأتي مع Pi OS. |
mkfs.vfat | لتهيئة صورة التخزين الكبير الخلفية في التشغيل الأول. قم بتعطيله إذا ألغيت التخزين الكبير. |
| وصول root للإعداد | يلمس systemd و udev و /boot/firmware/config.txt. |
/dev/hidg0plugdevpi إلى plugdev./var/badusb/ لصورة التخزين الكبير الخلفية.| المتغير | القيمة الافتراضية | المعنى |
|---|
ENABLE_MASS_STORAGE | 1 | 0 لأداة HID فقط. |
BACKING_FILE | /var/badusb/storage.img | الصورة المسطحة المعروضة للمضيف. |
BACKING_SIZE_MB | 64 | يتم إنشاؤها في التشغيل الأول إذا كانت مفقودة. |
BACKING_LABEL | BADUSB | تسمية وحدة FAT. |
MASS_STORAGE_RO | 1 | للقراءة فقط بشكل افتراضي. |
| متغير البيئة | القيمة الافتراضية | المعنى |
|---|
BADUSB_POST_PAYLOAD_FLUSH_S | 0.5 | النوم بعد الحمولة قبل إلغاء الربط لتصريف كتابات HID. |
BADUSB_REARM_COOLDOWN_S | 5 | المدة التي تظل فيها الأداة مخفية عن المضيف بين إلغاء الربط وإعادة الربط. |
BADUSB_MIN_INTER_FIRE_S | 10 | الحد الأدنى للثواني بين إطلاقين للحمولة؛ أقل من ذلك، يتم إلغاء الإطلاق وإعادة إلغاء الربط. |
BADUSB_MAX_FIRES_PER_MINUTE | 6 | الحد الأقصى الصارم؛ فوق ذلك، توقف لمدة BADUSB_RATELIMIT_PAUSE_S. |
BADUSB_RATELIMIT_PAUSE_S | 60 | مدة التوقف بعد تفعيل حد المعدل. |
RANDOM_*؛ RANDOM_<غير معروف> لا يفعل شيئًا ويحذر.INJECT_MOD استمرارية بايت المعدِّل عبر ضغطات المفاتيح اللاحقة.HOLD SHIFT يجعل كل حرف كبيرًا في STRINGLN abc.LAYOUT US مقابل LAYOUT UK ينتج تقارير مختلفة لـ @ و "؛ التخطيط غير المعروف يتراجع إلى التخطيط السابق.STRING_BLOCK يربط الأسطر؛ STRINGLN_BLOCK يحترم الحد الأدنى للمسافة البادئة.