الأمن السيبراني الأدلة التقنية

مراقبة السيرفرات مع Wazuh: من السجل Log إلى حظر المهاجم

شغلنا Wazuh مع وكيل على سيرفر تجريبي، فكشف تخمين كلمات مرور SSH وحظر المهاجم تلقائياً، ونبه على ملف PHP دخيل خلال ثانية.

مراقبة السيرفرات مع Wazuh: من السجل Log إلى حظر المهاجم

في مختبر الثغرات استخدمنا Wazuh لسؤال واحد هو «أي سيرفر متأثر بثغرة هذا الأسبوع؟»، وهذا جزء صغير مما صمم له، فالاستخدام الأساسي لـ Wazuh هو أن يقرأ سجلات Logs كل سيرفراتك في مكان واحد، ويطبق عليها آلاف القواعد Rules، وينبهك عندما يحاول أحد تخمين كلمة مرور SSH أو يضيف ملفاً إلى مجلد الموقع أو يمنح نفسه صلاحية مدير، ثم يتصرف وحده إذا طلبت منه ذلك فيحظر عنوان المهاجم. وفي هذا المقال سوف نبني هذا كله في مختبر Lab صغير على Docker، ونهاجم سيرفرنا التجريبي بأنفسنا، ونقرأ كل تنبيه Alert ظهر وكم ثانية احتاج.

📚
المواضيع في السلسلة: (1) كيف يعمل محرك كشف SIEM من الداخل؟ (2) حلول الأمن التجارية وبدائلها مفتوحة المصدر. (3) مراقبة السيرفرات مع Wazuh: من السجل إلى حظر المهاجم (الموضوع الحالي). (4) مراقبة الشبكة واكتشاف التسلل مع Suricata وZeek. (5) Security Onion. (6) Wazuh أم Security Onion؟

وقد شرحنا في محرك كشف SIEM من الداخل كيف يجمع النظام السجلات ويوحدها ويطبق عليها قواعد الكشف، فلن نعيد الفكرة هنا، وسوف نتناول في هذا المقال ما يلي:

  • مكونات Wazuh وما يحتاجه كل مكون من الذاكرة RAM والقرص Disk كما قسناها.
  • تثبيت عقدة واحدة Single Node على Docker، مع إيقاف كشف الثغرات في هذا المختبر لأنه وحده يحتاج 11 GB.
  • تسجيل وكيل Agent على سيرفر Debian، وتوزيع الإعداد عليه مركزياً من المدير Manager.
  • هجوم تخمين كلمات مرور SSH من داخل المختبر، والتنبيهات التي ظهرت، ثم الحظر التلقائي Active Response ورفعه بعد ثلاث دقائق.
  • مراقبة سلامة الملفات File Integrity Monitoring، ولماذا رفعنا مستوى بعض تنبيهاتها بقواعد خاصة.
  • كتابة قواعد لتطبيقك Custom Rules تقرأ سجلات JSON، واختبارها قبل التشغيل.
  • ما تطلبه ضوابط الهيئة الوطنية للأمن السيبراني في السجلات والمراقبة، والنسخ الاحتياطي، والمشكلات التي ظهرت لنا.
دليلكيف يعمل محرك كشف SIEM من الداخل؟كيف يجمع SIEM ملايين السجلات ويوحدها ويطبق قواعد الكشف، مع خط أنابيب Vector وLoki وقاعدة Sigma تطلق فعلاً.دليلحلول الأمن التجارية وبدائلها مفتوحة المصدر: متى توفر فعلاً؟لكل فئة من حلول الأمن التجارية الشائعة في السعودية بديل مفتوح المصدر، وهنا تعرف متى يوفر عليك فعلاً ومتى يكون التجاري أفضل.دليلمختبر Lab: اكتشف السيرفرات المتأثرة بثغرة CVE جديدة وأصلحهافحصنا ثلاثة سيرفرات قديمة وسيرفراً محدثاً بأدوات Trivy وWazuh وسكربت تنبيه صغير، فظهر من يكتشف ثغرة الأسبوع ومن يفوته.

ما الذي يفعله Wazuh؟ أربعة مكونات

يصف المشروع Wazuh بأنه منصة SIEM وXDR، والكلمتان تعنيان شيئين مختلفين: إدارة المعلومات والأحداث الأمنية Security Information and Event Management، واختصاراً SIEM، أي جمع السجلات وتحليلها والتنبيه، والكشف والاستجابة الموسعة Extended Detection and Response، واختصاراً XDR، أي أن يرى ما يحدث على الجهاز نفسه ويتصرف فيه. وفي التطبيق يتكون Wazuh من أربعة أجزاء:

  • الوكيل Agent: برنامج صغير على كل سيرفر أو جهاز، يقرأ ملفات السجلات، ويراقب الملفات، ويجمع قائمة الحزم والعمليات، وينفذ أوامر الاستجابة التي تصله من المدير.
  • المدير Manager: يستقبل البيانات من الوكلاء على المنفذ 1514، ويسجل الوكلاء الجدد على المنفذ 1515، وفيه المحلل wazuh-analysisd الذي يفك السجلات ويطبق القواعد، وواجهة API على المنفذ 55000.
  • الفهرس Indexer: نسخة من OpenSearch تحفظ التنبيهات وتبحث فيها، وهو المكون الأثقل في الذاكرة والقرص.
  • لوحة التحكم Dashboard: واجهة الويب التي تعرض التنبيهات والوكلاء والتقارير.

والكود مفتوح المصدر برخصة GPL-2.0 كما في ملف الرخصة، ولا توجد نسخة مدفوعة بمزايا مقفلة، وإنما تبيع الشركة الدعم الفني والخدمة السحابية. والمشروع نشط جداً، فآخر إصدار مستقر هو 4.14.9 بتاريخ 15 أكتوبر 2026، وصدر بعده الإصدار التجريبي 4.14.10-rc1 في 21 أكتوبر، والإصدار التجريبي الأول من السلسلة 5.0 في 5 أكتوبر. وفي هذا المقال نستخدم 4.14.9، ولا ينصح بتشغيل الإصدارات التجريبية RC على سيرفرات الإنتاج.

المتطلبات Requirements: الرسمية وما قسناه

تطلب صفحة البداية السريعة للعقدة الواحدة ما يلي، مع حفظ التنبيهات 90 يوماً:

عدد الوكلاءالمعالج CPUالذاكرة RAMالقرص لمدة 90 يوماً
من 1 إلى 254 vCPU8 GiB50 GB
من 26 إلى 508 vCPU8 GiB100 GB
من 51 إلى 1008 vCPU8 GiB200 GB

وفي مختبرنا كان استهلاك الذاكرة بعد ربع ساعة من التشغيل مع وكيل واحد كما يلي، من الأمر docker stats:

المكونالذاكرة RAMحجم ال Image
الفهرس wazuh.indexer1.63 GiB (الإعداد -Xms1g -Xmx1g)2.56 GB
المدير wazuh.manager627 MiB2.73 GB
لوحة التحكم wazuh.dashboard198 MiB2.14 GB
السيرفر web01 مع الوكيل وsshd وnginx65 MiBصغير

أي نحو 2.5 GiB للعقدة كاملة وقرابة 7.4 GB من ال Images قبل أي بيانات. وقد يتساءل البعض: لماذا كان المدير في مختبر الثغرات يحتاج 2.7 GiB وقرصاً بحجم 11 GB؟ والإجابة أن كشف الثغرات Vulnerability Detection يفك قاعدة ثغرات كبيرة ويحدثها باستمرار، وقد أوقفناه هنا لأننا نختبر جزء SIEM فقط، أما في الإنتاج فاتركه يعمل وخطط له القرص الذي ذكرناه هناك.

التثبيت على Docker في عقدة واحدة

نستخدم المستودع الرسمي wazuh-docker بوسم الإصدار نفسه، ثم ننشئ الشهادات Certificates التي تتواصل بها المكونات فيما بينها:

git clone -b v4.14.9 --depth 1 https://github.com/wazuh/wazuh-docker.git
cd wazuh-docker/single-node
docker compose -f generate-indexer-certs.yml run --rm generator

وقبل التشغيل غيرنا ثلاثة أشياء في docker-compose.yml: حذفنا نشر المنافذ 1514 و1515 و514 و55000 و9200 على السيرفر المضيف لأن الوكيل في شبكة Docker نفسها، وربطنا لوحة التحكم بالعنوان المحلي فقط، وسمينا الشبكة حتى نضيف إليها السيرفر التجريبي:

  wazuh.dashboard:
    ports:
      - "127.0.0.1:8443:5601"

networks:
  default:
    name: wazuh-lab-net

وفي ملف إعداد المدير config/wazuh_cluster/wazuh_manager.conf غيرنا موضعين، أوقفنا كشف الثغرات كما ذكرنا، وفعلنا استجابة الحظر firewall-drop على القاعدة 5763 التي سوف نراها بعد قليل:

  <vulnerability-detection>
    <enabled>no</enabled>
    <index-status>yes</index-status>
    <feed-update-interval>60m</feed-update-interval>
  </vulnerability-detection>

  <active-response>
    <command>firewall-drop</command>
    <location>local</location>
    <rules_id>5763</rules_id>
    <timeout>180</timeout>
  </active-response>
🛑
الملف الرسمي يضع كلمات مرور ثابتة مثل SecretPassword للفهرس وMyS3cr37P450r.*- لواجهة API، وهي مناسبة لمختبر معزول فقط. قبل أي تشغيل حقيقي غيرها كما في دليل Wazuh على Docker، ولا تنشر المنفذين 9200 و55000 على الإنترنت، وانشر 1514 و1515 فقط للشبكة التي فيها سيرفراتك.
docker compose up -d

وبعد 66 ثانية من الأمر ظهر في سجل المدير السطر API started successfully، وأصبحت كل خدماته تعمل، والأمر التالي يبين ذلك:

docker exec single-node-wazuh.manager-1 /var/ossec/bin/wazuh-control status
wazuh-clusterd not running...
wazuh-modulesd is running...
wazuh-monitord is running...
wazuh-logcollector is running...
wazuh-remoted is running...
wazuh-syscheckd is running...
wazuh-analysisd is running...
wazuh-maild not running...
wazuh-execd is running...
wazuh-db is running...
wazuh-authd is running...
wazuh-agentlessd not running...
wazuh-integratord not running...
wazuh-csyslogd not running...
wazuh-apid is running...

والخدمات المتوقفة طبيعية في العقدة الواحدة، فـ wazuh-clusterd للعنقود Cluster، وwazuh-maild لإرسال التنبيهات بالبريد ولم نفعله، وwazuh-integratord للربط مع أنظمة خارجية مثل Slack. وإذا كنت على Git Bash في Windows فاسبق أوامر docker exec بالمتغير MSYS_NO_PATHCONV=1، وإلا حول Git Bash المسار /var/ossec/bin إلى مسار Windows فيفشل الأمر برسالة no such file or directory.

السيرفر التجريبي والوكيل Agent

السيرفر الذي سوف نراقبه هو web01، وهو Debian 12 عليه SSH وnginx وrsyslog الذي يكتب سجلات الدخول، والوكيل بالإصدار نفسه للمدير، والملف Dockerfile كما يلي:

# A small Debian 12 web server with SSH, syslog, iptables and the Wazuh agent
FROM debian:bookworm-20261005-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
      openssh-server rsyslog iptables curl gnupg ca-certificates procps lsb-release nginx \
 && curl -fsSL https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --dearmor -o /usr/share/keyrings/wazuh.gpg \
 && echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" > /etc/apt/sources.list.d/wazuh.list \
 && apt-get update && apt-get install -y wazuh-agent=4.14.9-1 \
 && rm -rf /var/lib/apt/lists/*
RUN useradd -m -s /bin/bash deploy && echo 'deploy:Lab-Only-Pass-2026' | chpasswd && mkdir -p /run/sshd
COPY start.sh /start.sh
CMD ["sh", "/start.sh"]

والملف start.sh يشغل الخدمات ثم يوجه الوكيل إلى المدير:

#!/bin/sh
# start syslog, sshd and nginx, then point the agent at the manager and start it
rsyslogd
/usr/sbin/sshd
nginx
sed -i "s|<address>.*</address>|<address>$WAZUH_MANAGER</address>|" /var/ossec/etc/ossec.conf
/var/ossec/bin/wazuh-control start
exec tail -f /dev/null

ونحتاج Container ثانياً يمثل المهاجم Attacker، وهو Debian فيه عميل SSH والأداة sshpass فقط. والسيرفر يحتاج الصلاحية NET_ADMIN حتى يستطيع الوكيل أن يضيف قاعدة iptables عند الحظر:

docker build -t lab-web01 .
docker run -d --name web01 --hostname web01 --network wazuh-lab-net --cap-add NET_ADMIN \
  -e WAZUH_MANAGER=wazuh.manager lab-web01
docker run -d --name attacker --hostname attacker --network wazuh-lab-net lab-attacker sleep infinity
docker exec single-node-wazuh.manager-1 /var/ossec/bin/agent_control -l
Wazuh agent_control. List of available agents:
   ID: 000, Name: wazuh.manager (server), IP: 127.0.0.1, Active/Local
   ID: 001, Name: web01, IP: any, Active

وفي سجل الوكيل /var/ossec/logs/ossec.log يظهر التسجيل والاتصال خلال عشرين ثانية:

2026/10/25 19:32:10 wazuh-agentd: INFO: Requesting a key from server: wazuh.manager
2026/10/25 19:32:10 wazuh-agentd: INFO: Valid key received
2026/10/25 19:32:10 wazuh-agentd: INFO: Waiting 20 seconds before server connection
2026/10/25 19:32:30 wazuh-agentd: INFO: (4102): Connected to the server ([wazuh.manager]:1514/tcp).

لماذا لا يقرأ الوكيل سجل SSH؟

عندما قرأنا الإعداد الافتراضي للوكيل في /var/ossec/etc/ossec.conf وجدنا أنه يراقب سجلات nginx وdpkg.log، ولا يوجد فيه الملف /var/log/auth.log الذي يكتب فيه sshd كل محاولة دخول. والسبب أن حزمة الوكيل تضيف ملفات السجلات الموجودة لحظة التثبيت فقط، وفي ال Image كان rsyslog مثبتاً لكنه لم يعمل بعد، فلم يكن الملف موجوداً. وهذا يحدث أيضاً على سيرفر حقيقي ثبت عليه برنامج جديد بعد الوكيل، ولذلك لا تفترض أن الوكيل يرى كل شيء، واقرأ قائمة الملفات في سجله بعد كل تغيير، فهي تظهر في السطور التي تبدأ بـ Analyzing file.

الإعداد المركزي Centralized Configuration من المدير

الطريقة البسيطة أن تعدل ossec.conf على كل سيرفر بيدك، وهذه لا تصلح إذا كان لديك عشرون سيرفراً، لأن كل تعديل يصبح عشرين تعديلاً، وسوف ينسى أحدها. والحل الأنسب هو الإعداد المركزي، فتكتب الملف agent.conf مرة واحدة لكل مجموعة Group من الوكلاء على المدير، وكل وكيل جديد ينضم إلى المجموعة default تلقائياً. والملف الذي استخدمناه في المسار /var/ossec/etc/shared/default/agent.conf كما يلي:

<agent_config>
  <!-- SSH and sudo logins: rsyslog writes them here -->
  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/auth.log</location>
  </localfile>

  <!-- Our own application writes one JSON object per line -->
  <localfile>
    <log_format>json</log_format>
    <location>/srv/shop/logs/app.json</location>
  </localfile>

  <!-- File integrity monitoring in real time, with the diff of text files -->
  <syscheck>
    <directories realtime="yes" report_changes="yes">/var/www/html</directories>
    <directories realtime="yes" report_changes="yes">/root/.ssh</directories>
  </syscheck>
</agent_config>

ثم نتحقق من الملف قبل أن يصل إلى الوكلاء:

docker exec single-node-wazuh.manager-1 /var/ossec/bin/verify-agent-conf
verify-agent-conf: Verifying [etc/shared/default/agent.conf]
verify-agent-conf: OK

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

2026/10/25 19:33:22 wazuh-logcollector: INFO: (1950): Analyzing file: '/var/log/auth.log'.
2026/10/25 19:33:22 wazuh-logcollector: INFO: (1950): Analyzing file: '/srv/shop/logs/app.json'.
2026/10/25 19:33:22 wazuh-syscheckd: INFO: (6012): Real-time file integrity monitoring started.

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

  • الصيغة log_format تحدد طريقة القراءة، فسجل SSH بصيغة syslog، وسجل تطبيقنا بصيغة json لأن كل سطر فيه كائن JSON كامل، وقد شرحنا لماذا تكتب سجلات تطبيقك بهذه الطريقة في السجلات Logging للمطورين.
  • الخيار realtime="yes" يجعل المراقبة فورية عبر inotify بدلاً من الفحص الدوري كل 12 ساعة، والخيار report_changes="yes" يرسل الفرق Diff بين النسختين للملفات النصية.
  • لا تضع report_changes على مجلد فيه أسرار مثل ملفات .env، والسبب أن الفرق يصل إلى المدير والفهرس كما هو، أي أن كلمة المرور الجديدة سوف تظهر في لوحة التحكم.

نجرب الهجوم: تخمين كلمات مرور SSH

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

نجرب عشر كلمات مرور شائعة على المستخدم deploy، وهذا ما تفعله آلاف السكربتات على أي سيرفر يفتح المنفذ 22 للإنترنت:

docker exec attacker sh -c 'for p in 123456 password qwerty admin123 letmein Passw0rd welcome 2026 root toor; do
  sshpass -p $p ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 \
    -o LogLevel=ERROR deploy@web01 true
  echo "$(date -u +%T) $p rc=$?"
done'

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

Permission denied, please try again.
19:33:47 123456 rc=5
19:33:51 password rc=5
Permission denied, please try again.
Permission denied, please try again.
19:33:54 qwerty rc=5
Permission denied, please try again.
19:33:58 admin123 rc=5
Permission denied, please try again.
19:34:03 letmein rc=5
Permission denied, please try again.
19:34:07 Passw0rd rc=5
Permission denied, please try again.
19:34:11 welcome rc=5
Permission denied, please try again.
19:34:15 2026 rc=5
ssh: connect to host web01 port 22: Connection timed out
19:34:20 root rc=255
ssh: connect to host web01 port 22: Connection timed out
19:34:25 toor rc=255

فأول ثماني محاولات رفضها SSH بكلمة مرور خاطئة، أما التاسعة والعاشرة فلم يصل فيهما المهاجم إلى SSH أصلاً، والسبب في التنبيهات التالية من الملف /var/ossec/logs/alerts/alerts.json على المدير، وقد طبعنا من كل تنبيه الوقت ورقم القاعدة ومستواها Level وعدد مرات إطلاقها والوصف والعنوان ورقم أسلوب الهجوم في MITRE ATT&CK:

19:33:44 5503 5 1 PAM: User login failed. | 192.168.112.6 T1110.001
19:33:46 5760 5 1 sshd: authentication failed. | 192.168.112.6 T1110.001,T1021.004
19:33:48 5503 5 2 PAM: User login failed. | 192.168.112.6 T1110.001
19:33:50 5760 5 2 sshd: authentication failed. | 192.168.112.6 T1110.001,T1021.004
...
19:34:08 5503 5 7 PAM: User login failed. | 192.168.112.6 T1110.001
19:34:12 5760 5 7 sshd: authentication failed. | 192.168.112.6 T1110.001,T1021.004
19:34:12 5551 10 1 PAM: Multiple failed logins in a small period of time. | 192.168.112.6 T1110
19:34:14 5763 10 1 sshd: brute force trying to get access to the system. Authentication failed. | 192.168.112.6 T1110
19:34:16 651 3 1 Host Blocked by firewall-drop Active Response | 192.168.112.6

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

  • كل محاولة أعطت تنبيهين: الأول 5503 من PAM والثاني 5760 من sshd، وكلاهما بالمستوى 5، وهو مستوى يحفظ في الفهرس لكنه لا يستحق أن يوقظ أحداً، فمحاولة دخول فاشلة واحدة تحدث كل يوم.
  • القاعدة 5763 لا تقرأ سطراً جديداً: وإنما تعد، فهي قاعدة تكرار Frequency تطلق المستوى 10 عندما تتكرر القاعدة 5760 ثماني مرات من العنوان نفسه خلال مدة قصيرة، وقد جمع التنبيه في الحقل previous_output السطور السبعة السابقة من auth.log، وكانت أولها في الساعة 19:33:45 والثامنة في 19:34:14، أي 28 ثانية.
  • الرقم T1110 هو أسلوب Brute Force: في MITRE ATT&CK، وWazuh يضيفه إلى القواعد الجاهزة، فتستطيع أن تبحث في لوحة التحكم بالأسلوب بدلاً من رقم القاعدة.
  • القاعدة 651: هي تنبيه من الوكيل نفسه بأنه نفذ الحظر، فهو يقرأ سجل الاستجابة active-responses.log ويرسله كأي سجل آخر.

الحظر التلقائي Active Response: ماذا حدث على السيرفر؟

عندما أطلقت القاعدة 5763 أرسل المدير أمراً إلى الوكيل على web01 بتشغيل السكربت firewall-drop، وهو أحد سكربتات الاستجابة الجاهزة، فأضاف قاعدتين في جدار الحماية Firewall للسيرفر:

docker exec web01 iptables -S | grep DROP
-A INPUT -s 192.168.112.6/32 -j DROP
-A FORWARD -s 192.168.112.6/32 -j DROP

وهذا ما جعل المحاولة التاسعة تنتهي بالرسالة Connection timed out، فالسيرفر لم يعد يرد على المهاجم إطلاقاً. وفي سجل الاستجابة على السيرفر نجد البداية والنهاية:

2026/10/25 19:34:14 active-response/bin/firewall-drop: Starting
2026/10/25 19:34:14 active-response/bin/firewall-drop: {"version":1,"origin":{"name":"node01","module":"wazuh-execd"},"command":"add", ...
2026/10/25 19:34:14 active-response/bin/firewall-drop: Ended
2026/10/25 19:37:15 active-response/bin/firewall-drop: Starting
2026/10/25 19:37:15 active-response/bin/firewall-drop: {"version":1,"origin":{"name":"node01","module":"wazuh-execd"},"command":"delete", ...
2026/10/25 19:37:15 active-response/bin/firewall-drop: Ended

فالحظر استمر 181 ثانية ثم أزاله الوكيل وحده لأننا وضعنا timeout بقيمة 180، وظهر التنبيه 652 «Host Unblocked by firewall-drop Active Response»، وبعدها عادت محاولة جديدة من المهاجم تصل إلى SSH وترفض بكلمة المرور. والشكل التالي يجمع المسار والتوقيت:

المهاجم يجرب كلمات مرور SSH على web01، والوكيل يرسل السطور إلى المدير الذي يطلق القاعدة 5763 ثم يأمر الوكيل بحظر العنوان 180 ثانية
من أول محاولة فاشلة إلى الحظر خلال 30 ثانية، ورفع الحظر بعد ثلاث دقائق

وقد يتساءل البعض: لماذا لا نجعل الحظر دائماً؟ والإجابة أن توثيق Active Response يحذر من أن الاستجابة المصممة بشكل سيئ قد تزيد الخطر على السيرفر، والحظر الدائم بقاعدة عامة سوف يحظر يوماً ما شخصاً شرعياً نسي كلمة مروره، أو يحظر عنوان مكتبك كله إذا كان الموظفون يخرجون إلى الإنترنت بعنوان واحد. لذلك عليك بثلاثة أمور:

  • اجعل الحظر مؤقتاً بالقيمة timeout، فالسكربتات الآلية تنتقل إلى هدف آخر بعد دقائق.
  • أضف عناوين الإدارة والمراقبة وشبكة VPN إلى القائمة البيضاء white_list في قسم global من إعداد المدير، كما في مرجع الإعداد.
  • إذا كان السيرفر خلف Reverse Proxy أو Load Balancer فالعنوان الذي يراه التطبيق قد يكون عنوان ال Proxy، وحظره يعني إيقاف الموقع عن الجميع، فتأكد أن السجل يحمل العنوان الحقيقي للعميل قبل أن تربط به أي حظر.

وإذا كنت تستخدم Fail2ban على سيرفر واحد كما في تأمين خادم VPS من أول دخول، فالنتيجة هنا مشابهة، والفرق أن Wazuh يحفظ كل محاولة في مكان واحد لكل السيرفرات، فإذا جرب المهاجم نفسه عشرة سيرفرات فسوف تراه في بحث واحد، وتستطيع أن تربط الحظر بقواعد أخرى غير SSH.

مراقبة سلامة الملفات File Integrity Monitoring

المهاجم الذي ينجح في الدخول يترك أثراً في الملفات غالباً، فيرفع ملف PHP صغيراً يعطيه أوامر عن بعد Web Shell، أو يضيف مفتاحه إلى authorized_keys حتى يعود متى شاء. ومراقبة سلامة الملفات File Integrity Monitoring، واختصاراً FIM، تحفظ الهاش Hash والصلاحيات والمالك لكل ملف في المجلدات التي تحددها، وتنبهك عند أي تغيير. والآن سوف نقوم بثلاثة تغييرات على web01:

docker exec web01 sh -c '
  echo "<?php system(\$_GET[\"c\"]); ?>" > /var/www/html/up.php
  sed -i "s/Welcome to nginx/Hacked by lab/" /var/www/html/index.nginx-debian.html
  echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILabOnlyKeyForTheWazuhArticle00000000000 attacker@lab" >> /root/.ssh/authorized_keys'

نفذنا الأمر في الساعة 19:35:10، وظهرت التنبيهات الثلاثة في الثانية التالية:

19:35:11 554 5 1 File added to the system. | /var/www/html/up.php
19:35:11 550 7 1 Integrity checksum changed. | T1565.001 /var/www/html/index.nginx-debian.html
19:35:11 554 5 2 File added to the system. | /root/.ssh/authorized_keys

وفي تنبيه الملف المعدل يرسل الوكيل الفرق بين النسختين لأننا فعلنا report_changes، وهذا جزء من الحقل syscheck كما وصل:

{
  "path": "/var/www/html/index.nginx-debian.html",
  "mode": "realtime",
  "size_before": "615",
  "size_after": "609",
  "sha256_before": "fb47468a2cd3953c7131431991afcc6a2703f14640520102eea0a685a7e8d6de",
  "sha256_after": "795bc509905a6f1387a5bb8610c3866b224e5b4c640a8f8fcfcd0e8093f28ea3",
  "diff": "4c4\n< <title>Welcome to nginx!</title>\n---\n> <title>Hacked by lab!</title>\n12c12\n< <h1>Welcome to nginx!</h1>\n---\n> <h1>Hacked by lab!</h1>\n",
  "changed_attributes": ["size", "inode", "mtime", "md5", "sha1", "sha256"],
  "event": "modified"
}

المشكلة: ملف Web Shell بالمستوى 5 فقط

هناك مشكلة رئيسية في النتيجة أعلاه، فملف PHP جديد في مجلد الموقع ومفتاح SSH جديد للمستخدم root أخطر ما حدث، ومع ذلك أخذا المستوى 5، أي المستوى نفسه لمحاولة دخول فاشلة واحدة، بينما أخذ تعديل صفحة HTML المستوى 7. والسبب أن القاعدة الجاهزة 554 عامة لأي ملف جديد في أي مجلد مراقب، فهي لا تعرف أن مجلد الموقع لا يجب أن يظهر فيه ملف PHP إلا مع النشر. والحل أن نكتب قاعدتين فرعيتين في الملف /var/ossec/etc/rules/local_rules.xml على المدير، ترفعان المستوى إلى 12 بحسب المسار:

<group name="syscheck,local,">

  <rule id="100110" level="12">
    <if_sid>554</if_sid>
    <field name="file" type="pcre2">^/var/www/.+\.php$</field>
    <description>New PHP file in the web root: $(file)</description>
    <mitre>
      <id>T1505.003</id>
    </mitre>
  </rule>

  <rule id="100111" level="12">
    <if_sid>550,554</if_sid>
    <field name="file" type="pcre2">/\.ssh/authorized_keys$</field>
    <description>SSH authorized_keys changed: $(file)</description>
    <mitre>
      <id>T1098.004</id>
    </mitre>
  </rule>

</group>

ثم نتحقق من القواعد ونعيد تشغيل المدير، فالقواعد لا تقرأ إلا عند بدء المحلل:

docker exec single-node-wazuh.manager-1 /var/ossec/bin/wazuh-analysisd -t
docker exec single-node-wazuh.manager-1 /var/ossec/bin/wazuh-control restart

وبعد إضافة ملف PHP آخر وسطر جديد في authorized_keys كانت النتيجة كما يلي:

19:36:25 100110 12 1 New PHP file in the web root: /var/www/html/cache.php | T1505.003
19:36:25 100111 12 1 SSH authorized_keys changed: /root/.ssh/authorized_keys | T1098.004

والرقمان T1505.003 وT1098.004 هما في MITRE ATT&CK أسلوبا Web Shell وSSH Authorized Keys. والصورة التالية من صفحة File Integrity Monitoring في لوحة التحكم، وفيها التغييرات الخمسة على web01 بمستوياتها قبل القاعدتين وبعدهما:

صفحة File Integrity Monitoring في Wazuh تعرض خمسة تغييرات على web01، منها ملفا PHP وauthorized_keys بالمستوى 12 بعد القواعد المحلية
تغييرات الملفات على web01: القاعدتان المحليتان 100110 و100111 رفعتا المستوى إلى 12

لاحظ أن FIM لا يعرف من غير الملف في هذا الإعداد، فالحقل uname_after يعطيك مالك الملف وليس المستخدم الذي عدله، ولمعرفة من عدل الملف وبأي عملية يحتاج Wazuh وضع whodata الذي يعتمد على auditd في Linux كما في توثيق FIM، ولم نجربه هنا لأن auditd لا يعمل داخل Container عادي.

قواعد لتطبيقك Custom Rules من سجلات JSON

القواعد الجاهزة تغطي SSH وnginx وPAM وغيرها، لكنها لا تعرف تطبيقك، فإذا كان لديك متجر يكتب في سجله أن مستخدماً فشل في الدخول، أو أن موظفاً منح نفسه صلاحية مدير، فلن ينبهك أحد إلا إذا كتبت القاعدة بنفسك. ولنفرض أن تطبيقنا shop-api يكتب سطراً بصيغة JSON لكل حدث:

{"time":"2026-10-25T19:31:02Z","app":"shop-api","event":"login_failed","user":"sara","src_ip":"172.30.0.9"}

ولا نحتاج محللاً Decoder خاصاً، فـ محلل JSON الجاهز يفك كل المفاتيح، والقواعد كما يلي، في الملف نفسه local_rules.xml، والأرقام من 100000 إلى 120000 محجوزة للقواعد المحلية كما في توثيق القواعد الخاصة:

<group name="shop-api,">

  <rule id="100100" level="3">
    <decoded_as>json</decoded_as>
    <field name="app">^shop-api$</field>
    <description>shop-api: $(event)</description>
  </rule>

  <rule id="100101" level="5">
    <if_sid>100100</if_sid>
    <field name="event">^login_failed$</field>
    <description>shop-api: failed login for $(dstuser) from $(src_ip)</description>
    <group>authentication_failed,</group>
  </rule>

  <rule id="100102" level="10" frequency="5" timeframe="60" ignore="300">
    <if_matched_sid>100101</if_matched_sid>
    <same_field>src_ip</same_field>
    <description>shop-api: 5 failed logins from $(src_ip) within 60 seconds</description>
    <mitre>
      <id>T1110</id>
    </mitre>
    <group>authentication_failures,</group>
  </rule>

  <rule id="100103" level="12">
    <if_sid>100100</if_sid>
    <field name="event">^role_changed$</field>
    <field name="new_role">^admin$</field>
    <description>shop-api: $(dstuser) became admin, changed by $(by)</description>
    <mitre>
      <id>T1098</id>
    </mitre>
  </rule>

</group>

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

  • القاعدة 100100 هي الأب لكل أحداث التطبيق، ومستواها 3 وهو أقل مستوى يحفظ في هذا الإعداد، والقواعد الأخرى تبدأ منها بالشرط if_sid.
  • القاعدة 100102 تعد القاعدة 100101 بالشرط if_matched_sid، والشرط same_field يجعل العد لكل عنوان على حدة، فخمس محاولات من خمسة عناوين مختلفة لا تطلقها.
  • الخاصية ignore="300" تمنع القاعدة من الإطلاق مرة أخرى خلال خمس دقائق، وسوف نرى بعد قليل لماذا أضفناها.

اختبر القاعدة قبل التشغيل مع wazuh-logtest

لا تقم بنشر قاعدة جديدة ثم انتظار هجوم حقيقي لتعرف هل تعمل، فالأداة wazuh-logtest على المدير تأخذ السطر وتعرض لك المراحل الثلاث: ما قبل الفك Pre-decoding، والفك Decoding، والقواعد Rules. وفي المحاولة الأولى كانت القاعدة تستخدم $(user) في الوصف، فكان المخرج كما يلي:

echo '{"time":"2026-10-25T19:31:02Z","app":"shop-api","event":"login_failed","user":"sara","src_ip":"172.30.0.9"}' \
  | docker exec -i single-node-wazuh.manager-1 /var/ossec/bin/wazuh-logtest
**Phase 1: Completed pre-decoding.
	full event: '{"time":"2026-10-25T19:31:02Z","app":"shop-api","event":"login_failed","user":"sara","src_ip":"172.30.0.9"}'

**Phase 2: Completed decoding.
	name: 'json'
	app: 'shop-api'
	dstuser: 'sara'
	event: 'login_failed'
	src_ip: '172.30.0.9'
	time: '2026-10-25T19:31:02Z'

**Phase 3: Completed filtering (rules).
	id: '100101'
	level: '5'
	description: 'shop-api: failed login for  from 172.30.0.9'
	groups: '['shop-api', 'authentication_failed']'
	firedtimes: '1'
	mail: 'False'
**Alert to be generated.

لاحظ أن اسم المستخدم فارغ في الوصف، والسبب في المرحلة الثانية، فالمحلل وضع قيمة المفتاح user في الحقل dstuser لأن user من الحقول الثابتة في Wazuh، أما المفاتيح الأخرى فبقيت بأسمائها. لذلك غيرنا الوصف إلى $(dstuser)، وهذا الخطأ لن يظهر لك في أي رسالة، فالقاعدة تعمل والتنبيه يصل لكن ناقصاً. والشكل التالي يلخص المراحل الثلاث:

سطر JSON من التطبيق يمر بما قبل الفك ثم محلل json الذي يحول user إلى dstuser ثم القواعد 100100 و100101 و100102
المراحل الثلاث في المدير، والمفتاح user الذي يصبح dstuser

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

	id: '100101'
	level: '5'
	description: 'shop-api: failed login for sara from 172.30.0.9'
	firedtimes: '4'
	id: '100102'
	level: '10'
	description: 'shop-api: 5 failed logins from 172.30.0.9 within 60 seconds'
	firedtimes: '1'
	mitre.id: '['T1110']'
	mitre.tactic: '['Credential Access']'
	mitre.technique: '['Brute Force']'
	id: '100103'
	level: '12'
	description: 'shop-api: omar became admin, changed by sara'
	firedtimes: '1'
	mitre.id: '['T1098']'
	mitre.tactic: '['Persistence']'
	mitre.technique: '['Account Manipulation']'

فالسطور الأربعة الأولى أعطت 100101، والخامس أعطى 100102 بالمستوى 10، وسطر الصلاحية أعطى 100103 بالمستوى 12 مع اسم من غير الصلاحية.

ماذا يحدث على السيرفر الحقيقي؟ ولماذا ignore؟

بعد ذلك كتبنا الأسطر نفسها في الملف /srv/shop/logs/app.json على web01، ست محاولات بفاصل ثانية من العنوان 203.0.113.50، وفي النسخة الأولى من القواعد دون الخاصية ignore كانت النتيجة:

19:36:26 100101 5 1 shop-api: failed login for sara from 203.0.113.50 | 203.0.113.50
19:36:26 100101 5 2 shop-api: failed login for sara from 203.0.113.50 | 203.0.113.50
19:36:28 100101 5 4 shop-api: failed login for sara from 203.0.113.50 | 203.0.113.50
19:36:28 100101 5 3 shop-api: failed login for sara from 203.0.113.50 | 203.0.113.50
19:36:30 100102 10 1 shop-api: 5 failed logins from 203.0.113.50 within 60 seconds | 203.0.113.50 T1110
19:36:30 100102 10 2 shop-api: 5 failed logins from 203.0.113.50 within 60 seconds | 203.0.113.50 T1110
19:36:32 100103 12 1 shop-api: omar became admin, changed by sara | T1098

فالمحاولة السادسة أطلقت القاعدة 100102 مرة ثانية، ولو استمر المهاجم مئة محاولة لوصلك ستة وتسعون تنبيهاً بالمستوى 10، وهذا ما يسمى إرهاق التنبيهات Alert Fatigue الذي شرحناه في محرك كشف SIEM. لذلك أضفنا ignore="300"، وأرسلنا ثماني محاولات من عنوان آخر، فكانت النتيجة تنبيهاً واحداً بالمستوى 10 وسبعة بالمستوى 5:

19:38:26 100101 5 1 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23
19:38:26 100101 5 2 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23
19:38:28 100101 5 3 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23
19:38:30 100101 5 4 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23
19:38:30 100101 5 5 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23
19:38:32 100102 10 1 shop-api: 5 failed logins from 198.51.100.23 within 60 seconds | 198.51.100.23 T1110
19:38:32 100101 5 2 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23
19:38:34 100101 5 6 shop-api: failed login for khaled from 198.51.100.23 | 198.51.100.23

ولاحظ أن ترتيب التنبيهات وعدادها firedtimes ليسا متسلسلين دائماً عندما تصل الأسطر في الثانية نفسها، فالمحلل يعالج الأحداث بأكثر من خيط Thread، ولذلك اعتمد على الوقت والعنوان عند التحقيق وليس على العداد. والصورة التالية من صفحة الأحداث Events للوكيل web01 في لوحة التحكم، وفيها التنبيهات بأوقات السيرفر المحلية:

صفحة Threat Hunting في Wazuh تعرض أحداث web01 ومنها تنبيهات shop-api بالمستوى 5 والتنبيه 100102 بالمستوى 10
أحداث web01 في لوحة التحكم: تنبيهات التطبيق بجانب تنبيهات SSH

تقييم الإعدادات SCA: ما وجده Wazuh دون أن نطلب

بجانب ما أعددناه، شغل الوكيل وحده تقييم الإعدادات Security Configuration Assessment، واختصاراً SCA، الذي يقارن إعدادات السيرفر بمعيار CIS للتوزيعة كما في توثيق SCA، فوصل هذا الملخص في التنبيه 19004:

SCA summary: Center for Internet Security Debian Linux 12 Benchmark v1.1.0: Score less than 50% (43)
passed: 71, failed: 92, invalid: 44, total_checks: 207

والنتيجة 43% منطقية لأن ال Container ليس سيرفراً كاملاً، فلا يوجد فيه auditd ولا تقسيم للأقراص ولا إعداد للنواة Kernel، ولكن على سيرفر حقيقي فإن هذه القائمة من 92 فحصاً فاشلاً هي نقطة بداية جيدة للتقوية Hardening، وكل فحص فيها يذكر السبب وطريقة الإصلاح.

ماذا تطلب ضوابط الهيئة الوطنية للأمن السيبراني؟

إذا كانت جهتك ملزمة بالضوابط الأساسية للأمن السيبراني ECC 2-2024، فالمكون الفرعي 2-12 «إدارة سجلات الأحداث ومراقبة الأمن السيبراني» يطلب في الضابط 2-12-3 حداً أدنى، وهذا ما يغطيه المختبر منه وما لا يغطيه، وقد شرحنا الضوابط نفسها في الضوابط الأساسية بلغة بسيطة:

الضابطالمطلوبفي Wazuh
2-12-3-1تفعيل السجلات للأصول المعلوماتية الحساسةقراءة سجلات كل سيرفر حساس عبر الوكيل، مع التأكد من الملفات كما رأينا في auth.log
2-12-3-2تفعيل السجلات للحسابات ذات الصلاحيات الهامة ولأحداث الدخول عن بعدقواعد SSH وPAM وsudo الجاهزة، وقاعدة مثل 100103 لصلاحيات تطبيقك
2-12-3-3تحديد تقنيات SIEM المطلوبة لجمع السجلاتWazuh نفسه، ويوثق في سياسة الجهة
2-12-3-4المراقبة المستمرة لسجلات الأحداثتحتاج شخصاً يقرأ التنبيهات، والأداة لا تغني عنه
2-12-3-5الاحتفاظ بالسجلات مدة لا تقل عن 12 شهراًغير مغطى بالإعداد الافتراضي، ويحتاج خطة قرص وسياسة فهرس

والنقطة الأخيرة هي التي تفاجئ أغلب الفرق، فالمتطلبات الرسمية التي ذكرناها محسوبة على 90 يوماً، و12 شهراً تعني أربعة أضعاف القرص تقريباً، أو أن تنقل التنبيهات القديمة إلى أرشيف أرخص مثل نسخ الفهرس Snapshots إلى تخزين كائنات Object Storage، فاحسب هذا قبل أن تشتري السيرفر.

التكلفة: الاستضافة الذاتية أم Wazuh Cloud؟

الكود مجاني، والتكلفة الحقيقية في السيرفر وساعات المهندس، أما إذا أردت أن تدير الشركة المنصة عنك فصفحة Wazuh Cloud تعرض يوم 25 أكتوبر 2026 هذه الخطط:

الخطةالوكلاء النشطونالبيانات المفهرسةالأرشيفالسعر الشهري
Smallحتى 100شهر واحد3 أشهريبدأ من 571 دولاراً
Mediumحتى 2503 أشهرسنةيبدأ من 923 دولاراً
Largeحتى 5003 أشهرسنةيبدأ من 1467 دولاراً

والمقارنة مع منتجات SIEM التجارية التي تسعر بحجم البيانات، مثل Microsoft Sentinel وSplunk، شرحناها بالأرقام في حلول الأمن التجارية وبدائلها. وتذكر أن الخدمة السحابية تعني أن سجلات سيرفراتك تخرج إلى مزود خارجي، فإذا كانت الجهة ملزمة بضوابط تتعلق بموقع البيانات فهذا القرار يحتاج مراجعة قبل السعر.

النسخ الاحتياطي Backup والاستعادة

أهم ما تحفظه هو مجلد الإعداد /var/ossec/etc في المدير، ففيه مفاتيح الوكلاء client.keys، وإذا فقدته فعليك أن تعيد تسجيل كل الوكلاء، وفيه أيضاً ossec.conf والقواعد المحلية وملفات shared للمجموعات. والأمر التالي يحفظ ال Volume في ملف مضغوط:

docker run --rm -v single-node_wazuh_etc:/src:ro -v "$PWD":/backup alpine:3.22 \
  tar czf /backup/wazuh-etc.tgz -C /src .

وكان حجم الملف في المختبر 290 KB، وفيه client.keys وossec.conf وrules/local_rules.xml وshared/default/agent.conf. واحفظ معه مجلد الشهادات config/wazuh_indexer_ssl_certs وملفات compose، أما التنبيهات نفسها في الفهرس فتحفظ بنسخ الفهرس Snapshots كما في توثيق OpenSearch، والسؤال الذي يحدد طريقتك هو: هل تحتاج التنبيهات القديمة بعد الاستعادة؟ فإذا كانت الضوابط تلزمك بسنة من السجلات فالجواب نعم.

التحديث Upgrade إلى إصدار أحدث

في Docker يعني التحديث أن تأخذ وسم الإصدار الجديد من المستودع wazuh-docker، وتقارن ملفات الإعداد فيه بملفاتك، ثم تغير وسوم ال Images الثلاثة وتعيد التشغيل، كما يشرح دليل Docker. ولاحظ ترتيب الإصدارات، فالمدير يجب أن يكون بإصدار مساو للوكلاء أو أحدث منها، لذلك حدث المدير أولاً ثم الوكلاء. ولا تنتقل إلى السلسلة 5.0 قبل أن تقرأ ملاحظات إصدارها المستقر، والسبب أن الإصدار الرئيسي قد يغير السلوك الذي تعتمد عليه قواعدك ولوحاتك (Breaking Change).

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

  • لا تظهر تنبيهات SSH أبداً: تحقق من أن الملف /var/log/auth.log في سطور Analyzing file في سجل الوكيل، فإذا لم يكن موجوداً فأضفه في agent.conf كما فعلنا، وعلى التوزيعات التي تعتمد على journald فقط بلا rsyslog اقرأ السجل من journald بدلاً من الملف.
  • الوصف في التنبيه ناقص: اختبر السطر في wazuh-logtest واقرأ أسماء الحقول في المرحلة الثانية، فالمفتاح user في JSON يصبح dstuser.
  • القاعدة الجديدة لا تعمل: القواعد تقرأ عند بدء المحلل فقط، فأعد تشغيل المدير بعد كل تعديل، وشغل wazuh-analysisd -t قبلها حتى لا يتوقف المحلل بسبب خطأ في XML.
  • الحظر لا يحدث رغم ظهور القاعدة 5763: سكربت firewall-drop يحتاج iptables على السيرفر وصلاحية تعديله، وفي Container يحتاج --cap-add NET_ADMIN، واقرأ /var/ossec/logs/active-responses.log على السيرفر.
  • رسالة no such file or directory مع مسار Windows: على Git Bash استخدم MSYS_NO_PATHCONV=1 قبل أوامر docker exec.
  • لوحة التحكم عالقة على Health Check بعد التشغيل: الفهرس يحتاج بضع دقائق في أول تشغيل، فانتظر ثم أعد تحميل الصفحة قبل أن تبحث عن خطأ.

الخلاصة

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

  • العقدة الواحدة احتاجت نحو 2.5 GiB من الذاكرة دون كشف الثغرات، والفهرس وحده 1.63 GiB، فخطط للفهرس وقرصه قبل أي شيء آخر.
  • هجوم تخمين كلمات المرور على SSH أطلق القاعدة 5763 بعد ثماني محاولات خلال 28 ثانية، والحظر التلقائي أوقف المهاجم في الثانية نفسها ثم رفع بعد 180 ثانية، فاجعل الحظر مؤقتاً ومعه قائمة بيضاء.
  • مراقبة الملفات في الوقت الحقيقي نبهت على كل تغيير خلال ثانية، لكن القواعد الجاهزة أعطت ملف Web Shell المستوى 5 فقط، ولذلك تحتاج قواعد محلية تعرف مجلداتك المهمة.
  • قواعد تطبيقك من سجلات JSON لا تحتاج محللاً خاصاً، واختبرها دائماً في wazuh-logtest، واستخدم ignore حتى لا تغرق في التنبيهات المكررة.
  • الأداة لا تكفي للالتزام بالضابط 2-12، فالمراقبة المستمرة تحتاج شخصاً، والاحتفاظ 12 شهراً يحتاج قرصاً وخطة.

وفي المقال القادم بإذن الله سوف ننتقل من السيرفر إلى الشبكة، فنراقب الحركة نفسها مع Suricata وZeek، وهي البيانات التي لا يراها وكيل Wazuh.

دليلكيف يعمل محرك كشف SIEM من الداخل؟كيف يجمع SIEM ملايين السجلات ويوحدها ويطبق قواعد الكشف، مع خط أنابيب Vector وLoki وقاعدة Sigma تطلق فعلاً.دليلمختبر Lab: اكتشف السيرفرات المتأثرة بثغرة CVE جديدة وأصلحهافحصنا ثلاثة سيرفرات قديمة وسيرفراً محدثاً بأدوات Trivy وWazuh وسكربت تنبيه صغير، فظهر من يكتشف ثغرة الأسبوع ومن يفوته.دليلتأمين سيرفر VPS على Ubuntu من أول دخولقبل أن تثبت أي تطبيق على سيرفرك الجديد، هذه الخطوات تغلق أبرز الثغرات وأولها الدخول بمفتاح SSH بدل كلمة المرور.دليلالسجلات Logging للمطورين: ماذا تسجل وماذا لا تسجلكيف تكتب سجلات Logs تساعدك على فهم ما حدث في الإنتاج، وما الذي لا يدخل السجل أبداً، وكيف تجمعها في مكان واحد.

تدريب عملي Practice

  • اكتب قاعدة محلية ترفع إلى المستوى 12 أي تعديل على الملف /etc/sudoers أو إضافة ملف في /etc/sudoers.d، ثم عدل الملف على سيرفر تجريبي وتأكد من التنبيه.
  • اختر سجلاً حقيقياً من تطبيقك، واكتب له قاعدة فشل دخول وقاعدة تكرار بالشرط same_field، واختبرهما في wazuh-logtest قبل نشرهما.

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

  • أكتوبر 2026: كتابة الدليل وتنفيذ المختبر يوم 25 أكتوبر 2026 على Wazuh 4.14.9 في عقدة واحدة على Docker، مع وكيل على Debian 12 وهجوم SSH من داخل شبكة المختبر.
نشرة عرب رووت | ArabRoot

معرفة تستحق مكاناً في بريدك.

مقالات مختارة وأدوات مفيدة وأفكار لمشروعك القادم، في رسالة واحدة كل أسبوع.

يمكنك إلغاء الاشتراك متى شئت. الخصوصية

تم استلام طلبك. افتح بريدك واضغط رابط التأكيد لإتمام الاشتراك.