
maltrail v2.2
نظام كشف حركة المرور الخبيثة في الوقت الفعلي باستخدام القوائم السوداء العامة، وآثار البرامج الضارة الثابتة، والتحليل الاستدلالي لتحديد التهديدات عبر حركة DNS وHTTP وIP.

نظام كشف حركة المرور الخبيثة. يراقب Maltrail شبكتك بحثًا عن أي تواصل مع أمور معروفة بأنها خبيثة — ويخبرك، في سطر واحد، بما شوهد ولماذا يُعتبر خبيثًا.
"2026-08-07 09:14:22.117034" gw 10.13.13.2 57809 1.1.1.1 53 UDP DNS malware.bakewithdavid.com "asyncrat (malware)" (static)
لا لغة قواعد، ولا طقوس ضبط، ولا تعلُّم آلي. المسار (trail) هو نطاق، أو عنوان URL، أو عنوان IP، أو IP:port، أو User-Agent معروف بأنه ينتمي إلى شيء خبيث، ويخبرك Maltrail عند ظهور أيٍّ منها على الشبكة.
لماذا Maltrail
معظم أدوات كشف الشبكة تطلب منك وصف السلوك. يطرح Maltrail سؤالًا أبسط يجيب عن معظم الحوادث الحقيقية: هل يتواصل هذا المضيف مع شيء نعرف بالفعل أنه خبيث؟
- أكثر من 1.5 مليون مسار (trail)، من أكثر من 3,000 قائمة ثابتة منسّقة إضافةً إلى 46 خلاصة عامة، تُحدَّث يوميًا وتزداد باستمرار. بترجيح كبير نحو البرمجيات الخبيثة — نطاقات C2، وبرامج الإسقاط (droppers)، وسارقات البيانات (stealers)، والبنية التحتية لـ APT — لأن هذا ما يظهر في الاختراق الحقيقي.
- المسارات نصّ عادي. مؤشر واحد في كل سطر، في ملف يمكنك قراءته والبحث فيه بـ grep وإرسال طلب سحب (pull request) بشأنه. لهذا تبقى التغطية محدَّثة، ولهذا يمكنك دائمًا الإجابة عن سؤال «لماذا أطلق هذا التنبيه؟».
- سريع بما يكفي لتتوقف عن التفكير فيه. نواة واحدة تعالج رابط 10 GbE على مزيج حركة مرور واقعي؛ انظر الأداء.
- الاستدلالات (heuristics) إضافة فوق ذلك، وليست بديلًا — كلٌّ منها مُسمّى في الحدث، ولا تُعرض أبدًا كدرجة مجردة: فحص المنافذ، وفحص UDP والويب، واستنزاف DNS، والاستعلامات ذات البنية الشبيهة بـ DGA (عتبات الإنتروبيا والحروف الساكنة، والإفراط في NXDOMAIN)، والنطاقات المُغرقة (sinkholed) والمصادَرة والمتوقفة (parked)، والنطاقات الطويلة، وتنزيلات البرمجيات الخبيثة عبر IP المباشر وأجهزة إنترنت الأشياء (IoT)، ووكلاء المستخدم المشبوهون وفحوصات البروكسي.
البنية
عمليتان مستقلتان. شغّلهما على جهاز واحد أو على أجهزة متعددة.
┌──────────┐ events (UDP or file) ┌──────────┐
│ sensor │ ───────────────────────► │ server │ ◄── browser
└──────────┘ └──────────┘
Rust Python
libpcap + PACKET_FANOUT reporting UI + API
trail matching, heuristics
يمكن للمستشعر التسجيل محليًا (LOG_DIR)، أو إرسال الأحداث إلى خادم بعيد (LOG_SERVER)، أو كليهما معًا. وبالنسبة إلى نظام SIEM قائم، فإنه يُصدر أيضًا أحداث CEF عبر syslog (SYSLOG_SERVER) وLogstash بصيغة JSON (LOGSTASH_SERVER).
الأداء
المستشعر مكتوب بـ Rust، بخيط واحد لكل عامل التقاط، يتشاركون مخزن مسارات واحدًا غير قابل للتغيير. التكلفة لكل حزمة، حسب نوع حركة المرور:
| نوع حركة المرور | التكلفة لكل حزمة |
|---|---|
| صدى ICMP (58 B) | 101 ns |
| TCP SYN (70 B) | 302 ns |
| TLS بكميات كبيرة (1,473 B) | 402 ns |
| استعلام DNS، ذاكرة تخزين مؤقت دافئة (93 B) | 452 ns |
| حركة مرور مختلطة (متوسط 866 B) | 552 ns |
| طلب HTTP (169 B) | 602 ns |
| استعلام DNS، كل اسم فريد (فيضان DGA) | 1,102 ns |
العمال لا يتشاركون أي شيء قابل للتغيير، إذن هذه هي التكلفة التي يمنحك إياها كل نواة إضافية. عند إعادة تشغيل مزيج الـ 866 بايت:
| العمال | حزمة/ثانية | غيغابت/ثانية | مقابل عامل واحد |
|---|---|---|---|
| 1 | 1,687,991 | 11.69 | 1.00× |
| 2 | 3,209,627 | 22.24 | 1.90× |
| 4 | 5,379,436 | 37.27 | 3.19× |
| 8 | 8,552,231 | 59.25 | 5.07× |
| 16 | 10,165,773 | 70.43 | 6.02× |
نواة واحدة تُشبع رابط 10 GbE. التوسع شبه خطي حتى أربعة عمال ثم يتراجع على جهاز بثمانية أنوية مادية، لأن ما تبقى هو SMT — عتاد، وليس تنازعًا على الأقفال.
بالمقارنة مع مستشعر Python القديم: إعادة تشغيل نفس الالتقاط المكوَّن من 300,000 حزمة مع نفس المسارات البالغ عددها 1,505,265 وبنفس الإعدادات، عامل واحد لكلٍّ منهما — باستثناء زمن الإقلاع، إذن هذه تكلفة الحزمة في الحالة المستقرة. الرقمان هنا يشملان العملية بأكملها (قراءة pcap والتوزيع)، ولهذا يكون رقم المستشعر الحالي أعلى من تكلفة معالجة الحزمة البالغة 552 ns والمقاسة في عزلة أعلاه:
| التكلفة لكل حزمة | حزمة/ثانية | |
|---|---|---|
| المستشعر (Rust) | 865 ns | 1,156,423 |
| المستشعر القديم (Python) | 23,448 ns | 42,648 |
| أسرع 27× |
أعد إنتاج النتيجة بنفسك — الأداة (harness) مُودَعة في المستودع، وتطبع عدد أحداث كلا المستشعرين، بحيث لا يمكن أبدًا الاستشهاد برقم إنتاجية دون سياق صحته:
python3 sensor/tools/bench_compare.py --packets 300000 --trails ~/.maltrail/trails.csv --repeat 3
الذاكرة لا تنمو مع عدد الأنوية: مخزن الـ 1.5M مسارًا يبلغ 68.5 MB، يُبنى في 1.2 ثانية ويُشارَك بشكل غير قابل للتغيير بين كل العمال.
عامل التقاط واحد افتراضيًا، وهو ما يعادل ~1.1M حزمة/ثانية ويكفي لأي مضيف مستشعر تقريبًا. العمال الإضافيون اختيار صريح (CAPTURE_FANOUT)، لأن النواة تجزئ الالتقاط حسب التدفق (flow-hash) بينما تحسب استدلالات الفحص لكل مصدر: من تنبيهات الاستدلال التي يطلقها عامل واحد، يبقى 91% منها عند 2 sockets، و86% عند 4، و65% عند 8. كشف المسارات الدقيق متطابق عند أي عدد من العمال. وسّع النطاق عندما يشير maltrail_capture_dropped_total إلى ذلك، وليس قبل ذلك.
AMD Ryzen 7 PRO 4750U (8 أنوية مادية)، مع تفعيل الاستدلالات، مجموعة مسارات حقيقية، أسرع جولة من ثلاث جولات. تراوحت النسبة بين 14–27× عبر الجولات والعتاد؛ وتكاليف كل حزمة أعلاه هي التي تحدّد مقدار حركة المرور التي يمكن للعامل استيعابها. هذه أرقام لمسار البرمجيات — بطاقة الشبكة الحية (NIC) تضيف تكاليف السائق (driver) والحلقة (ring)، لذا قِس عتادك بنفسك وراقب maltrail_capture_dropped_total. المنهجية، والتفصيل حسب البروتوكول، وعدادات التعليمات، ومخرجات أداة التنميط (profiler) موجودة في sensor/docs/REPORT.md.
بدء سريع
Linux مع libpcap، وRust 1.74+ للمستشعر، وPython 3.7+ للخادم.
ملفات ثنائية جاهزة للمستشعر من أجل x86_64 وaarch64 مرفقة بكل إصدار مع مجموع اختباري SHA-256، لذا فإن سلسلة أدوات Rust (toolchain) ضرورية فقط للبناء من المصدر. وللبناء على أي حال:
git clone --depth 1 https://github.com/stamparm/maltrail.git
cd maltrail
# 1. build the sensor
cd sensor && cargo build --release && cd ..
# 2. let it capture without running as root
sudo setcap cap_net_raw,cap_net_admin=eip sensor/target/release/maltrail-sensor
# 3. give it somewhere to write events (LOG_DIR, /var/log/maltrail by default)
sudo install -d -o "$USER" -g "$USER" -m 750 /var/log/maltrail
# 4. check the deployment before trusting it — exits non-zero if anything is wrong
sensor/target/release/maltrail-sensor -T
# 5. run it (first start builds the trail set; takes a minute)
sensor/target/release/maltrail-sensor
في طرفية أخرى، أو على جهاز آخر:
python3 server.py
ثم افتح http://127.0.0.1:8338 وسجّل الدخول باستخدام بيانات الاعتماد الموجودة في maltrail.conf (USERS).
-T هو الاختصار لسؤال «هل سيعمل هذا؟» — يتحقق من الإعدادات، والمسارات، والقائمة البيضاء، ودليل السجلات، وفلتر الالتقاط، والصلاحيات، ويخبرك بالضبط بما هو ناقص:
[o] log directory: '/var/log/maltrail' is writable
[o] capture privileges: CAP_NET_RAW present
[o] capture filter: udp or icmp or (tcp and (tcp[tcpflags] == tcp-syn or port 80 or port...
[o] interface: any
[o] workers: 16 (PACKET_FANOUT required; verify with tools/fanout_check.py as root)
[o] whitelist: 3440 entries, 18 CIDR range(s)
[o] trails: 1505265 loaded (0 malformed row(s)), ipv4=144758 ipv4:port=253517 ipv6=2014 wildcard=29
[o] heuristics: on (disabled: none)
[i] configuration test PASSED
تخطّي الخطوة 2 أو 3 هو الطريقة الأكثر شيوعًا على الإطلاق للوصول إلى مستشعر يبدأ ولا يكتشف شيئًا؛ -T يسمّي الاثنين معًا.
كخدمة
sudo useradd --system --no-create-home --shell /usr/sbin/nologin maltrail
sudo rsync -a --exclude .git . /opt/maltrail/
sudo cp /opt/maltrail/maltrail-{server,sensor}.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now maltrail-server maltrail-sensor
هذا هو التثبيت بأكمله — لا أدلة تحتاج إنشاءها، ولا setcap. الوحدات (units) تنشئ وتمتلك /var/log/maltrail (الأحداث) و/var/lib/maltrail (مجموعة المسارات) عبر LogsDirectory=/StateDirectory= الخاصتَين بـ systemd، وتشغّل العمليتين كمستخدم maltrail غير مميّز مع نظام ملفات للقراءة فقط، وتمنح المستشعر CAP_NET_RAW وCAP_NET_ADMIN فقط — لا شيء غيرهما، ولا صلاحيات جذر في أي مكان. المستشعر يشغّل -T كخطوة ExecStartPre، لذا يفشل النشر المعطوب عند systemctl start بدلًا من أن يعمل بشكل أعمى.
تحقق منه: systemctl status maltrail-sensor وjournalctl -u maltrail-sensor -f.
Docker
docker compose -f docker/docker-compose.yml up -d
انظر docker/README.md.
الإعدادات
كل شيء موجود في maltrail.conf، مقسّمًا إلى [Sensor] و[Server]. الخيارات الأجدر بالمعرفة:
| الخيار | وظيفته |
|---|---|
MONITOR_INTERFACE | الواجهة(ات) التي يُلتقط منها، أو any |
CAPTURE_FILTER | فلتر BPF؛ الافتراضي يُبقي حركة المرور الضخمة بسرعة الخط خارج مساحة المستخدم |
PROCESS_COUNT | عمال الالتقاط — عامل واحد لكل نواة إعداد افتراضي معقول |
LOG_DIR | أين تُكتب الأحداث (/var/log/maltrail) |
TRAILS_FILE | أين توجد مجموعة المسارات المبنية (~/.maltrail/trails.csv؛ /var/lib/maltrail في الوحدات) |
LOG_SERVER | إرسال الأحداث إلى خادم بعيد بدلًا من التسجيل محليًا أو إضافةً إليه |
STATS_ADDRESS | كشف مقاييس Prometheus (للمستشعر؛ معطّل ما لم يُضبط) |
UPDATE_PERIOD | عدد مرات تحديث المسارات |
USER_WHITELIST | قائمتك الخاصة التي لا تُطلق تنبيهات أبدًا |
CUSTOM_TRAILS_DIR | مساراتك الخاصة، إلى جانب المسارات المرفقة |
المسارات
trails/static/malware/asyncrat.txt # one indicator per line
trails/static/malicious/…
trails/static/suspicious/…
trails/feeds/*.py # public feeds, pulled on update
إضافة مؤشر تعني إضافة سطر إلى ملف نصي. إضافة خلاصة (feed) هي وحدة Python صغيرة. كلاهما طلب سحب (pull request) عادي، وهذا الاحتكاك المنخفض هو سبب بقاء المجموعة مفيدة.
مؤشراتك الخاصة توضع في CUSTOM_TRAILS_DIR؛ وأي شيء لا تريد أن تُنبَّه بشأنه أبدًا يوضع في USER_WHITELIST.
الأحداث
سطر واحد لكل اكتشاف، مفصول بمسافات، مع اقتباس CSV حيثما لزم:
"<time>" <sensor> <src_ip> <src_port> <dst_ip> <dst_port> <proto> <type> <trail> "<info>" <reference>
type هو ما طابَق — DNS، IP، IPORT، URL، PATH، HTTP، UA، PORT — وinfo هو سبب اعتباره خبيثًا، وreference هو مصدر المسار: (static)، أو اسم خلاصة، أو (heuristic).
تشغيله
-
-Tيتحقق من الإعدادات ثم يخرج. يمكن استخدامه كبوابة نشر؛ وحدة systemd تشغّله كـExecStartPre. -
STATS_ADDRESSيكشف مقاييس Prometheus. الأربعة الجديرة بالتنبيه عليها، وكلها تعني أن هذا المستشعر لا يكتشف ما تظنه:المقياس ما يعنيه maltrail_up == 0لا يوجد عامل التقاط حي — هذا المضيف غير مراقَب rate(maltrail_capture_dropped_total)الحلقة تُسقط الحزم — اكتشافات فائتة rate(maltrail_local_log_errors_total)تم إنتاج اكتشافات ثم فُقدت maltrail_trail_generationلا يتقدمتوقفت المسارات عن التحديث مفيد أيضًا:
maltrail_log_dir_free_bytes(انظر أدناه) وmaltrail_state_saturations_total، ويكون غير صفري عندما يضيّق فيضان استنزاف الحالة (state-exhaustion) نطاق الاستدلالات. المطابقة الدقيقة للمسارات لا تتأثر بذلك، بحكم التصميم. -
systemctl reload(SIGHUP) يعيد تحميل المسارات دون إعادة تشغيل. المسارات التي يحدّثها أي شيء آخر تُلتقط خلال ثانية واحدة، مع تبديل ذرّي (atomic swap) — دون إعادة تشغيل، ودون حزم مُسقَطة. -
مخزن الملاحظات المكثّف (
USE_CONDENSED_STORAGE،meta.sqlite) الذي يغذّي وجهتَي/metaللحداثة (novelty) والبحث الاستعادي (retro-hunt) في الخادم يُكتب بنفس الصيغة التي ينتجها المستشعر القديم، ويُقارن الاثنان صفًّا بصف عبر أداة التكافؤ (parity harness). كل اختلاف مقصود بين المستشعرين مُدرج فيsensor/docs/COMPATIBILITY.md.
الاحتفاظ بالأحداث
Maltrail لا يحذف أدلة الأحداث أبدًا. لا يوجد إعداد احتفاظ يُنقص سجلاتك، وهذا مقصود: هذه هي السجلات التي تعود إليها بعد أي حادث، والأداة التي تتخلص منها بصمت أسوأ من عديمة الفائدة في الأسبوع الوحيد الذي تحتاجها فيه.
هذا يجعل المساحة الحرة شيئًا تديره بنشاط بدلًا من تجاهله:
- أرسل النسخة الدائمة خارج الجهاز (off-box).
LOG_SERVER(أوSYSLOG_SERVER/LOGSTASH_SERVER) يجعل الخادم أو نظام SIEM هو نظام السجل الرسمي (system of record)، وملف المستشعر المحلي مجرد مخزن مؤقت. هذه هي استراتيجية الاحتفاظ؛ القرص المحلي ليس كذلك. - نَبّه على
maltrail_log_dir_free_bytesبهامش أمان حقيقي.-Tيبلغ عنه أيضًا، ويصدر تحذيرًا عند انخفاضه عن 10 GB. وعند وصوله إلى الصفر لا يستطيع المستشعر الإلحاق وتُفقد الاكتشافات. - الأرشفة قرارك أنت. اضغط سجلات الأيام القديمة أو انقلها وفق جدولك الخاص إذا احتجت المساحة. لاحظ أن واجهة التقارير تقدم السجلات التاريخية كملفات عادية قابلة للبحث (seekable)، لذا فإن ضغطها في مكانها يزيل تلك الأيام من الواجهة — أرشِفها في مكان آخر.
إذا كانت سياستك تتطلب الحذف (سجلات الأحداث تحتوي عناوين IP ونطاقات، وهي بيانات شخصية في بعض الولايات القضائية)، فهذا قرار تشغيلي صريح — اتخذه بأدواتك الخاصة، عن قصد، بدلًا من ترك إعداد افتراضي في المستشعر يفعله بصمت.
التوثيق
sensor/docs/INSTALL.md | التثبيت، الصلاحيات، الإعدادات، استكشاف الأخطاء وإصلاحها |
sensor/docs/ARCHITECTURE.md | كيف يعمل المستشعر داخليًا |
sensor/docs/COMPATIBILITY.md | كل اختلاف مقصود عن المستشعر القديم |
sensor/docs/REPORT.md | القياسات، والملفات الشخصية (profiles)، ونتائج الاختبارات |
sensor/docs/ROADMAP.md | ما تبقى مفتوحًا |
old/README.md | مستشعر Python السابق، محفوظ كمرجع وكمرجع حقيقة للاختبارات (test oracle) |
المساهمة
المسارات هي المساهمة الأكثر قيمة: سطر في الملف الصحيح، مع مصدر. الخلاصات (feeds)، وتقارير الأخطاء، والعمل على المستشعر مرحّب بها بنفس القدر.
البوابة الكاملة للمستشعر هي أمر واحد:
bash sensor/tools/check.sh
تشغّل التنسيق، وفحوصات الكود (lints)، ومجموعة الاختبارات في كلا ملفَي تعريف التصحيح (debug) والإصدار (release)، وتعيد تشغيل مجموعة بيانات (corpus) عبر كلٍّ من المستشعر الحالي ومستشعر Python القديم، متطلبةً أحداثًا متطابقة بايتًا ببايت. الجانب Python هو bash tests/run.sh.
الترخيص
MIT. انظر LICENSE.