Bolek Trojanの投稿

dennis

投稿者:Dennis Schwarz
投稿アーカイブ:Bolek、マルウェア

数週間前、CERT Polskaは短文のブログ投稿で、Bolekとして知られる新たなマルウェアファミリを紹介しました。PhishMeとDr.Webはその後、このファミリについての新たな知見を付け加えました。このマルウェアのメモリダンプをざっと見ると、WebInjectセクションがひときわ目立ちます。WebInjectは通常、バンキング関係のマルウェアであることを暗示しているため、Bolekはその前身であるCarberpがやめたことを引き継いでいるように思えます。ここでは、このマルウェアのコマンド&コントロール(C2)の仕組みを詳しく見て、そのC2サーバーから構成ファイルを引き出す上で必要なことを考察します。

検体

リバース・エンジニアリングに使用した検体がこちらです。上記の分析で述べているように、Bolekには直ちに特定可能なBotConfig JSONオブジェクトがあり、そこにはC2サーバーとそのServerPub(以下で説明するC2サーバーの公開キー)が含まれています。

{

  "BotConfig": {

    "BotCommunity": "group_102",

    "FailPeriod": 600,

    "Hosts": [

      "mensabuxus[.]net",

      "ogrthuvwfdcfri5euwg[.]com",

      "ogrthuvfewfdcfri5euwg[.]com"

    ],

    "ServerPub": "44DCF35866EB4992264E809EDD001737C65E28BB4DAB8DC7DA5CFA7F1AA05619",

    "TaskPeriod": 600

  }

}

この調査の時点では、C2サーバーはダウンしており(そのうちの1つはすでにシンクホールでした)、このため2つ目の検体も使用しました。そのBotConfigを以下に示します。

	{

  "BotConfig": {

    "BotCommunity": "EXE1",

    "FailPeriod": 600,

    "Hosts": [

      "91[.]215[.]154[.]155"

    ],

    "ServerPub": "17C94201E5BA1FB36A0EEE839B5F350DAA9FD6CAA1E8C6D500F113A9A825003F",

    "TaskPeriod": 600

  }

}

コマンド&コントロールのプロトコル

C2の通信はHTTP POSTリクエストによるものです。リクエストの例は以下のとおりです。

first_request

そのレスポンスを以下に示します。

first_response

POSTおよびレスポンスのデータのいずれにもいくつかの暗号要素が含まれており、それを整理すると以下のような構造になります。

post_data_fmt-768x163

フィールドは以下のとおりです。

C2サーバーに送られた最初のリクエストには、感染したコンピュータのシステム情報が含まれています。その情報は、以下のBotStatus JSONオブジェクトにまとめられます(ここでのキー/値のペアのほとんどは自己記述型ですが、さらなる調査を利用するものもあります)。

{

"BotStatus": {

   "Antivirus": [],

   "BotCommunity": "group_102",

   "ComputerName": "JOHN-PC",

   "Domain": "",

   "FamilyID": "{39C4F8B7-9D7F-C831-D4A5-C9B8C9B01E3C}",

   "Firewall": [],

   "HostName": "John-PC",

   "IdleTime": "0",

   "InfectedByID": "{00000000-0000-0000-0000-000000000000}",

   "IntegrityLevel": "System",

   "Is64Bit": false,

   "KernelMode": false,

   "LocalUsers": [

     {

       "Groups": [

         {

           "Name": "HomeUsers"

         }

       ],

       "IsAdmin": false,

       "Username": "HomeGroupUser$"

     },

     {

       "Groups": [

         {

           "Name": "HelpLibraryUpdaters"

         },

         {

           "Name": "HomeUsers"

         },

         {

           "Name": "Administrators"

         }

       ],

       "IsAdmin": true,

       "Username": "John"

     }

   ],

   "Locale": "0409",

   "NetworkShares": [

     {

       "Comment": "",

       "Name": "JOHN-PC",

       "PlatformID": "500",

       "Shares": [

         {

           "Netname": "ADMIN$",

           "Remark": "Remote Admin",

           "Type": "2147483648"

         },

         {

           "Netname": "C$",

           "Remark": "Default share",

           "Type": "2147483648"

         },

         {

           "Netname": "IPC$",

           "Remark": "Remote IPC",

           "Type": "2147483651"

         },

         {

           "Netname": "Users",

           "Remark": "",

           "Type": "0"

         }

       ],

       "Type": "331779",

       "VersionMajor": "6",

       "VersionMinor": "1"

     }

   ],

   "OSInfectedCount": "1",

   "OSMajorVersion": "6",

   "OSMinorVersion": "1",

   "OSProductType": "1",

   "OSServicePack": "1",

   "Programs": [

     {

       "DisplayName": "Mozilla Firefox 21.0 (x86 en-US)",

       "DisplayVersion": "21.0",

       "InstallLocation": "C:\\Program Files\\Mozilla Firefox"

     },

     {

       "DisplayName": "WinSCP 5.5.1",

       "DisplayVersion": "5.5.1",

       "InstallLocation": "C:\\Program Files\\WinSCP\\"

     },

     {

        "DisplayName": "Java 7 Update 51",

       "DisplayVersion": "7.0.510",

       "InstallLocation": "C:\\Program Files\\Java\\jre7\\"

     }

   ],

   "StillLoader": false,

   "SystemTime": "130790246365655056",

   "Uloader32Hash": "0A0D933C0201612BE170234C872BE4872CDED4D1",

   "Uloader32Version": "16777472",

   "Uloader64Hash": "1DB2031C11403BD138D57C3AB5505E42C5DD3A10",

   "Uloader64Version": "16777472",

   "Uptime": "1966259856",

   "Version": "16777472"

},

"Filesystem": {

   "Files": [

     {

       "Hash": "7BCCAEC0A19E3B5AECC50498B62F87F0CAC40AEC",

       "LastWrite": "130790244399495344",

       "Path": "\\USER.ID",

       "Size": "16"

     }

   ],

   "Space": "33422848",

   "UsedSpace": "2560"

}

}

次に、システム情報JSONはZlib圧縮され、512バイトのヘッダーが先頭に付加されます。最初のリクエストについてのヘッダーは以下のとおりです。

data_hdr-768x284

フィールドは以下のとおりです。

BotConfigからのServerPubと2つの(mypublic)公開キーが暗示するように、Bolekは公開キー暗号を使用します。Bolekは、他のいくつかのバンキング関連マルウェアの傾向にならわず、またその暗号にはRSAを使用せず、代わりに楕円曲線暗号を使用します。具体的には、感染したホストとマルウェアのC2サーバーの間におけるキー交換の仕組みにはCurve25519を使用します。

このマルウェアによって2つのCurve25519キー・ペアが作成され、公開キーがC2サーバーに送られます。1つ(mypublic)はpost_data_format構造体において、もう1つ(mypublic2)はdata_header構造体においてです。このmyprivateの秘密キーとC2サーバーのServerPub公開キーを使用して、32バイトの共有秘密キー(mysecret)が生成されます。mysecretの最初の16バイトは、512バイトのヘッダーを暗号化するためのAES-128キーとして使用されます。16バイトのランダム値がIV用に生成されるようにCBCモードが使用されます。このIVはpost_data_format構造体で送られます。圧縮データは同じキーでAES暗号化されますが、別のIVを使用します。このIVは暗号化ヘッダーの最後の16バイトに由来します。

暗号化データの完全性を保証するためにHMAC-SHA1が使用されますが、そのキーはmysecretの最後の16バイトです。ハッシュ・ダイジェストもpost_data_format構造体で送られます。

疑似Pythonスニペットを使用したこの暗号化の全プロセスは以下のとおりです。

compressed_data = zlib.compress(data)

mysecret = curve25519._curve25519.make_shared(keypair["myprivate"], ServerPub)

iv = self.gen_rand_bytes(16)
aes = AES.new(mysecret[:16], AES.MODE_CBC, iv)
encrypted_header = aes.encrypt(header)

new_iv = encrypted_header[-16:]
aes = AES.new(mysecret[:16], AES.MODE_CBC, new_iv)
encrypted_data = aes.encrypt(compressed_data)

hmac_sha1 = HMAC.new(mysecret[16:], digestmod=SHA)
hmac_sha1.update(encrypted_header+encrypted_data)

C2サーバーからのレスポンスは類似の構造をしており、上記のように暗号化されていますが、2番目に生成された(mypublic2)Curve25519キー・ペアがキー交換に使用されています。復号化のプロセスは、ここでも疑似Pythonスニペットを使用して、以下のようになります。

hispublic = response[:32]
mysecret2 = curve25519._curve25519.make_shared(keypair["myprivate2"], hispublic)

iv = response[32:32+16]
aes = AES.new(mysecret2[:16], AES.MODE_CBC, iv)
header = aes.decrypt(response[68:68+512])
data_len = struct.unpack("I", header[12:12+4])[0]

new_iv = response[564:564+16]
aes = AES.new(mysecret2[:16], AES.MODE_CBC, new_iv)
compressed_data = aes.decrypt(response[580:580+data_len])
data = zlib.decompress(compressed_data)

すべての処理の後、最初のレスポンスのプレーン・テキスト・データは1つのNULLバイトです。

しかし、2番目の交換はもう少し中身があります。そのリクエスト・データは1つのNULLバイトで、そのヘッダーには以下に示すいくつかの変更があります。

data_hdr2-768x248

このレスポンスのプレーン・テキスト・データには、タスクのリストが入ったTasks JSONオブジェクトが含まれています。ほとんどのタスクには以下のキーが含まれています。

データはbase64でエンコードされ、コマンドにより、バイナリー・データまたは別のJSONオブジェクトを含んでいます。当調査の時点でこのC2サーバーが送っていたタスクが以下です。

コマンド:UpdateFile

ハッシュ:145c9b79efd10718118ce5c58cf0af2618c9e39c

時間:131097825775904000

パス:\JUPITER.32

データ:278028バイトのバイナリー・データで、offset 524で始まるPEファイルが含まれます。

コマンド:UpdateFile

ハッシュ:d85668e9ba963bb476f7b919d22bbf24bf993835

時間:131097825775904000

パス:\JUPITER.64

データ:323084バイトのバイナリー・データで、offset 524で始まるPEファイルが含まれます。

コマンド:UpdateFile

ハッシュ:33ba0092f1ceb4426142b23fddfc5c28f75a322d

時間:131081361515904000

パス:\JUPITER.JSON

データ:以下のJSONオブジェクト

{
"Filefilters": [
   {
     "Mask": "*wallet*",
     "MaxSize": 5000000
   },
   {
     "Mask": "*.key*",
     "MaxSize": 1000000
   },
   {
     "Mask": "*key*.dat*",
     "MaxSize": 1000000
   }
],
"Screencapfilters": [
   {
     "Count": 1,
     "Mask": "*bitcoin*"
   },
   {
     "Count": 1,
     "Mask": "*BSS*"
   },
   {
     "Count": 1,
     "Mask": "*Банк*"
   },
   {
     "Count": 1,
    "Mask": *ЗАО*
   },
   {
     "Count": 1,
     "Mask": *Клиент*
   },
   {
     "Count": 1,
     "Mask": "*eToken*"
   },
   {
     "Count": 1,
     "Mask": "*Remote Desktop*"
   },
   {
     "Count": 1,
     "Mask": *Бухгалтерия*
   },
   {
     "Count": 1,
     "Mask": "*iBank2*"
   },
   {
     "Count": 1,
     "Mask": "*ts.letok2.ru*"
   },
   {
     "Count": 1,
     "Mask": *Кассир*
   },
   {
     "Count": 1,
     "Mask": "*KASSA*"
   },
   {
     "Count": 1,
     "Mask": *Internet-Банкинг*
   },
   {
     "Count": 1,
     "Mask": *Банкинг*
   },
   {
     "Count": 1,
     "Mask": "*jp2launcher.exe*"
   }
],
"Webfilters": [
   "!*.facebook.com/*",
   "!*.skype.com/*",
   "!*plus.google.com/*",
   "!*plus.youtube.com/*",
   "!*.yandex.ru/*"
],
"Webinjects": [
   {
     "FLAG_CAPTURE_NOTPARSE": false,
     "FLAG_CONTEXT_CASE_INSENSITIVE": false,
     "FLAG_IS_CAPTURE": true,
     "FLAG_IS_INJECT": false,
     "FLAG_REQUEST_GET": true,
     "FLAG_REQUEST_POST": false,
     "FLAG_URL_CASE_INSENSITIVE": false,
     "Injects": [
       []
     ],
     "URL": "https://blockchainbdgpzk.onion/wallet/*format=json*"
   },
   {
     "FLAG_CAPTURE_NOTPARSE": false,
     "FLAG_CONTEXT_CASE_INSENSITIVE": false,
     "FLAG_IS_CAPTURE": true,
     "FLAG_IS_INJECT": false,
     "FLAG_REQUEST_GET": true,
     "FLAG_REQUEST_POST": false,
     "FLAG_URL_CASE_INSENSITIVE": false,
     "Injects": [
       []
     ],
     "URL": "https://blockchain.info/wallet/*format=json*"
   },
   {
     "FLAG_CAPTURE_NOTPARSE": false,
     "FLAG_CONTEXT_CASE_INSENSITIVE": false,
     "FLAG_IS_CAPTURE": false,
     "FLAG_IS_INJECT": true,
     "FLAG_REQUEST_GET": true,
     "FLAG_REQUEST_POST": true,
     "FLAG_URL_CASE_INSENSITIVE": false,
     "Injects": [
       {
         # hex decodes to 
         "Before": "3c626f642a3e",
         # hex decodes to 	<script type="text/javascript">\nalert("www.hh.com")\n	</script>
         "Inject": "3c73637269707420747970653d22746578742f6a617661736372697074223e0a616c65727428227777772e68682e636f6d22290a3c2f7363726970743e"
       }
     ],
     "URL": "http://hh.com*"
   }
]
}

コマンド:UpdateInjects

ハッシュ:af681805ebaa86e886d25c1a210b2900843c9040

時間:131085075165904000

データ:以下のJSONオブジェクト

{
"InjectConfig": [
   {
     "DllName": "JUPITER.32",
     "Modules": [
       "*"
     ]
   },
   {
     "DllName": "JUPITER.64",
     "Modules": [
       "*"
     ]
   }
]
}

上記JUPITER.*ファイルには、WebInject、画面キャプチャ、ファイル・フィルタ、Webフィルタ用のDLLとルールが含まれています。このルールのフォーマットはZeusのフォーマットに類似しています。

コマンド:UpdateWormConfig

ハッシュ:82de50660a03c6871a66872d92e3cc7e8f1cce79

時間:131085075165904000

データ:以下のJSONオブジェクト

{
"WormConfig": {
   "NetworkEnabled": true,
   "USBEnabled": true
}
}

コマンド:UpdateBackconnectConfig

ハッシュ:58213d91d17a7569916a3d82831e670f191cc255

時間:131085075165904000

データ:以下のJSONオブジェクト

{
"BackconnectConfig": {
   "RetryPeriod": 300,
   "Servers": [
     {
       "Host": "91[.]215[.]154[.]155",
       "Port": 443
     }
   ]
}
}

コマンド:UpdateFile

ハッシュ:8babe4cec02e1107335b75f2e11ec402c00c70a9

時間:131097825775904000

パス:\SKELETON.KEY

データ:以下に示す16バイトのバイナリー・データ

00000000 1f f7 01 a6 c8 7a c2 d0 0f 72 73 74 a0 ee 03 d7 |…..z…rst….|

00000010

コマンド:UpdateCore

ハッシュ:0b04cb54f29a2b2eceb24258e6923573040e7307

データ:470012バイトのバイナリー・データ。

結論

このブログでは、Bolekとして知られる新しいマルウェアファミリのC2メカニズムを詳しく取り上げました。今回解析した特定のBolekボットネットは、現在のところロシアの銀行とビットコイン関連サイトにフォーカスしているものの、Bolek自体は強力なバンキング・マルウェアとなる高度な機能を備えているため、あらゆる種類の金融機関を標的にできる威力があります。本稿作成時点で入手可能な少量のC2や検体だけでは、この脅威の現在および将来の活動や広がりの程度について判断するのは時期尚早といえます。