root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat easy-phish.md
// writeups

Easy Phish

26 Jul 2019 · 7 min read
Easy Phish — HTB challenge
Customers of secure-startup.com are getting hit with convincing phishing emails. Instead of chasing the phishing kit itself, the challenge asks a more useful question: why does spoofed mail from this domain sail through in the first place? The answer — and the flag, split in two — is sitting in plain sight in the domain's own SPF and DMARC DNS records.

Challenge overview

FieldValue
PlatformHack The Box · Challenge
CategoryOSINT / DNS
DifficultyEasy
StateRetired
Targetsecure-startup.com

Attack map

[Recon] secure-startup.com
      │
      ▼
[dig TXT] SPF record  →  "v=spf1 a mx ?all - HTB{RIP_SPF_Always_2nd"
      │
      ▼
[flag part 1] HTB{RIP_SPF_Always_2nd
      │
      ▼
[dig _dmarc TXT] DMARC record  →  "v=DMARC1;p=none;_F1ddl3_2_DMARC}"
      │
      ▼
[flag part 2] _F1ddl3_2_DMARC}
      │
      ▼
[FLAG] HTB{RIP_SPF_Always_2nd_F1ddl3_2_DMARC}

1. Reading the scenario

The prompt isn't "find a vulnerable server," it's a mail-authentication audit: employees at secure-startup.com are being phished with emails that look legitimate. That framing is the actual hint — the weakness isn't a server or a login form, it's how the domain tells the rest of the internet who is allowed to send mail on its behalf. That's exactly what the SPF and DMARC DNS records are for, so the whole challenge lives in dig queries against those two record types.

2. Why SPF and DMARC matter

SPF (Sender Policy Framework) is a TXT record that lists which mail servers/IP ranges are authorized to send email "from" a domain. Receiving mail servers check the SPF record against the sender's IP; if it doesn't match, the message fails SPF. Crucially, SPF's verdict on a failed check is configurable via the qualifier in front of the mechanism: -all (hard fail — reject), ~all (soft fail — accept but flag/quarantine), or ?all (neutral — no real policy at all, the check might as well not exist).

DMARC (Domain-based Message Authentication, Reporting & Conformance) sits on top of SPF and DKIM. It tells receiving servers what to actually do when a message fails alignment — p=none (do nothing, just report), p=quarantine (send to spam), or p=reject (drop it). A domain can have a perfectly formed SPF record and still be trivially spoofable if its DMARC policy is p=none, because p=none means "monitor only, take no enforcement action."

3. Query the SPF record

SPF is published as a plain TXT record on the domain's apex. A standard dig query against the domain, restricted to TXT records, is enough — no zone transfer, no brute force, nothing exotic.
dig secure-startup.com TXT
secure-startup.com. 1800 IN TXT "v=spf1 a mx ?all - HTB{RIP_SPF_Always_2nd"

4. Read the SPF record and pull the first fragment

Parsing the record: v=spf1 declares the SPF version, a and mx authorize the domain's own A and MX hosts to send mail, and ?all is the qualifier for everything else — neutral, i.e. "no opinion." An SPF record ending in ?all provides essentially zero anti-spoofing protection: any server not covered by a/mx is neither explicitly allowed nor rejected, so a filter has nothing solid to act on. That misconfiguration is precisely why the challenge hides the first half of the flag right there, appended after the SPF policy string:
HTB{RIP_SPF_Always_2nd

5. Query the DMARC record

DMARC policies are published as a TXT record on the reserved _dmarc subdomain, not the domain apex. Same tool, different name.
dig _dmarc.secure-startup.com TXT
_dmarc.secure-startup.com. 1232 IN TXT "v=DMARC1;p=none;_F1ddl3_2_DMARC}"

6. Read the DMARC record and pull the second fragment

v=DMARC1 declares the DMARC version, and p=none is the policy applied to messages that fail SPF/DKIM alignment: do nothing, just observe. Combined with the neutral SPF from step 4, this domain has effectively no enforced email-authentication policy at all — SPF doesn't hard-fail unauthorized senders, and DMARC doesn't act even when alignment fails. That's the root cause the challenge is pointing at: this is exactly the kind of domain whose name a phishing kit would spoof, because nothing downstream stops it. The second half of the flag is appended right after the policy:
_F1ddl3_2_DMARC}

7. Assemble the flag

Concatenating the two fragments recovered from the SPF and DMARC TXT records in order gives the complete flag.
HTB{RIP_SPF_Always_2nd_F1ddl3_2_DMARC}

Investigation summary

PhaseComponentVulnerabilityImpact
DNS enumerationSPF (TXT record, apex)Neutral qualifier (?all) — no enforcement for unauthorized sendersAny server can send mail claiming to be from the domain without failing SPF outright; flag part 1 exposed
DNS enumerationDMARC (TXT record, _dmarc subdomain)Monitor-only policy (p=none) — no quarantine/reject on failed alignmentSpoofed mail that fails authentication is still delivered; flag part 2 exposed

Lessons learned

  • SPF and DMARC records are public DNS data — a simple dig TXT against the domain and against _dmarc.<domain> reveals the entire email-authentication posture without touching a single mail server.
  • An SPF qualifier of ?all (or even ~all) is functionally close to having no SPF at all from an anti-spoofing standpoint; only -all enforces a hard fail.
  • DMARC's p=none is a monitoring mode, not a defense — it exists so domain owners can collect aggregate reports (rua/ruf tags) before safely moving to p=quarantine and eventually p=reject.
  • SPF and DMARC alone are not enough: DKIM (cryptographic signing) provides the alignment check that DMARC actually enforces against; a domain missing any one of the three legs of SPF/DKIM/DMARC is meaningfully easier to spoof.
  • This is also why real phishing works even against companies that "have security": misconfigured or half-adopted email-authentication records are common, and attackers actively scan for exactly the ?all / p=none combination seen here before spoofing a domain.