火曜日, 11月 17, 2015

ELF Linuxランサムウェア:復号機能の解析メモ #reversing

《 ELFマルウェアワークショップの方々へ 》


AVTOKYO-2015ELFマルウェアワークショップ「Swimming in the Sea of ELF」を開催しました。来てくれた皆さんに有難う御座いました。丁度最近Linuxランサムウェアが流行ったので、ワークショップ上でunix shellでリバーシングが必要な理由を説明しました。ワークショップで説明したr2をセットアップした後、下記のリバーシングメモを参考に練習が出来ると思います。

=> >English version is here and here

目次



(1)感染のバックグラウンド
(2)どんなソースコードを使用しているのか
(3)何処から何処まで暗号化されているのか
(4)復号機能のリバーシング
(5)なぜPolarSSLのソースコードが沢山使われたのか
(6)ずっと最初から「PolarSSL」を使われたのか
(7)結論

《 感染のバックグラウンド 》

【目次へ戻る】


感染されたサイトは例えば↓(下のサイトにはwordpressのファイルアップロード脆弱性がある)

検索のキーワードは「README_FOR_DECRYPT.txt」でdorkで検索したら出てくる。

感染されたサイトからの「README_FOR_DECRYPT.txt」のメッセージを確認すると、こんな感じ↓
(※クリックで拡大)


《 どんなソースコードを使用しているのか 》

【目次へ戻る】


実はどんな物なのか「Linux/Encoder.1」ランサムウェアのELF x86-64x86-32のバイナリサンプルを調査した。
リバーシングしたら中身は単純すぎで、本当にがっかりした。もしかしたら素人が作ったんじゃないのかと思うほど。

ソースコードのセットは↓

↑全部C言語で、マルウェア全体に使っているシステムコールのコードはソースコードに入ってる、目的は分かり易い。恐らくランサムウェアのメインコードは「main.c」だと思う。

メモ:秀丸のgrepでソースコードはさくっと検索が出きるよw


《 何処から何処まで暗号化されているのか 》

【目次へ戻る】


調査した結果上で、マルウェアで暗号化されているファイル/DIRじゃ「OK」と「禁止」ルールがある↓
0x002F1FC  /root/.ssh (exclusion)_ / 暗号禁止
0x002F207  /usr/bin (exclusion)_ / 暗号禁止
0x002F210  /etc/ssh (exclusion)_ / 暗号禁止
0x002F219  /home
0x002F21F  /root
0x002F225  /var/lib/mysql
0x002F234  /var/www
0x002F23D  /etc/nginx
0x002F248  /etc/apache2
0x002F255  /var/log

メモ:最初段階の暗号化されているターゲット↓


メモ:その次は下記の暗号化除外↓(別途サンプルx86-32 ELF種類)


下記のファイル拡張子の全ては暗号化されている↓
0x002F25E  .php
0x002F263  .html
0x002F269  .tar
0x002F26E  .gz
0x002F272  .sql
0x002F277  .js
0x002F27B  .css
0x002F280  .pdf
0x002F285  .tgz
0x002F28A  .war
0x002F28F  .jar
0x002F294  .java
0x002F29A  .class
0x002F2A1  .ruby
0x002F2A7  .rar
0x002F2AC  .zip
0x002F2B1  .db
0x002F2B5  .7z
0x002F2B9  .doc
0x002F2BE  .xls
0x002F2C3  .properties
0x002F2CF  .xml
0x002F2D4  .jpg
0x002F2D9  .jpeg
0x002F2DF  .png
0x002F2E4  .gif
0x002F2E9  .mov
0x002F2EE  .avi
0x002F2F3  .wmv
0x002F2F8  .mp3
0x002F2FD  .mp4
0x002F302  .wma
0x002F307  .aac
0x002F30C  .wav
0x002F311  .pem
0x002F316  .pub
0x002F31B  .docx
0x002F321  .apk
0x002F326  .exe
0x002F32B  .dll
0x002F330  .tpl
0x002F335  .psd
0x002F33A  .asp
0x002F33F  .phtml
0x002F346  .aspx
0x002F34C  .csv
0x002F36B  .git
0x002F370  .svn

それとgrep/regexで下記の単語が入っているファイルも↓
0x002F351  public_html
0x002F35D  webapp
0x002F364  backup

《 復号機能のリバーシング 》

【目次へ戻る】


【重要】暗号化されているファイルは「.encrypted」という拡張子名が追加される。
コードを見た限りでは本物のファイルが「unlink」で削除されていただけww(未だ確認出来てないですが恐らくext4だとリストアが出来るかと思われる…)。

decrypter(復号関数)は2つがあり、decrypt_all()decrypt_file()なので、
decrypt_all()の*SNIP*リバースデータはこんな感じ↓
[ xrefs: 0x004014f1 0x00401502 0x00401523 0x004014a5 0x004014b6 0x0040098e 0x00400ad3 ]

【重要】上記のリバーシング情報の大して、いくつかのポイント↓
1. その関数を動かす為に引数(arguement)が必ず必要、引数無しだとこのランサムウェアの動かす意味が無い。
例えばこのコマンドラインみたいに⇒ ./ランサムウェアファイル名 [crypt|decrypt] [キー]
x86-32のサンプルには引数のスイッチ機能が下記のように見えます↓

2. リバースコードを見たらLinuxサーバ全体に"/"DIRからのdecrypt(復号)が可能。
3. decrypt_all()は結局最後にdecrypt_file()を実行する。

decrypt_file()の関数について下記のアドレスで見れる、準備はこんな感じ↓
[ addr: 0x00400617 xref: 0x00400a4f xcall: setChmod() ]

【重要】ヒント:"Decrypting file: %s"のstringを探してください(とても分かりやすい)

この辺は面白い、ランサムウェアなのに、システムコール使うよりもstdio.hが使われているww
開いたファイルのデータはfread_unlockedで(void *data, size_t size, size_t count, FILE *stream)読み込みされる


次のリバーシングコードでマルウェアに暗号化されたファイルのdecrypt(復号)仕方の説明。

【重要】まず、このランサムウェアの復号機能の仕組みは、RSAプライベートキー(犯罪者が持っている)とパブリックキー(被害者が持っている)を使い、バイナリに書いた暗号化されているAESキーを取り戻す。そして、そのAESキーを使ってマルウェアに暗号化されているファイルの取り戻すことも出来る。

そのAESキーはプライベートキーで暗号化されている(バイナリの中で)↓
0x002FF58  -----BEGIN ENCRYPTED PRIVATE KEY-----
0x002FF80  9292758453063D803DD603D5E777D7888ED1D5BF35786190FA2F23EBC0848AEADDA92CA6C3D80B32C4D109BE0F36D6AE7130B9CED7ACDF54CFC7555AC14EEBAB93A89813FBF3C4F8066D2D800F7C38A81AE31942917403FF4946B0A83D3D3E05EE57C6F5F5606FB5D4BC6CD34EE0801A5E94BB77B07507233A0BC7BAC8F90F79
0x0030088  24BF6185468786FDD303083D25E64EFC66CA472BC44D253102F8B4A9D3BFA75091386C0077937FE33FA3252D28855837AE1B484A8A9A45F7EE8C0C634F99E8CDDF79C5CE07EE72C7F123142198164234CABB724CF78B8173B9F880FC86322407AF1FEDFDDE2BEB674CA15F3E81A1521E071513A1E85B5DFA031F21ECAE91A34D
0x0030190  C36D0EB7FCD285223CFB5AABA5BDA3D82C01CAD19EA484A87EA4377637E75500FCB2005C5C7DD6EC4AC023CDA285D796C3D9E75E1EFC42488BB4F1D13AC30A57
0x0030218  C000DF51A7C77AE8D7C7370C1FF55B69E211C2B9E5DB1ED0BF61D0D9899620F4910E4168387E3C30AA1E00C339A795088452DD96A9A5EA5D9DCA68DA636032AF
0x00302A0  C1ACF567564274FB07A0BBAD5D26E2983C94D22288ACD763FD8E5600ED4A702DF84198A5F06C2E72236AE490C93F07F83CC559CD27BC2D1CA488811730BB5725
0x0030328  4959CBF6F8FEF750AEE6977C155579C7D8AAEA56749EA28623272E4F7D0592AF7C1F1313CAC9471B5C523BFE592F517B407A1BD76C164B93DA2D32A383E58357
0x00303B0  9AE7FBC99546432DF71896FC239EADAEF38D18D2B2F0E2DD275AA977E2BF4411F5A3B2A5D33605AEBBCCBA7FEB9F2D2FA74206CEC169D74BF5A8C50D6F48EA08
(などなど…)
メモ:「などなど…」の所にRSAコマンドのアウトプットがそのままで全て書いてある。ようはAESキーを暗号化された時のアウトプットがバイナリにパース(PARSE)されていたと分かった。恐らくそれぞれのLinuxランサムウェアのバイナリを作った時にビルダーを使ったよう。

AESの種類はCBC(下記のリバーシングのコードと確認が出来る↓)
[ xref: 0x0400836 xcall: aes_decrypt() ]


そして、decrypt_file()関数をリバーシングしたらこんな感じで↓(もっと大きい画像はこちら)
[ xref: 0x00400a4f xcall: setChmod() ]

※このパラグラフが英語で説明した方が分かりやすいと思うので【こちらを】ご覧下さい。

《 なぜPolarSSLのソースコードが沢山使われたのか 》

【目次へ戻る】


本ランサムウェアをリバーシングしたら沢山のPolarSSLソースコードの関数を発見した。何故PolarSSLが使われたのか下記に説明する↓

AES復号機能の中にはmbedtls_aes_setkey_decmbedtls_aes_crypt_cbc のコードが使われ、両方はPolarSSL「mbedtls/pk.h」からかぱくってきたソースコードだと分かった。その関数の中でAESキーの長さとAESのCBC暗号種類を使ったのも分かった。AESビットの長さは、asmでコールの仕方を見たら何も設定されてないので標準のままで、128ビットだね。AES暗号・復号機能のために便利なオープンソース(polarSSL)からぱくってきたんだと思われる←PolarSSLを悪用する理由(1)

尚、暗号化されたファイルの復号機能の中で取り戻したファイルのデータもstdio.hでのfwrite_unlockedの書き込まれた。これでランサムウェアに暗号化されたファイル復号機能の説明は終わり。次はRSAで暗号化されているAESキーを復号する方法の説明。

RSA復号機能(AESキーのクラック機能)のasmコードを読むと、順序はこんな感じで↓(参考コードはこちらへ
0x400753でprivate_decrypt()の関数があり、その関数の中で分析を続けて行くとmbedtls_pk_decrypt()関数がある。mbedtls_pk_decrypt()関数の目的はバイナリで暗号化されたAESキーを復号する事。そして、そのAESキーを使うと暗号化されていたファイルをリストアする事が出来る。
mbedtls_pk_decryptコード自体もPolarSSLのソースコードであり、もともとSSLの上で暗号化されていたメッセージを復号する事がこの回数の目的。仕様書に確認するとmbedtls_pk_decryptは「RSA default padding type PKCS#1 v1.5」に対応している、という意味ではmbedtls_pk_decryptはRSA暗号の復号化が出来る←PolarSSLを悪用する理由(2)

上記の説明に当たり、AESキーの復号機能をリバーシングすると下記のように見える↓
[ xref: 0x0400753 xcall: private_decrypt() ]

※このパラグラフが英語で説明した方が分かりやすいと思うので【こちらを】ご覧下さい。


《 ずっと最初から「PolarSSL」を使われたのか 》

【目次へ戻る】


詰まり…PolarSSLの前は何のcryptoライブラリーを使用していたのか?何故最近になって「PolarSSL」が使われるようになったのか?
実は「Linux.Encoder.1」の前のLinuxランサムウェアのバーションがあったので、当時「PolarSSL」は使われず、「OpenSSL」だった。証拠は下記の2件↓

RSAプライベートキーの暗号化の機能のリバーシング↓


AESキーの暗号化機能のリバーシング↓

※最初から使われたAESキーの長さは128ビット。

cryptoライブラリーが変わった原因は恐らくPolarSSLの方がバグのない、かつ新しいコードが入っているからかと思われる。



《 結論 》

【目次へ戻る】


APIみたいな使い方で引数が必要 arg1=暗号|復号 arg2=RSA、感染されたサーバに残したスクリプトを確認が出来たら使い方が直ぐに分かると思われる。暗号機能がほぼPolarSSLからのコード。読み込みと書き込みはstdio.hの関数で作られた。システム周りのコマンドも結構そのままで実行される(unlink,chmod,など)…ブロックも行けそう。journaldに対応しているシステムではリストアが可能かと。いくつかの攻撃元アドレスと確認したので作者は東ヨーロッパの人っぽいね。

メモ以上


reversing by @unixfreaxjp - founder & team leader of MalwareMustDie

0 件のコメント:

コメントを投稿