आक्रामक संचालन में अवलोकन क्षमता
ईमेल मंगलवार सुबह 09:14 बजे आया। क्लाइंट के CISO का संक्षिप्त संदेश: "रात 03:42 पर तुम्हारे एजेंट ने ठीक-ठीक क्या किया? SOC ने एक बाहर जाने वाला कनेक्शन देखा जो runbook में नहीं था और उसे ब्लॉक कर दिया। हमें जानना है कि क्या यह तुम्हारा काम था।"
हमने ग्यारह मिनट में जवाब दिया। इसलिए नहीं कि हमारी याददाश्त अच्छी थी, बल्कि इसलिए कि हमने उस कमांड का trace_id खोजा जो SOC ने हमें भेजा था और पूरी श्रृंखला पुनर्निर्मित की: एजेंट ने एक एंडपॉइंट /api/internal/health ढूँढा था जो एक संस्करण banner के साथ जवाब दे रहा था, उसने तय किया कि क्या यह exploit योग्य है इसकी पुष्टि करे, और कुछ भेजने से पहले Sentinel ने ऑपरेशन काट दिया क्योंकि गंतव्य अधिकृत CIDR के बाहर था। वह "बाहर जाने वाला कनेक्शन" एक SYN था जिसने handshake भी पूरा नहीं किया था। हमने क्लाइंट को पूरा span भेजा, ATT&CK ID के साथ, policy engine के निर्णय के साथ, और तार पर गए 47 बाइट्स के साथ।
उस दिन हमने तय किया कि अवलोकन क्षमता एक उत्पाद होगी, nice-to-have नहीं।
आक्रामक अवलोकन क्षमता रक्षात्मक जैसी नहीं होती
मैंने SOCs के लिए वर्षों तक टेलीमेट्री पाइपलाइन बनाई हैं। Loki, Tempo, Jaeger, जो भी फिट हो। और पहले मैंने सोचा था कि आक्रामक एजेंट को इंस्ट्रूमेंट करना वही समस्या है, बस एक और schema के साथ। मैं ग़लत था।
एक रक्षात्मक SIEM मानता है कि सिस्टम का शोर ही संकेत है: हर auth.fail मायने रखता है, हर अजीब DNS मायने रखता है। कार्डिनैलिटी फूट पड़ती है लेकिन मानसिक मॉडल स्पष्ट है: सब कुछ रखो, बाद में तय करो। आक्रामक में मॉडल पलट जाता है। एजेंट परिभाषा से ही शोर है: यह scan करता है, परीक्षण करता है, असफल होता है, पुनः प्रयास करता है। अगर आप सब कुछ EDR की ग्रैन्युलैरिटी पर रखेंगे, तो चार घंटे का ऑपरेशन 18 GB टेलीमेट्री बनाएगा जिसे कोई नहीं पढ़ेगा।
लेकिन एक चीज़ है जिसे आपको शल्य चिकित्सा जैसी परिशुद्धता के साथ पुनर्निर्मित कर पाना होगा: ऐसी किसी भी कार्रवाई की कारण-श्रृंखला जो क्लाइंट को छूती है। कोई भी। अगर एजेंट प्रोडक्शन में payload भेजता है, तो आपको पता होना चाहिए कि उसने वह payload क्यों चुना, किस पूर्व जानकारी ने उसे न्यायोचित ठहराया, policy engine ने क्या मान्य किया और लक्ष्य ने क्या जवाब दिया। यह पैरानोइया नहीं है: यही वह चीज़ है जो पेशेवर red team को बजट वाले script kiddie से अलग करती है।
MITRE ATT&CK मैपिंग गाइड बिना घुमाए-फिराए कहती हैं: साक्ष्य वास्तविक टेलीमेट्री में लंगर डाला होना चाहिए, ऑपरेटर की धारणाओं में नहीं (CISA, 2023)[1]। अगर आपकी रिपोर्ट कहती है "host X के विरुद्ध T1190 निष्पादित किया गया", तो मैं http.request.body वाला span देखना चाहता हूँ, एजेंट का निर्णय, और रिस्पॉन्स कोड। इसके बिना, यह बस राय है।
इवेंट डिज़ाइन: spans, traces, attributes
हम OpenTelemetry को रीढ़ के रूप में इस्तेमाल करते हैं। इसलिए नहीं कि यह फैशन में है, बल्कि इसलिए कि semantic conventions हमारी एक वास्तविक समस्या सुलझाते हैं: हर ऑपरेटर अपनी मर्ज़ी से logs लिखता था। एक दिन target_host, दूसरे दिन dst, तीसरे दिन victim_ip। सहसंबंध असंभव। OpenTelemetry एक साझा schema थोपता है और, सबसे महत्वपूर्ण, प्रक्रियाओं और workers के बीच trace context का प्रचार करता है (OpenTelemetry, 2024)[2]।
Gandalf CLI हर कमांड को एक span के रूप में emit करता है। हर span अपना trace_id, अपना span_id, एक parent_span_id जो उसे जन्म देने वाले तर्क की ओर इंगित करता है, और मानक सिमेंटिक्स के ऊपर हमारी berialabs.* कन्वेंशन का पालन करने वाले attributes लेकर चलता है। आंतरिक नियम: अगर कोई attribute आधिकारिक spec में मौजूद है, तो हम उसे जस का तस इस्तेमाल करते हैं। अगर यह आक्रामकता-विशिष्ट है (ATT&CK technique, एजेंट का निर्णय, payload हैश), तो हम namespace को दूषित न करने के लिए prefix लगाते हैं।
एक ठोस उदाहरण। यह एक वास्तविक span है (गुमनाम किया गया) जो एक सर्च पैरामीटर पर SQL injection परीक्षण कर रहे एजेंट का है:
{
"name": "gandalf.exploit.sqli_attempt",
"trace_id": "4a1f9b2c8e3d7f6a5b4c3d2e1f0a9b8c",
"span_id": "7c8b9a0d1e2f3a4b",
"parent_span_id": "6b7a8c9d0e1f2a3b",
"start_time_unix_nano": 1709823742891000000,
"end_time_unix_nano": 1709823743104000000,
"kind": "SPAN_KIND_CLIENT",
"status": { "code": "STATUS_CODE_OK" },
"attributes": {
"http.request.method": "GET",
"http.response.status_code": 500,
"url.full": "https://target.example.com/api/search?q=*REDACTED*",
"server.address": "10.42.7.18",
"server.port": 443,
"berialabs.attack.tactic": "TA0001",
"berialabs.attack.technique": "T1190",
"berialabs.agent.decision_id": "dec_8f3a",
"berialabs.agent.reasoning_ref": "trace://4a1f9b2c.../6b7a8c9d",
"berialabs.payload.sha256": "9e3f...c7a1",
"berialabs.payload.family": "boolean_blind_sqli",
"berialabs.sentinel.scope_check": "passed",
"berialabs.sentinel.cidr_match": "10.42.0.0/16",
"berialabs.evidence.response_signature": "mysql_error_xpath"
},
"events": [
{
"name": "sentinel.validation",
"attributes": {
"policy.id": "scope_v3",
"policy.result": "allow"
}
},
{
"name": "response.received",
"attributes": {
"response.size_bytes": 1247,
"response.contains_error_signature": true
}
}
]
}इस फ़ॉर्मेट में तीन चीज़ें हैं जो मेरे लिए मायने रखती हैं। पहली, parent_span_id एजेंट के तर्क की ओर इंगित करता है, पिछले कमांड की ओर नहीं; इससे मैं क्यों उसने वह किया जो किया, यह पुनर्निर्मित कर सकता हूँ, सिर्फ़ क्या किया, नहीं। दूसरी, payload का sha256 संदर्भित है, inline नहीं: पूरा body एक अलग store में रहता है, और span केवल हैश रखता है। तीसरी, span के events मुख्य परिवर्तनों को कैप्चर करते हैं (Sentinel की मान्यता, रिस्पॉन्स) जिन्हें एक सपाट attribute अच्छी तरह से प्रदर्शित नहीं कर सकता।
ATT&CK एक attribute के रूप में, न कि ढीले tag के रूप में
हम हर कार्रवाई को उसकी ATT&CK technique पर span emit करते समय ही मैप करते हैं, बाद में नहीं। एजेंट के पास एक आंतरिक तालिका है जो payload परिवारों को technique IDs से जोड़ती है, और attribute span के साथ Tempo तक यात्रा करता है। जब क्लाइंट हमसे रिपोर्ट माँगता है, तो यह कोई पुरातात्विक अभ्यास नहीं है: यह Grafana में berialabs.attack.technique द्वारा फ़िल्टर करने वाली एक query है।
जो एजेंट आपको नहीं बताता उसे पकड़ने के लिए eBPF
यहाँ वह तरकीब है जिसे स्वीकार करने में मुझे समय लगा। आप अपने एजेंट को कितनी भी अच्छी तरह इंस्ट्रूमेंट करें, कुछ चीज़ें हैं जो एजेंट नहीं जानता कि वह कर रहा है। एक तीसरे-पक्ष की लाइब्रेरी जो एक socket खोलती है जिसकी आपको अपेक्षा नहीं थी। एक DNS कॉल जो getaddrinfo से होकर जाती है पर आपके HTTP क्लाइंट से नहीं। एक child प्रक्रिया जो एक अस्थायी फ़ाइल लिखती है। अगर आप केवल userspace इंस्ट्रूमेंटेशन पर भरोसा करते हैं, तो आपकी ट्रेसेबिलिटी में छेद हैं।
इसलिए हमने उस host के kernel में eBPF hooks लगाए जहाँ एजेंट चलता है। eBPF आपको kernel के भीतर sandboxed प्रोग्राम execute करने और उसे संशोधित किए बिना events कैप्चर करने देता है (Gregg, 2019; ebpf.io)[3]। हम चार चीज़ें hook करते हैं: tcp_connect, execve, openat और udp_sendmsg के माध्यम से DNS resolution। हर event को प्रक्रिया के cgroup_id से समृद्ध किया जाता है, जिसे हम एक छोटी shared-memory तालिका के माध्यम से एजेंट के सक्रिय trace_id से सहसंबंधित करते हैं।
परिणाम: अगर एजेंट उस IP से कनेक्शन खोलता है जिसके बारे में span कहता है कि उसने खोला, तो बढ़िया, सब मेल खाता है। अगर वह एक ऐसे IP से खोलता है जो किसी span में नहीं दिखता, तो एक alert आ जाता है। हमने इसे एक-दो बार यह पता लगाने के लिए इस्तेमाल किया कि एक scraping लाइब्रेरी बिना बताए favicons का prefetch कर रही थी। यह दुर्भावनापूर्ण नहीं था, लेकिन हो सकता था, और क्लाइंट को जानने का अधिकार था।
एक असुविधाजनक टिप्पणी: eBPF शक्तिशाली है, पर अभेद्य नहीं। सार्वजनिक काम है जो दिखाता है कि अगर हमलावर पहले से ही kernel नियंत्रित करता है, तो विशेष रूप से डिज़ाइन किए गए rootkits eBPF-आधारित उपकरणों को अंधा कर सकते हैं (Matheuz, 2024)[4]। हमारे मामले में threat model अलग है (हम अपने एजेंट का ऑडिट करना चाहते हैं, root वाले प्रतिद्वंद्वी से बचाव नहीं), पर इसे ध्यान में रखना उचित है।
पाइपलाइन
एजेंट से Grafana तक, छलांगें ये हैं। Gandalf CLI gRPC के माध्यम से OTLP को sidecar के रूप में चलने वाले OpenTelemetry Collector को emit करता है। Collector तीन काम करता है: एक processor के साथ संवेदनशील attributes फ़िल्टर करता है जो PII पैटर्न से मेल खाने वाली किसी भी चीज़ (ईमेल, कार्ड जैसे दिखने वाले नंबर, auth headers) को /dev/null में लिखता है, batch करता है और पुनः-निर्यात करता है। Traces Tempo में जाते हैं। संरचित logs otlphttp exporter के माध्यम से Loki में जाते हैं, जिसे Loki 3.0 से नेटिवली स्वीकार करता है (Grafana Labs, 2024)[5]। मेट्रिक्स (तकनीक के अनुसार विलंबता, Sentinel द्वारा ब्लॉक किए गए payloads का अनुपात, अनुरोध throughput) Prometheus में जाते हैं।
सब के ऊपर, Grafana। और killer feature कोई सुंदर dashboard नहीं है: यह trace-to-logs है। किसी भी span पर क्लिक करें, trace_id द्वारा सहसंबंधित logs पर कूद जाते हैं। किसी भी log पर क्लिक करें, span पर कूद जाते हैं। यही सहसंबंध है जिसने हमें ग्यारह मिनट में CISO को जवाब देने दिया।
वे trade-offs जो दर्द देते हैं
सब कुछ सुंदर नहीं है। तीन वास्तविक तनाव जिनसे हम बातचीत करते रहते हैं।
शोर बनाम संकेत। अगर आप एजेंट के हर आंतरिक निर्णय को इंस्ट्रूमेंट करते हैं, तो आप प्रति ऑपरेशन लाखों spans उत्पन्न करते हैं। अगर केवल बाहरी कमांड्स इंस्ट्रूमेंट करते हैं, तो कारण-श्रृंखला खो देते हैं। हमने एजेंट के निर्णय nodes (हर token नहीं) और बाहरी side-effects को बिना अपवाद इंस्ट्रूमेंट करते हुए एक उचित संतुलन पाया। फिर भी, लंबे ऑपरेशनों में हमने 200k spans/घंटा की चोटियाँ देखी हैं।
Retention। S3 पर Tempo सस्ता है, लेकिन उच्च कार्डिनैलिटी वाले Loki में logs महँगे पड़ते हैं। हमारी वर्तमान नीति: पूर्ण traces 90 दिन, logs 30 दिन, समुच्चय (मेट्रिक्स और सारांश) तीन साल। SOC 2 और red team अनुबंधों का कानूनी दबाव हमें कम नहीं, अधिक रखने के लिए प्रेरित करता है।
Logs में PII। यही वह है जो मुझे सबसे ज़्यादा चिंता देता है। अगर एजेंट प्रभाव दिखाने के लिए डेटाबेस का dump निकालता है, तो वह dump logs में नहीं रहना चाहिए। Collector का फ़िल्टर मदद करता है, लेकिन काफ़ी नहीं। हम दूसरी परत बनाए रखते हैं: संवेदनशील निष्कर्ष पाइपलाइन से छूने से पहले क्लाइंट की public key से एन्क्रिप्ट किए जाते हैं, और केवल संदर्भ संग्रहीत होते हैं।
इसने हमारे काम करने का तरीका कैसे बदला
यह पाइपलाइन होने से पहले, हम red team रिपोर्ट हाथ से बनाते थे। स्क्रीनशॉट, outputs की कॉपी-पेस्ट, स्मृति से पुनर्निर्मित कथा। दिन लगते थे। अब अधिकांश रिपोर्ट Tempo और Loki से query करके उत्पन्न होती है, और मानव ऑपरेटर व्याख्या करने पर ध्यान केंद्रित करता है, ट्रांसक्रिप्ट करने पर नहीं।
अधिक महत्वपूर्ण: हम क्लाइंट के साथ साझा ज़मीन से चर्चा करते हैं। "हमें लगता है कि एजेंट ने X किया" नहीं, बल्कि "यहाँ 03:42:18 का span है, निर्णय, payload और रिस्पॉन्स के साथ"। एक क्लाइंट ने पिछले महीने हमें बताया कि यह पहली बार था जब किसी red team ने उन्हें ऐसी टेलीमेट्री दी जिसे उनका SOC अपने डिटेक्शन नियमों को प्रशिक्षित करने के लिए जस का तस ingest कर सकता था। मेरे लिए वही मायने रखने वाला मेट्रिक है: कि आक्रामक अवलोकन क्षमता रक्षक के लिए भी उपयोगी हो।
और जब मंगलवार सुबह 09:14 बजे एक ईमेल आता है, हम ग्यारह मिनट में जवाब देते हैं।
संदर्भ
- CISA (2023). Best Practices for MITRE ATT&CK Mapping.
- OpenTelemetry Authors (2024). Semantic Conventions Specification 1.41.
- eBPF Foundation (2024). What is eBPF? An Introduction and Deep Dive into the eBPF Technology.
- Matheuz (2024). Breaking eBPF Security: How Kernel Rootkits Blind Observability Tools.
- Grafana Labs (2024). Ingesting logs to Loki using OpenTelemetry Collector.