NTTセキュリティ・ジャパン SOCアナリストマネージャー 羽田です。
2018 年 8 月に開催されたセキュリティ・キャンプ全国大会 2018 の脆弱性・マルウェア解析トラックで「マルウェアの暗号処理を解析しよう」という講義を行いました。今年の 8 月に開催されるセキュリティ・キャンプ全国大会 2019 でも、同名の講義をアナリストメンバーの幾世と担当させていただくことになりました。ここでは、昨年度の講義で取り組んだ内容を少し紹介したいと思います。
この講義では、マルウェア解析の中でも特に暗号処理にフォーカスして演習を行いました。インシデントレスポンスにおいて暗号化された通信が復号できると有用な手がかりとなるため、暗号アルゴリズムや鍵を特定する目的でマルウェア解析が行われることがあります。多くの研究者や技術者によってマルウェアに実装された暗号アルゴリズムを特定する手法が提案・実装されています。マルウェアのコードはパッキングや難読化によって解析が困難となることが多いのですが、暗号処理は意外と素のまま残っている場合もあります。一度解析を経験しておくと、コードを眺めながら何となく暗号アルゴリズムが見て分かることがあります。講義では、この「見れば分かる」という感覚を身に着けてもらった上で、それをツールとして実装してもらうという演習を行いました。
ソースとアセンブリから暗号処理を理解する
演習ではストリーム暗号の RC4 と、ブロック暗号の Blowfish を題材にしましたが、本記事では RC4 について講義中に取り上げた話題を紹介したいと思います。まずは RC4 のアルゴリズムを解説した上で、ソースとアセンブリを読んでもらいました。RC4 は鍵のセットアップと暗号化(または復号)という 2 段階の手続きを踏みます。ベーシックな実装では、鍵のセットアップでは 2 回の for 文が含まれています。
最も分かりやすい特徴として、1 回目の for 文では 256(=100h)個の配列を 0 から 255 まで初期化している部分が挙げられます。この処理をコンパイルしてアセンブリを調べると、以下のような命令が含まれることが確認できます。ecx が指すアドレスに対するインデックスに対して、インデックスと同じ値を次々と代入しています。
- mov [ecx+eax], al
- inc eax
- cmp eax, 100h
2 回目のループでは、同じくコンパイルしてアセンブリを確認すると、初期化した状態や鍵にアクセスするため、movzx 命令といった 1 バイトの値へのアクセスが含まれていました。また特徴的なものとして、鍵長を用いた modulo 演算でインデックスを調整する処理が cdq 命令、idiv 命令で実装されている様子がうかがえました。逆に、暗号アルゴリズムといえば xor 命令が続くという印象が強いかと思いますが、ゼロクリアなどの処理を除くと、RC4 では暗号化の中の 1 箇所にしか出現しません。また、鍵にアクセスする場所は鍵のセットアップの中で 1 箇所しかありません。これは鍵を発見する上での重要な手がかりとなります。
暗号処理が実装された関数を発見する
サンプルプログラムのアセンブリを眺めてこの辺りを理解しておくと、ある関数が RC4 かどうか見て判断できるようになります。そこで、演習 1 では実装された RC4 の関数を発見してもらいました。ここでは、演習用に作成したプログラムだけでなく、幾つかの実際のマルウェアにも挑戦してもらいました。手作業で探すのでそれなりに手間はかかりますが、一度見つけてしまえばすぐに「あ、あった!」という感覚になったのではないでしょうか。実際のマルウェアについてもアセンブリの形は多少崩れていますが、それでもこんなものかという感覚だったと思います。実際、多くの受講生が課題をクリアしていました。ちなみに、この演習の中にはほとんど RC4 に見えるが厳密には RC4 でないアルゴリズムが実装されているマルウェアがあり、課題をクリアした受講生にそれが何かを当てるクイズを出しました。このマルウェアでは鍵のセットアップにおける処理が少し改変されています。このような場合において通信を復号しようと思った場合は、関数のアタリをつけた後にさらに詳しく厳密な処理を解析する必要があります。
同様に演習 2 では Blowfish のサンプルプログラムを使って関数を探してもらいました。
暗号処理を特定する手法を考える
演習 1、2 でこのような感覚を身に着けてもらった上で、演習 3 ではこの講義の本題である暗号アルゴリズムを特定するための手法を考えて実装してもらいました。これは研究分野においてもひとつのテーマとなっています。ところで、演習 1、2で取り組んでもらって分かると思いますが、静的なコードの解析はパッキングや難読化に対して弱いという欠点があります。一方で、動的な解析では実行時の様子を観測して、より応用的な解析を行うことができます。演習ではマルウェアを動作させてそのログを命令単位で記録した実行トレースを用意し、これを処理して暗号アルゴリズムの場所を推定して、逆アセンブリで確かめてもらうという方法を取りました。
演習は短い時間なので大がかりなプログラムは実装できませんが、受講生の解答では、命令の順番や組み合わせ、命令の頻度、ループした回数、ループの数、マジックナンバーなどを手がかりにして検出するという、概ね想定どおりの手法を実装していました。
ちなみに、演習 2 で用いたプログラムを作成した後に実際のマルウェアを題材に演習 3 の評価用マルウェアを用意したのですが、暗号処理がアセンブリレベルで非常によく似たものになっていました。これは偶然でしたので少し驚きましたが、ソースコードの流用の可能性がある事例として紹介することができ、ちょうど良い題材となっていました。
暗号鍵を特定して暗号通信を復号する
演習 3 までが想定していた演習の範囲となりますが、全て完了した人のためにチャレンジ問題として演習 4 を用意しました。これは演習 3 で用いたマルウェアの暗号鍵を特定してメッセージを復号するという演習です。実行トレースには鍵に関する情報が含まれていますので、上手く解析すれば発見できるはずです。
RC4 では、鍵に関するアクセスは 1 箇所しかなかったことを思い出します。この命令を抽出することで実際にアクセスした鍵の値を知ることができます。
抽出した実行トレースからはかなり長い鍵が見えますが、これはこのマルウェアが外部に送信するたびに暗号処理を行っていることに起因しますので、一連の処理が何度も繰り返されているだけです。1 回分の処理を切り出すと、実際に使われた鍵が入手できます。Blowfish についても同様の解析を行いました。
演習は以上です。ここまでの演習で多くのマルウェアの暗号処理を解析できるようになったはずですが、これらの特徴はより手の込んだマルウェアによっていくらでも隠ぺいしようと思えばできてしまいます。万能な方法はありませんが、これに対抗するために研究者が色々な手法を考えています。最後にそれらの手法を紹介しましたが、これらはマルウェアが用いるアルゴリズムが既存のものと完全に一致していることが前提となっています。まだまだマルウェア解析の世界においては課題がある状況と言えます。
4 時間という短い時間でしたが、マルウェア解析における暗号処理の解析というテーマについて、暗号処理の特定から復号まで一通りの解析作業を演習しました。今年度も別の暗号アルゴリズムやマルウェアを題材に解析を行いたいと思います。