zeek/policy/protocols/http/file-hash.bro

105 lines
3.1 KiB
Text

##! Calculate hashes for HTTP body transfers.
@load http/file-ident
@load notice
module HTTP;
redef enum Notice::Type += {
## Indicates an MD5 sum in Team Cymru's Malware Hash Registry.
## http://www.team-cymru.org/Services/MHR/
HTTP_MHR_Malware,
## Notice type when locally defined MD5 sums are encountered.
HTTP_MD5,
};
export {
redef record Info += {
## The MD5 sum for a file transferred over HTTP will be stored here.
md5: string &log &optional;
## This value can be set per-transfer to determine per request
## if a file should have an MD5 sum generated. It must be
## set to T at the time of or before the first chunk of body data.
calc_md5: bool &default=F;
## This boolean value indicates if an MD5 sum is being calculated
## for the current file transfer.
calculating_md5: bool &default=F;
};
# Generate MD5 sums for these filetypes.
const generate_md5 = /application\/x-dosexec/ # Windows and DOS executables
| /application\/x-executable/ &redef; # *NIX executable binary
# MD5 sums that are "interesting" for your local network.
# The index is the MD5 sum and the yield value is used as the $msg value
# for notices so that you can filter in your local notice policy.
# TODO: this will change to use the intelligence framework.
const interesting_md5: table[string] of string &redef;
}
# Once a file that we're interested has begun downloading, initialize
# an MD5 hash.
event file_transferred(c: connection, prefix: string, descr: string, mime_type: string) &priority=5
{
if ( ! c?$http ) return;
if ( (generate_md5 in mime_type || c$http$calc_md5 ) &&
! c$http$calculating_md5 )
{
c$http$calculating_md5 = T;
md5_hash_init(c$id);
}
}
# As the file downloads, continue building the hash.
event http_entity_data(c: connection, is_orig: bool, length: count, data: string) &priority=-5
{
if ( is_orig ) return;
if ( c$http$calculating_md5 )
md5_hash_update(c$id, data);
}
# When the file finishes downloading, finish the hash, check for the hash
# in the MHR, and raise a notice if the hash is there.
event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) &priority=-4
{
if ( is_orig || ! c?$http ) return;
if ( c$http$calculating_md5 )
{
local url = build_url(c$http);
c$http$calculating_md5 = F;
c$http$md5 = md5_hash_finish(c$id);
if ( c$http$md5 in interesting_md5 )
{
NOTICE([$note=HTTP_MD5, $conn=c, $method=c$http$method,
$URL=url,
$msg=interesting_md5[c$http$md5],
$sub=c$http$md5]);
}
local hash_domain = fmt("%s.malware.hash.cymru.com", c$http$md5);
when ( local addrs = lookup_hostname(hash_domain) )
{
# 127.0.0.2 indicates that the md5 sum was found in the MHR.
if ( 127.0.0.2 in addrs )
{
local message = fmt("%s %s %s", c$id$orig_h, c$http$md5, url);
NOTICE([$note=HTTP_MHR_Malware, $msg=message, $conn=c,
$method=c$http$method, $URL=url]);
}
}
}
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c?$http && c$http$calculating_md5 )
md5_hash_finish(c$id);
}