Kort sagt: For at kontrollere databasen for skadelig kode gennemsøger I en eksport eller en kopi med læsende forespørgsler efter indsmuglede scripts, fremmede adresser og tilsløret kode i indhold og indstillinger. Kontrollér desuden triggere, planlagte hændelser, gemte procedurer og databasebrugerne. Ryd først op efter vurderingen og aldrig med blind søg og erstat, fordi serialiserede data ellers går i stykker.
Mange oprydningers blinde vinkel
Efter et indbrud kontrollerer de fleste driftsansvarlige filerne. De erstatter CMS-kernen, sletter mistænkelige PHP-filer og indspiller udvidelserne påny. Websitet ser derefter rent ud, og en uge senere omdirigerer det igen til fremmede sider. Årsagen ligger ofte i databasen, som blev overtaget uændret ved oprydningen.
For angribere er databasen et attraktivt skjulested. Et script i en widget leveres på hver side. En ændret adresseindstilling leder alle besøgende om. En ekstra adminkonto åbner døren til senere. Intet af det falder i øjnene ved en filscanning.
Efter PHP2Shell, sårbarhederne CVE-2026-109618 og CVE-2026-109619 med kodeudførelse uden login, hører databasen derfor med til enhver kontrol. Den, der kan udføre kode på serveren, kan som regel læse databasens adgangsdata fra konfigurationen og skrive vilkårligt dér. Hvordan applikationen overhovedet taler med databasen, forklarer PHP og databaser: PDO og mysqli.
Hvor skadelig kode sidder i databasen
| Fundsted | Typisk indhold | Virkning |
|---|---|---|
| Indhold (indlæg, sider, produkter) | <script>-blokke, usynlige links, <iframe> |
skadelig kode eller spam til besøgende |
| Indstillinger og optioner | ændret website-adresse, fremmede scripts i widgets eller tema-optioner | omdirigeringer, scripts på alle sider |
| Brugertabeller | ekstra administratorer | varig adgang |
| Triggere | kode, der ændrer indhold ved hver lagring | skadelig kode vender tilbage efter oprydning |
| Planlagte hændelser | tilbagevendende opgaver i databaseserveren | ændringer uden webadgang |
| Databasebrugere | ekstra konti med vidtrækkende rettigheder | adgang uden om CMS'et |
De sidste tre linjer overses særligt ofte, fordi de ikke ligger i CMS'ets tabeller, men i selve databaseserveren.
Ved onlineshops fortjener et fundsted særlig opmærksomhed: Indstillinger, hvorigennem yderligere scripts indbindes i kassen og ved afslutningen af bestillingen. Et fremmed script på dette sted kan læse kundernes indtastninger med, før de sendes krypteret videre til betalingstjenesten. Kontrollér derfor målrettet alle felter til kode i sidehoved og sidefod, sporingsindlejringer og designindstillinger, der virker på kassesider.
Tænk desuden på andre databaser på samme server. Test- og staging-kopier, gamle projektversioner eller andre websites' databaser ligger ofte ved siden af og kan nås med de samme adgangsdata. Det, der findes i live-databasen, bør også kontrolleres dér, før en kopi senere igen tjener som grundlag.
Kontrollér databasen for skadelig kode: Indhold og indstillinger
Arbejd på en eksport. Den er samtidig bevissikring og søgegrundlag. Eksporten kan gennemsøges som tekstfil uden at belaste den kørende database:
# Opret en konsistent eksport (adgangsdata forespørges)
mysqldump --single-transaction --routines --triggers --events -u BENUTZER -p DATENBANK > export.sql
sha256sum export.sql > export.sql.sha256
# Tæl typiske mønstre i eksporten
grep -oiE '<script[^>]{0,80}' export.sql | sort | uniq -c | sort -rn | head -30
grep -oiE '(eval\(|base64_decode|fromCharCode|document\.write|atob\()' export.sql | sort | uniq -c
grep -oiE 'https?://[a-z0-9.-]+' export.sql | sort | uniq -c | sort -rn | head -50
Den sidste forespørgsel opregner alle domæner, der forekommer i databasen, efter hyppighed. Fremmede domæner, som ingen i teamet kender, er de vigtigste kandidater. Til målrettede forespørgsler i selve databasen egner SELECT-kommandoer sig. Eksemplet bruger WordPress-tabeller; præfikset og tabelnavnene i andre systemer står i deres dokumentation:
-- Indstillinger med scripts eller mistænkelige funktioner
SELECT option_name, LENGTH(option_value) AS laenge
FROM wp_options
WHERE option_value LIKE '%<script%'
OR option_value LIKE '%eval(%'
OR option_value LIKE '%base64_decode%'
ORDER BY laenge DESC;
Poster med meget stort indhold fortjener særlig opmærksomhed. Baggrund om WordPress-specifikke skjulesteder giver vejledningen Find bagdøre i WordPress.
Triggere, hændelser og databasekonti
Triggere og planlagte hændelser er slet ikke tiltænkt i mange webapplikationer. Hvis de findes, bør nogen kunne forklare hvorfor. Disse forespørgsler læser kun fra systemtabellerne i MySQL og MariaDB:
-- Triggere i alle databaser
SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_OBJECT_TABLE, CREATED
FROM information_schema.TRIGGERS;
-- Planlagte hændelser
SELECT EVENT_SCHEMA, EVENT_NAME, STATUS, CREATED, LAST_EXECUTED
FROM information_schema.EVENTS;
-- Gemte procedurer og funktioner
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, CREATED
FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema');
-- Databasebrugere
SELECT user, host FROM mysql.user ORDER BY user;
Bruger jeres applikation PostgreSQL eller et andet databasesystem, hedder systemtabeller og kommandoer noget andet; princippet er det samme. Til analysen anbefales en egen databasebruger, der kun må læse. Så kan selv en tastefejl i en forespørgsel ikke ændre noget, og kontrollen efterlader ingen spor i dataene.
En trigger, der hænger kode på, når et indlæg gemmes, forklarer, hvorfor skadelig kode vender tilbage efter hver oprydning. Ukendte databasebrugere hører lige så meget med til kontoundersøgelsen som adminkonti i CMS'et; mere herom under Find fremmede adminkonti i CMS og server.
Rens rent uden at ødelægge data
Oprydningen er den mest følsomme del. Denne rækkefølge har vist sig at fungere:
- Vurdér fund: Hvert hit klassificeres som kendt, harmløst forklarligt eller fremmed. Sporings- og kortkoder er ofte legitime.
- Luk indgangen: Bring PHP op på en rettet version (8.5.12, 8.4.27, 8.3.36, 8.2.35 eller bekræftet backport), genstart alle workers, opdatér applikationen.
- Fjern målrettet: Rens fremmed indhold via applikationen eller med værktøjer, der håndterer serialiserede data korrekt. Slet fremmede triggere, hændelser og konti.
- Skift adgangsdata: Ny databaseadgangskode, indtastet i applikationens konfiguration, begræns applikationsbrugerens rettigheder til dens egen database.
- Kontrollér påny: Gentag søgeforespørgslerne efter nogle dage.
Erstat intet med søg og erstat i SQL-eksporten. Serialiserede PHP-data gemmer længden af hver tegnstreng med. Ændres længden, bliver indstillingen ulæselig, og websitet kan falde ud.
Omdirigeringer, der optræder trods en ren database, har deres årsag i et andet lag. Indlægget Websitet omdirigerer til fremmede sider hjælper med afgrænsningen.
Hvordan hjælper PHP SOS konkret?
- Vi sikrer databasen med kontrolsum og gennemsøger eksporten efter scripts, fremmede domæner og tilsløret kode.
- Vi kontrollerer triggere, hændelser, procedurer og databasebrugere, der ligger uden for CMS'et.
- Vi renser fund inden for rammerne af malwarefjernelsen uden at beskadige serialiserede data.
- Vi begrænser applikationsbrugerens rettigheder og gentager kontrollen efter oprydningen.
Ofte stillede spørgsmål
Kan skadelig kode sidde i databasen?
Ja. Angribere skriver JavaScript ind i indlæg, produktbeskrivelser eller widgets, ændrer adresseindstillinger til omdirigeringer eller opretter adminkonti. I MySQL og MariaDB kan triggere og planlagte hændelser desuden ændre data. En filscanning finder intet af det.
Hvordan gennemsøger jeg databasen uden at ødelægge noget?
Arbejd på en eksport eller en kopi, og brug kun SELECT-forespørgsler. En eksport kan desuden gennemsøges som tekstfil med grep. Ændringer sker først, når hvert fund er vurderet, og der findes en sikkerhedskopi.
Hvorfor skal jeg ikke rense fund med søg og erstat i eksporten?
Mange CMS gemmer indstillinger som serialiserede PHP-data, hvor længden af hver tegnstreng gemmes med. En erstatning ændrer længden, men ikke angivelsen, og indstillingen bliver ulæselig. Rens via applikationen eller med værktøjer, der forstår serialiserede data.
Er ethvert script i databasen mistænkeligt?
Nej. Sporingskoder, kort, videoer eller chat-widgets gemmes også som script. Afgørende er, om nogen i teamet kender posten og måladressen.