##! Identify suspicious POSTs that may indicate malware beaconing/data exfil @load httpsetup module SuspiciousPost; export { redef enum Log::ID += { LOG }; type Info: record { ctype: bool &log &default=F; ref: bool &log &default=F; is_ip: bool &log &default=F; post_host: string &log &default=""; msg: string &log &default="Normal POST"; }; global log_suspciousposts: event(rec: Info); } # let in for documentation so maybe I'll remember how to do this in the future #redef record HTTP::Info += { # is_post: bool &default=F; #}; event bro_init() { Log::create_stream(SuspiciousPost::LOG, [$columns=Info, $ev=log_suspciousposts]); } event HTTP::http_all_headers(c: connection, is_orig: bool, hlist: mime_header_list) &priority=0 { if ( !is_orig ) return; if ( c$http$method != "POST" ) return; local p: Info; # p$ctype = F; # p$ref = F; # p$is_ip = F; # p$post_host = ""; # p$msg = "Normal Post"; for ( i in hlist ) { if ( hlist[i]$name == "HOST" ) { if ( /[0-9]{0,3}\.[0-9]{0,3}\.[0-9]{0,3}\.[0-9]{0,3}/ in hlist[i]$value ) { p$is_ip = T; } p$post_host = hlist[i]$value; } if ( hlist[i]$name == "CONTENT-TYPE" ) { p$ctype = T; } if ( hlist[i]$name == "REFERER" ) { p$ref = T; } } if ( p$is_ip && !p$ctype && !p$ref ) p$msg = "Highly Suspicious POST"; if ( p$is_ip && !p$ctype && p$ref ) p$msg = "Suspicious POST without referer"; if ( p$is_ip && !p$ctype && p$ref ) p$msg = "Suspicious POST without content-type"; if ( !p$is_ip && p$ctype && p$ref ) p$msg = "Suspicious POST"; Log::write(SuspiciousPost::LOG, p); }