
प्रायोगिक डिकॉय ब्रोकर
एक कंटेनरीकृत नेटवर्क डिकॉय (हनीपॉट) जो SSH, RDP, और SMB का विज्ञापन करता है, eBPF के साथ प्रत्येक इनबाउंड कनेक्शन का निरीक्षण करता है, और प्रत्येक सत्र को एक पृथक डिकॉय कंटेनर में रिवर्स-प्रॉक्सी करता है।
डिज़ाइन दो चिंताओं को अलग करता है:
यह आपके स्वामित्व वाले या जिनकी निगरानी करने के लिए आप अधिकृत हैं, उन नेटवर्कों पर अनधिकृत गतिविधि का पता लगाने और उसका अध्ययन करने के लिए एक रक्षात्मक उपकरण है। इसे केवल वहीं तैनात करें जहाँ आपके पास वह अधिकार हो।
flowchart TB
A["Attacker / Scanner"]
subgraph host["Decoy Host"]
direction TB
NIC["broker eth0<br/>published: 22, 3389, 445"]
subgraph brk["broker container"]
direction TB
E["eBPF TC classifier<br/>logs every SYN<br/>sees true source IP"]
P["reverse proxy<br/>CONNECT to backend"]
L["structured JSON logs"]
end
subgraph dec["decoynet (internal, no host route)"]
direction LR
S["ssh-decoy<br/>OpenCanary ssh<br/>port 2222"]
D["rdp-decoy<br/>OpenCanary rdp<br/>port 3389"]
M["smb-decoy<br/>Impacket SMB server<br/>port 445"]
end
end
A --> NIC
NIC --> E
NIC --> P
E --> L
P --> S
P --> D
P --> M
कुल चार कंटेनर:
| कंटेनर | भूमिका | नेटवर्क |
|---|---|---|
broker | सार्वजनिक फ्रंट डोर: eBPF अवलोकन और रिवर्स प्रॉक्सी | edge + decoynet |
ssh-decoy | OpenCanary ssh मॉड्यूल (वास्तविक हैंडशेक, क्रेडेंशियल कैप्चर करता है) | केवल decoynet |
rdp-decoy | OpenCanary rdp मॉड्यूल (NLA नकल, उपयोगकर्ता नाम कैप्चर करता है) | केवल decoynet |
smb-decoy | Impacket SimpleSMBServer (वास्तविक SMB2/3, प्रमाणीकरण कैप्चर करता है) | केवल decoynet |
डिकॉय एक internal Docker नेटवर्क (decoynet) पर रहते हैं जिसमें होस्ट या बाहरी दुनिया के लिए कोई रूट नहीं है। केवल ब्रोकर उन तक पहुँच सकता है। एक डिकॉय के अंदर हमलावर जो कुछ भी करता है, वह सीधे होस्ट नेटवर्क तक नहीं पहुँच सकता।
ब्रोकर पोर्ट 22, 3389 और 445 को होस्ट पर प्रकाशित करता है, इसलिए इनबाउंड पैकेट ब्रोकर के eth0 पर आते हैं। फिर प्रत्येक पैकेट के साथ दो चीजें होती हैं:
broker/bpf/decoy.bpf.c) ईथरनेट, IP और TCP हेडर को पार्स करता है, और प्रत्येक नए कनेक्शन प्रयास (SYN सेट, ACK क्लियर) के लिए एक conn_event रिंग बफर में लिखता है: स्रोत IP और पोर्ट, गंतव्य पोर्ट, TCP फ़्लैग्स, और क्या पोर्ट एक विज्ञापित सेवा है। पैकेट बिना बदलाव के गुज़रता है (TC_ACT_OK)।CONNECT के समतुल्य कार्य करता है, फिर दोनों दिशाओं में बाइट रिले करता है।advertised_ports eBPF मैप स्टार्टअप पर config.yaml से भरा जाता है, ताकि क्लासिफायर टैग कर सके कि क्या प्रोब एक सेवा किए गए पोर्ट पर लगा या एक अनचाहे पर। यह क्षैतिज पोर्ट स्कैन को दृश्यमान बनाता है भले ही केवल तीन पोर्ट प्रॉक्सी किए गए हों।
यदि आप "सब कुछ खुला है" का विज्ञापन करना चाहते हैं और मनमानी गंतव्य पोर्ट को ब्रोकर में फ़नल करना चाहते हैं, तो क्लासिफायर को गंतव्य पोर्ट को फिर से लिखने या TPROXY / bpf_sk_assign रीडायरेक्ट का उपयोग करने के लिए विस्तारित करें। वर्तमान संस्करण पैकेट पथ को अछूता रखता है और खुद को अवलोकन तक सीमित रखता है, जो अधिक सुरक्षित डिफ़ॉल्ट है।
cyber-decoy/
├── README.md
├── docker-compose.yml # 4-container stack
├── docker-compose.override.yml # स्थानीय macOS विकास: कोई eBPF कैप, पोर्ट 22 रीमैप
├── Makefile # build / up / down / bpf सहायक
├── LICENSE
├── scripts/
│ └── setup.sh # होस्ट प्रीफ़्लाइट जाँच
├── broker/
│ ├── Dockerfile # eBPF ऑब्जेक्ट + Go बाइनरी संकलित करता है
│ ├── config.yaml # विज्ञापित सेवाएँ (कॉन्फ़िगरेबल)
│ ├── go.mod
│ ├── main.go # प्रवेश बिंदु
│ ├── bpf/
│ │ └── decoy.bpf.c # eBPF TC क्लासिफायर
│ └── internal/
│ ├── config/config.go # कॉन्फ़िग लोडर
│ ├── proxy/proxy.go # TCP रिवर्स प्रॉक्सी
│ └── bpf/loader.go # eBPF लोड और अटैच करता है, इवेंट स्ट्रीम करता है
└── decoys/ # तीनों OpenCanary चलाते हैं
├── ssh/
│ ├── Dockerfile
│ └── opencanary.conf # ssh मॉड्यूल, पोर्ट 2222
├── rdp/
│ ├── Dockerfile
│ └── opencanary.conf # rdp मॉड्यूल, पोर्ट 3389
└── smb/
├── Dockerfile # एकल Python प्रक्रिया, गैर-रूट
├── smb_decoy.py # Impacket SimpleSMBServer + JSON लॉगिंग
└── requirements.txt # impacket (पिन किया हुआ)
docker-compose.override.yml का उपयोग करते हैं, जो !reset / !override टैग पर निर्भर करता है)।sudo mount -t bpf bpf /sys/fs/bpf।ब्रोकर छवि अपने बिल्ड आर्किटेक्चर का पता लगाती है और मिलान करने वाले __TARGET_ARCH_* मैक्रो को clang को पास करती है, इसलिए यह x86_64 और aarch64 (Apple Silicon, Graviton) दोनों पर बनती है। ध्यान दें कि gcc-multilib जानबूझकर नहीं स्थापित किया गया है: यह केवल x86 पैकेज है जिसका कोई arm64 उम्मीदवार नहीं है, और इसे शामिल करने से arm64 पर apt एग्ज़िट कोड 100 के साथ बिल्ड टूट जाता है। eBPF ऑब्जेक्ट को संकलित करने के लिए केवल clang और libbpf-dev की आवश्यकता है।
macOS पर Docker Desktop कंटेनरों को आपके होस्ट कर्नेल के बजाय LinuxKit VM के अंदर चलाता है, इसलिए TC/TCX eBPF अटैच आमतौर पर वहाँ काम नहीं करेगा। यह घातक नहीं है: eBPF डिज़ाइन द्वारा सर्वोत्तम प्रयास है, इसलिए ब्रोकर ebpf disabled: attach failed लॉग करता है और रिवर्स प्रॉक्सी और तीनों डिकॉय सामान्य रूप से चलते और लॉग होते हैं। आप स्थानीय रूप से पूरे प्रॉक्सी पथ को विकसित और परीक्षण कर सकते हैं, फिर जब आप लिनक्स होस्ट पर तैनात करते हैं तो वास्तविक eBPF अवलोकन प्राप्त कर सकते हैं।
docker-compose.override.yml स्वचालित रूप से लोड होता है और इसे सुखद बनाता है: यह eBPF क्षमताओं को हटा देता है (VM में बेकार) और होस्ट पोर्ट 22 को 2022 पर रीमैप करता है, क्योंकि Mac का अपना sshd 22 का मालिक है।
docker compose up --build # स्थानीय विकास, ओवरराइड लागू
docker compose -f docker-compose.yml up -d # वास्तविक तैनाती, ओवरराइड को बायपास
पहले प्रीफ़्लाइट जाँच चलाएँ:
./scripts/setup.sh
# 1. सभी चार छवियाँ बनाएँ (ब्रोकर छवि के अंदर eBPF ऑब्जेक्ट संकलित करता है)
make build
# 2. स्टैक शुरू करें
make up
# 3. देखें क्या होता है
make logs
फिर इसे किसी अन्य मशीन (या स्मोक टेस्ट के लिए लोकलहोस्ट) से प्रोब करें:
ssh -p 22 user@DECOY_HOST # SSH डिकॉय को हिट करता है
nc DECOY_HOST 3389 # RDP डिकॉय को हिट करता है
nc DECOY_HOST 445 # SMB डिकॉय को हिट करता है
nc DECOY_HOST 8080 # अविज्ञापित: eBPF द्वारा देखा गया, कोई प्रॉक्सी नहीं
ब्रोकर eBPF प्रोब इवेंट और प्रॉक्सी किए गए सत्रों के लिए JSON उत्सर्जित करता है; प्रत्येक डिकॉय OpenCanary JSON इवेंट उत्सर्जित करता है। क्रेडेंशियल आने को देखने के लिए:
docker compose logs -f ssh-decoy | grep 4002
एक बैनर-ओनली स्टब के विपरीत, ssh -p 22 user@DECOY_HOST अब एक वास्तविक कुंजी विनिमय पूरा करता है और पासवर्ड के लिए संकेत देता है। हर प्रयास कैप्चर किया जाता है। सत्यापित करें कि सेवा फिंगरप्रिंट संस्करण का पता लगाने के तहत कायम है:
nmap -sV -p 22,3389,445 DECOY_HOST
नीचे लाएँ:
make down
broker/config.yaml में सेवाएँ परिभाषित हैं। प्रत्येक प्रविष्टि स्वतंत्र रूप से टॉगल करने योग्य और रीमैप करने योग्य है:
services:
- name: ssh
enabled: true
listen_port: 22
backend: ssh-decoy:2222
एक सेवा जोड़ने के लिए, यहाँ एक प्रविष्टि जोड़ें, docker-compose.yml में पोर्ट प्रकाशित करें, और एक डिकॉय कंटेनर जोड़ें। एक को अक्षम करने के लिए, enabled: false सेट करें (और वैकल्पिक रूप से इसका प्रकाशित पोर्ट हटाएँ)।
ध्यान दें कि होस्ट पोर्ट 22 आमतौर पर होस्ट के वास्तविक SSH डेमन द्वारा लिया जाता है। एक प्रयोगशाला के लिए आप docker-compose.yml में प्रकाशित पक्ष को रीमैप कर सकते हैं, उदाहरण के लिए "2022:22", और अपने स्कैनर को वहाँ इंगित करें।
तीनों डिकॉय OpenCanary (Thinkst) चलाते हैं, जिन्हें इस प्रकार कॉन्फ़िगर किया गया कि प्रत्येक कंटेनर ठीक एक मॉड्यूल सक्षम करता है। लॉग stdout पर JSON के रूप में उत्सर्जित होते हैं, इसलिए docker compose logs और कोई भी SIEM शिपर बिना अतिरिक्त प्लंबिंग के काम करता है।
| कंटेनर | OpenCanary मॉड्यूल | सुनता है | यह वास्तव में क्या करता है |
|---|---|---|---|
ssh-decoy | ssh | 2222 | twisted.conch के माध्यम से वास्तविक SSH कुंजी विनिमय। प्रत्येक उपयोगकर्ता नाम/पासवर्ड जोड़ी कैप्चर करता है। |
rdp-decoy | rdp | 3389 | NLA-सक्षम सर्वर का अनुकरण करता है, हमेशा लॉगिन विफलता लौटाता है, mstshash उपयोगकर्ता नाम निकालता है। |
smb-decoy | Impacket | 445 | शुद्ध-Python SMB2/3 सर्वर। बेट शेयर प्रस्तुत करता है और कनेक्शन और NTLM प्रमाणीकरण प्रयासों को JSON के रूप में लॉग करता है। |
OpenCanary प्रत्येक इवेंट को एक संख्यात्मक logtype के साथ टैग करता है। यहाँ आप जो देखेंगे:
| logtype | opencanary/logger.py में Constant | अर्थ |
|---|---|---|
| 1000 | LOG_BASE_BOOT | डेमन स्टार्टअप |
| 4000 | LOG_SSH_NEW_CONNECTION | SSH कनेक्शन खुला |
| 4001 | LOG_SSH_REMOTE_VERSION_SENT | क्लाइंट ने अपना संस्करण स्ट्रिंग भेजा |
| 4002 | LOG_SSH_LOGIN_ATTEMPT | SSH लॉगिन प्रयास (USERNAME और PASSWORD शामिल है) |
| 5000 | LOG_SMB_FILE_OPEN | SMB फ़ाइल खोली गई (USER, SHARENAME, FILENAME शामिल है) |
| 14001 | LOG_RDP | RDP कनेक्शन / लॉगिन प्रयास |
एक कैप्चर किया गया SSH क्रेडेंशियल इस तरह दिखता है:
{"dst_port": 2222, "logtype": 4002, "node_id": "decoy-ssh",
"src_host": "10.0.0.66", "src_port": 42958,
"logdata": {"USERNAME": "admin", "PASSWORD": "Passw0rd123"}}
यह ब्रोकर आर्किटेक्चर का प्रत्यक्ष परिणाम है, और इन लॉग को पढ़ने के बारे में समझने के लिए यह सबसे महत्वपूर्ण बात है।
ब्रोकर हमलावर के TCP कनेक्शन को समाप्त करता है और डिकॉय के लिए एक नया कनेक्शन खोलता है। इसलिए OpenCanary के दृष्टिकोण से, क्लाइंट ब्रोकर है। डिकॉय इवेंट में प्रत्येक src_host decoynet पर ब्रोकर का पता होगा, वास्तविक स्रोत नहीं।
वास्तविक स्रोत IP अभी भी कैप्चर किया गया है, बस एक अलग जगह पर:
| स्तर | वास्तविक स्रोत IP जानता है? | जानता है क्या प्रयास किया गया? |
|---|---|---|
eBPF क्लासिफायर (probe observed) | हाँ | नहीं, केवल SYN मेटाडेटा |
ब्रोकर प्रॉक्सी (session opened) | हाँ | नहीं, केवल बाइट गणना |
OpenCanary डिकॉय (logtype 4002) | नहीं | हाँ, क्रेडेंशियल/फ़ाइलें |
इसलिए एट्रिब्यूशन के लिए ब्रोकर लॉग को डिकॉय लॉग के साथ सहसंबंधित करना आवश्यक है, टाइमस्टैम्प और सेवा पर जॉइन करना। ब्रोकर प्रत्येक सत्र के लिए remote (वास्तविक हमलावर पता) और backend लॉग करता है, जो जॉइन को संभव बनाता है:
docker compose logs broker | grep 'session opened' # कौन
docker compose logs ssh-decoy | grep '"logtype": 4002' # उन्होंने क्या प्रयास किया
यदि आपको डिकॉय के अंदर ही वास्तविक IP की आवश्यकता है, तो विकल्प हैं PROXY प्रोटोकॉल भेजना (डिकॉय इसे पार्स नहीं करते, इसलिए इसका मतलब उन्हें पैच करना होगा), या यूज़रस्पेस प्रॉक्सी को एक पारदर्शी रीडायरेक्ट (TPROXY या eBPF bpf_sk_assign) से बदलना जो मूल स्रोत पते को संरक्षित करता है। दोनों रोडमैप के अंतर्गत सूचीबद्ध हैं। तब तक, ब्रोकर को "कौन" के लिए सत्य का स्रोत मानें और डिकॉय को "क्या" के लिए सत्य का स्रोत मानें।
SSH और RDP के विपरीत, यह डिकॉय OpenCanary का उपयोग नहीं करता। OpenCanary का smb मॉड्यूल केवल एक लॉग वॉचर है: यह एक फ़ाइल को टेल करता है और वास्तविक Samba सर्वर द्वारा उत्सर्जित smbd_audit लाइनों को पार्स करता है, जिसका अर्थ है Samba और rsyslog और opencanaryd को supervisord के तहत चलाना, एक पाँच-कड़ी श्रृंखला जहाँ कोई भी कड़ी चुपचाप विफल हो सकती है।
smb-decoy उस सब को Impacket के SimpleSMBServer पर बने एक एकल Python प्रक्रिया से बदल देता है, SMB1/2/3 का शुद्ध-Python कार्यान्वयन। यह 445 को बाइंड करता है, केवल-पढ़ने के लिए बेट शेयर प्रस्तुत करता है, SMB2/3 नेगोशिएशन का उत्तर देता है (ताकि nmap -sV एक वास्तविक सेवा देखे), और कनेक्शन और NTLM प्रमाणीकरण प्रयासों को stdout पर प्रति पंक्ति एक JSON ऑब्जेक्ट के रूप में लॉग करता है। हमलावर के authenticate संदेश से कैप्चर किया गया उपयोगकर्ता नाम, डोमेन और वर्कस्टेशन क्रेडेंशियल-कैप्चर भुगतान है।
सुरक्षा नोट: Impacket के smbserver में एक महत्वपूर्ण पथ ट्रैवर्सल, CVE-2021-31800, था जो विशेष रूप से हनीपॉट को प्रभावित करता था। इसे 0.9.23 में ठीक किया गया था। requirements.txt एक वर्तमान रिलीज़ को पिन करता है और इसे उससे नीचे डाउनग्रेड नहीं किया जाना चाहिए। कंटेनर गैर-रूट, केवल-पढ़ने के लिए चलता है, NET_BIND_SERVICE को छोड़कर सभी क्षमताएँ हटा दी गई हैं।
प्रत्येक डिकॉय का अपना opencanary.conf होता है (/etc/opencanaryd/ में स्थापित)। उपयोगी नॉब:
decoys/ssh/opencanary.conf में ssh.version। यह वर्तमान में SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.1 का दावा करता है। इसे उस OS से मिलाएँ जिसका आप दिखावा कर रहे हैं; एक Ubuntu बैनर जो Windows होने का दावा करने वाली मशीन पर एक संकेत है।decoys/smb/smb_decoy.py में addShare(...) कॉल, साथ ही decoys/smb/Dockerfile में बनाई गई बेट फ़ाइलें। शेयर नाम और फ़ाइल नाम लालच हैं।broker/config.yaml में backend के साथ संरेखित रखें।एक और OpenCanary मॉड्यूल (ftp, telnet, mysql, vnc, redis और अन्य उपलब्ध हैं) सक्षम करने के लिए, <module>.enabled और <module>.port सेट करें, एक डिकॉय कंटेनर जोड़ें, और broker/config.yaml में एक मिलान सेवा जोड़ें।
ssh-decoy /var/lib/opencanary (ssh.key_path) पर एक नामित वॉल्यूम माउंट करता है, ताकि उत्पन्न होस्ट कुंजी पुनरारंभ के बाद बची रहे। इसके बिना OpenCanary प्रत्येक प्रारंभ पर एक नई कुंजी उत्पन्न करता है और बदलती फिंगरप्रिंट एक स्पष्ट संकेत है।
SMB डिकॉय अब एक एकल प्रक्रिया है, इसलिए समस्या निवारण सीधा है।
docker compose logs -f smb-decoy
हर पंक्ति JSON है। आपको बूट पर एक smb_decoy_start देखना चाहिए, फिर smb_connect, smb_auth_attempt, और smb_tree_connect इवेंट जैसे ही क्लाइंट इंटरैक्ट करते हैं। किसी भी SMB क्लाइंट के साथ होस्ट से परीक्षण करें:
# macOS Finder: Go > Connect to Server
open 'smb://guest@localhost/HR-Payroll'
# या Linux से
smbclient -L //localhost -p 445 -N
सामान्य समस्याएँ:
smb_decoy_start पंक्ति नहीं और कंटेनर बाहर निकलता है: requirements.txt को साफ-सुथरा स्थापित करने की जाँच करें। Impacket को Python 3.8+ चाहिए; छवि 3.12 का उपयोग करती है।smb_auth_attempt नहीं: कुछ क्लाइंट बिना प्रमाणीकरण के गुमनाम रूप से शेयरों की गणना करते हैं। यह अभी भी smb_connect और smb_tree_connect उत्पन्न करता है। उपयोगकर्ता नाम के साथ एक शेयर मैप करके प्रमाणीकरण बाध्य करें।src_host ब्रोकर का पता है, वास्तविक हमलावर नहीं। ब्रोकर लॉग के साथ टाइमस्टैम्प पर सहसंबंधित करें।NET_ADMIN (और हाल के कर्नेल पर BPF / PERFMON) की आवश्यकता है। Compose फ़ाइल इन स्कोप्ड क्षमताओं का अनुरोध करती है। यदि आपका होस्ट या Docker संस्करण उन्हें अस्वीकार करता है, तो फ़ॉलबैक ब्रोकर सेवा पर privileged: true है, जो व्यापक है और केवल तब उपयोग किया जाना चाहिए जब स्कोप्ड कैप काम न करें।internal नेटवर्क पर बैठते हैं जिसमें कोई होस्ट रूट नहीं है। इसे ऐसे ही रखें। प्रत्येक डिकॉय कंटेनर को संभावित रूप से समझौता किए गए के रूप में मानें।bpf_sk_assign के माध्यम से डिकॉय में हमलावर के स्रोत IP को संरक्षित करें, ब्रोकर और डिकॉय लॉग को सहसंबंधित करने की आवश्यकता को समाप्त करें।MIT. LICENSE देखें।