किल चेन ऑर्केस्ट्रेशन के लिए ReAct प्रॉम्प्टिंग
पहली बार जब हमने एक एकल मॉडल से पूरे पेंटेस्ट अभियान को ऑर्केस्ट्रेट करने की कोशिश की, तो वह चालीसवें मिनट पर विफल हो गया। तकनीकी क्षमता की कमी के कारण नहीं। मॉडल को अच्छी तरह से पता था कि एक्सपोज्ड Redis के साथ क्या करना है, बिना प्रमाणीकरण के Jenkins के साथ क्या करना है, और SSRF को क्लाउड मेटाडेटा के साथ कैसे चेन करना है। समस्या कुछ और थी, अधिक उबाऊ: चालीस पन्नों के संदर्भ में, एजेंट उस स्कोप को भूल चुका था जो हमने उसे शुरू में दिया था। उसने स्कोप से बाहर की रेंज स्कैन करना शुरू कर दिया, हमारे टूलबॉक्स में मौजूद नहीं दो टूल्स की कल्पना की (nmap-fast-aggressive और burp-pro-headless, दोनों असली नहीं), और एक ऐसे CVE का शोषण करने का प्रस्ताव रखा जो क्लाइंट के पास इंस्टॉल भी नहीं था।
उस रात हमने ऑर्केस्ट्रेटर का अच्छा हिस्सा फिर से लिखा। उससे जो निकला वह आज Gandalf CLI के इंजन का आधार है: ReAct फ्रेमवर्क का एक काफी जिद्दी विस्तार, लंबे, बहु-चरण अभियानों के लिए अनुकूलित, जहाँ कई मॉडल एक ही छत के नीचे सहयोग करते हैं। यह लेख यह बताने का प्रयास है कि हम उस डिज़ाइन तक क्यों पहुँचे, हमने क्या उधार लिया, हमें खुद क्या आविष्कार करना पड़ा, और हम कहाँ अपनी नाक तोड़ते रहते हैं।
ReAct, बिना मार्केटिंग के
ReAct को Yao और साथियों ने 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 ट्रेस जितना दिखता है उससे कहीं अधिक जगह घेरता है। उचित /24 के विरुद्ध एक एकल nmap -sV -p- Observation में कई हजार टोकन है। बीस होस्ट से गुणा करें, HTTP फिंगरप्रिंटिंग के साथ मिलाएँ, और दो घंटे बाद संदर्भ संतृप्त हो जाता है। जब ऑर्केस्ट्रेटर नए संदेशों को फिट करने के लिए पुराने संदेशों को काटना शुरू करता है, तो आमतौर पर सबसे पहले जो खो जाता है वह वही होता है जो सबसे ज्यादा मायने रखता है: एंगेजमेंट के नियम, प्रारंभिक परिकल्पना, क्लाइंट की प्रतिबंधाएँ।
दूसरी है drift। प्रत्येक दौर में स्पष्ट रूप से एक उद्देश्य को फिर से एंकर किए बिना, मॉडल भटक जाता है। यह "एक प्रारंभिक वेक्टर खोजने" से शुरू होता है और एक ऐसे प्रदाता के सबडोमेन गिनाने पर समाप्त होता है जो स्कोप का हिस्सा नहीं था। 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 ने योजना में PIN-संरक्षित डिबगर की उम्मीद में /console पथ आज़माने का निर्णय लिया।
वहाँ तक, परफेक्ट। समस्या Gwaihir में आई। टूलबॉक्स में एक werkzeug-debugger-pin-bruteforce मॉड्यूल था जो आंतरिक शाखा में deprecated के रूप में चिह्नित था लेकिन फिर भी चयन योग्य था। Gwaihir ने इसे चुना, मॉड्यूल ने उस दर पर अनुरोध शुरू किए जिसे WAF ने दुरुपयोग के रूप में चिह्नित किया, और उन्होंने अभियान के बीच में हमारा मूल IP बंद कर दिया।
मूल कारण मॉडल का नहीं था। यह टूलबॉक्स का था। टूल रजिस्ट्री में एक deprecated: true फ्लैग था जिसका लोडर सम्मान नहीं कर रहा था। लोडर में तीन लाइन का परिवर्तन और एक रिग्रेशन टेस्ट। लेकिन इस विफलता ने हमें कुछ गहरा सिखाया: चरणों के बीच क्रॉस-वैलिडेशन यह मानता है कि टूलबॉक्स सही है। यदि टूलबॉक्स झूठ बोलता है, तो पूरा ऑर्केस्ट्रेटर झूठ बोलता है।
तब से हमारे पास प्रत्येक एजेंट को शुरू करते समय एक अतिरिक्त जाँच है: यह उन टूल्स को सूचीबद्ध करता है जिन्हें वह कॉल कर सकेगा, उन्हें लॉग में प्रिंट करता है, और एक मानव पहली बार उस सेट पर हस्ताक्षर करता है जब वह एक नए क्लाइंट के विरुद्ध निष्पादित होता है। यह सुरुचिपूर्ण नहीं है। लेकिन कोई भी एजेंट, चाहे वह कितनी भी अच्छी तरह से ऑर्केस्ट्रेट किया गया हो, उत्पादन दांव पर होने पर एक जोड़ी आँखों की जगह नहीं ले सकता।
Thought/Action/Observation लूप अभी भी सबसे अच्छा प्रिमिटिव है जिसे हम जानते हैं ताकि एक LLM दुनिया से बात कर सके। एक वास्तविक अभियान में जो बदलता है वह यह है कि लूप के बीच क्या होता है। वहीं आप जीतते या हारते हैं।
संदर्भ
- Yao, S. et al. (2022). ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629.
- Wei, J. et al. (2022). Chain-of-Thought Prompting Elicits Reasoning in Large Language Models. arXiv:2201.11903.
- Deng, G. et al. (2023). PentestGPT: An LLM-empowered Automatic Penetration Testing Tool. arXiv:2308.06782.
- Yao, S. et al. (2023). Tree of Thoughts: Deliberate Problem Solving with Large Language Models. arXiv:2305.10601.
- Wang, L. et al. (2023). A Survey on Large Language Model based Autonomous Agents. arXiv:2308.11432.