No redirect_uri in the db for web-internal clientKey leads to one-click DoS on gitter.im
HackerOne report #702987 by gregxsunday
on 2019-09-27, assigned to @cmaxim:
Summary
In the oauthclients collection of the default gitter installation, there's no value registeredRedirectUri in the database for web-internal clientKey. The request to
/login/oauth/authorize?response_type=code&client_id=web-internal&redirect_uri=http://whatever
causes the app to crash when trying to parse the client.registeredRedirectUri, which in this situation becomes the value undefined.
Steps to reproduce
- deploy the standard installation of the gitter application
- make the GET request to
http://localhost:5000/login/oauth/authorize?response_type=code&client_id=web-internal&redirect_uri=http://whatever
Impact
The application crashes and does not wake up on its own.
2019-09-27T13:01:09.013Z - error: Uncaught exceptionTypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined forcing shutdown
[15:01:09] [nodemon] app crashed - waiting for file changes before starting...
What is the current bug behavior?
When the request to
/login/oauth/authorize?response_type=code&client_id=web-internal&redirect_uri=http://whatever
is made, the database lookup is being done:
oauthService.findClientByClientKey(clientKey, function(err, client) {
if (err) {
return done(err);
}
those are the lines 127-130 from server/web/oauth2.js, https://gitlab.com/gitlab-org/gitter/webapp/blob/3e3ed1013a7ca1b8b4047a842a8fe5787ff743ae/server/web/oauth2.js#L127-130
The clientKey
is web-internal
, its record in the Mongo looks like this:
{
"_id": ObjectID("5d8453d62edc221c1e5a2f6c"),
"clientKey": "web-internal",
"clientSecret": <clientSecret>,
"name": "Web Client",
"tag": "web-app"
}
The query returned something, so the following check is being passed:
if (!client) {
return done(new OauthAuthorizationError('Provided clientKey does not exist.'));
}
those are the lines 132-134 from server/web/oauth2.js, https://gitlab.com/gitlab-org/gitter/webapp/blob/3e3ed1013a7ca1b8b4047a842a8fe5787ff743ae/server/web/oauth2.js#L132-134
Then, in the 136th line there's parsing that is the root cause of the problem, https://gitlab.com/gitlab-org/gitter/webapp/blob/3e3ed1013a7ca1b8b4047a842a8fe5787ff743ae/server/web/oauth2.js#L136
const urlData = url.parse(client.registeredRedirectUri);
as the client.registeredRedirectUri
is undefined
, it throws the Uncaught exceptionTypeError
.
2019-09-27T13:01:09.011Z - error: ----------------------------------------------------------------
2019-09-27T13:01:09.011Z - error: -- A VeryBadThing has happened.
2019-09-27T13:01:09.011Z - error: ----------------------------------------------------------------
2019-09-27T13:01:09.012Z - error: Uncaught exceptionTypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined
{ message:
'The "url" argument must be of type string. Received type undefined',
name: 'TypeError [ERR_INVALID_ARG_TYPE]' }
2019-09-27T13:01:09.012Z - error: TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined
What is the expected correct behavior?
The app should not crash on such error. To mitigate the issue you can
- simply catch the error
- add registeredRedirectUri to the database record. It can be done by adding a line to scripts/dataupgrades/001-oauth-client/002-add-redirect-uri.sh which currently looks like this:
db.oauthclients.update(
{ clientKey: 'web-internal' },
{ clientKey: 'web-internal',
clientSecret: '$(generate_password)',
name: 'Web Client',
tag: 'web-app',
}, true /* upsert */);
Relevant logs and/or screenshots
019-09-27T13:01:09.006Z - error: No error reporting is enabled so just logging to logger:
{ exception:
{ message:
'The "url" argument must be of type string. Received type undefined',
stack:
'TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined\n at Url.parse (url.js:154:11)\n at Object.urlParse [as parse] (url.js:148:13)\n at /home/gniedziela/projects/gitlab/gitter/webapp/server/web/oauth2.js:137:27\n at tryCatcher (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/util.js:16:23)\n at Promise.successAdapter [as _fulfillmentHandler0] (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/nodeify.js:23:30)\n at Promise._settlePromise (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/promise.js:566:21)\n at Promise._settlePromise0 (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/promise.js:614:10)\n at Promise._settlePromises (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/promise.js:693:18)\n at Async._drainQueue (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/async.js:133:16)\n at Async._drainQueues (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/async.js:143:10)\n at Immediate.Async.drainQueues (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/async.js:17:14)\n at runCallback (timers.js:705:18)\n at tryOnImmediate (timers.js:676:5)\n at processImmediate (timers.js:658:5)\n at process.topLevelDomainCallback (domain.js:126:23)',
name: 'TypeError [ERR_INVALID_ARG_TYPE]' },
meta:
{ errorString:
'TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined',
type: 'uncaught' },
tags:
{ host: 'c7caee1658e769b17e9c1e0e254cb54939a3e982', job: 'web' } }
2019-09-27T13:01:09.011Z - error: ----------------------------------------------------------------
2019-09-27T13:01:09.011Z - error: -- A VeryBadThing has happened.
2019-09-27T13:01:09.011Z - error: ----------------------------------------------------------------
2019-09-27T13:01:09.012Z - error: Uncaught exceptionTypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined
{ message:
'The "url" argument must be of type string. Received type undefined',
name: 'TypeError [ERR_INVALID_ARG_TYPE]' }
2019-09-27T13:01:09.012Z - error: TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined
at Url.parse (url.js:154:11)
at Object.urlParse [as parse] (url.js:148:13)
at /home/gniedziela/projects/gitlab/gitter/webapp/server/web/oauth2.js:137:27
at tryCatcher (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/util.js:16:23)
at Promise.successAdapter [as _fulfillmentHandler0] (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/nodeify.js:23:30)
at Promise._settlePromise (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/promise.js:566:21)
at Promise._settlePromise0 (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/promise.js:693:18)
at Async._drainQueue (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/async.js:133:16)
at Async._drainQueues (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/async.js:143:10)
at Immediate.Async.drainQueues (/home/gniedziela/projects/gitlab/gitter/webapp/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
at process.topLevelDomainCallback (domain.js:126:23)
2019-09-27T13:01:09.013Z - error: Uncaught exceptionTypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined forcing shutdown
[15:01:09] [nodemon] app crashed - waiting for file changes before starting...
Impact
Complete Denial of Service of the Gitter installation.