# # $Id: http-sensitive_POSTs.bro,v 1.1 2014/04/24 22:38:20 bro Exp bro $ # # http-sensitive_POSTs.bro - Regular expression matching on POST bodies. # module HTTP; export { redef enum Notice::Type += { ## Sensitive POST seen HTTPSensitivePOST, }; # Regular expression to match (unescaped) POST body global BadPOSTBody = /[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd]|[Pp][Aa][Ss][Ss][Ww][Dd]/ &redef; # Are we just concerned with inbound POSTs? global BadPOSTInboundOnly = F &redef; # Do we only want to see POSTs that returned successful HTTP status codes? global BadPOSTSuccessfulOnly = F &redef; # Maximum size of POST data to process global BadPOSTLength = 512 &redef; } global POST_entities: table[string] of string &default = ""; global POST_requests: table[string] of string; event http_request(c: connection, method: string, original_URI: string, unescaped_URI: string, version: string) &priority=3 { # Is it a POST & one we want to look at if ( method == "POST" && ( ! BadPOSTInboundOnly || Site::is_local_addr(c$id$resp_h) ) ) { # If this a connection we're interested in, record the UID for the conn POST_requests[c$uid] = unescaped_URI; } } # Delete data for a specified connection function POST_cleanup(c: connection) { delete POST_entities[c$uid]; delete POST_requests[c$uid]; } # Process the response code from the server event http_reply(c: connection, version: string, code: count, reason: string) { if (c$uid in POST_requests && BadPOSTSuccessfulOnly) { # If we didn't get an affirmative authentication code, fuggetaboutit if (code < 200 || code > 299) POST_cleanup(c); } } # Process the data posted by the client event http_entity_data(c: connection, is_orig: bool, length: count, data: string) { if (is_orig && c$uid in POST_requests) { if (|POST_entities[c$uid]| + length > BadPOSTLength) POST_cleanup(c); else POST_entities[c$uid] += data; } } # When client all done with POST, raise a notice event http_end_entity(c: connection, is_orig: bool) { if (is_orig && c$uid in POST_requests) { local uentity = unescape_URI(POST_entities[c$uid]); if ( |uentity| <= BadPOSTLength && BadPOSTBody in uentity ) { #print POST_entities[c$uid]; local message=fmt("Request: %s - Data: %s", POST_requests[c$uid], uentity); NOTICE([$note = HTTPSensitivePOST, $conn = c, #$src = c$id$orig_h, $msg = message ]); } } POST_cleanup(c); } # Cleanup of stale records as a safety net event connection_end(c: connection) { POST_cleanup(c); }