Closed cjackett closed 2 months ago
Lot going on here, so going to try to take it one by one.
The admin-login.ts endpoint
Permalink to file for reference: https://github.com/siv-org/siv/blob/9011544bfd1752f1d056e7700af8b08658fe23e1/pages/api/admin-login.ts (snapshot from when this issue was opened)
lacks proper input validation and sanitization for the email field, resulting in potential security vulnerabilities.
Relevant lines: https://github.com/siv-org/siv/blob/9011544bfd1752f1d056e7700af8b08658fe23e1/pages/api/admin-login.ts#L8-L16
Agree the email validation there could be improved.
Special characters in the email input are not adequately handled
Sure.
leading to internal server errors
That's not so bad. Just crashes the temporary endpoint, created only for you. When deployed, all endpoints are independent serverless functions from each other, so you can't harm other users this way.
and exposure of detailed error messages.
Might be unsightly or intimidating, but not a security issue.
Ok, that covers the intro. Now moving onto the next sections...
Just tried running Reproduction Example 1:
curl -X POST http://localhost:3000/api/admin-login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com<script>alert(\"XSS\")</script>"}'
I'm seeing the html for an error page like:
<!DOCTYPE html>
<html>
<head>
<style data-next-hide-fouc="true">
body{display:none}
</style><noscript data-next-hide-fouc="true"><style>body{display:block}</style></noscript>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="next-head-count" content="2" /><noscript data-n-css=""></noscript>
<script defer="" nomodule="" src="/_next/static/chunks/polyfills.js?ts=1723019276418"></script>
<script src="/_next/static/chunks/webpack.js?ts=1723019276418" defer=""></script>
<script src="/_next/static/chunks/main.js?ts=1723019276418" defer=""></script>
<script src="/_next/static/chunks/pages/_app.js?ts=1723019276418" defer=""></script>
<script src="/_next/static/chunks/pages/_error.js?ts=1723019276418" defer=""></script>
<script src="/_next/static/development/_buildManifest.js?ts=1723019276418" defer=""></script>
<script src="/_next/static/development/_ssgManifest.js?ts=1723019276418" defer=""></script><noscript id="__next_css__DO_NOT_USE__"></noscript></head>
<body>
<div id="__next"></div>
<script src="/_next/static/chunks/react-refresh.js?ts=1723019276418"></script>
<script id="__NEXT_DATA__" type="application/json">
{"props":{"pageProps":{"statusCode":500}},"page":"/_error","query":{"__NEXT_PAGE":"/api/admin-login"},"buildId":"development","isFallback":false,"err":{"name":"Error","source":"server","message":"Value for argument \"documentPath\" must point to a document, but was \"admin@example.com\u003cscript\u003ealert(\"xss\")\u003c/script\u003e\". Your path does not contain an even number of components.","stack":"Error: Value for argument \"documentPath\" must point to a document, but was \"admin@example.com\u003cscript\u003ealert(\"xss\")\u003c/script\u003e\". Your path does not contain an even number of components.\n at CollectionReference.doc (/Users/dsernst/Documents/siv/node_modules/@google-cloud/firestore/build/src/reference.js:2065:19)\n at __WEBPACK_DEFAULT_EXPORT__ (webpack-internal:///(api)/./pages/api/admin-login.ts:21:103)\n at Object.apiResolver (/Users/dsernst/Documents/siv/node_modules/next/dist/server/api-utils/node.js:366:15)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async DevServer.runApi (/Users/dsernst/Documents/siv/node_modules/next/dist/server/next-server.js:481:9)\n at async Object.fn (/Users/dsernst/Documents/siv/node_modules/next/dist/server/next-server.js:741:37)\n at async Router.execute (/Users/dsernst/Documents/siv/node_modules/next/dist/server/router.js:252:36)\n at async DevServer.run (/Users/dsernst/Documents/siv/node_modules/next/dist/server/base-server.js:365:29)\n at async DevServer.run (/Users/dsernst/Documents/siv/node_modules/next/dist/server/dev/next-dev-server.js:709:20)\n at async DevServer.handleRequest (/Users/dsernst/Documents/siv/node_modules/next/dist/server/base-server.js:303:20)"},"gip":true,"scriptLoader":[]}
</script>
</body>
</html>
Some things I notice about this:
alert('XSS')
is not running."Value for argument \"documentPath\" must point to a document, but was \"admin@example.com\u003cscript\u003ealert(\"xss\")\u003c/script\u003e\"
So this first Reproduction Example seems invalid. (For now, at least...)
Please correct me if I appear mistaken about any of this.
2 "HTML Injection Attempt":
curl -X POST http://localhost:3000/api/admin-login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com<b>bold</b>"}'
and 5 "XML Injection Attempt"::
curl -X POST http://localhost:3000/api/admin-login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com<foo>bar</foo>"}'
are also nearly identical to 1.
1 would seem the most dangerous of the 3, since its trying to run js, but all 3 are a very similar vector of trying to smuggle in arbitrary <tags>
.
So if 1 isn't an issue (per comment above), it seems safe to assume 2 and 5 wouldn't be either.
Yes, all the examples produced a similar response from the backend. While they are not true security issues, they highlight areas where improved validation and sanitization on the front end would be beneficial. The timing of my attention to this codebase was coincidental with the hacking comp. Additionally, I have gathered some UI/UX observations that might interest you, which are also unrelated to the DEF CON HACK.
curl -X POST http://localhost:3000/api/admin-login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com../../../../etc/passwd"}'
When I run this, I'm again getting a firebase error:
Value for argument \"documentPath\" must point to a document, but was \"admin@example.com../../../../etc/passwd\". Your path does not contain an even number of components.
I think of all of these, this one is the one I was the most concerned might work, because Firebase does have a shorthand for specifying document paths. But now researching the issue, everything I'm seeing is saying Firebase does not support ..
as a special character in documents, and just treats it as a plain string.
4 Command Injection-like Input:
curl -X POST http://localhost:3000/api/admin-login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com; ls -la;"}'
Runs at least without erroring, but just gives me an innocuous:
'admin@example.com; ls -la;' is not approved election manager
The ls
unix command is not running. Firebase is just treating the whole thing as a plain string.
Seems also like not an issue?
Ok, I'm going to skip running the rest of these. No reason to think they would be any worse than the ones I did try to reproduce.
The main valid thing here is that we can and should totally just run a proper email validator function over the input. Would be shorter than our double .includes('@')
.includes(.)
checks. Doesn't appear there's actually a live security issue here, given Firebase is doing its own sanitization + hardening, and the other mitigations mentioned in my 1st comment reply. But would be good to handle the validation better anyway, in case we want to switch out Firebase later, for example.
(IIRC, that double includes()
check was from very early on, before we started using an email validator elsewhere. It was just meant to be quick to warn people who accidentally try to enter a username, or forget to include .com
, etc)
Cleaned up the email validation here: https://github.com/siv-org/siv/commit/12253ce847e394ff1d6bf92f188242085ee32361
Yes, all the examples produced a similar response from the backend. While they are not true security issues, they highlight areas where improved validation and sanitization on the front end would be beneficial. The timing of my attention to this codebase was coincidental with the hacking comp. Additionally, I have gathered some UI/UX observations that might interest you, which are also unrelated to the DEF CON HACK.
Well it was still useful to think through all these malicious payload possibilities. And review how the system handles against them. And the provided curl
examples, ready to copy-and-paste right in, were especially nice to make testing quick and easy. 👍👍
Ok, closing this issue for now. Still valid for HACK SIV prizes though!
Thanks again for participating!
DEF CON 2024, August 6-11 hack.siv.org
Type: Implementation
In Favor:
Against:
Total: $281.79
Track process on https://github.com/siv-org/hack.siv.org/issues/10
Description
The
admin-login.ts
endpoint lacks proper input validation and sanitization for the email field, resulting in potential security vulnerabilities. Special characters in the email input are not adequately handled, leading to internal server errors and exposure of detailed error messages.Steps to Reproduce
XSS Injection Attempt:
HTML Injection Attempt:
Path Traversal-like Input:
Command Injection-like Input:
XML Injection Attempt:
Embedded URL:
Malformed Email Address:
SQL-like Payload with Union:
Observed Response and Error Logs
Impact
Recommendations
Implement Robust Email Validation: Use a library such as
validator
to ensure proper email format validation.Sanitize Input: Sanitize the email input to remove or escape potentially harmful characters.
Improve Error Handling: Avoid exposing detailed error messages to users. Log detailed errors internally and provide generic error messages to users.
Consistent Input Handling: Apply consistent input validation and sanitization across all inputs and contexts within the application.