Network Error Loggingを用いたポートスキャン手法について

先日、紹介した「Network Error Logging」を使用することでユーザのプライベートネットワークをポートスキャン可能であることを開発者様に報告した。

その手法と、仕様上の問題点について説明する。

仕組みは単純なので、もっと早く気づけても良かったかもしれない...orz

Network Error Logging

前回紹介したとおり、ブラウザで発生するネットワークエラーをレポートとして受け取れるようになる仕様である。
asnokaze.hatenablog.com

レスポンスを返す際に、nelヘッダを指定すると、そのページを閲覧している際に発生する、TCPコネクションタイムアウトTLS証明書エラー・名前解決エラー・リダイレクトループなどが、レポートとして指定したエンドポイントに提出される。

nel: {"report-to": "network-errors", "max-age": 360, "include-subdomains": true,}

例えば、画像が404で読み込めなかったりすると、こんな感じのJSONが指定したエンドポイントにPOSTされる

	{
		"age": 240003,
		"report": {
			"elapsed-time": 33,
			"protocol": "http/1.1",
			"referrer": "https://asnokaze.com/nel.html",
			"sampling-fraction": 1,
			"server-ip": "160.16.124.39",
			"status-code": 404,
			"type": "http.error",
			"uri": "https://asnokaze.com/img/b.gif"
		},
		"type": "network-error",
		"url": "https://asnokaze.com/img/b.gif"
	},

ポートスキャン手法

Network Error Loggingでは、include-subdomainsを指定することでサブドメインのリソースに対するネットワークエラーもレポート対象に含めることができる。

例えば、example.comサブドメインとしてプライベートIPのサブドメインを用意する。具体的には127.0.0.1と名前解決されるような127-0-0-1.example.comという感じである。

example.comへのアクセスで、include-subdomainsを指定してnelヘッダを返してやる

NEL: {"report-to": "nel", "include-subdomains": true,
      "success-fraction": 1.0, "failure-fraction": 1.0}

あとは、HTML内に、こんな感じで用意したサブドメインへリクエストが飛ぶようにしてやる。

<img src="https://127-0-0-1.example.com:2000" />
<img src="https://127-0-0-1.example.com:2001" />
<img src="https://127-0-0-1.example.com:2002" />
<img src="https://127-0-0-1.example.com:2003" />

Network Error Loggingでは、以下のようなTCPエラーが定義されているため、既存の手法(onerrorイベント)よりも多くの情報を得ることが可能である

  • tcp.timed_out TCP接続タイムアウト
  • tcp.closed TCP接続がクローズされた
  • tcp.reset TCP接続がリセットされた
  • tcp.refused TCP接続が拒否された
  • tcp.aborted TCP接続が中断された
  • tcp.address_invalid TCP接続のアドレスが正しくない
  • tcp.address_unreachable TCP接続のアドレスへ到達できない

直接的になにかの脅威があるわけではないが、何かしらの攻撃の足がかりになる可能性も考えられる

仕様上の問題点

すでに上記問題は、仕様の問題として議論がされている
https://github.com/WICG/network-error-logging/issues/74

主には2点

  • サブドメインのリソースをレポート対象に含めるべきか。CORSのようなそのサブドメインで動作するサーバの許可を得るか、サブドメインの指定をそもそもできなくする
  • TCPのエラー情報などを実際に取得可能にしてよいのか。例えば、Fetch APIでは詳細エラーを取れるようにしてほしいという意見が出るが、今の所そのようにはなっていない。

Same-Origin Policyを超えて設定が指定されること、サブドメインにプライベートIPが指定されうることは、結構良くないパターンがありそうですね。パットは思いつかなかったが、他の仕様でもなんかあるかもしれない。(cookieとか)

あらためて、新しい機能を作るって難しいなと実感しました。