Update the SOCKS analyzer to support user/pass login.

- This addresses BIT-1011
 - Add a new field to socks.log; "password".
 - Two new events; socks_login_userpass and socks_login_reply.
 - One new weird for unsupported authentication method.
 - A new test for authenticated socks traffic.
 - Credit to Nicolas Retrain for the initial patch.  Thanks!
This commit is contained in:
Seth Hall 2015-02-05 12:44:10 -05:00
parent 565ad360c6
commit 9592f64225
11 changed files with 162 additions and 21 deletions

View file

@ -16,8 +16,10 @@ export {
id: conn_id &log;
## Protocol version of SOCKS.
version: count &log;
## Username for the proxy if extracted from the network.
## Username used to request a login to the proxy.
user: string &log &optional;
## Password used to request a login to the proxy.
password: string &log &optional;
## Server status for the attempt at using the proxy.
status: string &log &optional;
## Client requested SOCKS address. Could be an address, a name
@ -91,3 +93,21 @@ event socks_reply(c: connection, version: count, reply: count, sa: SOCKS::Addres
if ( "SOCKS" in c$service )
Log::write(SOCKS::LOG, c$socks);
}
event socks_login_userpass(c: connection, user: string, password: string) &priority=5
{
# Authentication only possible with the version 5.
set_session(c, 5);
c$socks$user = user;
c$socks$password = password;
}
event socks_login_reply(c: connection, code: count) &priority=5
{
# Authentication only possible with the version 5.
set_session(c, 5);
c$socks$status = v5_status[code];
}

View file

@ -57,8 +57,7 @@ void SOCKS_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
// with the rest of the conneciton.
//
// Note that we assume that no payload data arrives before both endpoints
// are done with there part of the SOCKS protocol.
// are done with their part of the SOCKS protocol.
if ( ! pia )
{
pia = new pia::PIA_TCP(Conn());

View file

@ -27,3 +27,19 @@ event socks_request%(c: connection, version: count, request_type: count, sa: SOC
## p: The destination port for the proxied traffic.
event socks_reply%(c: connection, version: count, reply: count, sa: SOCKS::Address, p: port%);
## Generated when a SOCKS client performs username and password based login.
##
## c: The parent connection of the proxy.
##
## user: The given username.
##
## password: The given password.
event socks_login_userpass%(c: connection, user: string, password: string%);
## Generated when a SOCKS server replies to a login attempt.
##
## c: The parent connection of the proxy.
##
## code: The response code for the attempted login.
event socks_login_reply%(c: connection, code: count%);

View file

@ -148,6 +148,31 @@ refine connection SOCKS_Conn += {
return true;
%}
function socks5_auth_request_userpass(request: SOCKS5_Auth_Request_UserPass): bool
%{
StringVal* user = new StringVal(${request.username}.length(), (const char*) ${request.username}.begin());
StringVal* pass = new StringVal(${request.password}.length(), (const char*) ${request.password}.begin());
BifEvent::generate_socks_login_userpass(bro_analyzer(),
bro_analyzer()->Conn(),
user, pass);
return true;
%}
function socks5_unsupported_authentication(auth_method: uint8): bool
%{
reporter->Weird(bro_analyzer()->Conn(), fmt("socks5_unsupported_authentication_%d", auth_method));
return true;
%}
function socks5_auth_reply(reply: SOCKS5_Auth_Reply): bool
%{
BifEvent::generate_socks_login_reply(bro_analyzer(),
bro_analyzer()->Conn(),
${reply.code});
return true;
%}
function version_error(version: uint8): bool
%{
bro_analyzer()->ProtocolViolation(fmt("unsupported/unknown SOCKS version %d", version));
@ -176,3 +201,18 @@ refine typeattr SOCKS5_Request += &let {
refine typeattr SOCKS5_Reply += &let {
proc: bool = $context.connection.socks5_reply(this);
};
refine typeattr SOCKS5_Auth_Negotiation_Reply += &let {
};
refine typeattr SOCKS5_Auth_Request_UserPass += &let {
proc: bool = $context.connection.socks5_auth_request_userpass(this);
};
refine typeattr SOCKS5_Auth_Reply += &let {
proc: bool = $context.connection.socks5_auth_reply(this);
};
refine typeattr SOCKS5_Unsupported_Authentication += &let {
proc: bool = $context.connection.socks5_unsupported_authentication($context.connection.v5_auth_method());
};

View file

@ -2,9 +2,10 @@
type SOCKS_Version(is_orig: bool) = record {
version: uint8;
msg: case version of {
4 -> socks4_msg: SOCKS4_Message(is_orig);
5 -> socks5_msg: SOCKS5_Message(is_orig);
default -> socks_msg_fail: SOCKS_Version_Error(version);
1 -> socks5_auth_msg: SOCKS5_Auth_Message(is_orig);
4 -> socks4_msg: SOCKS4_Message(is_orig);
5 -> socks5_msg: SOCKS5_Message(is_orig);
default -> socks_msg_fail: SOCKS_Version_Error(version);
};
};
@ -14,10 +15,11 @@ type SOCKS_Version_Error(version: uint8) = record {
# SOCKS5 Implementation
type SOCKS5_Message(is_orig: bool) = case $context.connection.v5_past_authentication() of {
true -> msg: SOCKS5_Real_Message(is_orig);
false -> auth: SOCKS5_Auth_Negotiation(is_orig);
true -> msg: SOCKS5_Real_Message(is_orig);
};
type SOCKS5_Auth_Negotiation(is_orig: bool) = case is_orig of {
true -> req: SOCKS5_Auth_Negotiation_Request;
false -> rep: SOCKS5_Auth_Negotiation_Reply;
@ -32,6 +34,32 @@ type SOCKS5_Auth_Negotiation_Reply = record {
selected_auth_method: uint8;
} &let {
past_auth = $context.connection.set_v5_past_authentication();
set_auth = $context.connection.set_v5_auth_method(selected_auth_method);
};
type SOCKS5_Auth_Message(is_orig: bool) = case is_orig of {
true -> req: SOCKS5_Auth_Request;
false -> rep: SOCKS5_Auth_Reply;
};
type SOCKS5_Auth_Request = case $context.connection.v5_auth_method() of {
0x02 -> userpass : SOCKS5_Auth_Request_UserPass;
default -> unsupported : SOCKS5_Unsupported_Authentication;
};
type SOCKS5_Unsupported_Authentication = record {
crap: bytestring &restofdata;
};
type SOCKS5_Auth_Request_UserPass = record {
ulen : uint8;
username : bytestring &length=ulen;
plen : uint8;
password : bytestring &length=plen;
};
type SOCKS5_Auth_Reply = record {
code : uint8;
};
type SOCKS5_Real_Message(is_orig: bool) = case is_orig of {
@ -55,10 +83,10 @@ type SOCKS5_Address = record {
} &byteorder = bigendian;
type SOCKS5_Request = record {
command: uint8;
reserved: uint8;
remote_name: SOCKS5_Address;
port: uint16;
command : uint8;
reserved : uint8;
remote_name : SOCKS5_Address;
port : uint16;
} &byteorder = bigendian;
type SOCKS5_Reply = record {
@ -99,10 +127,12 @@ type SOCKS4_Reply = record {
refine connection SOCKS_Conn += {
%member{
bool v5_authenticated_;
uint8 selected_auth_method_;
%}
%init{
v5_authenticated_ = false;
selected_auth_method_ = 255;
%}
function v5_past_authentication(): bool
@ -115,5 +145,16 @@ refine connection SOCKS_Conn += {
v5_authenticated_ = true;
return true;
%}
function set_v5_auth_method(method: uint8): bool
%{
selected_auth_method_ = method;
return true;
%}
function v5_auth_method(): uint8
%{
return selected_auth_method_;
%}
};

View file

@ -0,0 +1,10 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path socks
#open 2015-02-05-16-13-12
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user password status request.host request.name request_p bound.host bound.name bound_p
#types time string addr port addr port count string string string addr string port addr string port
1368517392.724989 CXWv6p3arKYeMETxOg 192.168.0.2 55951 192.168.0.1 1080 5 bob alice succeeded 192.168.0.2 - 22 192.168.0.1 - 55951
#close 2015-02-05-16-13-12

View file

@ -0,0 +1,10 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path tunnel
#open 2015-02-05-16-13-12
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action
#types time string addr port addr port enum enum
1368517392.728523 - 192.168.0.2 0 192.168.0.1 1080 Tunnel::SOCKS Tunnel::DISCOVER
#close 2015-02-05-16-13-12

View file

@ -3,8 +3,8 @@
#empty_field (empty)
#unset_field -
#path socks
#open 2013-08-26-19-04-20
#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
1340213015.276495 CjhGID4nQcgTWjvg4c 10.0.0.55 53994 60.190.189.214 8124 5 - succeeded - www.osnews.com 80 192.168.0.31 - 2688
#close 2013-08-26-19-04-20
#open 2015-02-05-17-39-14
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user password status request.host request.name request_p bound.host bound.name bound_p
#types time string addr port addr port count string string string addr string port addr string port
1340213015.276495 CjhGID4nQcgTWjvg4c 10.0.0.55 53994 60.190.189.214 8124 5 - - succeeded - www.osnews.com 80 192.168.0.31 - 2688
#close 2015-02-05-17-39-14

View file

@ -3,8 +3,8 @@
#empty_field (empty)
#unset_field -
#path socks
#open 2013-08-26-19-04-20
#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
1340113261.914619 CXWv6p3arKYeMETxOg 10.0.0.50 59580 85.194.84.197 1080 5 - succeeded - www.google.com 443 0.0.0.0 - 443
#close 2013-08-26-19-04-20
#open 2015-02-05-17-39-29
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version user password status request.host request.name request_p bound.host bound.name bound_p
#types time string addr port addr port count string string string addr string port addr string port
1340113261.914619 CXWv6p3arKYeMETxOg 10.0.0.50 59580 85.194.84.197 1080 5 - - succeeded - www.google.com 443 0.0.0.0 - 443
#close 2015-02-05-17-39-29

Binary file not shown.

View file

@ -0,0 +1,5 @@
# @TEST-EXEC: bro -r $TRACES/socks-auth.pcap %INPUT
# @TEST-EXEC: btest-diff socks.log
# @TEST-EXEC: btest-diff tunnel.log
@load base/protocols/socks