http80

Web security research

XSS attack via Certificate / Payloadを埋め込んだ証明書でのXSS攻撃手法

f:id:reinforchu:20190911233601p:plain
 Webブラウザの脆弱性を探していたところ、変わった切り口のXSS攻撃手法を思いつきました。本稿は、SSL/TLS サーバ証明書にXSSのペイロードを仕込んだ場合の挙動はどうなるのか、Webブラウザの警告ページで脆弱性は内在しているのかといった部分に触れます。

 

概要


 本稿での証明書とは、https通信においてのSSL/TLSサーバ証明書を指します。本来サーバ証明書は非常にざっくり表現すると、対向のWebサーバの妥当性の検証をするためにも用いられますが、今回はあえて自己署名証明書やCommonNameの不一致などの不正な証明書を意図的に生成し、その証明書に悪意のあるコードを仕込んだ場合、Webブラウザはどのような挙動を示すのかを実験しました。

 

XSS証明書の作成方法


 今回はWindows 10 Proで自己署名証明書を作成するコマンドを応用して、XSSを引き起こすコードを仕込んだサーバ証明書を作成し、IISのWeb Siteにバインドして確認します。証明書の作成自体はOpenSSLでも可能ですが、IIS 6.0 Resources KitのselfsslコマンドがWindows 10でエラー出るようになってしまっていたので、代替方法を探した結果、そのナレッジ共有も兼ねてWindows 10 Proでの作成方法を題材にします。Windows  10 Homeの場合は、おそらくIIS Expressでもやり方があると思われますが、これは未検証です。

 

0. 環境準備

 IISの準備とPowerShellを使えるところがスタートですので、詳細手順は割愛しますが、「Windows 機能の有効化または無効化」からIISとPowerShellを有効にします。

 

1. 証明書を発行

 管理者権限でPowerShellを起動し、プロンプトに下記のコマンドを流して実行します。

 New-SelfSignedCertificate -Subject "CN=<script>alert(1)</script>,OU=<script>alert(1)</script>,DC=<script>alert(1)</script>" -DnsName "</p>:\""><script>alert(1)</script>\0" -CertStoreLocation "cert:\LocalMachine\My" -KeyAlgorithm RSA -KeyLength 2048

f:id:reinforchu:20190911171413p:plain

 上記のコマンドを実行すると証明書が発行され、自動的に証明書がストアされます。

 

2. サーバ証明書をバインド

 MMC(IISの管理)から「Default Web Site>バインド>https」を選択または、ない場合はhttps/443を追加します。次に、「編集>SSL証明書」のプルダウンメニューの中から「"<script>alert(1)</script>"」を選択しOKボタンを押下します。

f:id:reinforchu:20190911171441p:plain

 

3. Webブラウザで確認

 「https://127.0.0.1/」などでアクセスし、上手くブラウザの警告ページが表示されれば成功です。Firefox Nightlyで確認すると面白いです。

f:id:reinforchu:20190911195329p:plain

 

 各ブラウザの挙動


●Firefox Nightly 71.0a1

f:id:reinforchu:20190911170730p:plain

 面白い切り口だと思ったのですが、view-source:で見ると、HTMLエンティティに置換されるため、XSSは刺さらず。 

 

●Safari Technology Preview Release 91

f:id:reinforchu:20190911195358p:plain

 証明書ビュアーの画面は特に何も起きず、これでは面白くないので、違うアプローチでやってみました。

f:id:reinforchu:20190911195500p:plain

 ひたすら長い文字列を挿入した変な証明書を作ってみると、Safariの証明書ビュアーの画面が外に出てしまい、カーソルでOKボタンが押せなくなります。ただし、既定の選択がOKボタンなので、Enterキーで閉じることができるため、完全な操作不能に陥ることはありませんでした。

 

 実際にこれは刺さる?


 調べてみると実際の事例として、証明書を検証するサービスにて、証明書のOU=内にJavaScriptコードを挿入した結果、XSSの脆弱性がありました。

www.silverf0x00.com

 この他、いくつかのXSSの脆弱性の事例が見つかりました。 

 

対策方法


 いわゆる一般的なXSS攻撃の対策方法と同様に、HTMLとして出力する際、特別な意味を持つ記号「"><';)(」などは、HTMLエンティティに置換するなど、入力値をそのまま出力しないように改修することを推奨します。

 

安全でない証明書の存在


 例示したコマンドでは、CommonNameなどに<script>alert(1)</script>を挿入しており、明らかな悪意のある証明書を作成することは可能でした。私の考えですが、X.509の構造的にSubjectなどに、ある程度の任意の文字列を埋め込むことは可能であるため、SSL/TLSサーバ証明書に限らず、広義の証明書においても無関係な話ではありません。端的に言うと、証明書であるから必ず安全である(安全な文字列しか入力されない)ということは落とし穴になるかもしれません。