
ボットネットのコマンド&コントロールモニター
Hale は、新しい C&C サーバーで使用されるプロトコルを監視する新しいモジュールを簡単に開発できるモジュール設計を備えた、ボットネットの C&C モニター/スパイです。Hale には、大量の接続を処理できるスケーラビリティを備えた Twisted で開発された IRC モニターと HTTP モニターが含まれています。これらのモジュールは、プロトコルの文法とボット設定を構成可能ですが、必要に応じて変更することもできます。取得したすべてのログとファイルはデータベースに保存され、IRC の場合は追跡された IP 番号も保存されます。
オペレーターの場所を隠すために、SOCKSv5 プロキシを介して接続できます。これは Web インターフェースから設定でき、すべてのログを統計チャートやタイムラインと一緒に参照することもできます。このインターフェースは Django と Google Visualization API で開発されました。Web UI のその他の機能には、OAuth をサポートした RESTful API と検索エンジンがあります。
Hale の主なアイデアは、センサー(Hale モニター)のネットワークを作成して、ボットネットハンティングと研究が協力できるようにすることです。このアイデアを発展させるために、中央の XMPP サーバーに接続する XMPP ボットを利用できます。現在、センサー間の調整には 2 つの異なるグループルームが使用され、ログとファイルを共有するためのルームが 1 つあります。調整ルームでは、ボットネット設定のユニークキーから生成されるボットネットハッシュを使用します。これにより、同じハッシュ(識別子)を持つ 2 つのボットネットを同時に監視する必要がなくなり、利用率が向上します。サードパーティがこのネットワークを利用できるように、ボットは調整ルームに参加し、未追跡のボットネットの設定を送信して、センサーに追跡開始を依頼できます。さらに、共有ルームでは、サードパーティのボットがセンサーによってリアルタイムに取得されたログやファイルを入手できます。ログ履歴を参照するには、GET リクエストをサポートする Web API を使用できます。
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
さらに、モニターには、django が使用するデータベースに対応するデータベースバックエンドドライバが必要です。これらのライブラリがインストールされたら、ここからソースをダウンロードして任意の場所に展開します。
最初に、Hale が使用するデータベースを作成します。データベースエンジンは任意のものを選択できます。既存のデータベースを使用する場合は、この手順をスキップしてください。
次に、サーバーエンジンで使用されているデータベースに対応する Python データベースバックエンドドライバをインストールします。
hale/src/webdb/ 内の settings.py を編集し、次の設定を変更します: ENGINE、NAME、USER、PASSWORD、HOST、PORT。エンジン設定は、サーバーエンジンが MySQL の場合、例えば django.db.backends.mysql となります。name 設定は、データベース作成時に使用したデータベース名です。
独自の Web UI を起動しない場合は、この手順をスキップして 8) に進んでください。settings.py で、PATH_TO_APP を Django アプリケーションのフルパスを指すように変更します。例: '/home/..../Hale/src/webdb'。webdb ディレクトリで次のコマンドを実行します: python manage.py syncdb。ここでエラーが発生した場合、その多くは settings.py のデータベース設定が正しくないことが原因です。また、同期中に、ユーザー管理時に使用するスーパーユーザーを設定してください。
Web インターフェースでの検索をサポートするには、python manage.py rebuild_index を実行して、初回の検索エンジンのインデックスを作成します。これにより、whoosh.index/ という名前のディレクトリが作成されます。Web サーバーがここに書き込めるようにするには、chmod o+w whoosh.index/ を実行してください。以降は、python manage.py update_index を実行し、これを cron ジョブとして設定して、任意の間隔でインデックスを更新することをお勧めします。
python manage.py runserver を実行し、http://127.0.0.1:8000 にアクセスして、セットアップが正しく行われたか確認します。
runserver コマンドは開発用サーバーを起動します。パフォーマンスの問題があるため、本番環境での使用には推奨されません。代わりに、Apache 用の mod_wsgi をインストールして Web UI をデプロイします。Ubuntu を使用している場合は、apt-get install libapache2-mod-wsgi を実行します。/etc/apache2/sites-available/default に次の内容を追加します:
Alias /media /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media/ <Location /media> Order allow,deny Allow from all
WSGIDaemonProcess username processes=2 maximum-requests=500 threads=10 WSGIProcessGroup group
WSGIScriptAlias / /home/..../webdb/django.wsgi
また、WSGI デーモンを実行するユーザー名とグループ名を編集してください。WSGIScriptAlias は、webdb ディレクトリにある django.wsgi ファイルのフルパスに設定する必要があります。上記の Alias は、管理ページを正しく表示するために必要です。Web インターフェースからモジュールをアップロードできるようにするには、chmod o+w webdb/modules を実行してください。
hale/src/modules/ から使用するモジュールをアップロードするか、独自のモジュールを作成します(開発のセクションを参照)。管理インターフェースで目的のモジュールをアップロードし、例えばモジュール名を irc、ファイル名を ircModule.py に設定します。モジュールの設定ルールは、hale/conf/modules.conf の対応するセクションで指定し、テキストボックスに入力します。また、アップロードするモジュールの uniqueKeys セクションも追加してください。
モニターを実行する前に、XMPP サーバーを使用する場合は hale/src/conf/ 内の hale.conf を編集します。XMPP ボットを有効にするには、use 設定を True に設定し、既存のアカウントとサーバーのログイン情報を編集するか、独自の XMPP サーバーを起動します。XMPP サーバーを起動する際の重要な手順として、max stanza サイズをデフォルト値から 10Mb 程度に増やします。そうしないと、マルウェアの告知ができなくなります。hale.conf の channel 設定はボットが使用する共有グループルーム用で、coord 設定はセンサー間のすべての調整が行われるグループルーム用です。
hale.conf を編集し、クライアントとサーバーの設定を行います。
モニターを起動するには、hale/src/ に移動し、python server.py を実行します。エラーが発生した場合は、django の settings.py が正しく設定されていないか、一部のライブラリが不足しています。クライアントを使用するとサーバーにコマンドを発行できますが、サーバーに対してユーザー認証を行う必要があります。アクセスは、Web インターフェースでスタッフメンバーとして設定されたユーザーにのみ許可されます。クライアントの実行中に 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 というセクションがあり、モジュールのすべてのユニークフィールドが指定され、ボットネットハッシュの生成に使用されます。通常、正しいボットネット追跡を維持するためにこれを変更しないでください。これが完了したら、useconf section を実行して設定を読み込み、exec modulename id でボットを起動します。ここで id はボットネットを識別するために任意に設定します。
Web インターフェースは、インデックスページからアクセスできるデータベース内のすべての取得データへのアクセスを提供します。また、検索機能があり、ボットネットとファイルのハッシュ、関連する IP 番号、ボットネット ID、使用されているボットネットモジュール、ボットネットホストを検索できます。プロキシやモジュールを編集する権限がある場合は、管理セクションで編集できます。URL は http://.../admin です。管理者はユーザーモードを設定し、Web API のコンシューマを追加することもできます。
モジュールを実装します。例:
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
register 関数(この場合は module_setup)にデコレータを追加します。この関数は、現在の設定を引数として、ユニークキーから生成された設定ハッシュとともに呼び出されます。この関数名は任意に変更できます。設定をモジュールオブジェクトに渡します。configHandler は KeyError をキャッチするため、誤った設定がこの関数に送信された場合、configHandler がその旨を通知します。
また、命名規則に従って nameModule.py と @moduleManager.register("name") を使用し、moduleManager をインポートしてください。そうしないと、moduleManager がエラーを通知します。
モジュールコードの残りの部分は省略されていますが、Twisted の factory オブジェクトを作成し、run メソッド内で reactor を使って起動する必要があります。既存のモジュールに例があります。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)
ファクトリオブジェクトでの接続エラー処理:
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)
これにより、エラーはエラーバケットに送信されます。CLI で showlog を実行すると表示できます。
ロギング:
# 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 の処理は、モジュールがサポートするプロトコルに使用する正規表現を適用することで行われます。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) ファイルをモジュールディレクトリにドラッグして配置します。moduleManager が自動的にインポートし、エラーをチェックします。
modules.conf で設定を編集します。
モジュールを Web UI にアップロードします。モジュール名を例えば irc、ファイル名を ircModule.py に設定し、このモジュールの設定例を追加します。
ボットネットの追跡リクエストを送信する場合、グループチャットの調整ルームに対して次のようにリクエストを行います
sensorLoadReq
すべてのセンサーは、自分の id とキューの長さ(監視中のボットネット数)で応答します
sensorLoadAck id=353f6650859547ed06597dbfa1dcfd88 queue=0
フィーダーは、この情報に基づいて 1 つのセンサーを選択します。たとえば、キューの長さが最も短いセンサーを選択します。複数のセンサーのキューの長さが同じ場合は、センサー ID をアルファベット順に並べたときに最も小さい値を持つセンサーが選択されます。
フィーダーがセンサーを選択すると、センサーにプライベートチャットメッセージを送信します
startTrackReq config
config は設定の文字列表現です。例:
module=irc botnet=irc.freenode.net etc..
センサーは、確認応答とともに config ハッシュを返信します。このハッシュは、共有チャンネル内の他のログからそのボットネットのログを区別するために使用できます。確認応答の例:
startTrackAck hash
これは、他にこのボットネットを監視しているセンサーがいない場合です。一方、ボットネットがすでに監視されている場合、またはセンサーがこのボットネット用のモジュールをインストールしていない場合は、startTrackNack を受信します。
マルウェアの共有は、センサーが次のようなメッセージを送信することによって行われます:
fileCaptured hash=353f6650... file content
ここで、コンテンツは Base64 でエンコードされ、ファイルハッシュ値の直後に続きます。
API にアクセスするには、コンシューマキーとシークレットキーが必要です。これらは管理者が作成でき、OAuth による認証に使用されます。JSON 形式でデータを取得するために利用できる URL は次のとおりです:
http://.../api/botnet will reply with all botnets monitored
http://.../api/botnet/botnethash will reply with the botnet with hash equal to botnethash
http://.../api/host/hostname will reply with all botnets monitored with host equal to hostname
http://.../api/type/module will reply with all botnets monitored with the module
http://.../api/botips/hash will reply with all ips captured by botnet with the value hash
http://.../api/bologs/hash will reply with all logs for botnet with value hash
http://.../api/bofiles/hash will reply with file hashes captured by botnet with value hash
http://.../api/file/hash returns botnet(s) info for those that have captured file with the hash specified
http://.../api/ip/addr will reply with botnet(s) info for those that have detected an IP with number addr
現在、GET リクエストのみが可能であることに注意してください。