sdgathman / pyspf

Other
52 stars 26 forks source link

spf.py crash on invalid SPF record, say "ip4:1.2.3.4\010" #15

Closed apircalabu closed 5 years ago

apircalabu commented 5 years ago

Initially submitted to https://bugs.launchpad.net/pypolicyd-spf/+bug/1842005

Aug 30 06:09:43 central1 policyd-spf[29530]: Traceback (most recent call last): Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/bin/policyd-spf", line 809, in Aug 30 06:09:43 central1 policyd-spf[29530]: instance_dict, configData, peruser, peruserconfigData) Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/bin/policyd-spf", line 623, in _spfcheck Aug 30 06:09:43 central1 policyd-spf[29530]: mres = mfromquery.check() Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/lib/python3.4/site-packages/spf.py", line 547, in check Aug 30 06:09:43 central1 policyd-spf[29530]: rc = self.check1(spf, self.d, 0) Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/lib/python3.4/site-packages/spf.py", line 586, in check1 Aug 30 06:09:43 central1 policyd-spf[29530]: return self.check0(spf, recursion) Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/lib/python3.4/site-packages/spf.py", line 906, in check0 Aug 30 06:09:43 central1 policyd-spf[29530]: if self.cidrmatch([arg], cidrlength): break Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/lib/python3.4/site-packages/spf.py", line 1348, in cidrmatch Aug 30 06:09:43 central1 policyd-spf[29530]: for netwrk in [ipaddress.ip_network(ip) for ip in ipaddrs]: Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/lib/python3.4/site-packages/spf.py", line 1348, in Aug 30 06:09:43 central1 policyd-spf[29530]: for netwrk in [ipaddress.ip_network(ip) for ip in ipaddrs]: Aug 30 06:09:43 central1 policyd-spf[29530]: File "/usr/lib64/python3.4/ipaddress.py", line 84, in ip_network Aug 30 06:09:43 central1 policyd-spf[29530]: address) Aug 30 06:09:43 central1 policyd-spf[29530]: ValueError: '119.18.39.164\n' does not appear to be an IPv4 or IPv6 network

The txt record triggers the crash: "v=spf1 ip4:203.143.89.146 ip4:203.27.138.188 ip4:119.18.39.164\010 include:spf.protection.outlook.com ~all"

sdgathman commented 5 years ago

Thanks, this looks like a pretty clear bug. Is the \010 literal? Or is it an octal escape? The first step is a test case in the portable test suite. This will be a doozy!

sdgathman commented 5 years ago

It looks from the traceback like it is a \x0a - i.e. newline. Were it two segments to the TXT record? Or only one?

sdgathman commented 5 years ago

This fails to get the same error - it just gets a permerror like it should.

  badip4:
    description: >-
      Mechanisms are separated by spaces only, not any control char.
    spec: 4.6.1/2
    helo: foobar
    host: 192.0.2.5
    mailfrom: "oops@badip.example.com"
    result: permerror
zonedata:
    badip.example.com:
    - SPF:  "v=spf1 ip4:192.0.2.5\x0a include:spf.protection.outlook.com ~all"
sdgathman commented 5 years ago

So, what version of pyspf are you using? It works fine with that test.

sdgathman commented 5 years ago

Running from CLI:

$ python spf.py -v "v=spf1 ip4:192.0.2.5\n include:spf.protection.outlook.com ~all" 192.0.2.5 oops@badip.example.com foobar
result: ('permerror', 550, 'SPF Permanent Error: Invalid IP4 address: ip4:192.0.2.5\\n') None

This is the correct behavior. I am closing this until the issue can be reproduced.

sdgathman commented 5 years ago

Checked that 2.0.12 also works correctly.

sdgathman commented 5 years ago

I can now reproduce on 2.0.12 with python3:

$ python3 spf.py -v "v=spf1 ip4:192.0.2.1 ip4:192.0.2.3 ip4:192.0.2.5
 include:spf.protection.outlook.com ~all" 192.0.2.5 oops@badip.example.com foobar
Traceback (most recent call last):
  File "spf.py", line 1954, in <module>
    r = q.check(argv[0])
  File "spf.py", line 574, in check
    rc = self.check1(spf, self.d, 0)
  File "spf.py", line 613, in check1
    return self.check0(spf, recursion)
  File "spf.py", line 933, in check0
    if self.cidrmatch([arg], cidrlength): break
  File "spf.py", line 1376, in cidrmatch
    for netwrk in [ipaddress.ip_network(ip) for ip in ipaddrs]:
  File "spf.py", line 1376, in <listcomp>
    for netwrk in [ipaddress.ip_network(ip) for ip in ipaddrs]:
  File "/usr/lib64/python3.7/ipaddress.py", line 84, in ip_network
    address)
ValueError: '192.0.2.5\n' does not appear to be an IPv4 or IPv6 network

Python2 and 2.0.13 are ok. I'll make sure the test case reproduces on 2.0.12, but otherwise this is fixed in new version.

sdgathman commented 5 years ago

I confirmed that the test case added reproduces the issue for 2.0.12. @apircalabu Thanks for the test case! It it is good one. Maybe it will trip up some other implementations.

apircalabu commented 5 years ago

@sdgathman I was using 2.0.12, now upgraded to 2.0.13. However, I can't replicate the crash from cli on 2.0.12, the backslash always gets excaped :( $ python3 spf.py 'v=spf1 ip4:192.0.2.1 ip4:192.0.2.3 ip4:192.0.2.5\010 include:spf.protection.outlook.com ~all' 192.0.2.5 oops@badip.example.com foobar result: ('permerror', 550, 'SPF Permanent Error: Invalid IP4 address: ip4:192.0.2.5\010') None $ python3 -V Python 3.4.3

sdgathman commented 5 years ago

I couldn't remember the bash syntax for inserting an actual newline via backslash - so I just pressed enter within the quotes to insert the newline for cli. The test case uses yaml syntax, which is like python.

apircalabu commented 5 years ago

Ah of course :) Can now confirm the issue for 2.0.12 and the fix in 2.0.13. Any chance to have the fix pulled via pip?

sdgathman commented 5 years ago

I uploaded a 2.0.13 release to pypi - I don't use pip, so don't know if it works.