Det er nå noen måneders tid siden min blogg ikke har gitt ut noen nyheter.
Jeg satt faktisk rolig med å spise is foran Simpsons når jeg fikk et e-post fra WordPress:
|
Quelqu’un a demandé la réinitialisation du mot de passe pour le compte suivant : |
|
Titre du site : Stunivers |
|
Identifiant : [nom du compte admin ici] |
|
Si ceci est une erreur, ignorez cet e-mail et rien ne se passera. |
|
Pour renouveler votre mot de passe, cliquez sur le lien suivant : |
|
> lien de réinitialisation ici |
|
Cette demande de réinitialisation de mot de passe provient de l’adresse IP xxx.xxx.xxx.xxx . |
|
1. De første informasjonene
Etter forskjellige undersøkelser synes det at hackeren sannsynligvis ikke har gjort noe for å skjule seg, og at han er en del av et automatisk scan av nettet.
Den oppgitte IP-adressen ble nevnt flere ganger i loggene til min blogg før hacken, totalt 17 gang.
Landet var Indien, og byen var Delhi.
Jeg tror at med tanke på landet er det sannsynligvis ikke en feil lokaliseringsdata, selv om det ikke vil hjelpe meg mye.
Det verste var at hackeren brukte en gammel versjon av Google Chrome som ikke var oppdatert på et Windows 10, uten script som kjørte fra en VPS.
Hvordan skal jeg si at jeg er rasende?
2. Skaden
Jeg kunne ikke logge meg inn i mitt produktionsmiljø med mine egne legitimasjoner. Det ser ut til at ingen følsom informasjon har lekket ut etter lesing av alle loggene, fra min hoster og de handlingene som ble gjort på nettsiden.
3. Hva var det vi hadde i stedet for sikkerhet?
Min blogg representerer ingenting på Internett, bare tre besøk pr år nå, fantastisk!
Men, det betyr ikke at automatiske hack-kampanjer vil ha ingen effekt, sannsynligvis er dette hva som har hatt sted.
På den andre side var mange sikkerhetsforhold på min hostingside allerede i plass, med aktivitetsdeteksjon og annet... det hindret likevel en del bots (og det er mye av dem når du bruker WordPress!).
Jeg tok også for meg å sørge for at lenken til wp-admin-tilkoblingen endres for å unngå et stort angrepsspor.
Jeg gjorde også en manuell oppgradering av bloggen, siden jeg faktisk har et oppdateringspipeline!
Men jeg fant ut at dette pipeline... det fungerte på noen versjoner, ikke andre.
Det mislyktes likevel ikke alltid, så jeg fikk aldri feilmeldinger om manglende oppdatering, og jeg var derfor ikke bekymret.
Og det er helt min egen skyld, jeg kan bare skjelne meg selv.
4. Hva brukt hakeren?
Hakeren brukte denne CVE:
CVE-2026-19632 — TranslatePress
Og det er nettopp pluginet jeg bruker for å oversette min side som hadde problem opp til versjon 3.3.1, når de fikløst den.
Denne dumme sårbarheten la en uautentisert angriper til å hente ut reset-urlen for et administrator-passord, og bruke det til å sette et nytt passord og ta kontroll over admin-kontoen.
Angrepsmekanismen var ganske dum, hvor hakeren først utløste en passordgjenopprettingsprosess, og TranslatePress kunne registrere reset-urlen i sin oversettelsesdatabase.
Via en publikk tilgjengelig AJAX-reques, kan angriper da hente denne URL-en, inkludert gjenoppretningsnøkkelen.
Angriperen kan deretter endre administrator-passordet – eller hvordan man virkelig blir hacket …
5. Fullstendig omsetting av oversettingene
Da jeg vet hvor raskt det kan gå å bli bedrevet på WordPress, har jeg kodet alle mine plugins.
Alle, unntatt TranslatePress, et stort jobb ...
TranslatePress er en veldig interessant plugin med de funksjoner den tilbyr, og jeg må avstå fra å si at jeg ble sløv da jeg så det.
Derfor har jeg lyst på TranslatePress for ikke å trengte å kode det igjen.
Og i slutten, har jeg likevel kodet min egen oversettelsesplugin.
Det tok meg tid, fordi detaljene er viktigste.
For det første ville jeg lese koden til TranslatePress, og deretter forstå de deler som rørte meg og var interessante for meg.
Min kode er ikke basert på den, men inspirert.
Alt dette for å unngå at noe blir offentliggjort.
6. Omsetting av oppdateringspipeline
Første gang jeg startet min blogg, gjorde jeg det med hjelpemidler fra mitt hosting.
Jeg hadde da bare e-postvarsel.
Deretter installerte jeg WordPress selv for å unngå en dum begrensning som ikke burde ha blokkert noen andre, men som blokkerte meg på et punkt jeg faktisk husker ikke lenger.
Her bestemte jeg meg for ikke å løpe etter oppdateringene, men å lage mitt eget oppdateringspipeline.
Det er langt fra enkelt bare å gjøre et git pull på prosjektet.
Jeg brukte Cron, WP-CLI med plugin update --all, selvfølgelig core update og ingen oppdateringer på temaet, jeg hadde også koding av eget tema raskt.
Vi glepper ikke å sjekke checksums via wp core verify-checksums og vi er sikre.
Da jeg bare har et ekstern plugin, virket det bra.
Men så brøt mitt pipeline helt på grunn av en stille feil som bleårsaket av TranslatePress som ikke lenger kunne oppdatere seg.
Og her var det fullstendig min egen feil.
Jeg hadde planlagt å hente tilbake koden fra WP-CLI, men mitt håndtering bak der var helt dumt.
I grunn handterte jeg en bestemt feil jeg hadde møtt under testene riktig. Men hvis en annen feil oppstod, logget jeg den bare og fortsatte.
Så noe i denne stil:
|
output=$(wp plugin update --all 2>&1) |
exit_code=$? |
|
if [[ $exit_code -ne 0 ]]; then |
if [[ "$output" == *"Error: Download failedd."* ]]; then |
echo "An error occured" |
log-mail "$output" |
exit 1 |
else |
log "$output" |
exit 2 |
fi |
fi |
|
# The rest of the pipeline |
|
Jo.
Første, koden er skummel.
Men hovedproblemet var at jeg handterte en kjent feil, ikke generelle feil.
Dermed kunne mitt pipeline møte et problem under oppdatering av mine plugins, logge det, og fortsatt som om alt var bra nok.
Og siden jeg ikke hadde noen alarm i dette spesialtilfellet, fikk jeg selvfølgelig ingen e-poster.
Jeg trodde derfor at mine oppdateringer funket.
De virket faktisk ikke lenger.
Dermed kunne WordPress også ikke merke seg oppdateringene, og alt ble stående på grunn av en dårlig kodebehandling.
Det frustrerende er at denne feilen kom direkte fra mine egne testers.
Jeg hadde skrevet en spesifikk håndtering for den situasjonen jeg var interessert i, det virket, jeg var fornøyd og satte det i produksjon uten å teste de andre tilfellene godt nok eller å ta et steg tilbake for å se på hele skriptet.
Jeg var spesielt veldig opptatt av å få alt opp i nettet.
Etter noen måneder fant jeg meg med en sårbar plugin som ikke ble oppdatert, selv om jeg hadde skrevet et helt pipeline for å unngå nettopp denne typen situasjon.
Utrolig.
6.1. Hva jeg endret
Selvfølgelig rettet jeg meg mot feilen.
Men jeg gjorde ikke bare noen tre linjer til å håndtere TilPress-situasjonen.
Jeg revurderet hvordan min pipeline håndterer feil og rekkefølgen på operasjoner den utfører.
Her er en lettversjon som jeg har fullstendig endret for å vise deg litt om hvordan jeg tenkte:
#!/bin/bash |
|
set -o pipefail |
|
SITE_DIR="/home/USER/www" |
LOG_DIR="/home/USER/logs" |
LOG_FILE="$LOG_DIR/update-$(date '+%Y-%m-%d').log" |
|
MAIL_TO="admin@example.com" |
SITE_NAME="Mon WordPress" |
|
mkdir -p "$LOG_DIR" |
|
# ============================================================ |
# LOG + MAIL |
# ============================================================ |
|
log-mail() { |
local text="$1" |
local exit_code="$2" |
local date |
date="$(date '+%Y-%m-%d %H:%M:%S')" |
|
echo "[$date] $text" >> "$LOG_FILE" |
|
if [ "$exit_code" -eq 0 ]; then |
printf '[%s] SUCCESS : %s\n' "$date" "$text" |
printf '%s\n' "$text" | mail \ |
-s "[OK] $SITE_NAME - Pipeline" \ |
"$MAIL_TO" |
else |
printf '[%s] ERROR : %s\n' "$date" "$text" |
printf '%s\n' "$text" | mail \ |
-s "[ERREUR] $SITE_NAME - Pipeline" \ |
"$MAIL_TO" |
fi |
} |
|
|
# ============================================================ |
# EXECUTE A COMMAND |
# ============================================================ |
|
run_step() { |
local name="$1" |
shift |
|
echo "" |
echo "==========================================" |
echo "$name" |
echo "==========================================" |
|
local output |
output=$("$@" 2>&1) |
local exit_code=$? |
|
echo "$output" >> "$LOG_FILE" |
|
if [ "$exit_code" -ne 0 ]; then |
log-mail "$name as failled : |
|
$output" "$exit_code" |
|
exit "$exit_code" |
fi |
|
log-mail "$name completed successfully : |
|
$output" 0 |
} |
|
|
# ============================================================ |
# INITIALISATION |
# ============================================================ |
|
cd "$SITE_DIR" || { |
log-mail "Unable to accesss to $SITE_DIR" 1 |
exit 1 |
} |
|
log-mail "Start the updating pipeline" 0 |
|
|
# ============================================================ |
# WORDPRESS - CORE |
# ============================================================ |
|
run_step \ |
"Updating WordPress Core" \ |
wp core update |
|
|
# ============================================================ |
# WORDPRESS - PLUGINS |
# ============================================================ |
|
run_step \ |
"Updating WordPress Plugins" \ |
wp plugin update --all |
|
|
# ============================================================ |
# WORDPRESS - THEMES |
# ============================================================ |
|
run_step \ |
"Updating THEMES (i'm not using that but ..)" \ |
wp theme update --all |
|
|
# ============================================================ |
# PHP - COMPOSER |
# ============================================================ |
|
run_step \ |
"Updating Composer Dependencies" \ |
composer update --no-interaction --prefer-dist |
|
|
# ============================================================ |
# NODE / REACT |
# ============================================================ |
|
run_step \ |
"Updating Node Dependencies" \ |
npm ci |
|
|
# ============================================================ |
# REACT - BUILD |
# ============================================================ |
|
run_step \ |
"Build React" \ |
npm run build |
|
|
# ============================================================ |
# FIN |
# ============================================================ |
|
log-mail "Pipeline completed with success." 0 |
|
exit 0 |
Selv om det, må man absolutt huske at en feil ikke lenger er noe jeg bare kan logge og glede meg bort fra.
Og spesielt, det må kunne testes og verifisert.
Jeg tok klart ikke tid til å gjøre dette, og jeg glemte faktisk å komme tilbake til det selv om jeg visste det, og ignorerte det med å si meg at jeg er for liten til at noe slikt skulle skje.
Jeg har derfor også testet koden mitt, i sted for bare å si til meg selv:
« Det virker nå, det vil alltid virke. »
Hvis en kritisk steg feiler, må pipelineen vite om det, stoppe riktig og varsle meg.
Og jeg betrakter ikke lenger det som nok å bare teste de feilene jeg kjenner til.
Fordi det er nettopp slik jeg endte opp med en pipeline som virket perfekt... til den dagen den ikke lenger virket.
Denne gangen har jeg også revurdert avhengighetene til min blogg.
Og jeg vil nå bare ha WordPress-koden og mitt eget kode.
Som man ser, kommer vi tilbake til å skrive tester, selv for et pipeline-skript.
7. Utsetting
Jeg skriver denne artikkelen fra utviklingsmiljøet mitt, noe som ikke vil være tilfellet når du leser den.
Du vet jo at alt jeg gjør er open source.
Koden til min nye plugin er enda ikke frigitt.
Jeg vil ta meg tid til å finne eventuelle bugg jeg har glemt.
Jeg vil gi deg oppdateringer når jeg er klar med dette.
Kommentarer
Ingen godkjente kommentarer ennå.
Logg inn med en kommentatorkonto for å publisere en kommentar. Logg inn.