
جالا: مصيدة ويب مدعومة بنماذج اللغة الكبيرة.
المُلخّص: Galah (/ɡəˈlɑː/ - يُنطق 'guh-laa') هو وعاء عسل (honeypot) ويب مُشغّل بواسطة LLM مصمم لمحاكاة تطبيقات متنوعة والاستجابة ديناميكيًا لطلبات HTTP التعسفية. يدعم Galah مزودي LLM الرئيسيين، بما في ذلك OpenAI وGoogleAI وGCP's Vertex AI وAnthropic وCohere وOllama.
على عكس أوعية العسل التقليدية للويب التي تحاكي يدويًا تطبيقات ويب أو ثغرات محددة، يقوم Galah بصياغة استجابات ذات صلة ديناميكيًا—بما في ذلك رؤوس HTTP ومحتوى النص—لأي طلب HTTP. يتم تخزين الاستجابات التي يولدها LLM مؤقتًا لمدة قابلة للتكوين لمنع التوليد المتكرر للطلبات المتطابقة، مما يقلل من تكاليف API. التخزين المؤقت خاص بالمنفذ، مما يضمن عدم إعادة استخدام الاستجابات التي تم إنشاؤها لمنفذ معين لنفس الطلب على منفذ مختلف.
يمكن لـ Galah اختياريًا فحص طلبات HTTP الواردة مقابل مجموعة من قواعد Suricata، ومطابقة مخازن HTTP المختلفة بما في ذلك الطريقة وURI والرؤوس وملفات تعريف الارتباط ونص الطلب (لا يدعم التنفيذ الحالي جميع كلمات Suricata الأساسية، ومعالجة PCRE محدودة). لتفعيل وتكوين مطابقة القواعد، راجع Suricata HTTP Rule Matching.
تكوين الموجه (prompt) هو المفتاح في وعاء العسل هذا. بينما يمكنك تحديث الموجه في ملف التكوين، من الضروري الحفاظ على الجزء الذي يوجه LLM لإنتاج استجابات بتنسيق JSON المحدد.
ملاحظة: تم تطوير Galah كمشروع عطلة نهاية أسبوع ممتع لاستكشاف قدرات LLMs في صياغة رسائل HTTP. قد يمكن التعرف على وعاء العسل من خلال طرق مختلفة مثل تقنيات بصمة الشبكة، وأوقات الاستجابة المطولة اعتمادًا على مزود LLM والنموذج، والاستجابات غير القياسية. للحماية من هجمات Denial of Wallet، تأكد من تحديد حدود الاستخدام على API LLM الخاص بك.
config.yaml إذا لزم الأمر.git clone [email protected]:0x4D31/galah.git
cd galah
go mod download
mkdir bin
go build -o bin/galah ./cmd/galah
./bin/galah --help
██████ █████ ██ █████ ██ ██
██ ██ ██ ██ ██ ██ ██ ██
██ ███ ███████ ██ ███████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██
██████ ██ ██ ███████ ██ ██ ██ ██
وعاء عسل ويب قائم على llm | الإصدار 1.1.1
المؤلف: Adel "0x4D31" Ka
الاستخدام: galah --provider PROVIDER --model MODEL [--server-url SERVER-URL] [--temperature TEMPERATURE] [--api-key API-KEY] [--cloud-location CLOUD-LOCATION] [--cloud-project CLOUD-PROJECT] [--interface INTERFACE] [--config-file CONFIG-FILE] [--rules-config-file RULES-CONFIG-FILE] [--event-log-file EVENT-LOG-FILE] [--cache-db-file CACHE-DB-FILE] [--cache-duration CACHE-DURATION] [--log-level LOG-LEVEL] [--suricata-enabled] [--suricata-rules-dir SURICATA-RULES-DIR]
الخيارات:
--provider PROVIDER, -p PROVIDER
مزود LLM (openai, googleai, gcp-vertex, anthropic, cohere, ollama) [env: LLM_PROVIDER]
--model MODEL, -m MODEL
نموذج LLM (مثل gpt-3.5-turbo-1106, gemini-1.5-pro-preview-0409) [env: LLM_MODEL]
--server-url SERVER-URL, -u SERVER-URL
عنوان URL لخادم LLM (مطلوب لـ Ollama) [env: LLM_SERVER_URL]
--temperature TEMPERATURE, -t TEMPERATURE
درجة حرارة أخذ العينات LLM (0-2). القيم الأعلى تجعل المخرجات أكثر عشوائية [الافتراضي: 1, env: LLM_TEMPERATURE]
--api-key API-KEY, -k API-KEY
مفتاح API لـ LLM [env: LLM_API_KEY]
--cloud-location CLOUD-LOCATION
منطقة موقع السحابة لـ LLM (مطلوب لـ GCP's Vertex AI) [env: LLM_CLOUD_LOCATION]
--cloud-project CLOUD-PROJECT
معرف مشروع السحابة لـ LLM (مطلوب لـ GCP's Vertex AI) [env: LLM_CLOUD_PROJECT]
--interface INTERFACE, -i INTERFACE
الواجهة التي سيتم الخدمة عليها
--config-file CONFIG-FILE, -c CONFIG-FILE
مسار ملف التكوين [الافتراضي: config/config.yaml]
--rules-config-file RULES-CONFIG-FILE, -r RULES-CONFIG-FILE
مسار ملف تكوين القواعد (محرك القواعد معطل إذا تم حذفه)
--event-log-file EVENT-LOG-FILE, -o EVENT-LOG-FILE
مسار ملف سجل الأحداث [الافتراضي: event_log.json]
--cache-db-file CACHE-DB-FILE, -f CACHE-DB-FILE
مسار ملف قاعدة البيانات للتخزين المؤقت للاستجابات [الافتراضي: cache.db]
--cache-duration CACHE-DURATION, -d CACHE-DURATION
مدة التخزين المؤقت للاستجابات المُنشأة (بالساعات). استخدم 0 لتعطيل التخزين المؤقت، و -1 لتخزين مؤقت غير محدود (بدون انتهاء صلاحية). [الافتراضي: 24]
--log-level LOG-LEVEL, -l LOG-LEVEL
مستوى التسجيل (debug, info, error, fatal) [الافتراضي: info]
--suricata-enabled تفعيل فحص قواعد HTTP لـ Suricata (الافتراضي: false)
--suricata-rules-dir SURICATA-RULES-DIR
الدليل الذي يحتوي على ملفات قواعد .rules الخاصة بـ Suricata للتحقق من طلبات HTTP
--help, -h عرض هذه المساعدة والخروج
% git clone [email protected]:0x4D31/galah.git
% cd galah
% mkdir logs
% export LLM_API_KEY=your-api-key
% docker build -t galah-image .
% docker run -d --name galah-container -p 8080:8080 -v $(pwd)/logs:/galah/logs -e LLM_API_KEY galah-image -o logs/galah.json -p openai -m gpt-3.5-turbo-1106
./galah -p openai -m gpt-4.1-mini --suricata-enabled --suricata-rules-dir rules
اختبار:
curl --http1.1 --path-as-is -X POST \
-H 'SOAPAction: "http://purenetworks.com/HNAP1/GetGuestNetworkSettings"' \
-H 'Content-Type: text/xml' \
--data '<GetGuestNetworkSettings xmlns="http://purenetworks.com/HNAP1/">' \
http://127.0.0.1:8888/HNAP1/ -v
ملاحظة: استخدام غير ضروري لـ -X أو --request، POST مستنتج بالفعل.
* Trying 127.0.0.1:8888...
* Connected to 127.0.0.1 (127.0.0.1) port 8888
> POST /HNAP1/ HTTP/1.1
> Host: 127.0.0.1:8888
> User-Agent: curl/8.7.1
> Accept: */*
> SOAPAction: "http://purenetworks.com/HNAP1/GetGuestNetworkSettings"
> Content-Type: text/xml
> Content-Length: 64
>
* upload completely sent off: 64 bytes
< HTTP/1.1 200 OK
< Server: TP-LINK HTTP Server/1.0
< Date: Mon, 21 Apr 2025 01:28:43 GMT
< Content-Length: 545
< Content-Type: text/xml; charset=utf-8
<
<?xml version="1.0" encoding="utf-8"?>
<GetGuestNetworkSettingsResponse xmlns="http://purenetworks.com/HNAP1/">
<GetGuestNetworkSettingsResult>OK</GetGuestNetworkSettingsResult>
<GuestNetworkEnabled>true</GuestNetworkEnabled>
<GuestNetworkSSID>TPLink_Guest</GuestNetworkSSID>
<GuestNetworkSecurity>WPA2-PSK</GuestNetworkSecurity>
<GuestNetworkPassword>guest1234</GuestNetworkPassword>
<GuestNetworkIsolation>true</GuestNetworkIsolation>
<GuestNetworkSSIDBroadcast>true</GuestNetworkSSIDBroadcast>
سجل الأحداث بصيغة JSON:
{
"eventTime": "2025-04-21T02:28:43.583386+01:00",
"httpRequest": {
"body": "<GetGuestNetworkSettings xmlns=\"http://purenetworks.com/HNAP1/\">",
"bodySha256": "836c42168ebbad0b7192daa70ad8e4ea8d5930097162f513045f5ecb6ae9d5bd",
"headers": {
"Accept": "*/*",
"Content-Length": "64",
"Content-Type": "text/xml",
"Soapaction": "\"http://purenetworks.com/HNAP1/GetGuestNetworkSettings\"",
"User-Agent": "curl/8.7.1"
},
"headersSorted": "Accept,Content-Length,Content-Type,Soapaction,User-Agent",
"headersSortedSha256": "3a44fecf9284eca3947c45ffeb2301ce6d9b3d0a3cc5a7491ccea2b6ed61edaa",
"method": "POST",
"protocolVersion": "HTTP/1.1",
"request": "/HNAP1/",
"sessionID": "1745198923587092000_qHLNEPBNPrH6qw==",
"userAgent": "curl/8.7.1"
},
"httpResponse": {
"headers": {
"Content-Length": "454",
"Content-Type": "text/xml; charset=utf-8",
"Server": "TP-LINK HTTP Server/1.0"
},
"body": "<?xml version=\"1.0\" encoding=\"utf-8\"?> <GetGuestNetworkSettingsResponse xmlns=\"http://purenetworks.com/HNAP1/\"> <GetGuestNetworkSettingsResult>OK</GetGuestNetworkSettingsResult> <GuestNetworkEnabled>true</GuestNetworkEnabled> <GuestNetworkSSID>TPLink_Guest</GuestNetworkSSID> <GuestNetworkSecurity>WPA2-PSK</GuestNetworkSecurity> <GuestNetworkPassword>guest1234</GuestNetworkPassword> <GuestNetworkIsolation>true</GuestNetworkIsolation> <GuestNetworkSSIDBroadcast>true</GuestNetworkSSIDBroadcast> </GetGuestNetworkSettingsResponse>"
},
"level": "info",
"msg": "successfulResponse",
"port": "8888",
"responseMetadata": {
"generationSource": "llm",
"info": {
"model": "gpt-4.1-mini",
"provider": "openai",
"temperature": 1
}
},
"sensorName": "mbp",
"srcHost": "localhost",
"srcIP": "127.0.0.1",
"srcPort": "62418",
"suricataMatches": [
{
"msg": "ET WEB_SPECIFIC_APPS D-Link DIR-823G Multiple HNAP SOAPAction Endpoints Authentication Bypass",
"sid": "2061623"
}
],
"tags": null,
"time": "2025-04-21T02:28:43.587152+01:00"
}
راجع أمثلة أخرى هنا.
يمكن استخدام حزمة galah كمكتبة مستقلة. قم بإنشاء galah.Service واستدعاء GenerateHTTPResponse مع http.Request لإنتاج استجابة. إذا تم حذف ConfigFile أو EventLogFile أو CacheDBFile، يتم استخدام مساراتها الافتراضية (config/config.yaml وevent_log.json وcache.db). حدد RulesConfigFile لتفعيل فحص القواعد؛ تركه فارغًا يعطل محرك القواعد تمامًا. يمكن تزويد Options.Logger بـ *log.Logger؛ إذا كان nil، يقوم Galah بإنشاء مسجل نصي افتراضي.
svc, err := galah.NewService(context.Background(), galah.Options{
LLMProvider: "openai",
LLMModel: "gpt-4.1-mini",
LLMAPIKey: "YOUR_KEY",
ConfigFile: "config/config.yaml",
RulesConfigFile: "config/rules.yaml", // احذفه لتعطيل محرك القواعد
EventLogFile: "event_log.json",
CacheDBFile: "cache.db",
Logger: log.NewWithOptions(os.Stderr, log.Options{}),
})
if err != nil {
log.Fatal(err)
}
req, _ := http.NewRequest("GET", "https://example.com", nil)
respBytes, err := svc.GenerateHTTPResponse(req, "8080")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(respBytes))
يمكنك أيضًا بناء خدمة من تكوين محمل مسبقًا:
cfg, _ := config.LoadConfig("config.yaml")
rulesCfg, _ := config.LoadRules("rules.yaml")
svc, err := galah.NewServiceFromConfig(context.Background(), cfg, rulesCfg.Rules, galah.Options{
LLMProvider: "openai",
LLMModel: "gpt-4.1-mini",
LLMAPIKey: "YOUR_KEY",
EventLogFile: "event_log.json", // استخدم الافتراضي إذا كان فارغًا
CacheDBFile: "cache.db", // استخدم الافتراضي إذا كان فارغًا
Logger: log.NewWithOptions(os.Stderr, log.Options{}),
})
لإيقاف فحص القواعد تمامًا، احذف RulesConfigFile عند إنشاء خدمة أو مرر nil/شريحة فارغة إلى NewServiceFromConfig. يمكن ترك أي حقول خيارية غير مستخدمة فارغة للاعتماد على الإعدادات الافتراضية الخاصة بها.
تكشف الخدمة أيضًا عن طرق مساعدة للتخزين المؤقت وتسجيل الأحداث عند استخدامها كمكتبة:
respBytes, _ := svc.CheckCache(req, "8080") // تُرجع nil إذا لم يكن هناك إدخال مخبأ
svc.LogEvent(req, llm.JSONResponse{Headers: map[string]string{"Content-Type": "text/plain"}, Body: "hi"}, "8080", "llm", nil)