Modified the DNS protocol analyzer to add a new parameter to the dns_request event which includes the DNS query in its original case. Added a policy script that will add the original_case to the dns.log file as well. Created new btests to test both.

This commit is contained in:
Ryan Victory 2020-06-17 10:13:04 -05:00
parent 86a75c8ac8
commit 63d99595fe
9 changed files with 73 additions and 14 deletions

View file

@ -0,0 +1,19 @@
##! This script adds the query with its original letter casing
##! to the DNS log.
@load base/protocols/dns/main
module DNS;
export {
redef record Info += {
## Query with original letter casing
original_query: string &log &optional;
};
}
event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count, original_query: string)
{
if ( ! c$dns?$original_query )
c$dns$original_query = original_query;
}

View file

@ -73,6 +73,7 @@
@load protocols/dhcp/sub-opts.zeek @load protocols/dhcp/sub-opts.zeek
@load protocols/dns/auth-addl.zeek @load protocols/dns/auth-addl.zeek
@load protocols/dns/detect-external-names.zeek @load protocols/dns/detect-external-names.zeek
@load protocols/dns/log-original-query-case.zeek
@load protocols/ftp/detect-bruteforcing.zeek @load protocols/ftp/detect-bruteforcing.zeek
@load protocols/ftp/detect.zeek @load protocols/ftp/detect.zeek
@load protocols/ftp/software.zeek @load protocols/ftp/software.zeek

View file

@ -171,7 +171,7 @@ bool DNS_Interpreter::ParseQuestion(DNS_MsgInfo* msg,
u_char name[513]; u_char name[513];
int name_len = sizeof(name) - 1; int name_len = sizeof(name) - 1;
u_char* name_end = ExtractName(data, len, name, name_len, msg_start); u_char* name_end = ExtractName(data, len, name, name_len, msg_start, false);
if ( ! name_end ) if ( ! name_end )
return false; return false;
@ -196,9 +196,16 @@ bool DNS_Interpreter::ParseQuestion(DNS_MsgInfo* msg,
if ( dns_event && ! msg->skip_event ) if ( dns_event && ! msg->skip_event )
{ {
BroString* question_name = BroString* original_name = new BroString(name, name_end - name, true);
new BroString(name, name_end - name, true);
SendReplyOrRejectEvent(msg, dns_event, data, len, question_name); // Downcase the Name to normalize it
for ( u_char* np = name; np < name_end; ++np )
if ( isupper(*np) )
*np = tolower(*np);
BroString* question_name =
new BroString(name, name_end - name, true);
SendReplyOrRejectEvent(msg, dns_event, data, len, question_name, original_name);
} }
else else
{ {
@ -353,9 +360,15 @@ bool DNS_Interpreter::ParseAnswer(DNS_MsgInfo* msg,
return status; return status;
} }
u_char* DNS_Interpreter::ExtractName(const u_char*& data, int& len,
u_char* name, int name_len,
const u_char* msg_start) {
return DNS_Interpreter::ExtractName(data, len, name, name_len, msg_start, true);
}
u_char* DNS_Interpreter::ExtractName(const u_char*& data, int& len, u_char* DNS_Interpreter::ExtractName(const u_char*& data, int& len,
u_char* name, int name_len, u_char* name, int name_len,
const u_char* msg_start) const u_char* msg_start, bool downcase)
{ {
u_char* name_start = name; u_char* name_start = name;
@ -375,9 +388,10 @@ u_char* DNS_Interpreter::ExtractName(const u_char*& data, int& len,
} }
// Convert labels to lower case for consistency. // Convert labels to lower case for consistency.
for ( u_char* np = name_start; np < name; ++np ) if (downcase)
if ( isupper(*np) ) for ( u_char* np = name_start; np < name; ++np )
*np = tolower(*np); if ( isupper(*np) )
*np = tolower(*np);
return name; return name;
} }
@ -1388,7 +1402,8 @@ bool DNS_Interpreter::ParseRR_CAA(DNS_MsgInfo* msg,
void DNS_Interpreter::SendReplyOrRejectEvent(DNS_MsgInfo* msg, void DNS_Interpreter::SendReplyOrRejectEvent(DNS_MsgInfo* msg,
EventHandlerPtr event, EventHandlerPtr event,
const u_char*& data, int& len, const u_char*& data, int& len,
BroString* question_name) BroString* question_name,
BroString* original_name)
{ {
RR_Type qtype = RR_Type(ExtractShort(data, len)); RR_Type qtype = RR_Type(ExtractShort(data, len));
int qclass = ExtractShort(data, len); int qclass = ExtractShort(data, len);
@ -1400,7 +1415,8 @@ void DNS_Interpreter::SendReplyOrRejectEvent(DNS_MsgInfo* msg,
msg->BuildHdrVal(), msg->BuildHdrVal(),
make_intrusive<StringVal>(question_name), make_intrusive<StringVal>(question_name),
val_mgr->Count(qtype), val_mgr->Count(qtype),
val_mgr->Count(qclass) val_mgr->Count(qclass),
make_intrusive<StringVal>(original_name)
); );
} }

View file

@ -240,9 +240,12 @@ protected:
bool ParseAnswer(DNS_MsgInfo* msg, bool ParseAnswer(DNS_MsgInfo* msg,
const u_char*& data, int& len, const u_char* start); const u_char*& data, int& len, const u_char* start);
u_char* ExtractName(const u_char*& data, int& len,
u_char* label, int label_len,
const u_char* msg_start);
u_char* ExtractName(const u_char*& data, int& len, u_char* ExtractName(const u_char*& data, int& len,
u_char* label, int label_len, u_char* label, int label_len,
const u_char* msg_start); const u_char* msg_start, bool downcase);
bool ExtractLabel(const u_char*& data, int& len, bool ExtractLabel(const u_char*& data, int& len,
u_char*& label, int& label_len, u_char*& label, int& label_len,
const u_char* msg_start); const u_char* msg_start);
@ -308,7 +311,7 @@ protected:
const u_char* msg_start); const u_char* msg_start);
void SendReplyOrRejectEvent(DNS_MsgInfo* msg, EventHandlerPtr event, void SendReplyOrRejectEvent(DNS_MsgInfo* msg, EventHandlerPtr event,
const u_char*& data, int& len, const u_char*& data, int& len,
BroString* question_name); BroString* question_name, BroString* original_name);
analyzer::Analyzer* analyzer; analyzer::Analyzer* analyzer;
bool first_message; bool first_message;

View file

@ -34,12 +34,14 @@ event dns_message%(c: connection, is_orig: bool, msg: dns_msg, len: count%);
## ##
## msg: The parsed DNS message header. ## msg: The parsed DNS message header.
## ##
## query: The queried name. ## query: The queried name (normalized to all lowercase).
## ##
## qtype: The queried resource record type. ## qtype: The queried resource record type.
## ##
## qclass: The queried resource record class. ## qclass: The queried resource record class.
## ##
## original_query: The queried name, with the original case kept intact
##
## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_end ## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_end
@ -47,6 +49,7 @@ event dns_message%(c: connection, is_orig: bool, msg: dns_msg, len: count%);
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply ## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_max_queries dns_session_timeout dns_skip_addl ## dns_rejected dns_max_queries dns_session_timeout dns_skip_addl
## dns_skip_all_addl dns_skip_all_auth dns_skip_auth ## dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count, original_query: string%);
event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%); event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%);
## Generated for DNS replies that reject a query. This event is raised if a DNS ## Generated for DNS replies that reject a query. This event is raised if a DNS
@ -63,12 +66,14 @@ event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qcl
## ##
## msg: The parsed DNS message header. ## msg: The parsed DNS message header.
## ##
## query: The queried name. ## query: The queried name (normalized to all lowercase).
## ##
## qtype: The queried resource record type. ## qtype: The queried resource record type.
## ##
## qclass: The queried resource record class. ## qclass: The queried resource record class.
## ##
## original_query: The queried name, with the original case kept intact
##
## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_end ## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_end
@ -76,6 +81,7 @@ event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qcl
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply ## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_request dns_max_queries dns_session_timeout dns_skip_addl ## dns_request dns_max_queries dns_session_timeout dns_skip_addl
## dns_skip_all_addl dns_skip_all_auth dns_skip_auth ## dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_rejected%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count, original_query: string%);
event dns_rejected%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%); event dns_rejected%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%);
## Generated for each entry in the Question section of a DNS reply. ## Generated for each entry in the Question section of a DNS reply.

View file

@ -19,6 +19,7 @@
[2] query: string = mail.patriots.in [2] query: string = mail.patriots.in
[3] qtype: count = 1 [3] qtype: count = 1
[4] qclass: count = 1 [4] qclass: count = 1
[5] original_query: string = mail.patriots.in
1254722767.492060 protocol_confirmation 1254722767.492060 protocol_confirmation
[0] c: connection = [id=[orig_h=10.10.1.4, orig_p=56166/udp, resp_h=10.10.1.1, resp_p=53/udp], orig=[size=34, state=1, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:e0:1c:3c:17:c2], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:1f:33:d9:81:60], start_time=1254722767.49206, duration=0 secs, service={\x0a\x0a}, history=D, uid=CHhAvVGS1DHFjwGM9, tunnel=<uninitialized>, vlan=<uninitialized>, inner_vlan=<uninitialized>, successful=F, dpd=<uninitialized>, dpd_state=<uninitialized>, conn=<uninitialized>, extract_orig=F, extract_resp=F, thresholds=<uninitialized>, dce_rpc=<uninitialized>, dce_rpc_state=<uninitialized>, dce_rpc_backing=<uninitialized>, dhcp=<uninitialized>, dnp3=<uninitialized>, dns=[ts=1254722767.49206, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=10.10.1.4, orig_p=56166/udp, resp_h=10.10.1.1, resp_p=53/udp], proto=udp, trans_id=31062, rtt=<uninitialized>, query=mail.patriots.in, qclass=1, qclass_name=C_INTERNET, qtype=1, qtype_name=A, rcode=<uninitialized>, rcode_name=<uninitialized>, AA=F, TC=F, RD=T, RA=F, Z=0, answers=<uninitialized>, TTLs=<uninitialized>, rejected=F, total_answers=<uninitialized>, total_replies=<uninitialized>, saw_query=F, saw_reply=F], dns_state=[pending_query=[ts=1254722767.49206, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=10.10.1.4, orig_p=56166/udp, resp_h=10.10.1.1, resp_p=53/udp], proto=udp, trans_id=31062, rtt=<uninitialized>, query=mail.patriots.in, qclass=1, qclass_name=C_INTERNET, qtype=1, qtype_name=A, rcode=<uninitialized>, rcode_name=<uninitialized>, AA=F, TC=F, RD=T, RA=F, Z=0, answers=<uninitialized>, TTLs=<uninitialized>, rejected=F, total_answers=<uninitialized>, total_replies=<uninitialized>, saw_query=F, saw_reply=F], pending_queries=<uninitialized>, pending_replies=<uninitialized>], ftp=<uninitialized>, ftp_data_reuse=F, ssl=<uninitialized>, http=<uninitialized>, http_state=<uninitialized>, irc=<uninitialized>, krb=<uninitialized>, modbus=<uninitialized>, mysql=<uninitialized>, ntlm=<uninitialized>, ntp=<uninitialized>, radius=<uninitialized>, rdp=<uninitialized>, rfb=<uninitialized>, sip=<uninitialized>, sip_state=<uninitialized>, snmp=<uninitialized>, smb_state=<uninitialized>, smtp=<uninitialized>, smtp_state=<uninitialized>, socks=<uninitialized>, ssh=<uninitialized>, syslog=<uninitialized>] [0] c: connection = [id=[orig_h=10.10.1.4, orig_p=56166/udp, resp_h=10.10.1.1, resp_p=53/udp], orig=[size=34, state=1, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:e0:1c:3c:17:c2], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:1f:33:d9:81:60], start_time=1254722767.49206, duration=0 secs, service={\x0a\x0a}, history=D, uid=CHhAvVGS1DHFjwGM9, tunnel=<uninitialized>, vlan=<uninitialized>, inner_vlan=<uninitialized>, successful=F, dpd=<uninitialized>, dpd_state=<uninitialized>, conn=<uninitialized>, extract_orig=F, extract_resp=F, thresholds=<uninitialized>, dce_rpc=<uninitialized>, dce_rpc_state=<uninitialized>, dce_rpc_backing=<uninitialized>, dhcp=<uninitialized>, dnp3=<uninitialized>, dns=[ts=1254722767.49206, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=10.10.1.4, orig_p=56166/udp, resp_h=10.10.1.1, resp_p=53/udp], proto=udp, trans_id=31062, rtt=<uninitialized>, query=mail.patriots.in, qclass=1, qclass_name=C_INTERNET, qtype=1, qtype_name=A, rcode=<uninitialized>, rcode_name=<uninitialized>, AA=F, TC=F, RD=T, RA=F, Z=0, answers=<uninitialized>, TTLs=<uninitialized>, rejected=F, total_answers=<uninitialized>, total_replies=<uninitialized>, saw_query=F, saw_reply=F], dns_state=[pending_query=[ts=1254722767.49206, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=10.10.1.4, orig_p=56166/udp, resp_h=10.10.1.1, resp_p=53/udp], proto=udp, trans_id=31062, rtt=<uninitialized>, query=mail.patriots.in, qclass=1, qclass_name=C_INTERNET, qtype=1, qtype_name=A, rcode=<uninitialized>, rcode_name=<uninitialized>, AA=F, TC=F, RD=T, RA=F, Z=0, answers=<uninitialized>, TTLs=<uninitialized>, rejected=F, total_answers=<uninitialized>, total_replies=<uninitialized>, saw_query=F, saw_reply=F], pending_queries=<uninitialized>, pending_replies=<uninitialized>], ftp=<uninitialized>, ftp_data_reuse=F, ssl=<uninitialized>, http=<uninitialized>, http_state=<uninitialized>, irc=<uninitialized>, krb=<uninitialized>, modbus=<uninitialized>, mysql=<uninitialized>, ntlm=<uninitialized>, ntp=<uninitialized>, radius=<uninitialized>, rdp=<uninitialized>, rfb=<uninitialized>, sip=<uninitialized>, sip_state=<uninitialized>, snmp=<uninitialized>, smb_state=<uninitialized>, smtp=<uninitialized>, smtp_state=<uninitialized>, socks=<uninitialized>, ssh=<uninitialized>, syslog=<uninitialized>]

View file

@ -0,0 +1,10 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path dns
#open 2020-06-17-14-47-26
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id rtt query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected original_query
#types time string addr port addr port enum count interval string count string count string count string bool bool bool bool count vector[string] vector[interval] bool string
1592402712.248901 CHhAvVGS1DHFjwGM9 192.168.3.138 63374 192.168.3.1 53 udp 20877 - us.v27.distributed.net 1 C_INTERNET 1 A - - F F T F 2 - - F Us.V27.DiStRiBuTeD.NET
#close 2020-06-17-14-47-26

Binary file not shown.

View file

@ -0,0 +1,3 @@
# @TEST-EXEC: zeek -r $TRACES/dns_original_case.pcap %INPUT
# @TEST-EXEC: btest-diff dns.log
@load protocols/dns/log-original-query-case