‘LibSPF2 DNS TXT Record Parsing Bug’
Summary
‘
Credit:
‘The information has been provided by Dan Kaminsky.’
Details
‘Vulnerable Systems:
* libSPF2 version 1.2.5
Immune Systems:
* libSPF2 version 1.2.8
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 = ‘