7.8 High
CVSS3
Attack Vector
LOCAL
Attack Complexity
LOW
Privileges Required
LOW
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
6.9 Medium
CVSS2
Access Vector
LOCAL
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:L/AC:M/Au:N/C:C/I:C/A:C
Today, Rapid7 is disclosing 9 vulnerabilities that affect 3 open-source projects: EspoCRM, Pimcore, and Akaunting. Right out of the gate, Iβd like to give a special thanks to these 3 open-source project maintainers. While itβs never great to learn of new vulnerabilities in your own product, all 3 project maintainers accepted, validated, and provided fixes for these vulnerabilities within one day, which is amazing when it comes to vulnerability disclosure. EspoCRM was notified on May 4, 2021 and patched source on May 5; Akaunting, on May 13 and turned it around on May 14; and Pimcore validated their vulnerabilities on April 29 after learning about them on April 28, 2021. Nice work, all around.
Now, Iβm not sure why open source is just so much faster than the typical proprietary software vuln-patching pipeline, at least for the disclosures Iβve been involved in. It might be because, in open source, youβre almost guaranteed to have your first communication with a hands-on-keyboard software engineer who is personally and emotionally invested in the software; whereas in proprietary land, first contact might be a lightly monitored support alias, staffed by a third-party provider. Rapid7βs vulnerability disclosure process assumes a minimum of 60 days for remediation of any vulnerability we report to a vendor, and Iβd say about half the time, weβre looking at more like 90 to 120 days from report to disclosure β and, sometimes, we are left with the unhappy option of publishing without a fix in hand at all.
Of course, proprietary software occasionally offers fast turnaround times on validation and fixes to source, as well (SonicWall comes to mind), and proprietary vendors often have very good reason to take their time with acknowledging, fixing, testing, and releasing fixes; but the fact remains that whatβs normal in open source communities β hyperfast turnaround on fixing reported vulnerabilities β is a rarity in proprietary software.
By the way, these arenβt one- or two-person passion projects. All 3 of these projects have real users, real customers of their attendant support services and cloud-hosted versions, and are undoubtedly the core applications supporting thousands of small to medium businesses running today. This popularity is the reason why Trevor and Wiktor took a look at them in the first place; they suspected these small-to-medium business applications havenβt seen a ton of attention from the eye of a penetration tester, and this blog post is a result of testing that hypothesis.
With that, Iβll stop picking on proprietary software vendors in general and switch gears to take a look at the specific vulnerabilities in these specific projects.
From this completely unscientific and statistically insignificant sampling of vulnerabilities, we can draw the deeply unsurprising conclusion that enterprise web applications tend to suffer from common web-application vulnerabilities. 3 are examples of persistent cross-site scripting (XSS), where a malicious user can plant a bit of browser-executable code in the application, which is designed to lie in wait and trigger when someone else comes along and loads that code, and 2 are SQL injection (SQLi) vulnerabilities, where the attacker uses the web application as a convoluted portal to issue direct commands to the backing database, usually to steal data or create powerful web-app users.
SQL injection used to be a nice way to get a command injection path to the underlying operating system, but thatβs something of a rarity these days. But, 1 issue disclosed here is a command injection issue, which we rate as the highest critical vulnerability of the bunch, since it can allow the attacker to commandeer the operating system and do things like use it as a beachhead into the rest of the network, install a cryptominer or ransomware, or perform other nefarious lower-level actions.
The remaining vulnerabilities are: a denial-of-service vulnerability, where the attacker can crash the whole application with a naughty HTTP request; an authentication bypass, where the attacker can move from one logical group to another without authorization; and a weak password-reset vulnerability, where the attacker can abuse the βI forgot my passwordβ function to source a phishing email from the application to a registered user.
The table below provides the salient information about the 9 vulnerabilities being disclosed today. Note that every vulnerability listed here was promptly fixed by the vendor in the typical open-source manner. In short: if you use any of these applications in your business and keep up on your updates, you already have the fixes. The rest of this post details the individual findings by Wiktor SΔdkowski of Nokia and Trevor Christiansen of Rapid7, who worked together on this project and disclosed these issues through Rapid7βs vulnerability disclosure process.
Weβre publishing these details today so other, similar web applications can be made aware of these vulnerability classes and take a look at their own codebases to make sure theyβre not making the same mistakes. Thanks, Wiktor and Trevor!
CVE | Affected Project | CWE | Base CVSS | Status |
---|---|---|---|---|
CVE-2021-3539 | EspoCRM v6.1.6 | CWE-79 (Persistent XSS) | 6.3 (Medium) | Fixed in version 6.1.7 |
CVE-2021-31867 | Pimcore Customer Data Framework v3.0.0 | CWE-89 (SQL Injection) | 6.5 (Medium) | Fixed in v3.0.2 |
CVE-2021-31869 | Pimcore AdminBundle v6.8.0 | CWE-89 (SQL Injection) | 6.5 (Medium) | Fixed in v6.9.4 |
CVE-2021-36800 | Akaunting v2.1.12 | CWE-94 (Code injection) | 8.7 (High) | Fixed in Akaunting v2.1.13 |
CVE-2021-36801 | Akaunting v2.1.12 | CWE-639 (Auth bypass) | 8.5 (High) | Fixed in Akaunting v2.1.13 |
CVE-2021-36802 | Akaunting v2.1.12 | CWE-248 (Uncaught Exception DoS) | 6.5 (Medium) | Fixed in Akaunting v2.1.13 |
CVE-2021-36803 | Akaunting v2.1.12 | CWE-79 (Persistent XSS) | 6.3 (Medium) | Fixed in Akaunting v2.1.13 |
CVE-2021-36804 | Akaunting v2.1.12 | CWE-640 (Weak Password Reset) | 5.4 (Medium) | Fixed in Akaunting v2.1.13 |
CVE-2021-36805 | Akaunting v2.1.12 | CWE-79 (Persistent XSS) | 5.2 (Medium) | Fixed in Akaunting v2.1.13 |
EspoCRM is an open-source customer relationship management (CRM) application used in all sorts of industries, although it seems to enjoy special success in the real estate sector. More about EspoCRM can be found at the vendorβs website.
Any user with default rights, which allows them to upload their own avatar, can abuse the API for this by providing executable Javascript code instead of an image. An example call to the API is detailed below:
PUT /api/v1/User/609108e6b123bb29d HTTP/1.1
Host: 10.0.0.10:8443
{redacted}
Content-Length: 43
Origin: https://10.0.0.10:8443
Connection: close
Referer: https://10.0.0.10:8443/
Cookie: {redacted}
{
"avatarId":"\" onerror=\"alert(0)\" "
}
This leads to rendering the avatar as:
resulting in triggering the onerror
event:
Because EspoCRM allows administrators to install arbitrary, custom extensions, an attacker can leverage this XSS to silently coerce an administrator (who views the attackerβs avatar) to install a malicious extension, thus retaining permanent control of the web application, as seen in the screenshot below.
Pimcore CDF is a component of the Pimcore platform and is a CRM enterprise application. More about Pimcore CDF can be found at the vendorβs website.
An SQL injection vulnerability exists in the Customer Management Framework Bundle, specifically in the SegmentAssignmentController.php component. The vulnerable code was introduced in commit 6fc8aff8f95fc168d173ef3b473760dd98d026c4 and is shown below.
php
public function inheritableSegments(Request $request)
{
$id = $request->get('id') ?? '';
$type = $request->get('type') ?? '';
/* @var $db Connection */
$db = $this->get(Connection::class);
$parentIdStatement = sprintf('SELECT `%s` FROM `%s` WHERE `%s` = "%s"', $type === 'object' ? 'o_parentId' : 'parentId', $type.'s', $type === 'object' ? 'o_id' : 'id', $id);
$parentId = $db->fetchOne($parentIdStatement);
$segments = $this->get(SegmentManagerInterface::class)->getSegmentsForElementId($parentId, $type);
$data = array_map([$this, 'dehydrateSegment'], array_filter($segments));
return $this->adminJson(['data' => array_values($data)]);
}
$id
is retrieved from the request parameters and then placed directly into the SQL query through the use of sprintf
and then executed (as long as $type
is something other than object
). This allows a malicious actor to inject the SQL query through the use of a single quote β
.
This vulnerability can be thought of as a Boolean-based Blind SQL Injection, as an exploit is unable to pull out data from the database directly, but has to piece together the information through a series of True/False requests.
This image below shows a request that tests if the integer 1 equals 1:
The response returns a 200 OK
along with the data that has an id
of 137:
This second request tests if the integer 1 is equal to 2:
This time, the response is a 500 Internal Server Error
along with a stack trace.
Using these 2 queries, a malicious actor can automate the retrieval of information from the database. This last example shows a query to find the first character of the version from the database server.
Pimcore AdminBundle is part of the core Pimcore platform, a Product Information Management (PIM) platform, which is closely related to the Enterprise Resource Planning (ERP) functions of a business. More about the Pimcore platform can be found at the vendorβs website.
Requests sent to /admin/object/grid-proxy
are handled by Bundles/AdminBundle/Controller/Admin/DataObject/DataObjectController.php
file, starting on line 1568, as shown below:
This file collects all the parameters (line 1586), then includes the parameters in a call to prepareListingForGrid
shown below:
prepareListingForGrid
is found in the previously mentioned Pimcore/Bundles/AdminBundle/Helper/GridHelperService.php
file and starts on line 489. This function builds the SQL query from the provided parameters. The parameter specificID
is vulnerable to SQL injection, since the specificId
parameter data is concatenated directly into the string and then added to the $conditionFilters
array, as shown below:
A request to the grid-proxy
url is shown below. In this query, the specificId
field is set to 1+or+βaβ=βaβ
. The response shows a content-length of 7546.
GET /admin/object/grid-proxy/classId=BS&[other params]&specificId=1+or+βaβ=βaβ&query=[other params] HTTP/1.1
This next request sets the specificId
parameter to 1+orβaβ=βbβ
. As shown in the following image, the response length is now 47, and no records were returned.
By combining these 2 requests, a malicious actor can programmatically return data from the database by testing each character and monitoring the response. The image below shows an example of this by requesting the database version and checking if the first character of the version is equal to 8.
Akaunting is an enterprise accounting system, providing a variety of services related to the normal day-to-day business operations, notably in the retail sector, such as invoicing and expense tracking. More about Akaunting can be found at the vendorβs website.
The Akaunting application allows for PHP code sent to the application to be executed by the web server. This can lead to a shell directly on the host operating system. The vulnerability was introduced upon the creation of the Money.php
file in the first commit, 1c01d2120941d99f758cf23be20fe5931bdd4a36. To exploit this vulnerability, the attacker must first be authenticated and already have permissions to add or modify sales invoices.
A POST sent to /{company_id}/sales/invoices/{invoice_id}
with an items[0][price]
that includes a PHP callable function is executed directly. The image below shows the post body, including a items[0][price]
set to phpinfo
. The response on the right shows the response, which includes the results from the application executing phpinfo()
:
This is due to a lack of input sanitization in the Money.php middleware component. The following is the code responsible for the execution; as shown, it checks to see if what is received is callable and, if so, executes it.
protected function parseAmountFromCallable($amount)
{
if (!is_callable($amount)) {
return $amount;
}
return $amount();
}
A user is able to change the company their account is associated with, allowing them to view/modify information from another company. This vulnerability was introduced in the first commit of the application. To exploit this vulnerability, the attacker must first be authenticated as any user.
The first image shows that the user Test_company_1
is associated with the company named My Company
:
While logged in as the user Test_company_1
we click on Profile
to change the user settings:
By clicking on the Save
button and intercepting the request, we can modify the companies[0]
field to the id
of another company. The image below shows changing the company information from 1 to 2 while updating the profile information:
Once done, viewing the dashboard shows that the associated company has been changed:
Any user can crash the Akaunting platform by supplying an invalid βlocaleβ variable as part of an otherwise well-formed HTTP POST request. This vulnerability was introduced in the first commit of the application. To exploit this vulnerability, the attacker must first be authenticated as any user.
The image below shows a post to /2/settings/settings
with an invalid locale that is successfully processed without error:
Visiting any page will result in a 500 response:
A user can inject HTML into the avatar upload process and trigger an XSS for anyone who views it, including high-privilege administrators of the application. This vulnerability was introduced in the first commit of the application. To exploit this vulnerability, the attacker must first be authenticated as any user.
The image below shows a post to /{company_id}/auth/users/{user_id}
with HTML embedded in the image upload field:
Example payload:
\-----------------------------11088376342107705763341750165
Content-Disposition: form-data; name="picture"; filename="Screenshot_2021-05-02_05_11_16.png"
Content-Type: image/png
</pre><html><b>test</b><script>alert('xss')</script><pre>
The HTML is directly rendered on screen while accessing the avatar URL; e.g /{company_id}/uploads/{upload_id}:
Setting the host header while sending a Post to /auth/forgot
endpoint changes the link generated by the application. An attacker can send a password-reset request for an existing user and modify the host header to point to a web server they control. If the user clicks on the password reset URL, the attacker will receive the password-reset token and can then set the password to something the attacker knows. This vulnerability was introduced in the first commit of the application. To exploit this vulnerability, the attacker must first know or guess the email address of a valid user.
The image below shows a post to the /auth/forgot endpoint, with the Host set to example.com:
The email sent by the application directs the user to the example.com domain with the password reset token.
Note that the root of this vulnerability is due to a design decision in the Laravel framework and how proxy headers are handled with respect to single instance and multi-tenant implementations. In other words, while CVE-2021-36804 is a (now fixed) vulnerability in Akaunting, other multi-tenant implementations involving Laravel should be aware that the default configuration of that framework is likely vulnerable to a similar issue. For more information on this design issue, please see Enlightnβs Host Injection Analyzer, Daniel Coulbourneβs tweet, and PR 5477 in the Laravel GitHub repository.
The Akaunting application allows for HTML to be written to the footer of a sales invoice and relies on its built-in βfirewallβ to prevent malicious code, such as XSS, from being accepted. The following example shows how specially crafted HTML code can bypass the filtering. This vulnerability was introduced in the first commit of the application. To exploit this vulnerability, the attacker must have the permissions to add or modify sales invoices.
A POST sent to /{company_id}/sales/invoices/{invoice_id}
with a footer
that includes the following HTML will execute the javascript:
Proof of concept payload:
POST /1/sales/invoices/201 HTTP/1.1
...
-----------------------------11766653461285783364827965738
Content-Disposition: form-data; name="footer"
'\"<img src>
7.8 High
CVSS3
Attack Vector
LOCAL
Attack Complexity
LOW
Privileges Required
LOW
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
6.9 Medium
CVSS2
Access Vector
LOCAL
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:L/AC:M/Au:N/C:C/I:C/A:C