
مستودع SSH وهمي مستقل لالتقاط تفاعلات المهاجمين وتحويلها إلى استخبارات أمنية منظمة.
SSHintel هي مصيدة SSH خفيفة الوزن مبنية باستخدام Python وParamiko. تحاكي قشرة Linux زائفة لتسجيل محاولات الوصول غير المصرح بها، والتقاط بيانات الاعتماد، وتحليل سلوك المهاجم في بيئة خاضعة للتحكم.
ls, cd, pwd, cat, echo, grep, find, tree, head, tail, wc, stat, ps, df, free, env, id, whoami, وغيرها)--tarpit اختياري لإبطاء المهاجمين عبر تأخير المخرجاتSSHintel ليست قشرة Bash/Linux كاملة. إنها تحاكي مجموعة فرعية معقولة من الأوامر الشائعة لجمع بيانات المهاجم. يتم توزيع الأوامر عبر سجل خفيف الوزن؛ إضافة أمر تعني إضافة دالة معالج صغيرة.
pip install -r requirements.txt
ملاحظة: يتم إنشاء مفتاح مضيف SSH تلقائيًا عند أول تشغيل. لا حاجة لتوليد مفتاح يدوي.
شغّل المصيدة بمنفذ واسم مستخدم وكلمة مرور محددة:
python3 run.py serve --port 2222 --username user1 --password pass123
المنفذ الافتراضي هو
2222والمضيف هو0.0.0.0.
تقوم المصيدة بتوليد تلقائي لمفتاح مضيف SSH في static/server.key عند أول تشغيل إذا لم يكن موجودًا. لا حاجة لتوليد مفتاح يدوي.
لتفعيل وضع tarpit:
python3 run.py serve --port 2222 --username user1 --password pass123 --tarpit
لتعطيل تخزين SQLite (JSONL فقط):
python3 run.py serve --port 2222 --username user1 --password pass123 --no-db
تحمي SSHintel من استنزاف الموارد بسبب العديد من الاتصالات المتزامنة أو الاتصالات التي تبقى نشطة إلى أجل غير مسمى. هذه قابلة للتكوين عبر واجهة سطر الأوامر:
مثال:
python3 run.py serve --port 2222 --username user1 --password pass123 \
--max-connections 25 --auth-timeout 30 --session-idle-timeout 300
عندما يكون هناك عدد كبير جدًا من الاتصالات المفتوحة، يتم إغلاق الاتصال الإضافي فورًا ويتم كتابة حدث أمان connection_rejected (مع reason: connection_limit) في سجل JSONL. يتم تسجيل المصادقة المتعطلة كفصل مع reason: auth_timeout؛ تنتهي القشرة الخاملة مع reason: idle_timeout.
وضع Tarpit يرسل المخرجات ببطء عمدًا لإبقاء المهاجم منشغلًا، لذا فإن حلقة لافتة tarpit لا تخضع لمهلة عدم النشاط — لكن جلسات tarpit تُحتسب ضمن حد الاتصال.
تتضمن SSHintel لوحة تحكم ويب محلية تصور بيانات الأمان المخزنة في SQLite.
python3 run.py dashboard
ثم افتح http://localhost:5000 في متصفحك.
تقرأ لوحة التحكم من قاعدة بيانات SQLite في
data/sshintel.dbافتراضيًا. ابدأ المصيدة أولاً حتى يتم التقاط البيانات، ثم شغّل لوحة التحكم لمشاهدتها تمتلئ.
انقر على معرف جلسة (أو انتقل إلى /session/<session_id>) لفتح عرض التحقيق في الجلسة، الذي يعيد بناء هجوم واحد ترتيبًا زمنيًا:
$ command لكل ما كتبه المهاجم، مع أدلة العمل# الطرفية 1: ابدأ المصيدة
python3 run.py serve --port 2222 --username user1 --password pass123
# الطرفية 2: ابدأ لوحة التحكم
python3 run.py dashboard
# الطرفية 3: محاكاة مهاجم
ssh user1@localhost -p 2222
# (نفّذ بعض الأوامر، ثم اخرج)
ثم افتح http://localhost:5000 لفحص النشاط الملتقط.
تدعم لوحة التحكم البيانات المباشرة — تستقصي المصيدة كل ثانيتين وتتحدث تلقائيًا. تظهر الجلسات والأوامر والأحداث الجديدة في الوقت الفعلي دون تحديث الصفحة. مؤشر مباشر (● Live) يظهر حالة الاتصال.
افتح طرفية ثانية وحاول الاتصال:
ssh user1@localhost -p 2222
إذا تطابقت بيانات الاعتماد، ستُسقط في القشرة المحاكاة.
لإزالة بصمات SSH القديمة:
notepad "%USERPROFILE%\.ssh\known_hosts"
احذف السطر ذي الصلة الذي يحتوي على
localhostأو عنوان IP الخاص بالمصيدة.
creds_loggerfunnel_loggerlog_files/events.jsonl كـ JSON Lines (JSONL) — كائن JSON صالح واحد لكل سطريتضمن كل حدث JSONL طابعًا زمنيًا timestamp بصيغة UTC ISO-8601، وevent_type، وsession_id فريدًا، وsource_ip. يتم تسجيل الاتصال ومحاولات/نتائج المصادقة وتنفيذ الأوامر وتفعيل tarpit والفصل كأحداث منظمة.
يتم تتبع كل اتصال SSH وارد كـ جلسة مستقلة مع session_id خاص بها. تسجل الجلسة عنوان IP المصدر، وأوقات الاتصال/الفصل، ونتيجة المصادقة، ومدة الاتصال، وكل حدث يُنشأ داخل ذلك الاتصال يحمل نفس session_id (بحيث يمكن ربط محاولات المصادقة والأوامر والفصل باتصال واحد). الجلسات معزولة لكل اتصال — لا تتم مشاركة أي حالة بين العملاء المتزامنين.
تتلقى كل جلسة أيضًا نظام ملفات زائفًا معزولًا خاصًا بها في الذاكرة — يتم إنشاء نظام الملفات المحاكى من جديد لكل اتصال وتنظيفه عند انتهاء الاتصال. الملفات والدلائل ودليل العمل التي ينشئها أو يغيرها مهاجم واحد لا تكون مرئية أبدًا لمهاجم آخر متصل في نفس الوقت. نظام الملفات بأكمله محاكى في ذاكرة Python ولا يلمس أبدًا نظام ملفات المضيف الحقيقي.
قيم event_type الحالية: connect, auth_attempt, auth_success, auth_failure, command, disconnect, connection_rejected, tarpit.
SSHintel/
├── honeypot/ # منطق المصيدة الأساسي
│ ├── __init__.py
│ ├── main.py # حلقة القبول + تحديد الاتصال
│ ├── handlers.py # إعداد نقل SSH + القشرة المحاكاة
│ ├── server.py # واجهة خادم Paramiko (المصادقة)
│ ├── session.py # تتبع الجلسة لكل اتصال
│ ├── fs.py # نظام ملفات زائف في الذاكرة (معزول لكل جلسة)
│ ├── shell.py # القشرة الزائفة: سجل الأوامر + الموزع
│ ├── limits.py # تحديد الاتصالات المتزامنة الآمن للخيوط
│ ├── logger.py # تسجيل أحداث JSONL + جسر SQLite
│ └── telemetry_store.py # مخزن بيانات SQLite + طبقة الاستعلام
│
├── dashboard/ # لوحة التحكم الويب المحلية
│ ├── app.py # تطبيق Flask + مسارات API
│ ├── templates/
│ │ ├── index.html # قالب لوحة التحكم الرئيسي
│ │ └── session.html # قالب التحقيق في الجلسة
│ └── static/
│ ├── style.css # أنماط لوحة التحكم
│ ├── dashboard.js # جافاسكريبت لوحة التحكم الرئيسية (تحديثات مباشرة)
│ └── session.js # جافاسكريبت التحقيق في الجلسة
│
├── log_files/ # سجلات التشغيل (مستثناة من git)
│ ├── creds_audits.log # محاولات بيانات الاعتماد
│ ├── cmd_audits.log # سجل تدقيق الأوامر
│ └── events.jsonl # أحداث أمان JSONL منظمة
│
├── data/ # قاعدة بيانات SQLite (مستثناة من git)
│ └── sshintel.db
│
├── static/ # مفتاح مضيف SSH (مولّد تلقائيًا)
│ └── server.key
│
├── .github/workflows/ # إعداد CI
│ └── tests.yml
│
├── Dockerfile
├── README.md
├── requirements.txt # تبعيات التشغيل (paramiko, flask)
├── requirements-dev.txt # تبعيات الاختبار (pytest, pytest-cov)
└── run.py # نقطة دخول CLI
إذا كنت تفضل تشغيل المصيدة في بيئة حاويات، يمكنك استخدام Dockerfile المرفق.
docker build -t sshintel .
هذا ينشئ صورة Docker باسم
sshintel.
docker run -p 2222:2222 sshintel
سيؤدي هذا إلى:
static/server.key (إذا لم يكن موجودًا بالفعل)2222 ببيانات اعتماد افتراضية:username: user1, password: pass123افتح طرفية ثانية واتصل عبر SSH:
ssh user1@localhost -p 2222
ستُسقط في القشرة المحاكاة إذا تطابقت بيانات الاعتماد.
لإيقاف الحاوية:
docker ps # ابحث عن معرف الحاوية
docker stop <container_id>
لإزالة الصورة:
docker rmi sshintel
يمكنك أيضًا تصدير الصورة باستخدام
docker save -o sshintel.tar sshintelوتحميلها لاحقًا باستخدامdocker load -i sshintel.tar.
هذا المشروع مرخص بموجب رخصة MIT.
| Flag | Default | Purpose |
|---|
--max-connections | 50 | الحد الأقصى للاتصالات النشطة المتزامنة؛ يتم رفض الاتصالات الإضافية وتسجيلها كحدث connection_rejected |
--auth-timeout | 60 (ثانية) | الوقت المسموح لإكمال مصافحة SSH/المصادقة؛ يتم فصل العملاء المتعطلين |
--session-idle-timeout | 300 (ثانية) | مهلة عدم النشاط لقشرة مصادق عليها؛ تنتهي الجلسة الخاملة، لكن المهاجم الذي يكتب بنشاط لا يُقتل أبدًا |