
مراقب القيادة والتحكم للبوت نت
Hale هو أداة مراقبة/تجسس على أوامر وتحكم البوتنت (C&C) بتصميم معياري (modular) لتسهيل تطوير وحدات جديدة تراقب البروتوكولات الجديدة المستخدمة من قبل خوادم C&C. يأتي Hale مع مراقبَين لـ IRC وHTTP مطوَّرَين باستخدام Twisted للتعامل مع قابلية التوسع لعدد كبير من الاتصالات. تمتلك هذه الوحدات قواعد بروتوكول (grammar) وإعدادات بوت قابلة للتهيئة، ويمكن أيضاً تعديلها لتناسب احتياجاتك. تُحفظ جميع السجلات والملفات الملتقطة في قاعدة بيانات، وفي حالة IRC، تُحفظ أيضاً أرقام IP المتتبَّعة.
لإخفاء موقع المشغِّل، يمكن إجراء الاتصالات عبر وكلاء SOCKSv5، وهذا قابل للتهيئة عبر واجهة الويب حيث تتوفر أيضاً جميع السجلات للتصفح مع مخططات إحصائية وخطوط زمنية. طُوِّرت الواجهة باستخدام Django وGoogle Visualization API. من الإضافات في واجهة الويب: دعم واجهة برمجة تطبيقات RESTful مع دعم OAuth ومحرك بحث.
الفكرة الرئيسية من Hale هي المساعدة في اصطياد البوتنتات والبحث فيها من خلال التعاون عبر إنشاء شبكة من المستشعرات (مراقبات Hale). لتحسين هذه الفكرة، يتوفر بوت XMPP للاتصال بخادم XMPP مركزي حيث تُستخدم حالياً غرفتا مجموعة مختلفتان للتنسيق بين المستشعرات، وغرفة لمشاركة السجلات والملفات. تستخدم غرفة التنسيق تجزئات البوتنت (botnet hashes) المُنشأة من المفاتيح الفريدة في إعدادات البوتنت، وبهذه الطريقة لا يلزم مراقبة بوتنتين لهما نفس التجزئة (الهوية) في نفس الوقت، مما يحسّن الاستخدام. لمساعدة الأطراف الثالثة على الاستفادة من هذه الشبكة، يمكن لبوت الانضمام إلى غرفة التنسيق وطلب بدء تتبع بوتنت من مستشعر إذا لم يكن متتبَّعاً، وذلك بإرسال الإعدادات الخاصة به. بالإضافة إلى ذلك، في غرفة المشاركة، يمكن لبوتات الأطراف الثالثة الحصول على السجلات والملفات الملتقطة من قبل المستشعرات في الوقت الفعلي. للمساعدة في الاطلاع على سجل الأحداث (log history)، يمكن استخدام واجهة برمجة تطبيقات الويب التي تدعم طلبات GET.
لدى Hale التبعيات التالية:
Python == 2.6
Django == 1.2.1
Twisted == 10.1.0
GeoIP-Python == 1.2.4 (and GeoIP C lib)
Whoosh == 0.3.18
django-haystack == 1.0.1-final
django-piston == 0.2.3rc1
pefile == 1.2.10-63
sleekxmpp == 0.9Rrc1
wsgiref == 0.1.2
zope.interface == 3.6.1
oauth2 == 1.2.0
httplib2 == 0.6.0
بالإضافة إلى ذلك، يتطلب المراقب برنامج تشغيل للواجهة الخلفية لقاعدة البيانات (database backend driver) يطابق قاعدة البيانات المستخدمة من قبل django. عند تثبيت هذه المكتبات، حمّل الكود المصدري من هنا واستخرج محتواه في أي مكان.
أولاً أنشئ قاعدة بيانات ستُستخدم من قبل Hale، ويمكن أن يكون محرك قاعدة البيانات أي محرك من اختيارك. إذا كنت تستخدم قاعدة بيانات موجودة مسبقاً فتخطَّ هذه الخطوة.
الخطوة التالية هي تثبيت برامج تشغيل الواجهة الخلفية لقاعدة بيانات بايثون (python database backend drivers) المطابقة لتلك المستخدمة من قبل محرك الخادم.
عدّل settings.py في hale/src/webdb/ وعدّل الإعدادات التالية: ENGINE وNAME وUSER وPASSWORD وHOST وPORT، حيث يكون إعداد المحرك مثلاً django.db.backends.mysql إذا كان محرك الخادم لديك هو MySQL. إعداد name هو اسم قاعدة البيانات التي استخدمتها عند إنشائها.
إذا كنت لا تريد تشغيل واجهة الويب الخاصة بك فتخطَّ هذه الخطوة وانتقل إلى 8). في settings.py، غيّر PATH_TO_APP ليشير إلى المسار الكامل لتطبيق Django، على سبيل المثال: '/home/..../Hale/src/webdb'. في دليل webdb شغّل الأمر التالي: python manage.py syncdb. إذا واجهت أي أخطاء هنا فمن المرجح أن إعدادات قاعدة البيانات في settings.py غير صحيحة. وأيضاً، أثناء المزامنة، عيِّن المستخدم الفائق (superuser) الذي سيُستخدم عند إدارة المستخدمين.
لدعم البحث في واجهة الويب، شغّل python manage.py rebuild_index للسماح لمحرك البحث بالفهرسة لأول مرة. سيُنشئ هذا دليلاً باسم ، وللسماح لخادم الويب بالكتابة هنا، نفّذ الأمر . بعد ذلك شغّل بدلاً منه، ويُنصح بوضع هذا كوظيفة cron (cron job) لتحديث الفهارس على فترات منتظمة من اختيارك.
Alias /media /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media/
<Location /media>
Order allow,deny
Allow from all
</Location>
WSGIDaemonProcess username processes=2 maximum-requests=500 threads=10
WSGIProcessGroup group
WSGIScriptAlias / /home/..../webdb/django.wsgi
وعدّل username وgroup اللذين يجب أن يعمل بهما خفي WSGI (daemon). يجب تعيين WSGIScriptAlias إلى المسار الكامل لملف django.wsgi الموجود في دليل webdb. إعداد Alias المحدد أعلاه ضروري لعرض صفحة الإدارة بشكل صحيح. لتمكين رفع الوحدات من خلال واجهة الويب، نفّذ chmod o+w webdb/modules.
ارفع الوحدات التي ستُستخدم من hale/src/modules/ أو اكتب وحداتك الخاصة (انظر قسم التطوير). ارفع الوحدة المطلوبة في واجهة الإدارة وعدّل مثلاً اسم الوحدة إلى irc واسم الملف إلى ircModule.py. حدد قواعد الإعداد (config rules) للوحدة في القسم المقابل الموجود في hale/conf/modules.conf وضعها في مربع النص، وأضف أيضاً أقسام uniqueKeys للوحدة التي يتم رفعها.
قبل تشغيل المراقب، عدّل hale.conf في hale/src/conf/ إذا كنت تريد استخدام خادم XMPP. لتفعيل بوت XMPP اضبط إعداد use على True، وإما عدّل معلومات تسجيل الدخول إلى حساب وخادم موجودين أو ابدأ تشغيل خادم XMPP خاص بك. خطوة مهمة عند بدء تشغيل خادم XMPP هي زيادة الحد الأقصى لحجم الـ stanza من القيمة الافتراضية إلى شيء مثل 10Mb. وإلا فلن يكون إعلان البرمجيات الخبيثة (malware advertisement) ممكناً. تُستخدم إعدادات channel في hale.conf لغرفة المشاركة الجماعية المستخدمة من قبل البوت، ويُستخدم إعداد coord للغرفة الجماعية التي يحدث فيها كل التنسيق بين المستشعرات.
عدّل hale.conf واضبط إعدادات العميل (client) والخادم (server).
لبدء تشغيل المراقب، انتقل إلى hale/src/ ونفّذ python server.py. إذا بدأ مع أخطاء فإن ملف django settings.py غير مضبوط بشكل صحيح أو أن بعض المكتبات مفقودة. مع العميل (client) يمكن إصدار أوامر إلى الخادم، لكنه يتطلب من المستخدم مصادقة نفسه على الخادم، ويُمنح الوصول للمستخدمين المعيَّنين كأعضاء طاقم (staff) عبر واجهة الويب. عند تشغيل العميل، اكتب help أو ? للحصول على الأوامر المتاحة. اكتب help command للحصول على مزيد من المعلومات حول الأمر المحدد. يتم تشغيل بوت المراقبة بتحرير ملف hale/src/conf/modules.conf أولاً، على سبيل المثال باستخدام إعداد IRC كما يلي:
[uniqueKeys]
irc = botnet, *grammar
[ircConf]
module = irc
botnet = irc.freenode.net
port = 6667
password = None
nick = nickname
username = agent007
realname = Spying
channel = #channelname
channel_pass = somepass
pass_grammar = PASS
nick_grammar = NICK
user_grammar = USER
join_grammar = JOIN
version_grammar = VERSION
time_grammar = TIME
privmsg_grammar = PRIVMSG
topic_grammar = TOPIC
currenttopic_grammar = 332
ping_grammar = PING
pong_grammar = PONG
عدّل أو أنشئ إعداداً جديداً بتحديد قسم جديد باسم فريد (جزء [ircConf]). في أعلى ملف الإعداد يوجد قسم باسم uniqueKeys حيث تُحدد جميع الحقول الفريدة للوحدة وتُستخدم لتوليد تجزئة البوتنت (botnet hash)، ولا ينبغي تغيير هذا عادةً للحفاظ على تتبع صحيح للبوتنت. عند الانتهاء من ذلك، شغّل useconf section لتحميل الإعداد ثم شغّل البوت بالأمر exec modulename id حيث يتم تعيين id من قبلك لتحديد هوية البوتنت.
توفر واجهة الويب الوصول إلى جميع البيانات الملتقطة في قاعدة البيانات، وهي متاحة من الصفحة الرئيسية (index page). توجد أيضاً وظيفة بحث تتيح للمستخدم البحث عن تجزئات البوتنت والملفات، وأرقام IP ذات الصلة، ومعرفات البوتنت، ووحدات البوتنت المستخدمة، ومضيفي البوتنت. إذا كان لدى المستخدم صلاحية تحرير الوكلاء (proxies) أو الوحدات، فيمكن القيام بذلك في قسم الإدارة، ورابط ذلك هو http://.../admin. يمكن للمسؤول تعيين أوضاع المستخدمين وإضافة مستهلكين (consumers) لواجهة برمجة تطبيقات الويب أيضاً.
نفّذ وحدة، على سبيل المثال:
import moduleManager from utils import moduleInterface
@moduleManager.register("irc") def module_setup(config, hash): """ Function to register modules, simply implement this to pass along the config and hash to the module object and return the it back. """
return IRC(config, hash)
class IRC(moduleInterface.Module):
def __init__(self, config, hash):
self.config = config
self.hash = hash
# must be implemented
def stop(self):
# stop execution
# must be implemented
def run(self):
# start execution
# must be implemented
def getConfig(self):
return self.config
أضف الـ decorator لدالة التسجيل (في هذه الحالة module_setup) والتي ستُستدعى مع الإعداد الحالي كوسيط (argument) وتجزئة الإعداد المُنشأة من المفاتيح الفريدة. يمكن تسمية هذه الدالة بأي اسم. مرر الإعدادات إلى كائن الوحدة، يلتقط configHandler أخطاء KeyError، لذا إذا أُرسلت إعدادات خاطئة إلى هذه الدالة فسيُعلمك configHandler بالأمر.
اتبع أيضاً اصطلاح التسمية nameModule.py و**@moduleManager.register("name")** واستورد moduleManager، وإلا فسيُعلمك moduleManager بأي أخطاء.
تم حذف بقية كود الوحدة، لكن يجب إنشاء كائن twisted factory وبدء تشغيله مع reactor في دالة run، راجع الوحدات الموجودة للحصول على مثال. للاطلاع على دروس البرمجة باستخدام Twisted، يرجى الاطلاع هنا. توجد أيضاً بعض الأدوات (utils) التي يمكن استخدامها عند تطوير الوحدات، ويتم ذلك كما يلي:
Socksify:
# import all utils
from utils import *
# in the constructor create a new proxy object
self.prox = proxySelector.ProxySelector()
# in the run method add the following after having created the factory method.
proxyInfo = self.prox.getRandomProxy()
if proxyInfo == None:
self.connector = reactor.connectTCP(host, port, factory)
else:
proxyHost = proxyInfo['HOST']
proxyPort = proxyInfo['PORT']
proxyUser = proxyInfo['USER']
proxyPass = proxyInfo['PASS']
socksify = socks5.ProxyClientCreator(reactor, factory)
if len(proxyUser) == 0:
self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE")
else:
self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE", proxyUser, proxyPass)
معالجة أخطاء الاتصال في كائن المصنع (factory):
def clientConnectionFailed(self, connector, reason):
"""
Called on failed connection to server
"""
moduleCoordinator.ModuleCoordinator().putError("Error connecting to " + self.config['botnet'], self.module)
def clientConnectionLost(self, connector, reason):
"""
Called on lost connection to server
"""
moduleCoordinator.ModuleCoordinator().putError("Connection lost to " + self.config['botnet'], self.module)
سيرسل هذا الأخطاء إلى سلة الأخطاء (error bucket) التي يمكن الوصول إليها بإصدار الأمر showlog في واجهة سطر الأوامر (CLI).
التسجيل (Logging):
# in the factory create the following method to handle logs (note that the hash and config must be sent to the factory)
# and call it in the protocol class with: self.factory.putLog(data)
def putLog(self, log):
"""
Put log to the event handler
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.LOG_EVENT, log, self.hash, self.config)
# apply reg expression to look for URLs containing possible malware
# and call it in the protocol class with: self.factory.checkForURL(data)
def checkForURL(self, data):
"""
Check for URL in the event handler
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.URL_EVENT, data, self.hash)
# if you module should detect IP numbers of other bots and herders implement the following method in the factory
def addRelIP(self, data):
"""
Put possible ip related to the botnet being monitored
in the event handler.
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.RELIP_EVENT, data, self.hash)
يتم التعامل مع عناوين IP ذات الصلة بتطبيق تعبير نمطي (regular expression) يُستخدم للبروتوكول الذي ستدعمه الوحدة، وفي حالة وحدة IRC يبدو الكود كما يلي:
checkHost = data.split(':')[1].split(' ')[0].strip()
match = self.factory.expr.findall(checkHost)
if match:
self.factory.addRelIP(data.split('@')[1].split(' ')[0].strip())
حيث يكون التعبير النمطي كما يلي:
self.expr = re.compile('!~.*?@')
2) انقل الملف إلى دليل modules. سيقوم moduleManager بعد ذلك باستيراده تلقائياً والتحقق من الأخطاء.
عدّل الإعداد في modules.conf
ارفع الوحدة إلى واجهة الويب بتعيين اسم الوحدة مثلاً إلى irc واسم الملف ircModule.py ثم أضف مثال إعداد لهذه الوحدة.
عند إرسال طلب لتتبع بوتنت، يُقدَّم الطلب كما يلي إلى غرفة التنسيق الجماعية
sensorLoadReq
حيث يرد جميع المستشعرات بمعرفاتهم (id) وطول قائمة الانتظار (عدد البوتنتات المراقَبة)
sensorLoadAck id=353f6650859547ed06597dbfa1dcfd88 queue=0
يختار المرسِل (feeder) بعد ذلك مستشعراً واحداً بناءً على هذه المعلومات مثل أقل طول قائمة انتظار، وإذا تساوت هذه القيم لعدة مستشعرات، فيُختار معرف المستشعر الأقل ترتيباً أبجدياً.
عندما يختار المرسِل مستشعراً، يرسل رسالة محادثة خاصة إلى المستشعر
startTrackReq config
حيث config هو تمثيل نصي للإعداد، على سبيل المثال
module=irc botnet=irc.freenode.net etc..
يرد المستشعر بعد ذلك بإقرار (acknowledgement) مع تجزئة الإعداد (config hash) التي يمكن استخدامها لتمييز سجلات البوتنت عن السجلات الأخرى في قناة المشاركة. مثال على الإقرار:
startTrackAck hash
إذا لم يكن أي شخص آخر يراقب هذا البوتنت، وإلا فسيتم استلام startTrackNack إذا كان البوتنت مراقَباً بالفعل أو إذا لم تكن الوحدة مثبتة لدى المستشعر لهذا البوتنت. تتم مشاركة البرمجيات الخبيثة بإرسال المستشعرات رسالة مثل:
fileCaptured hash=353f6650... file content
حيث يكون المحتوى مشفراً بترميز Base64 ويأتي مباشرة بعد قيمة تجزئة الملف.
للوصول إلى واجهة البرمجة تحتاج إلى مفتاح مستهلك (consumer key) ومفتاح سري (secret key)، ويمكن إنشاؤهما بواسطة المسؤول ويُستخدمان مع OAuth للمصادقة. عناوين URL التالية متاحة لجلب البيانات بصيغة JSON:
http://.../api/botnet سيرد بجميع البوتنتات المراقَبة
http://.../api/botnet/botnethash سيرد بالبوتنت الذي تجزئته تساوي botnethash
http://.../api/host/hostname سيرد بجميع البوتنتات المراقَبة التي مضيفها يساوي hostname
http://.../api/type/module سيرد بجميع البوتنتات المراقَبة باستخدام الوحدة
http://.../api/botips/hash سيرد بجميع عناوين IP الملتقطة بواسطة البوتنت ذي القيمة hash
http://.../api/bologs/hash سيرد بجميع سجلات البوتنت ذي القيمة hash
http://.../api/bofiles/hash سيرد بتجزئات الملفات الملتقطة بواسطة البوتنت ذي القيمة hash
http://.../api/file/hash يعيد معلومات البوتنت(ات) التي التقطت ملفاً بالتجزئة المحددة
http://.../api/ip/addr سيرد بمعلومات البوتنت(ات) التي رصدت عنوان IP بالرقم addr
لاحظ أنه حالياً طلبات GET فقط هي الممكنة.
whoosh.index/chmod o+w whoosh.index/python manage.py update_indexشغّل python manage.py runserver وانتقل إلى http://127.0.0.1:8000 للتحقق من أن الإعداد تم بشكل صحيح.
ينشر أمر runserver خادم تطوير لا يُنصح باستخدامه في بيئة الإنتاج بسبب مشاكل الأداء. بدلاً من ذلك، انشر واجهة الويب بتثبيت mod_wsgi لأباتشي، وبافتراض أنك تستخدم أوبونتو، شغّل apt-get install libapache2-mod-wsgi. في /etc/apache2/sites-available/default أضف ما يلي: