Fixed some problems with the SOCKS analyzer and tests.

This commit is contained in:
Seth Hall 2012-06-20 22:57:46 -04:00
parent f59736cb17
commit 6b8b4dab71
9 changed files with 63 additions and 71 deletions

View file

@ -202,8 +202,9 @@ signature dpd_socks5_client {
signature dpd_socks5_server { signature dpd_socks5_server {
ip-proto == tcp ip-proto == tcp
requires-reverse-signature dpd_socks5_client requires-reverse-signature dpd_socks5_client
# Watch for a single authentication method to be chosen by the server. # Watch for a single authentication method to be chosen by the server or
payload /^\x05\x01[\x00\x01\x02]/ # the server to indicate the no authentication is required.
payload /^\x05(\x00|\x01[\x00\x01\x02])/
tcp-state responder tcp-state responder
enable "socks" enable "socks"
} }

View file

@ -2402,6 +2402,17 @@ type bittorrent_benc_dir: table[string] of bittorrent_benc_value;
## bt_tracker_response_not_ok ## bt_tracker_response_not_ok
type bt_tracker_headers: table[string] of string; type bt_tracker_headers: table[string] of string;
module SOCKS;
export {
## This record is for a SOCKS client or server to provide either a
## name or an address to represent a desired or established connection.
type Address: record {
host: addr &optional;
name: string &optional;
} &log;
}
module GLOBAL;
@load base/event.bif @load base/event.bif
## BPF filter the user has set via the -f command line options. Empty if none. ## BPF filter the user has set via the -f command line options. Empty if none.

View file

@ -17,16 +17,12 @@ export {
user: string &log &optional; user: string &log &optional;
## Server status for the attempt at using the proxy. ## Server status for the attempt at using the proxy.
status: string &log &optional; status: string &log &optional;
## Client requested address. Mutually exclusive with req_name. ## Client requested SOCKS address. Could be an address, a name or both.
req_h: addr &log &optional; request: SOCKS::Address &log &optional;
## Client requested domain name. Mutually exclusive with req_h.
req_name: string &log &optional;
## Client requested port. ## Client requested port.
req_p: port &log &optional; request_p: port &log &optional;
## Server bound address. Mutually exclusive with bound_name. ## Server bound address. Could be an address, a name or both.
bound_h: addr &log &optional; bound: SOCKS::Address &log &optional;
## Server bound domain name. Mutually exclusive with bound_h.
bound_name: string &log &optional;
## Server bound port. ## Server bound port.
bound_p: port &log &optional; bound_p: port &log &optional;
}; };
@ -57,15 +53,12 @@ function set_session(c: connection, version: count)
} }
event socks_request(c: connection, version: count, request_type: count, event socks_request(c: connection, version: count, request_type: count,
dstaddr: addr, dstname: string, p: port, user: string) &priority=5 sa: SOCKS::Address, p: port, user: string) &priority=5
{ {
set_session(c, version); set_session(c, version);
if ( dstaddr != [::] ) c$socks$request = sa;
c$socks$req_h = dstaddr; c$socks$request_p = p;
if ( dstname != "" )
c$socks$req_name = dstname;
c$socks$req_p = p;
# Copy this conn_id and set the orig_p to zero because in the case of SOCKS proxies there will # Copy this conn_id and set the orig_p to zero because in the case of SOCKS proxies there will
# be potentially many source ports since a new proxy connection is established for each # be potentially many source ports since a new proxy connection is established for each
@ -75,7 +68,7 @@ event socks_request(c: connection, version: count, request_type: count,
Tunnel::register([$cid=cid, $tunnel_type=Tunnel::SOCKS, $payload_proxy=T]); Tunnel::register([$cid=cid, $tunnel_type=Tunnel::SOCKS, $payload_proxy=T]);
} }
event socks_reply(c: connection, version: count, reply: count, dstaddr: addr, dstname: string, p: port) &priority=5 event socks_reply(c: connection, version: count, reply: count, sa: SOCKS::Address, p: port) &priority=5
{ {
set_session(c, version); set_session(c, version);
@ -84,15 +77,11 @@ event socks_reply(c: connection, version: count, reply: count, dstaddr: addr, ds
else if ( version == 4 ) else if ( version == 4 )
c$socks$status = v4_status[reply]; c$socks$status = v4_status[reply];
if ( dstaddr != [::] ) c$socks$bound = sa;
c$socks$bound_h = dstaddr;
if ( dstname != "" )
c$socks$bound_name = dstname;
c$socks$bound_p = p; c$socks$bound_p = p;
} }
event socks_reply(c: connection, version: count, reply: count, dstaddr: addr, dstname: string, p: port) &priority=-5 event socks_reply(c: connection, version: count, reply: count, sa: SOCKS::Address, p: port) &priority=-5
{ {
Log::write(SOCKS::LOG, c$socks); Log::write(SOCKS::LOG, c$socks);
} }

View file

@ -48,6 +48,8 @@ int tcp_excessive_data_without_further_acks;
RecordType* x509_type; RecordType* x509_type;
RecordType* socks_address;
double non_analyzed_lifetime; double non_analyzed_lifetime;
double tcp_inactivity_timeout; double tcp_inactivity_timeout;
double udp_inactivity_timeout; double udp_inactivity_timeout;
@ -345,6 +347,8 @@ void init_net_var()
x509_type = internal_type("X509")->AsRecordType(); x509_type = internal_type("X509")->AsRecordType();
socks_address = internal_type("SOCKS::Address")->AsRecordType();
non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime"); non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
tcp_inactivity_timeout = opt_internal_double("tcp_inactivity_timeout"); tcp_inactivity_timeout = opt_internal_double("tcp_inactivity_timeout");
udp_inactivity_timeout = opt_internal_double("udp_inactivity_timeout"); udp_inactivity_timeout = opt_internal_double("udp_inactivity_timeout");

View file

@ -51,6 +51,8 @@ extern int tcp_excessive_data_without_further_acks;
extern RecordType* x509_type; extern RecordType* x509_type;
extern RecordType* socks_address;
extern double non_analyzed_lifetime; extern double non_analyzed_lifetime;
extern double tcp_inactivity_timeout; extern double tcp_inactivity_timeout;
extern double udp_inactivity_timeout; extern double udp_inactivity_timeout;

View file

@ -6112,7 +6112,7 @@ event signature_match%(state: signature_state, msg: string, data: string%);
## p: The destination port for the proxied traffic. ## p: The destination port for the proxied traffic.
## ##
## user: Username given for the SOCKS connection. This is not yet implemented for SOCKSv5. ## user: Username given for the SOCKS connection. This is not yet implemented for SOCKSv5.
event socks_request%(c: connection, version: count, request_type: count, dstaddr: addr, dstname: string, p: port, user: string%); event socks_request%(c: connection, version: count, request_type: count, sa: SOCKS::Address, p: port, user: string%);
## Generated when a SOCKS reply is analyzed. ## Generated when a SOCKS reply is analyzed.
## ##
@ -6127,7 +6127,7 @@ event socks_request%(c: connection, version: count, request_type: count, dstaddr
## dstname: The name the server sent the traffic to. Only applicable for SOCKSv5. ## dstname: The name the server sent the traffic to. Only applicable for SOCKSv5.
## ##
## p: The destination port for the proxied traffic. ## p: The destination port for the proxied traffic.
event socks_reply%(c: connection, version: count, reply: count, dstaddr: addr, dstname: string, p: port%); event socks_reply%(c: connection, version: count, reply: count, sa: SOCKS::Address, p: port%);
## Generated when a protocol analyzer finds an identification of a software ## Generated when a protocol analyzer finds an identification of a software
## used on a system. This is a protocol-independent event that is fed by ## used on a system. This is a protocol-independent event that is fed by

View file

@ -22,19 +22,16 @@ refine connection SOCKS_Conn += {
function socks4_request(request: SOCKS4_Request): bool function socks4_request(request: SOCKS4_Request): bool
%{ %{
RecordVal* sa = new RecordVal(socks_address);
StringVal *dstname = 0; sa->Assign(0, new AddrVal(htonl(${request.addr})));
if ( ${request.v4a} ) if ( ${request.v4a} )
dstname = array_to_string(${request.name}); sa->Assign(1, array_to_string(${request.name}));
else
dstname = new StringVal("");
BifEvent::generate_socks_request(bro_analyzer(), BifEvent::generate_socks_request(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
4, 4,
${request.command}, ${request.command},
new AddrVal(htonl(${request.addr})), sa,
dstname,
new PortVal(${request.port} | TCP_PORT_MASK), new PortVal(${request.port} | TCP_PORT_MASK),
array_to_string(${request.user})); array_to_string(${request.user}));
@ -45,12 +42,14 @@ refine connection SOCKS_Conn += {
function socks4_reply(reply: SOCKS4_Reply): bool function socks4_reply(reply: SOCKS4_Reply): bool
%{ %{
RecordVal* sa = new RecordVal(socks_address);
sa->Assign(0, new AddrVal(htonl(${reply.addr})));
BifEvent::generate_socks_reply(bro_analyzer(), BifEvent::generate_socks_reply(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
4, 4,
${reply.status}, ${reply.status},
new AddrVal(htonl(${reply.addr})), sa,
new StringVal(""),
new PortVal(${reply.port} | TCP_PORT_MASK)); new PortVal(${reply.port} | TCP_PORT_MASK));
bro_analyzer()->ProtocolConfirmation(); bro_analyzer()->ProtocolConfirmation();
@ -66,23 +65,22 @@ refine connection SOCKS_Conn += {
return false; return false;
} }
AddrVal *ip_addr = 0; RecordVal* sa = new RecordVal(socks_address);
StringVal *domain_name = 0;
// This is dumb and there must be a better way (checking for presence of a field)... // This is dumb and there must be a better way (checking for presence of a field)...
switch ( ${request.remote_name.addr_type} ) switch ( ${request.remote_name.addr_type} )
{ {
case 1: case 1:
ip_addr = new AddrVal(htonl(${request.remote_name.ipv4})); sa->Assign(0, new AddrVal(htonl(${request.remote_name.ipv4})));
break; break;
case 3: case 3:
domain_name = new StringVal(${request.remote_name.domain_name.name}.length(), sa->Assign(1, new StringVal(${request.remote_name.domain_name.name}.length(),
(const char*) ${request.remote_name.domain_name.name}.data()); (const char*) ${request.remote_name.domain_name.name}.data()));
break; break;
case 4: case 4:
ip_addr = new AddrVal(IPAddr(IPv6, (const uint32_t*) ${request.remote_name.ipv6}, IPAddr::Network)); sa->Assign(0, new AddrVal(IPAddr(IPv6, (const uint32_t*) ${request.remote_name.ipv6}, IPAddr::Network)));
break; break;
default: default:
@ -91,17 +89,11 @@ refine connection SOCKS_Conn += {
break; break;
} }
if ( ! ip_addr )
ip_addr = new AddrVal(uint32(0));
if ( ! domain_name )
domain_name = new StringVal("");
BifEvent::generate_socks_request(bro_analyzer(), BifEvent::generate_socks_request(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
5, 5,
${request.command}, ${request.command},
ip_addr, sa,
domain_name,
new PortVal(${request.port} | TCP_PORT_MASK), new PortVal(${request.port} | TCP_PORT_MASK),
new StringVal("")); new StringVal(""));
@ -112,23 +104,22 @@ refine connection SOCKS_Conn += {
function socks5_reply(reply: SOCKS5_Reply): bool function socks5_reply(reply: SOCKS5_Reply): bool
%{ %{
AddrVal *ip_addr = 0; RecordVal* sa = new RecordVal(socks_address);
StringVal *domain_name = 0;
// This is dumb and there must be a better way (checking for presence of a field)... // This is dumb and there must be a better way (checking for presence of a field)...
switch ( ${reply.bound.addr_type} ) switch ( ${reply.bound.addr_type} )
{ {
case 1: case 1:
ip_addr = new AddrVal(htonl(${reply.bound.ipv4})); sa->Assign(0, new AddrVal(htonl(${reply.bound.ipv4})));
break; break;
case 3: case 3:
domain_name = new StringVal(${reply.bound.domain_name.name}.length(), sa->Assign(1, new StringVal(${reply.bound.domain_name.name}.length(),
(const char*) ${reply.bound.domain_name.name}.data()); (const char*) ${reply.bound.domain_name.name}.data()));
break; break;
case 4: case 4:
ip_addr = new AddrVal(IPAddr(IPv6, (const uint32_t*) ${reply.bound.ipv6}, IPAddr::Network)); sa->Assign(0, new AddrVal(IPAddr(IPv6, (const uint32_t*) ${reply.bound.ipv6}, IPAddr::Network)));
break; break;
default: default:
@ -137,17 +128,11 @@ refine connection SOCKS_Conn += {
break; break;
} }
if ( ! ip_addr )
ip_addr = new AddrVal(uint32(0));
if ( ! domain_name )
domain_name = new StringVal("");
BifEvent::generate_socks_reply(bro_analyzer(), BifEvent::generate_socks_reply(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
5, 5,
${reply.reply}, ${reply.reply},
ip_addr, sa,
domain_name,
new PortVal(${reply.port} | TCP_PORT_MASK)); new PortVal(${reply.port} | TCP_PORT_MASK));
bro_analyzer()->ProtocolConfirmation(); bro_analyzer()->ProtocolConfirmation();

View file

@ -3,6 +3,6 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path socks #path socks
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user status req_h req_name req_p bound_h bound_name bound_p #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user status request.host request.name request_p bound.host bound.name bound_p
#types time string addr port addr port count string string addr string port addr string port #types time string addr port addr port count string string addr string port addr string port
1340213015.276495 UWkUyAuUGXf 10.0.0.55 53994 60.190.189.214 8124 5 - succeeded - www.osnews.com 80 192.168.0.31 - 2688 1340213015.276495 UWkUyAuUGXf 10.0.0.55 53994 60.190.189.214 8124 5 - succeeded - www.osnews.com 80 192.168.0.31 - 2688

View file

@ -3,6 +3,6 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path socks #path socks
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user status req_h req_name req_p bound_h bound_name bound_p #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user status request.host request.name request_p bound.host bound.name bound_p
#types time string addr port addr port count string string addr string port addr string port #types time string addr port addr port count string string addr string port addr string port
1340113261.914619 UWkUyAuUGXf 10.0.0.50 59580 85.194.84.197 1080 5 - succeeded - www.google.com 443 0.0.0.0 - 443 1340113261.914619 UWkUyAuUGXf 10.0.0.50 59580 85.194.84.197 1080 5 - succeeded - www.google.com 443 0.0.0.0 - 443