---
title: "Da WordPress holdt, men e-posten åpnet døren"
date: 2026-06-01
description: "En fullt patchet WordPress-side motsto alt på web-laget. Veien inn gikk via DMARC p=none, brukerenumerering og manglende MFA."
tags: ["wordpress", "pentest", "email-security", "dmarc"]
url: https://erik.no/blogg/2026-06-01-da-wordpress-holdt-men-e-posten-apnet-doren
---

<Callout type="info">
  **FIKTIVT:** Alle firmanavn, personnavn, domener og e‑postadresser i dette
  innlegget er oppdiktet. Eventuell likhet med ekte virksomheter eller
  personer er tilfeldig. Detaljer fra reelle oppdrag er sanert.
</Callout>

Jeg fikk i oppdrag å teste nettstedet til Måneskinn AS (`maneskinnas.no`) – en
WordPress-side på managed hosting. Jeg gikk inn med forventning om å finne en
sårbar plugin et sted. Det gjorde jeg ikke. Web-laget holdt. Det som ikke holdt,
var e-posten – og det var nok til å ta over hele nettstedet på papiret.

## Kontekst

Black-box-test av én WordPress-side. Målet var det vanlige: finne lekkasje av
kundedata, credentials, og «har vi bugs». Siden lå bak en CDN med WAF, på managed
WordPress-hosting, og brukte en typisk stack med Elementor, JetEngine og noen
addons.

Arbeidsmåten min er moderne pentest med AI i loopen: jeg styrer retning, scope og
prioritering, og lar AI-en gjøre selve gravingen – skrive scripts, kjøre sweeps,
prøve angrepsvektorer og lese output. Jeg plukker ut det interessante og bryter inn
der det trengs menneskelig dømmekraft.

## Det jeg fant

### Web-laget var kjedelig solid

Jeg lot AI-en kjøre wpscan og nuclei mot siden, og krysse pluginversjoner mot
CVE-databasene. Alt var på nyeste, patchede versjon. De interessante endepunktene
fantes – men var stengt:

- Code Snippets-pluginen (kjører vilkårlig PHP) hadde REST-endepunkter bak auth:

```http
POST /wp-json/code-snippets/v1/snippets
-> 401 rest_forbidden
```

- Jeg ba AI-en prøve klassisk uautentisert filopplasting og LFI gjennom de vanlige
  Elementor/JetEngine-AJAX-actionene. Traversering ble stoppet av WAF-en, og
  JetEngine-versjonen var patchet mot den uautentiserte SQL-injeksjonen som ellers
  hadde vært en åpning.
- Brute-force mot login traff en rate-limiter etter tre forsøk. Jeg stoppat der –
  å hamre videre ville bare låst ut den ekte brukeren.

<Callout type="success">
  Dette er sånn et nettsted bør se ut: oppdaterte komponenter, WAF, rate limiting,
  stengte REST-endepunkter. Ingen rød tråd å trekke i på web-laget.
</Callout>

### REST API-et delte litt for villig

Det første som sprakk var brukerlisten. Standard WordPress REST-endepunkt,
uautentisert:

```bash
curl -s https://maneskinnas.no/wp-json/wp/v2/users
```

```json
[
  {"id": 1, "name": "Kari Berg", "slug": "kariberg"},
  {"id": 4, "name": "kari.berg@maneskinnas.no", "slug": "kariberg-maneskinnas-no"}
]
```

Der har jeg både et gyldig brukernavn og administrators e-postadresse. Bruker 4
hadde til og med e-posten som offentlig visningsnavn.

### Ingen andre faktor

AI-en sjekket etter de vanlige MFA-pluginene (Two-Factor, Wordfence Login
Security, miniOrange og flere). Ingen treff. Admin-pålogging så ut til å være
passord alene. Isolert sett dempet rate-limiteren dette – men jeg hadde nå en
e-postadresse, et brukernavn, og ingen andre faktor i veien.

### E-posten var den åpne døren

Jeg fikk AI-en til å slå opp e-postoppsettet for domenet. SPF var stramt (`-all`),
men DMARC fortalte en annen historie:

```text
SPF    : v=spf1 include:spf.protection.outlook.com -all
DMARC  : v=DMARC1; p=none;
DKIM   : ingen selector publisert
```

`p=none` betyr at mottakere ikke avviser forfalsket e-post – policyen overvåker
bare. Kombinert med manglende DKIM er domenet i praksis spoofbart. For å bekrefte
det skrev AI-en et lite Python-script som koblet seg rett mot mottakerens MX og
sendte en melding med forfalsket avsender:

```python
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "kari.berg@maneskinnas.no"   # forfalsket
msg["To"] = "mottaker@eksempel.no"
msg["Subject"] = "[PENTEST PoC] Spoof (DMARC p=none)"
msg.set_content("Autorisert pentest – proof of concept. Ikke sendt av Maneskinn AS.")

with smtplib.SMTP("mx.eksempel.no", 25, timeout=40) as smtp:
    smtp.ehlo("mail.pentest-poc.example")
    smtp.send_message(msg)
```

Mottakerens server tok imot den uten å blunke:

```text
-> MAIL FROM:<kari.berg@maneskinnas.no>
<- 250 2.1.0 Sender OK
-> RCPT TO:<mottaker@eksempel.no>
<- 250 2.1.5 Recipient OK
<- 250 2.6.0 Queued mail for delivery
```

Avsender-IP-en var ikke i SPF-posten, det fantes ingen DKIM-signatur, og
DMARC-justeringen feilet. Likevel: levert. På en Microsoft 365-mottaker havnet den
i **innboksen**, ikke i søppelpost. Det var poenget. En forfalsket e-post fra
`kari.berg@maneskinnas.no` lander der folk faktisk leser den.

## Angrepskjeden

Ingen av delene er spektakulær alene. Til sammen er de en vei inn:

```text
1. Hent admin-epost   ->  /wp-json/wp/v2/users
2. Forfalsk avsender  ->  DMARC p=none, ingen DKIM  ->  innboks
3. Phishing-lenke     ->  falsk wp-admin / M365-login  ->  passord fanges
4. Ingen MFA          ->  passordet alene gir admin
5. Admin              ->  Code Snippets  ->  vilkårlig PHP på serveren
```

Funn: <Severity level="high" /> for e-postforfalskningen, <Severity level="medium" />
for brukerenumerering og manglende MFA hver for seg. Den patchede WordPress-siden
ble aldri brutt – kjeden går via identitet og menneske.

<Callout type="warning">
  Et nettsted kan være teknisk solid og likevel være enkelt å ta over, hvis
  e-postdomenet kan forfalskes og kontoene mangler MFA. Web-skanneren ser ikke
  den kjeden.
</Callout>

## Hva jeg lærte

- **Ikke stopp på web-laget.** Den beste veien inn var DNS og e-post, ikke en
  plugin-CVE. Sjekk alltid SPF/DKIM/DMARC som en del av en webtest.
- **`p=none` er ikke «DMARC er på».** Det er overvåkning. Uten enforcement og DKIM
  er domenet spoofbart.
- **Brukerenumerering er drivstoff.** Et lekket brukernavn og en e-postadresse gjør
  phishing presist.
- **MFA er det billigste laget som faktisk stopper kjeden.** Hadde det vært påtvunget,
  stoppet et fanget passord ved andre faktor.
- **La AI gjøre sweepene, ta selv vurderingen.** AI-en fant de tekniske trådene fort;
  prioritering, scope-grense (jeg stoppet brute-force) og selve angrepskjeden er
  min vurdering.

## Veien videre

Anbefalingene til kunden var enkle og rimelige: DMARC til `p=quarantine` og deretter
`p=reject`, aktiver DKIM, legg på `rua`-rapportering, påtving MFA på admin, og steng
brukerenumereringen i REST. Det kollapser hele kjeden. Web-laget trengte de knapt å
røre – det var aldri problemet.
