Default | Coy | Dark | Funky | Okaidia | Solarized | Twilight
In this example, line numbering is enabled.
##! A script for handling URLs in SMTP traffic. This script does
##! two things. It logs URLs discovered in SMTP traffic. It
##! also records them in a bloomfilter and looks for them to be
##! visited through HTTP requests.
##!
##! Authors: Aashish Sharma
##! Seth Hall
@load base/utils/urls
module SMTP_URL;
export {
redef enum Log::ID += { Links_LOG };
type Info: record {
## When the email was seen.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## Connection details.
id: conn_id &log;
## Depth of the email into the SMTP exchange.
trans_depth: count &log;
## The host field extracted from the discovered URL.
host: string &log &optional;
## URL that was discovered.
url: string &log &optional;
};
redef enum Notice::Type += {
## A link discovered in an email appears to have been clicked.
Link_in_Email_Clicked,
## An email was seen in email that matched the pattern in
## `SMTP_URL::suspicious_urls`
Suspicious_URL,
## Certain file extensions in email links can be watched for
## with the pattern in `SMTP_URL::suspicious_file_extensions`
Suspicious_File_Extension,
## URL with a dotted IP address seen in an email.
Dotted_URL
};
const suspicious_file_extensions = /\.([rR][aA][rR]|[eE][xX][eE]|[zZ][iI][pP])$/ &redef;
const suspicious_urls = /googledocs?/ &redef;
const ignore_file_types = /\.([gG][iI][fF]|[pP][nN][gG]|[jJ][pP][gG]|[xX][mM][lL]|[jJ][pP][eE]?[gG]|[cC][sS][sS])$/ &redef;
## The following
const ignore_mail_originators: set[subnet] = { } &redef;
const ignore_mailfroms = /bro@|alerts|reports/ &redef;
const ignore_notification_emails = {"alerts@example.com", "notices@example.com"} &redef;
const ignore_site_links = /http:\/\/.*\.example\.com\/|http:\/\/.*\.example\.net/ &redef;
}
# The bloomfilter that stores all of the links seen in email.
global mail_links_bf: opaque of bloomfilter;
redef record connection += {
smtp_url: Info &optional;
};
event bro_init() &priority=5
{
# initialize the bloomfilter
mail_links_bf = bloomfilter_basic_init(0.00000001, 10000000, "SMTP_URL");
Log::create_stream(Links_LOG, [$columns=Info]);
}
function extract_host(name: string): string
{
local split_on_slash = split(name, /\//);
return split_on_slash[3];
}
function log_smtp_urls(c: connection, url: string)
{
c$smtp_url = Info($ts = c$smtp$ts,
$uid = c$uid,
$id = c$id,
$trans_depth = c$smtp$trans_depth,
$host = extract_host(url),
$url = url);
Log::write(SMTP_URL::Links_LOG, c$smtp_url);
}
event SMTP_URL::email_data(f: fa_file, data: string)
{
# Grab the connection.
local c: connection;
for ( cid in f$conns )
{
c = f$conns[cid];
break;
}
if( c$smtp?$mailfrom && ignore_mailfroms in c$smtp$mailfrom )
{
return;
}
if ( c$smtp?$to )
{
for ( to in c$smtp$to )
{
if ( to in ignore_notification_emails )
return;
}
}
local mail_info = Files::describe(f);
local urls = find_all_urls(data);
for ( link in urls )
{
#local link = sub(a,/(http|https):\/\//,"");
#local _bf_lookup = bloomfilter_lookup(mail_links_bf, link);
#if (link !in mail_links_bf && ignore_file_types !in link )
#if ((_bf_lookup == 0) && ignore_file_types !in link )
if ( ignore_file_types !in link )
{
bloomfilter_add(mail_links_bf, link);
log_smtp_urls(c, link);
if ( suspicious_file_extensions in link )
{
NOTICE([$note = Suspicious_File_Extension,
$msg = fmt("Suspicious file extension embedded in URL %s from %s", link, c$id$orig_h),
$sub = mail_info,
$conn = c]);
}
if ( suspicious_urls in link )
{
NOTICE([$note = Suspicious_URL,
$msg = fmt("Suspicious text embedded in URL %s from %s", link, c$smtp$uid),
$sub = mail_info,
$conn = c]);
}
if ( /([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}.*/ in link )
{
NOTICE([$note = Dotted_URL,
$msg = fmt("Embedded IP address in URL %s from %s", link, c$id$orig_h),
$sub = mail_info,
$conn = c]);
}
}
}
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool)
{
if ( f$source == "SMTP" && c?$smtp &&
c$id$orig_h !in ignore_mail_originators )
{
Files::add_analyzer(f, Files::ANALYZER_DATA_EVENT, [$stream_event=SMTP_URL::email_data]);
}
}
event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) &priority=-3
{
local str = HTTP::build_url_http(c$http);
if ( bloomfilter_lookup(SMTP_URL::mail_links_bf, str) > 0 &&
ignore_file_types !in str &&
ignore_site_links !in str)
{
NOTICE([$note=SMTP_URL::Link_in_Email_Clicked,
$msg=fmt("URL %s ", str),
$conn=c]);
}
}