How to bypass DNS-based spam-filters using DNS
I've been sitting on this one since more than a month. I've contacted upstream on the 19.08.2010 and the Debian maintainer on the 02.09.2010. No reaction from them till today, and no, my spamfilter does not eat mail ;) Still, I won't tell you the name of the software (but you could easily guess or check...) So let's put the grey hat on and begin ;) Foreword: when I write spam-filter, I mean some DNSBL/SPF/blah filter, not SpamAssassin, crm114 or other content-based filters.
common spam-filters
There are plenty of spam-filters out there which work after the following schema:for check in checks: if check(mail) == BAD: reject(mail) breakAnd the checks often look like this:
def check(mail): errors = False result = some_magic(mail) if not errors: return result else: return GOODHere
some_magic
is a function that do the actual checks (DNSBL lookups etc) and which stores possible happened errors in errors
. If an error occurred, it's safer to say the mail was good (or at least not bad) than bad.
the problem
This looks like a sane approach on the first sight: iterate over all checks and execute them until a mail is found to be spam (and the corresponding check did not end up in an error (imagine some weird DNS error for DNSBL or SPF checks here)). But then the author realizes that the errors might be "global", like with DNS: when the first check notices that it can't resolve anything (ie. it ran into a DNS timeout three times in a row), the second check (which also utilizes DNS queries) will most probably result in an error too. After this he adds a global counter for DNS errors and skips all the checks that use DNS if this counter is >=3. "Great idea", you say, "saving resources is good". "Bad idea", I say... The reason is simple: DNSError != DNSError. Why? The local resolver might be broken, then every DNS query will end up with an error and DNS-based checks should be really disabled. The first three (out of eg. ten) DNSBLs might be down, but that's not a reason to skip the other seven and the SPF check. Etc... Now let's assume all configured DNSBLs are working properly, so is the local resolver and the checks are:checks = [check_HELO, check_SPF, check_DNSBL]How could one attack this filter?
the attack
Set up the following zonespam.example.com IN NS ns1.example.com spam.example.com IN NS ns2.example.com spam.example.com IN NS ns3.example.com spam2.example.com IN MX mx1.spam.example.com spam2.example.com IN MX mx2.spam.example.com spam2.example.com IN MX mx3.spam.example.com spam2.example.com IN MX mx4.spam.example.com ns1.example.com IN A 10.1.1.1 ns2.example.com IN A 10.2.2.2 ns3.example.com IN A 10.3.3.3and greet the to-be-spammed-MTA with
EHLO client1.spam.example.com
What happens? The spam-filter tries to resolve client1.spam.example.com in check_HELO to check whether the hostname matches the IP-address the connection is coming from, fails three times (there are no reachable DNS servers in 10.0.0.0/8) and continues with the next two checks, but these are skipped because of previous DNS errors. As no checks could identify the mail as being spam, the mail is delivered to the users mailbox.
With some creativity this can also be used in SPF records (via spam2.example.com
), sender-domains etc.
Comments