Created
September 14, 2017 18:35
-
-
Save grigorescu/f4275949ffbe2ad540500ced52cf777f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##! A detection script for UDP DoS Flows | |
@load base/protocols/conn | |
module UDPDoS; | |
export { | |
redef enum Notice::Type += { | |
Detected, | |
}; | |
## Number of bytes transferred before marking a connection as bulk | |
const size_threshold = 1024*1024 &redef; #1 megabytes | |
## Time during which we check whether a connection's size exceeds the | |
## :bro:see:`UDPDoS::size_threshold`. | |
const max_time = 2 min &redef; | |
## Raised when a Bulk data channel is detected. | |
## | |
## c: The connection pertaining to the Bulk data channel. | |
global connection_detected: event(c: connection, from: string); | |
## The initial criteria used to determine whether to start polling | |
## the connection for the :bro:see:`Bulk::size_threshold` to have | |
## been exceeded. | |
## c: The connection which may possibly be a Bulk data channel. | |
## | |
## Returns: true if the connection should be further polled for an | |
## exceeded :bro:see:`Bulk::size_threshold`, else false. | |
const dos_initial_criteria: function(c: connection): bool &redef; | |
const AFS_ports: set[port] = {4711/udp, 7000/udp, 7001/udp, 7003/udp}; | |
const dos_ports: set[port] = {19/udp, 53/udp, 69/udp, 111/udp, 123/udp, 161/udp, 520/udp, 1434/udp, 1900/udp} &redef; | |
const run_on_all_ports = F &redef; | |
} | |
function is_bad(c: connection): bool | |
{ | |
local relevant_size = Site::is_local_addr(c$id$orig_h) ? c$orig$num_bytes_ip : c$resp$num_bytes_ip; | |
local other_size = Site::is_local_addr(c$id$orig_h) ? c$resp$num_bytes_ip : c$orig$num_bytes_ip; | |
return (relevant_size > size_threshold && other_size > 100); | |
} | |
event ConnThreshold::bytes_threshold_crossed(c: connection, threshold: count, is_orig: bool) | |
{ | |
if ( dos_initial_criteria(c) && is_bad(c)) { | |
event UDPDoS::connection_detected(c, "threshold"); | |
} | |
} | |
function dos_initial_criteria(c: connection): bool | |
{ | |
local id = c$id; | |
# If we aren't running on all ports, the port must be in dos_ports | |
if (run_on_all_ports == F && !(c$id$orig_p in dos_ports || c$id$resp_p in dos_ports)) { | |
return F; | |
} | |
# We only care about UDP | |
if (get_port_transport_proto(id$resp_p) != udp) { | |
return F; | |
} | |
local local_orig = Site::is_local_addr(id$orig_h); | |
local local_resp = Site::is_local_addr(id$resp_h); | |
# We want inside->out or outside->in | |
if (local_orig == local_resp) { | |
return F; | |
} | |
# But we don't care about RFC1918 address space | |
# Or neighbor nets | |
if (local_orig && (Site::is_private_addr(id$resp_h) || Site::is_neighbor_addr(id$resp_h))) { | |
return F; | |
} | |
if (local_resp && (Site::is_private_addr(id$orig_h) || Site::is_neighbor_addr(id$orig_h))) { | |
return F; | |
} | |
# https://en.wikipedia.org/wiki/QUIC | |
if (local_orig && id$resp_p == 443/udp) { | |
return F; | |
} | |
if (id$orig_p in AFS_ports && id$resp_p in AFS_ports) { | |
return F; | |
} | |
return T; | |
} | |
event udp_dos_timeout(c: connection) | |
{ | |
if (!c?$duration) { | |
ConnThreshold::delete_bytes_threshold(c, size_threshold, F); | |
} | |
} | |
event new_connection(c: connection) &priority=-3 | |
{ | |
if ( dos_initial_criteria(c) ) { | |
ConnThreshold::set_bytes_threshold(c, size_threshold, F); | |
schedule max_time { udp_dos_timeout(c) }; | |
} | |
} | |
event connection_state_remove(c: connection) | |
{ | |
if ( dos_initial_criteria(c) && is_bad(c)) { | |
event UDPDoS::connection_detected(c, "remove"); | |
} | |
} | |
event connection_detected(c: connection, from: string) { | |
local bytes = c$orig$num_bytes_ip + c$resp$num_bytes_ip; | |
local msg = fmt("UDP DoS between %s:%s and %s:%s - orig_bytes=%d resp_bytes=%d from=%s", | |
c$id$orig_h, c$id$orig_p, c$id$resp_h, c$id$resp_p, c$orig$num_bytes_ip, c$resp$num_bytes_ip, from); | |
local ident = cat(c$id$orig_h, "-", c$id$resp_h); | |
NOTICE([$note=Detected, | |
$msg=msg, | |
$conn=c, | |
$identifier=ident, | |
$sub=cat(bytes) | |
]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment