MAMP Server preauth XSS leading to Host Compromise (0day)

According to their wiki, MAMP is a solution stack composed of free and open-source and proprietary commercial software used together to develop and run dynamic websites on Apple Macintosh computers. It is what I know as the most popular php debugging and development stack used on Macbooks. It is not reachable from the internet unless its “Cloud” settings are on, which should never happen. You should basically think of MAMP as the XAMPP/WAMP server for OS X devices. It is a local development software stack usually composed of Apache/Ngnix/MySQL/FTP applications.

The assumption most people have when running their local web servers on their personal computers and other devices is that they are not reachable from the internet since its running on a “localhost” domain. This assumption can lead to the entire host getting compromised because it is not entirely true. There are ways for an attacker to reach your localhost thanks to how browsers work (this will soon change in Chrome).

Vulnerability:
On a default install of MAMP server the file /Applications/MAMP/htdocs/index.php hosts the following file:

$switch_language = (string) '';
  foreach ($available_languages as $available_language) {
    if ($available_language['token'] !== $language) {
        $switch_language .= '<a href="'.strip_tags($_SERVER['PHP_SELF']).'?language='.$available_language['token'].'" lang="'.$available_language['token'].'" hreflang="'.$available_language['token'].'">'.$available_language['name'].'</a> | ';
    print $switch_language;
}
  }

As you can see a user controlled input ($_SERVER[‘PHP_SELF’]) is used in an <a href> tag with insufficent sanitization(strip_tags). While strip_tags will get rid of tags like <> , it is still possible to add quotes and escape the “href” attribute to add or manipulate the <a href> tag. For example, we can use the onmouseover attribute combined with some font CSS tricks to fill the page with our XSS payload, so the payload executes when the page loads.

PoC:

http://localhost:8888/index.php/lol%22onmouseover=%22alert(document.domain+’ says ‘+’ hi ‘);%22%20style=%22font-size:100000px;background-color:white%22;

Will pop an alert when our victim visits the above link:

Sending our victim to the above localhost url will therefore trigger the payload as long as they have MAMP running. The payload basically tricks anyone who has access to the device (they don’t have to be authenticated) to trigger our XSS in the scope of “localhost”, and therefore with just a single click we can access their “localhost” despite localhost not being accessible from the internet to the attacker.

This means a lot of wonderful things for a creative hacker, since MAMP is full of features that are accessible only from “localhost”, with little work it should mean complete server compromise. MAMP ships with lots of features an attacker can use like: full database manipulation through phpMyAdmin (which doesn’t require authentication from localhost but requires antiCSRF tokens which our XSS exploit can easily harvest for us), theft of victim’s system and configuration info from phpinfo.php file found on “localhost”, ability to change select_priv, insert_priv, drop_priv, shutdown_priv, file_priv and other sensitive tables that could grant the attacker further read, write, and modify access via Adminer (which also ships with MAMP), and execution of code and commands via the endless server-side vulnerabilities found within PhpPGAdmin portal (also accessible from localhost) – plenty of unserialize() and open() calls are with unsanitized user input in the older PhpPGAdmin that ships with latest MAMP. The possibilities are as creative as an attacker wants to get with them.

Making practical page

MAMP is hosted on port 8888 by default but even if it isn’t, doing a simple port scan from the attacker website should let us quickly find it. Sending a victim to a localhost URL might not be the least noisy thing, but we can exploit this vulnerability without the victim knowing anything about their localhost being accessed by a remote website. This can be done by using something like:

1. Embed the localhost domain with its text payload occupying all of the page into an invisible iframe
2. Send victim to attackers innocent seeming page
3. Our XSS payload executes and we can exploit other vulnerabilities we won’t disclose in this post.
4. w00t!

<iframe style="position:absolute;height:100%;width:100%;opacity:20%;z-index:1" src="http://localhost:8888/index.php/lol%22onmouseover=%22alert(document.domain+' says '+' hi ');further_exploit();%22%20style=%22font-size:100000px;background-color:white%22;"></iframe>

<center><h1 style="z-index: 99;font-color:black;color:black; position:abolsute; left: 200px; top: 0px; font-size:92px"><br>
Welcome to our evil site</h1><br><img src="https://thumbs.dreamstime.com/b/severe-predatory-evil-cat-eyes-77679888.jpg"></center>

So why is this a 0day?

We reported the vulnerability to MAMP on Sept, 2021 but they have told us that “localhost” isn’t reachable from the internet and therefore its not worth fixing the vulnerability. We were not able to convince them it can be reached despite our repeated attempts and therefore went ahead with publishing the details of the vulnerability.

We are not proponents of publishing unpatched zero-day vulnerability details and therefore we have omitted further details that could grant attackers the ability to read files, execute code and sql queries, as those affect different applications shipping with MAMP. We hope this post convinces the developers of MAMP to reconsider their decision.

If you are someone who uses MAMP regularly on your personal computer, we can’t emphasize enough how dangerous it is to run MAMP with an internet connected device and we suggest you remove the /index.php file located in the htdocs folder or, if not possible, modify line 30 of the index.php with htmlentities(strip_tags($_SERVER[‘PHP_SELF’])) and you should should be safe.