ai-ml

استخدام ReAct لتنسيق سلسلة القتل

في المرة الأولى التي حاولنا فيها جعل نموذج واحد ينسق حملة اختبار اختراق كاملة، فشل في الدقيقة الأربعين. ليس بسبب نقص في القدرة التقنية. كان النموذج يعرف تماماً ما يجب فعله مع Redis مكشوف، وما يجب فعله مع Jenkins غير مصادق عليه، وكيفية ربط SSRF ببيانات وصفية سحابية. كانت المشكلة شيئاً آخر، أكثر مللاً: عند أربعين صفحة من السياق، كان الوكيل قد نسي النطاق الذي أعطيناه إياه في البداية. بدأ في مسح نطاقات خارج النطاق المحدد، وهلوس بأداتين غير موجودتين في صندوق أدواتنا (nmap-fast-aggressive و burp-pro-headless، كلاهما غير حقيقي)، واقترح استغلال CVE لم يكن لدى العميل حتى مثبتاً.

في تلك الليلة أعدنا كتابة جزء كبير من المنسق. ما خرج من ذلك هو أساس ما هو اليوم محرك Gandalf CLI: امتداد عنيد إلى حد ما لإطار ReAct مكيف للحملات الطويلة متعددة المراحل، مع عدة نماذج تتعاون تحت سقف واحد. هذه المقالة هي محاولة لشرح لماذا وصلنا إلى ذلك التصميم، وما الذي استعرناه، وما الذي اضطررنا إلى اختراعه بأنفسنا، وأين نستمر في كسر وجوهنا.

ReAct، بدون تسويق

نشر Yao وزملاؤه ReAct في أواخر 2022 (Yao et al., 2022)[1]. الفكرة بسيطة بشكل خادع. بدلاً من أن تطلب من النموذج إجابة فقط، أو إجراءً فقط، تطلب منه التداخل بين ثلاثة أشياء: Thought (تفكير صريح باللغة الطبيعية حول ما يجب القيام به)، و Action (استدعاء لأداة خارجية، عادةً ما تكون مكتوبة جيداً) و Observation (الإخراج الذي تعيده الأداة، والذي يعود إلى السياق). حلقة. دورة أخرى. وهكذا حتى يقرر النموذج أن لديه ما يكفي.

الشيء المهم هو أن التفكير يظهر كنص في الرولوت نفسه. هذا يحل شيئين في نفس الوقت. من ناحية، يكتسب النموذج قدرة Chain-of-Thought (Wei et al., 2022)[2]، أي تفكيك مشكلة قبل التصرف. من ناحية أخرى، لا يعلق في رأسه: كل بضع تكرارات يجب أن يلمس العالم الحقيقي ويعود بملاحظات حقيقية. هذا يقلل بشكل كبير من الهلوسة مقارنة بـ CoT النقي.

بالنسبة لسؤال HotpotQA أو وصفة WebShop، إنه مثالي. لتشغيل اختبار اختراق، ليس كذلك.

أين ينكسر ReAct عندما تستمر الحملة لأكثر من ساعة

ثلاثة إخفاقات عشناها عملياً في جميع الاختبارات التي أجريناها مع ReAct العادي على أهداف حقيقية.

الأول هو الانضغاط. تحتل تتبعات Thought/Action/Observation في جلسة استطلاع لائقة مساحة أكبر بكثير مما يبدو. مجرد nmap -sV -p- ضد /24 معقول هو عدة آلاف من الرموز في Observation. اضرب ذلك في عشرين مضيفاً، اخلطه مع بصمة HTTP، وبعد ساعتين يكون السياق مشبعاً. عندما يبدأ المنسق في قص الرسائل القديمة لتناسب الجديدة، فإن أول ما يضيع عادةً هو بالضبط ما يهم أكثر: قواعد الاشتباك، والفرضية الأولية، وقيود العميل.

الثاني هو الانحراف. بدون هدف معاد تثبيته بشكل صريح في كل دورة، يبتعد النموذج عن الموضوع. يبدأ بـ "إيجاد متجه أولي" وينتهي بتعداد نطاقات فرعية لمزود لم يكن جزءاً من النطاق. وثّق PentestGPT (Deng et al., 2023)[3] هذه المشكلة بشكل جيد إلى حد ما واقترح تقسيمها إلى وحدات. وصلنا إلى استنتاج مماثل بمفردنا.

الثالث هو هلوسة الأدوات. عندما يمر النموذج بالعديد من التكرارات، يبدأ في اختراع إجراءات ليست في صندوق الأدوات. masscan-with-banners، burp-active-scan، nuclei-cloud-edition. أسماء معقولة غير موجودة. إذا كان مشغلك صارماً، فإنه يفشل بشدة. إذا كان متساهلاً، أسوأ: يفعل شيئاً مشابهاً ولكن ليس ما طلبته.

ما أضفناه: التسليم حسب المرحلة والمنتجات المكتوبة

كان الحدس الرئيسي بالنسبة لنا هو التعامل مع سلسلة القتل كآلة حالات، وليس كحلقة واحدة. كل مرحلة (Recon، Planning، Execution، Reporting) لها وكيلها الخاص، ومطالبتها الخاصة، ونموذجها الخاص. وبين المراحل لا يمر سياق خام: تمر artifacts.

artifact هو هيكل مكتوب ينتجه وكيل عند إغلاق مرحلته ويستهلكه آخر عند فتح مرحلته. ليس التتبع الكامل. ليست الأفكار الوسيطة. إنه الاستنتاج المقطر، الذي تم التحقق منه بواسطة خطوة مراجعة ثانية قبل التقدم.

اليوم التوزيع الذي نستخدمه في Gandalf CLI افتراضياً هو التالي: Beorn للاستطلاع، حيث نريد نموذجاً رخيصاً ومقاوماً للملاحظات الصاخبة. Gandalf للتخطيط، حيث نحتاج إلى أدق تفكير متاح ونقبل دفع زمن الاستجابة. Gwaihir للتنفيذ، حيث نعطي الأولوية للإنتاجية والاستجابة السريعة لتغذية الأداة المرتدة. كل واحد لديه نظام المطالبات المكيف الخاص به والأهم من ذلك، صندوق أدواته المقيد. لا يمكن لـ Beorn استدعاء الاستغلالات. لا يمكن لـ Gwaihir تعديل النطاق.

هذا الأخير متعمد. تقييد صندوق الأدوات حسب المرحلة هو أرخص طريقة وجدناها لقطع هلوسة الأدوات. النموذج لا يخترع ما لا يراه.

مثال متتبع

ليكن هذا كعينة. ينهي وكيل Beorn مرحلة الاستطلاع على مضيف بهذا:

Thought: He completado el escaneo de servicios. El host expone
SSH (22), HTTP (80), HTTPS (443) y un Jenkins en 8080 con
header X-Jenkins: 2.346.1. Ese build tiene CVE-2024-23897
(arbitrary file read pre-auth). Esto es relevante.

Action: emit_artifact({
  "phase": "recon",
  "host": "10.42.0.17",
  "services": [...],
  "candidate_cves": ["CVE-2024-23897"],
  "confidence": "high",
  "evidence": "banner X-Jenkins: 2.346.1"
})

Observation: artifact_id=art_8c1a stored. handoff ready.

ينتقل المنتج إلى Gandalf، الذي يدخل في التخطيط. لا يرى Gandalf التتبع الكامل لـ Beorn. يتلقى فقط المنتج وقواعد الاشتباك والمخزون الحالي. وظيفته هي تحديد المتجه.

Thought: CVE-2024-23897 permite leer ficheros arbitrarios
sin autenticación vía el CLI de Jenkins. El objetivo del
cliente es validar acceso a credenciales. La ruta natural
es leer /var/jenkins_home/secrets/master.key y luego
credentials.xml. Confianza alta, ruido bajo. Acepto.

Action: emit_plan({
  "vector": "cve-2024-23897-file-read",
  "steps": [
    {"id": 1, "tool": "jenkins-cli-cve", "target": "10.42.0.17:8080",
     "args": {"file": "/var/jenkins_home/secrets/master.key"}},
    {"id": 2, "tool": "jenkins-cli-cve", "target": "10.42.0.17:8080",
     "args": {"file": "/var/jenkins_home/credentials.xml"}}
  ],
  "abort_if": ["http_status != 200", "response_size < 16"]
})

Observation: plan_id=pln_2f9b validated. handoff to execution.

يلتقط Gwaihir الخطة، وينفذ خطوة بخطوة، ويعيد دليلاً خاماً ومعيارياً. إذا فشلت خطوة، فإنه لا يرتجل: يعيد التحكم إلى Gandalf لإعادة التخطيط. هذا القرار، عدم السماح لوكيل التنفيذ بالارتجال، هو من أكثر القرارات التي خفضت لنا الإيجابيات الكاذبة.

التحقق المتقاطع بين المراحل

بين إخراج وكيل واحد ومدخل التالي ندخل خطوة تحقق ليست من الوكيل الأصلي. بالنسبة للمنتجات الحرجة (مرشحات CVE، وبيانات الاعتماد الموجودة، وقرارات الاستغلال)، يقوم نموذج ثانٍ، عادةً نفس Gandalf في الوضع الحرج، بمراجعة ما إذا كان المنتج مشكلاً بشكل جيد، وما إذا كانت الأدلة تبرر الاستنتاج، وما إذا كانت الخطوة التالية لا تخرج عن النطاق.

إنه مكلف من حيث الرموز. نتقبل ذلك. البديل الذي جربناه في البداية، الثقة في الاتساق الذاتي للوكيل نفسه، لم ينجح. يميل النموذج إلى الاتفاق مع نفسه.

مقارنة مع ما كان موجوداً بالفعل

لم نخترع أي شيء جديد جذرياً. ما فعلناه هو خلط قطع من أماكن مختلفة.

مقارنةً بـ Chain-of-Thought النقي (Wei et al., 2022)، نكتسب القدرة على التصرف والتحقق ضد العالم. CoT في حد ذاته مطالبة جيدة للمشاكل المغلقة، وليس للحملات ذات التغذية المرتدة الخارجية.

مقارنةً بـ Tree of Thoughts (Yao et al., 2023)[4]، نبسط. يقترح ToT استكشاف عدة فروع تفكير بالتوازي مع التتبع الخلفي. إنه أنيق، لكن التكلفة في الرموز وزمن الاستجابة باهظة عندما يتضمن فرع إطلاق ماسح حقيقي ضد البنية التحتية. ما اعتمدناه هو فكرة تقييم المرشحين قبل الالتزام.

مقارنةً بـ AutoGPT وأحفاده، الذين يسعون إلى استقلالية كاملة بوكيل واحد، نسير في الاتجاه المعاكس. مراجعة المجال (Wang et al., 2023)[5] واضحة: الوكلاء المستقلون الأحاديون يعلقون في حلقات، ويحرقون الميزانية ويفقدون الخيط. متعدد الوكلاء مع تسليم منضبط يمنحنا قابلية تنبؤ أكبر بكثير.

مقارنةً بـ PentestGPT (Deng et al., 2023)، نتشارك التقسيم الوحدي حسب المهام الفرعية وفكرة عزل السياق. الفرق الرئيسي هو أننا نكتب المنتجات ونفرض التحقق المتقاطع، لا نسمح لتسليم بين الوحدات أن يكون نصاً حراً.

المقايضات الصادقة

هناك ثلاثة توترات دائمة لا نحلها، نديرها فقط.

الأول هو زمن الاستجابة مقابل الدقة. كل تسليم يضيف ثوانٍ. كل تحقق متقاطع، أكثر. حملة كان وكيل أحادي يرسلها في خمس عشرة دقيقة، تستغرق منا أربعين. قررنا أن هذا جيد. يفضل العميل الانتظار وتلقي تقرير بدون هلوسة.

الثاني هو ميزانية الرموز. التحقق المتقاطع يعني الدفع مرتين للقرارات الحرجة. نعوض ذلك باستخدام نماذج رخيصة لمراحل المخاطر المنخفضة وحجز النماذج باهظة الثمن للتخطيط. بدون ذلك التقسيم ستكون التكلفة لكل ارتباط لا تطاق.

الثالث هو debugging. عندما تفشل حملة، عليك إعادة بناء أي وكيل قرر ماذا بأي سياق. تسجيل تتبعات Thought/Action/Observation الكاملة غير قابل للتفاوض. بدون ذلك لا يمكنك إجراء فحص ما بعد الوفاة. لكنه يحتل قدراً غير لائق من القرص.

فشل الشهر الماضي

نختتم بمثال حديث، لا يزال ساخناً. حملة ضد محيط ويب. اكتشف Beorn نقطة نهاية كانت تستجيب بترويسة Server: Werkzeug/3.0.1 Python/3.11.4. وضع منتجه علامة "Flask محتمل في وضع التصحيح" بثقة متوسطة. قرر Gandalf، في التخطيط، تجربة المسار /console متوقعاً مصححاً محمياً بـ PIN.

حتى تلك النقطة، مثالي. جاءت المشكلة في Gwaihir. كان لصندوق الأدوات وحدة werkzeug-debugger-pin-bruteforce تم وضع علامة عليها كمهملة في فرع داخلي ولكنها لا تزال قابلة للاختيار. اختارها Gwaihir، أطلقت الوحدة طلبات بمعدل اعتبره WAF كإساءة، وأغلقوا علينا IP الأصل في منتصف الارتباط.

السبب الجذري لم يكن من النموذج. كان من صندوق الأدوات. كان لسجل الأدوات علامة deprecated: true لم يكن المحمل يحترمها. ثلاثة أسطر من التغيير في المحمل واختبار انحدار. لكن الفشل علمنا شيئاً أعمق: التحقق المتقاطع بين المراحل يفترض أن صندوق الأدوات صحيح. إذا كذب صندوق الأدوات، فإن المنسق بأكمله يكذب.

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

تبقى حلقة Thought/Action/Observation أفضل أوّلية نعرفها لـ LLM للتحدث إلى العالم. ما يتغير، في حملة حقيقية، هو ما يحدث بين الحلقات. هناك تربح أو تخسر.

المراجع

  1. Yao, S. et al. (2022). ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629.
  2. Wei, J. et al. (2022). Chain-of-Thought Prompting Elicits Reasoning in Large Language Models. arXiv:2201.11903.
  3. Deng, G. et al. (2023). PentestGPT: An LLM-empowered Automatic Penetration Testing Tool. arXiv:2308.06782.
  4. Yao, S. et al. (2023). Tree of Thoughts: Deliberate Problem Solving with Large Language Models. arXiv:2305.10601.
  5. Wang, L. et al. (2023). A Survey on Large Language Model based Autonomous Agents. arXiv:2308.11432.