Je hebt alle bestanden gescand en alles is schoon. Toch stuurt je checkout kaartgegevens weg. Dan zit de skimmer waarschijnlijk in je database.
Je hebt alle bestanden gescand en alles is schoon. Toch stuurt je checkout kaartgegevens weg. Dan zit de skimmer waarschijnlijk in je database.
Een bestandsscan kijkt naar PHP en JavaScript op schijf. Maar Magento slaat veel content en instellingen in de database op, en die wordt gewoon in je pagina's gerenderd. Aanvallers weten dat. Wie code in de database zet, ontloopt elke tool die alleen bestanden controleert.
Waarom file-scans niet genoeg zijn
Een bestandsscanner zoekt naar bekende patronen in bestanden. Een skimmer in de database is voor hem onzichtbaar, om drie redenen.
- Er is geen bestand. De code is een tekstwaarde in een tabel. Een scanner op het bestandssysteem komt er niet.
- Het is legitiem gebruik van een functie. Magento staat HTML en scripts in CMS-blocks en configuratie toe. Dat is een feature, geen bug.
- Het overleeft een schoonmaak. Je verwijdert alle verdachte bestanden en deployt opnieuw, maar de code in de database blijft staan. Dan werkt de skimmer gewoon door.
Dat laatste is de reden dat we na een incident altijd de database nalopen. Zonder die stap ruim je het symptoom op en blijft de besmetting. Zie ook Magento 2 gehackt: wat nu?.
Hoe komt code in de database?
Er zijn grofweg twee routes.
- Via de admin. Een aanvaller met een gestolen admin-account zet code in een CMS-block of de configuratie. Dit is simpel en vraagt geen exploit. Zie admin beveiligen.
- Via een kwetsbaarheid. Een lek in Magento of een extensie geeft schrijftoegang tot de database of tot het aanmaken van content, zonder dat de aanvaller een admin-wachtwoord heeft. De bekende lekken in onze lijst van grote Magento-lekken zijn voorbeelden van hoe een aanvaller ver kan komen.
Welke route is gebruikt, bepaalt wat je daarna dicht moet zetten. Alleen de code verwijderen is niet genoeg als de ingang openblijft.
Waar in de database zit het?
Dit zijn de plekken waar wij standaard kijken. De volgorde is die van de kans dat we iets vinden.
core_config_data
Deze tabel bevat de configuratie van de shop. Enkele paden zijn bijzonder interessant voor aanvallers, omdat de waarde direct in elke pagina wordt gerenderd:
design/head/includes: extra code in devan elke pagina.design/footer/absolute_footer: extra code onderaan elke pagina.design/head/scripts: scripts in de head, afhankelijk van de versie en configuratie.
Vooral design/head/includes en design/footer/absolute_footer zien we terug. Ze staan op elk scope-niveau (default, website, store view) opgeslagen, dus kijk naar alle scopes.
cms_block en cms_page
CMS-blocks en -pagina's mogen HTML bevatten, dus ook -tags. Een aanvaller zet een klein script in een block dat op de betaalpagina of in de footer wordt getoond. Controleer de inhoud van alle actieve blocks en pagina's, niet alleen de pagina's die je regelmatig bewerkt.
E-mailtemplates
De tabel email_template bevat aangepaste e-mailtemplates. Dat is een minder voor de hand liggende plek, maar template-injectie heeft in het verleden een rol gespeeld bij grote lekken. Denk aan TrojanOrders (CVE-2022-24086), een template-injectie via de checkout. Controleer op onbekende of recent gewijzigde templates.
Overig
- Admin-gebruikers in
admin_user: een account dat je niet kent. - Cron en queue: taken in
cron_scheduleof berichten die onbekende acties starten. - Extensie-tabellen: sommige extensies bewaren scripts of tracking-codes in eigen tabellen, bijvoorbeeld voor marketing-pixels. Daar zit legitieme code tussen, dus beoordeel per geval.
- Productbeschrijvingen en categorie-content kunnen HTML bevatten. Het is een minder gebruikelijke plek, maar op grote catalogi niet uitgesloten.
Queries om te zoeken
Draai deze bij voorkeur op een kopie van de database of op een read-replica. Het zijn leesopdrachten, maar je wilt geen risico nemen op productie.
Config met scripts of externe verwijzingenSELECT config_id, scope, scope_id, path, LEFT(value, 200) AS preview
FROM core_config_data
WHERE value LIKE '%<script%'
OR value LIKE '%eval(%'
OR value LIKE '%atob(%'
OR value LIKE '%document.write%';
SELECT config_id, scope, scope_id, path, LEFT(value, 300) AS preview
FROM core_config_data
WHERE path IN ('design/head/includes', 'design/footer/absolute_footer')
AND value IS NOT NULL AND value <> '';
SELECT block_id, identifier, title, update_time
FROM cms_block
WHERE content LIKE '%<script%';
SELECT page_id, identifier, title, update_time
FROM cms_page
WHERE content LIKE '%<script%';
SELECT block_id, identifier, update_time
FROM cms_block
ORDER BY update_time DESC
LIMIT 20;
SELECT template_id, template_code, modified_at
FROM email_template
ORDER BY modified_at DESC;
SELECT user_id, username, email, created, logdate, is_active
FROM admin_user
ORDER BY created DESC;
Een paar kanttekeningen:
- Legitieme scripts zoals Google Tag Manager of een chatwidget geven ook hits. Het gaat om de hits die je niet herkent.
- Let op verwijzingen naar domeinen die je niet kent, op sterk geobfusceerde tekst (lange reeksen tekens,
atob,fromCharCode, hex- of base64-blokken) en op scripts die code dynamisch bijladen. - Aanvallers houden zich soms aan een patroon dat past bij je eigen domeinnaam of bij een bekende dienst, zodat het niet opvalt. Zoek ook naar kleine, afwijkende toevoegingen in verder normale scripts.
- Zoek niet alleen naar

