Learning Man's Blog

对 Cookie 的一点学习

字数统计: 1.2k阅读时长: 5 min
2019/12/25 Share

通过Abusing feature to steal your tokens这篇文章发现对 cookie 了解还是不够透彻,学习之

对于 cookie 的相关内容还可以在网上找些相关资料,就上面的PDF放几张图简单了解一下

-w865

-w774

在攻击角度着重于:Domain、Path、HttpOnly

  • SameSite、Secure是在 RFC6265bis 中的内容
创建域 cookie example.com sub.example.com sub.of.sub.example.com
example.com Set-Cookie: foo=bar; domain=.example.com - 可见 可见
sub.example.com Set-Cookie: foo=bar; domain=.example.com 可见 - 可见
sub.example.com Set-Cookie: foo=bar; 不可见 - 不可见

作者提到了一个很有趣的问题,在实际测试时候,也可以看到domain=example.com会被解析成domain=.example.com

-w594

而这个问题感觉是在实现此规范时的误读

-w616

简单总结:

  1. 设置 cookie 时如果没有指明特定的 domain 属性,则此 cookie 只属于当前域;如果设置 domain 属性,则还属于其下所有子域。
  2. 当在某子域攻击 cookie 时,可能影响到相关其他(子)域

此漏洞产生的原因有几个:

  1. 大多服务器限制了request headers长度,即请求头长度
  2. 如果接收的头部超出长度限制,会返回 413 或者 431 错误
  3. 限制性cookie注射(直翻理解下),可能导致客户端DoS
  4. DomainExpire属性会帮助将攻击传播至(子)域

这里有一个可以在线测试浏览器 cookie 是否有某些限制的页面

案例

源自客户端:referrer、parameter、hash
源自服务端:js-code-injection

function d(a) {
...
        var b = document.referrer || "none",
            d = "ev_redir_" + encodeURIComponent(a) + "=" + b + "; path=/";
        document.cookie = d;
...
}
...
window.location.hash != "" && d(window.location.hash.substr(1).toLowerCase())

可以看到,代码将锚点部分作为新cookie部分键内容,只要构造附有超长hash页面跳转至此漏洞页面,即可造成客户端Dos

var getURLParameter = function(name) {
    return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/+/g, '%20')) || null;
}

var brandedKeyword = function(ref) {
    var match1 = new RegExp("((google|yahoo|bing)(.)&?q=([^&])shopify)", "gi").test(ref);
    return (match1);
}

var ref = getURLParameter('ref');
var ssid = getURLParameter('ssid');

if (ref && !brandedKeyword(document.referrer)) {
    var days = 30;
    var expire = new Date(today + days * 1000 * 60 * 60 * 24);
    setCookieWithExpiration('source', ref, expire);
    if (ssid) {
        setCookieWithExpiration('ssid', ssid, expire);
    }
}

var setCookieWithExpiration = function(key, value, expire) {
    var match = document.location.hostname.match(/shopify..*/)
    var domain
    if (match) {
        domain = '.' + match[0]
    } else {
        domain = '.shopify.com'
    }
    document.cookie = key + "=" + escape(value) + ";path=/" + ";expires=" + expire.toUTCString() + ';domain=' + domain;
};

这段代码通过获取参数refssid创建相应的cookie,也是利用超长造成客户端 dos

Bomb + OAuth

思考:就 OAuth 开始的 CSRF Login,code 2 token,到后来的 Redirect get code,就目前来说,还是存在重定向获取一次性登录 code 比较多,但是在修复经过强校验跳转地址后,是不是就没有攻击点了?

回到重定向获取 code 原理,主要是利用终端 oauth 认证流程的同时获取 code,这样既能保持 code有效性,又能获取到 code 进行利用

那么现在考虑一下:利用 cookie bomb 阻断跳转,同时利用 xss 获取 code

翻译Cookie 传递不知道准不准确

  1. Cookie 有元组(名称、域、路径)组成
  2. 每个 cookie 键值都有其自己的属性列表
  3. (子)域可以强制传输同名 cookie 到其他(子)域
  4. 浏览器会发送所有同名的cookie而不夹带属性
  5. 服务器无法分辨任意 cookie 来自哪个域/路径

假如现在我们在子域名上有一个受 http-only 属性限制的 cookie 值,如何将其利用并影响到其他(子)域名呢?

当我们想试图来修改某个cookie,但受其 http-only 限制无法使用 javascript API 进行修改,那么利用上面提到的第 4 个特性,写一个新的非 http-only 的同名 cookie,例如如下

Name Value Domain
user_sess original -
user_sess attacker’s .exapmle.com

这时候,我们希望在 HTTP 传输中会实现以下的结构

POST /i/create HTTP/1.1
...
Cookie: user_sess=attacker's; user_sess=original

...

但是实际上,可能会是这样

POST /i/create HTTP/1.1
...
Cookie: user_sess=original; user_sess=attacker's

...

原因在于标准文档规范

-w594

利用这个规定,我们可以创建一个新 cookie 如下

Name Value Domain Path
user_sess original - /
user_sess attacker’s .exapmle.com /i/

这样就会生成我们上面想要的请求内容了,恶意 cookie 排序在前

标准文档中,规定每个域名最多传输 50 个 cookie 内容,

-w596

规定,如果超过限制则会优先删除”老旧的”cookie

-w624

但是注意一点,在实际利用中,如果利用超额删除,由于不同的浏览器实现的标准,即允许的 cookie 上限是不一致的;且在攻击用户时,不容易知道其已有 cookie 的数量

参考资料

  1. The cookie monster in your browsers
  2. XSS by tossing cookies
CATALOG
  1. 1. Cookie 跨域
  2. 2. Cookie Bomb
    1. 2.1. 案例
      1. 2.1.1. Twitter - DOM based cookie bomb
      2. 2.1.2. [livechat.shopify.com] Cookie bomb at customer chats
    2. 2.2. Bomb + OAuth
    3. 2.3. Cookie Tossing
      1. 2.3.1. 案例 1 cookie 排序问题
      2. 2.3.2. 案例 2 同名 cookie 数量问题
  3. 3. 参考资料