Learning Man's Blog

对 Cookie 的一点学习

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

对于 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. Cookie 跨域
  2. Cookie Bomb
    1. 案例
      1. Twitter - DOM based cookie bomb
      2. [livechat.shopify.com] Cookie bomb at customer chats
    2. Bomb + OAuth
    3. Cookie Tossing
      1. 案例 1 cookie 排序问题
      2. 案例 2 同名 cookie 数量问题
  3. 参考资料