hacktricks/src/pentesting-web/hacking-with-cookies

Cookies Hacking

{{#include ../../banners/hacktricks-training.md}}

Cookiesには、ユーザーのブラウザでの動作を制御するいくつかの属性があります。これらの属性について、より受動的な声で説明します。

Expires and Max-Age

Cookieの有効期限はExpires属性によって決まります。対照的に、Max-age属性はCookieが削除されるまでの時間秒単位を定義します。Max-ageを選択することをお勧めします。これはより現代的な慣行を反映しています。

Domain

Cookieを受け取るホストはDomain属性によって指定されます。デフォルトでは、これはCookieを発行したホストに設定され、サブドメインは含まれません。しかし、Domain属性が明示的に設定されると、サブドメインも含まれます。これにより、サブドメイン間でのCookie共有が必要なシナリオで、Domain属性の指定が制限の少ないオプションとなります。たとえば、Domain=mozilla.orgを設定すると、developer.mozilla.orgのようなサブドメインでもCookieにアクセスできます。

Path

Cookieヘッダーが送信されるために要求されたURLに存在しなければならない特定のURLパスは、Path属性によって示されます。この属性は/文字をディレクトリセパレーターとして考慮し、サブディレクトリ内での一致も可能にします。

Ordering Rules

同じ名前のCookieが2つある場合、送信されるCookieは以下に基づいて選択されます

  • 要求されたURL内で最も長いパスに一致するCookie。
  • パスが同じ場合は、最も最近設定されたCookie。

SameSite

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

Cookieを設定する際には、これらの属性を理解することで、さまざまなシナリオで期待通りに動作することを確保できます。

Request Type Example Code Cookies 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_属性を持つCookieは、CSRF攻撃を軽減します。

*Chrome802019年2月以降、CookieにSameSite属性がない場合のデフォルトの動作はLaxになります (https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/).
この変更を適用した後、一時的にChromeではSameSiteポリシーのないCookie最初の2分間はNoneとして扱われ、その後はトップレベルのクロスサイトPOSTリクエストに対してLaxとして扱われます。

Cookies Flags

HttpOnly

これにより、クライアントがCookieにアクセスするのを防ぎます例えば、Javascript経由で:document.cookie)。

Bypasses

  • ページがリクエストのレスポンスとしてCookieを送信している場合(例えば、PHPinfoページで、XSSを悪用してこのページにリクエストを送り、レスポンスからCookieを盗むことが可能です(例はこちらを参照)。
  • TRACE HTTPリクエストを使用することでバイパス可能です。サーバーからのレスポンスは送信されたCookieを反映します。この技術はCross-Site Trackingと呼ばれます。
  • この技術は、モダンブラウザがJSからTRACEリクエストを送信することを許可しないことによって回避されます。ただし、IE6.0 SP2に対してTRACEの代わりに\r\nTRACEを送信するなど、特定のソフトウェアでのバイパスが見つかっています。
  • もう一つの方法は、ブラウザのゼロデイ脆弱性を悪用することです。
  • Cookie Jarオーバーフロー攻撃を実行することで、HttpOnly Cookieを上書きすることが可能です:

{{#ref}} cookie-jar-overflow.md {{#endref}}

  • これらのCookieを外部に持ち出すためにCookie Smuggling攻撃を使用することが可能です。

Secure

リクエストは、HTTPSなどの安全なチャネルを介して送信される場合にのみ、HTTPリクエストでCookieを送信します

Cookies Prefixes

__Secure-で始まるCookieは、HTTPSで保護されたページからsecureフラグとともに設定される必要があります。

__Host-で始まるCookieには、いくつかの条件が満たされなければなりません

  • secureフラグで設定されなければなりません。
  • HTTPSで保護されたページから発信されなければなりません。
  • ドメインを指定することは禁じられており、サブドメインへの送信を防ぎます。
  • これらのCookieのパスは/に設定されなければなりません。

__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でログインすることに依存しています。

サブドメインにXSSを見つけた場合サブドメインを制御している場合は、次をお読みください:

{{#ref}} cookie-tossing.md {{#endref}}

Session Donation

ここでは、攻撃者が被害者に攻撃者のセッションCookieを使用させるように仕向けます。被害者は自分のアカウントにログインしていると信じて、攻撃者のアカウントのコンテキストで意図せずにアクションを実行します。

サブドメインにXSSを見つけた場合サブドメインを制御している場合は、次をお読みください:

{{#ref}} cookie-tossing.md {{#endref}}

JWT Cookies

前のリンクをクリックして、JWTの可能な欠陥を説明するページにアクセスしてください。

Cookieで使用されるJSON Web TokensJWTも脆弱性を示す可能性があります。潜在的な欠陥とそれを悪用する方法についての詳細情報を得るには、JWTのハッキングに関するリンクされた文書にアクセスすることをお勧めします。

Cross-Site Request Forgery (CSRF)

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

Empty Cookies

(詳細は元の研究を参照してくださいブラウザは名前のないCookieの作成を許可しており、次のようにJavaScriptを通じて示すことができます

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

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

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

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

これにより、ブラウザはすべてのウェブサーバーによって a という名前のクッキーと b という値を持つクッキーとして解釈されるクッキー ヘッダーを送信します。

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

Chromeでは、Unicodeサロゲートコードポイントがセットクッキーの一部である場合、document.cookie が破損し、その後空の文字列を返します:

document.cookie = "\ud800=meep"

この結果、document.cookieは空の文字列を出力し、永続的な破損を示します。

パースの問題によるクッキーのスモグリング

(詳細は元の研究を参照) JavaJetty、TomCat、UndertowやPythonZope、cherrypy、web.py、aiohttp、bottle、webobを含むいくつかのウェブサーバーは、古いRFC2965サポートのためにクッキー文字列を誤って処理します。彼らは、セミコロンを含んでいても、ダブルクオートされたクッキー値を単一の値として読み取ります。セミコロンは通常、キーと値のペアを区切るべきです。

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

(Check further details in theoriginal research) サーバーによるクッキーの不適切な解析、特にUndertow、Zope、およびPythonのhttp.cookie.SimpleCookiehttp.cookie.BaseCookieを使用しているものは、クッキーインジェクション攻撃の機会を生み出します。これらのサーバーは新しいクッキーの開始を適切に区切ることができず、攻撃者がクッキーを偽装することを可能にします:

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

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

Cookies $version and WAF bypasses

According to this blogpost, $Version=1クッキー属性を使用して、バックエンドがRFC2109のために古いロジックを使用してクッキーを解析することが可能かもしれません。さらに、**$Domain$Path**のような他の値も、クッキーを使用してバックエンドの動作を変更するために使用できます。

Bypassing value analysis with quoted-string encoding

この解析は、クッキー内のエスケープされた値をアンエスケープすることを示しており、したがって"\a"は"a"になります。これはWAFを回避するのに役立つ可能性があります

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

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

最後に、異なるバックドアは、異なるクッキーヘッダーで渡された異なるクッキーを文字列に結合します。

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

これにより、この例のようにWAFをバイパスできる可能性があります:

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

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

追加の脆弱なクッキーチェック

基本チェック

  • クッキーは、ログインするたびに同じです。
  • ログアウトして、同じクッキーを使用してみてください。
  • 2つのデバイスまたはブラウザで同じアカウントに同じクッキーを使ってログインしてみてください。
  • クッキーに情報が含まれているか確認し、変更を試みてください。
  • ほぼ同じユーザー名でいくつかのアカウントを作成し、類似点が見えるか確認してください。
  • "ログイン状態を保持する"オプションが存在する場合、その動作を確認してください。存在し、脆弱である可能性がある場合は、他のクッキーを使用せずにログイン状態を保持するのクッキーを常に使用してください。
  • パスワードを変更しても前のクッキーが機能するか確認してください。

高度なクッキー攻撃

ログイン時にクッキーが同じ(またはほぼ同じ)である場合、これはおそらくクッキーがアカウントのいくつかのフィールド(おそらくユーザー名)に関連していることを意味します。次に、あなたは:

  • 非常に似たユーザー名でたくさんのアカウントを作成し、アルゴリズムがどのように機能しているかを推測してみてください。
  • ユーザー名をブルートフォースしてみてください。クッキーがあなたのユーザー名の認証方法としてのみ保存されている場合、ユーザー名"Bmin"でアカウントを作成し、クッキーのすべてのビットブルートフォースすることができます。なぜなら、あなたが試すクッキーの1つは"admin"に属するものだからです。
  • パディング オラクルを試してください(クッキーの内容を復号化できます)。padbusterを使用してください。

パディングオラクル - Padbusterの例

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は複数回試行し、どの条件がエラー条件無効なものであるかを尋ねます。

その後、クッキーの復号を開始します(数分かかる場合があります)。

攻撃が成功した場合、任意の文字列を暗号化してみることができます。たとえば、encrypt user=administratorを暗号化したい場合。

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

この実行により、文字列 user=administrator が内部に含まれたクッキーが正しく暗号化され、エンコードされます。

CBC-MAC

クッキーには何らかの値があり、CBCを使用して署名される可能性があります。その場合、値の整合性は、同じ値を使用してCBCで作成された署名です。IVとしてヌルベクターを使用することが推奨されるため、このタイプの整合性チェックは脆弱である可能性があります。

攻撃

  1. ユーザー名 administ の署名を取得 = t
  2. ユーザー名 rator\x00\x00\x00 XOR t の署名を取得 = t'
  3. クッキーに値 administrator+t' を設定 (t'(rator\x00\x00\x00 XOR t) XOR t = rator\x00\x00\x00 の有効な署名になります)

ECB

クッキーがECBを使用して暗号化されている場合、脆弱である可能性があります。
ログインすると、受け取るクッキーは常に同じでなければなりません。

検出と攻撃方法:

ほぼ同じデータユーザー名、パスワード、メールなどを持つ2つのユーザーを作成し、与えられたクッキー内のパターンを発見しようとします。

例えば "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" というユーザーを作成し、クッキーにパターンがあるかどうかを確認しますECBは同じキーで各ブロックを暗号化するため、ユーザー名が暗号化されると同じ暗号化されたバイトが現れる可能性があります

使用されるブロックのサイズでパターンが存在するはずです。したがって、"a" の一群がどのように暗号化されるかを知っていれば、ユーザー名を "a"*(ブロックのサイズ)+"admin" と作成できます。その後、クッキーから "a" のブロックの暗号化パターンを削除することができます。そして、ユーザー名 "admin" のクッキーを得ることができます。

参考文献

{{#include ../../banners/hacktricks-training.md}}