🍊

IPアドレスの直接指定とHTTPS, HTTPのあれこれ

に公開

技術的に間違っているところがあった場合優しく教えてください!

何の記事?

本記事では以下のシンプルな疑問を実際に検証してみた結果をまとめています。

  1. HTTPSアクセスをIPアドレスの直接入力で行った場合、サーバー証明書によるドメイン名の検証はどうなるのか
  2. IPアドレスの直接入力によるアクセスができないサイト(HTTP)に心当たりがあるが、これはどうやっているのか

本記事の疑問に至るまでの雑談(スキップ可)

最近、CVEが欲しくてOSSを漁っていたところ、とあるWEBアプリケーションでSSRFを発見しました(報告中)。
SSRFはWEBアプリケーションが異なるサーバーにアクセスする仕組みがある際にそれを悪用したもので、典型的な例で言うと

?url=http://localhost/
?url=http://192.168.xx.xx/

のようなペイロードでURLを指定することでWEBアプリケーションにローカルIPアドレスへのアクセスを強制し、それにより攻撃者が本来到達できない内部サーバーにアクセスしたりネットワークスキャンができてしまう脆弱性です。
なお、CVSSで言うとScopeが"Changed"になる場合が多いので高いスコアになりがちです。
事実、例えばCVE-2021-41773のように単一のHTTPリクエストで攻撃が可能になる脆弱なサーバーが内部に存在した場合、SSRFからのチェーンが成立し、Scopeの外まで多大な影響が生じる可能性があります。

また、近年では以下のようにクラウド環境を狙った情報窃取も注目されているそうです。

?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/test-role

SSRFの影響度は、単にリクエストが飛ぶかどうかだけではなくレスポンスをどの程度見ることができるか、他のスキームを許すかなどにもよります。

閑話休題

さて、今回の主題はSSRFではありません。
SSRFではたいていURLにIPアドレスを直接入力するパターンが多いです。そこで、取り組み中にふと以下のような単純な疑問が生じました。

  1. HTTPSアクセスをIPアドレスの直接入力で行った場合、サーバー証明書によるドメイン名の検証はどうなるのか
  2. IPアドレスの直接入力によるアクセスができないサイト(HTTP)に心当たりがあるが、これはどうやっているのか

本記事ではこれらを簡単に検証してみた結果をまとめました。

1.IPアドレスの直接入力によるHTTPSアクセス時のサーバー証明書との整合

HTTPSといえば、通信の機密性完全性と接続先の真正性を確保が主となる目的です。(たぶん)
接続先の真正性の検証は、接続先のドメインが本当に正当なものなのかを調べてくれます。これにより、DNSキャッシュポイズニングだったり怪しいフリーwifiによって偽サイトに誘導された場合でも、ブラウザはちゃんとエラーや警告を出してくれます。(毎度思いますがブラウザって本当に偉いですね)
以下はブラウザから確認できるzenn.devのサーバー証明書の例です。

zenn.devのサーバー証明書
さて、ブラウザはURLのホスト名とサーバー証明書のSANやCNが一致しているかで行うわけですが(間違ってたらごめんなさい)、URLにはIPアドレスを直接入力することも可能です。そういった場合この検証はどうなるのでしょうか。

試してみました!

試した方が早い!(SSL/TLSあんまわかってないため)
まず自己証明書をつくって、簡易のHTTPSサーバーを立ててみましょう。
ドメイン名はconamikan.test、IPアドレス(ローカル)は192.168.0.53です。

terminal
brew install mkcert nss
mkcert -install
mkcert conamikan.test

chatGPTくんありがとう
/etc/hostsで紐づけてこれにアクセスしてみると、

無事アクセスできました。
それでは今度は本題のIPアドレスによる直接アクセスを試してみましょう。

証明書エラーが起きました。
IPアドレスによるアクセスではURLのホスト名とSAN・CNが一致しないので、検証がうまくいかずエラーが出たということでしょうか。
ひとまず今回の疑問の答えとしては「証明書エラーが出る」でした。
はい終わり!

ではない(余談)

今回は証明書エラーでブラウザから警告が出たわけですが、これは「192.168.0.53 にアクセスする(安全ではありません)」をクリックすると無視して突き進むこともできます。でもふだんネットサーフィンをしてると、なんかこれを無視できない時もありますね。

こんな感じ
これはHSTS(HTTP Strict Transport Security)という機能で、WEBサーバー側がこれをレスポンスヘッダから指定すると、ブラウザは次からHTTPSでのみ接続を許すように制御してくれます。ブラウザって本当に偉いですね。(じゃあ初回時にHTTP接続しちゃった場合はどうなの?みたいな話もあるのですが今回は割愛します。)
ちなみにちなみにですが、HSTSの設定はホスト名ごとに保管されるっぽいので、IPアドレスの直接入力による警告無視強行アクセスをHSTSによりブロックすることはできませんでした。

2.IPアドレスの直接指定によるHTTPアクセスができないサイト

上記の検証から、HTTPSの場合はサーバー証明書のエラーによってIPアドレスの直接指定によるアクセスは難しいことがわかりました。
では、HTTPの場合はどうでしょうか。サーバー証明書がないので、ドメイン名によるアクセスとIPアドレスによるアクセスは区別できないように思えます。
ですが私はこれを区別しているサイトに心当たりがあります。そう、Hacktheboxの一部のマシンです。

試してみました!_コピー

TwoMillionを例に見てみましょう。
マシンのIPアドレスを直接指定してアクセスしようとすると、

となり、2million.htbにリダイレクトさせられます。(厳密にはHTTPアクセス自体は成立していますね。)

ドメイン名だとちゃんとアクセスできる
IPアドレスを入力した際とドメイン名を入力した際で挙動が異なっていることがわかります。ですが、内部的にはどちらも同じサーバーを指しているはずです。そして今回はHTTPSではなく単なるHTTP接続です。
ではこの制御はどのように行なわれているのでしょうか。
真っ先に考えられるのはHTTPリクエストヘッダの何らかの情報を用いることでしょう。すなわちHostヘッダです。
ということで、試しにHostヘッダをドメイン名に指定した状態で、IPアドレスの直接指定でアクセスしてみましょう。

アクセス成功!
IPアドレスの直接指定ですがリダイレクトされることなくWEBサイトにアクセスできました。
ということで、疑問の答えとしては「Hostヘッダを検証している」でした。

実装

最後に実際のWEBサーバーでどんな実装になっているかを覗いてみましょう。(TwoMillionは既に攻略済みなので、自身のwriteupから既知のcredsを使って侵入しました。)

/etc/nginx/nginx.conf(抜粋)
    server {
        listen 80 default_server;
        listen [::]:80 default_server;

        return 301 http://2million.htb$request_uri;
    }
/etc/nginx/sites-enabled/default(抜粋)
server {
    listen 80;
    server_name 2million.htb;

server_nameに合致しないものに対しては301のリダイレクトを返しています。
なおこれは別にIPアドレスによる直接アクセスを防ぐ機能というわけではなく、単に同一IPアドレスで複数のドメインのWEBアプリケーションを運用するための仕組みです。

まとめ

IPアドレスの直接指定によるアクセスに関して、ふと浮かんだ疑問について調べてみました!
いかがでしたか?(クソNEVERまとめ)
技術的にそんな込み入った話ではないのですが、アウトプットの練習がしたいなーという気持ちとLTのネタ保管庫も兼ねて(個人名義では)はじめて記事を書いてみました。
関係ないですが、私の近況として、
・CVE取得に向けて数件報告中(記事書きたい)
・OSWE勉強中(デシリアライズ関連難しい)
・セキスペ合否待ち(だめかも)
・来年度から社会人(ちょっと楽しみ)
といった感じです。特にOSWE、頑張らねば。

Discussion