Identify Brute Forcing

triggers

#1

Hi All,

Is it possible to create a trigger that would be able to identify brute force attacks?

I have a trigger that I use to identify hits (and the username that’s requested) against a specific URI but I would like to know if you can set a trigger up so it logs/charts up when an single IP attempts multiple usernames (5 for example). Currently I’m relying on trend alerts but that’s not always a good indication.

The trigger so far to pull the usernames out is:

if (HTTP.uri.indexOf("/multi") == -1) { // only interested in this URI
return
}

var application_name = “Login URI”;

if (event == “HTTP_REQUEST” && HTTP.method == “POST”){
var payload = HTTP.payload;

var x_username = /x_username=(.+?)&/.exec(payload) || null;
if (x_username){ 
    Flow.store.username = x_username[1];
}
Flow.store.ua = HTTP.userAgent;

} else if ((event == “HTTP_RESPONSE”) && Flow.store.username){
var cookies = HTTP.cookies;
var cookit = “”;
var i;
for (i = 0; i < cookies.length; i++) {
cookit += printCookie(cookies[i]);
}
var referer = HTTP.referer || “no_referer”;
var detail = "client: " + Flow.client.ipaddr +
" ~ server: " + Flow.server.ipaddr +
" ~ username: " + Flow.store.username +
" ~ user-agent: " + Flow.store.ua +
" ~ referer: " + referer +
cookit;
// Application(application_name).commit();
Application(application_name).metricAddCount(“multi”, 1);
Application(application_name).metricAddDetailCount(“multi_detail”, detail, 1);
Application(application_name).metricAddDetailCount(“multi_by_client”, Flow.client.ipaddr, 1);
Application(application_name).metricAddDetailCount(“multi_by_server”, Flow.server.ipaddr, 1);
Application(application_name).metricAddDetailCount(“multi_by_user_agent”, Flow.store.ua, 1);
Application(application_name).metricAddDetailCount(“multi_by_referer”, referer, 1);
Application(application_name).metricAddDetailCount(“multi_by_username”, Flow.store.username, 1);
Flow.store.username = null;
Flow.store.ua = null;
}

function printCookie(cookie) {
var cookie_string = " ~ cookie: ";
for(var c in cookie) {
cookie_string+=(c + “=” + cookie[c] + " ");
}
return(cookie_string);
}

Any help appreciated!


#2

Yes, you certainly can. Use the session table for counting the number of occurrences of the bad login. You can use the client IP as the key for the your session table entry. Sometimes folks will create compound keys and then hash them with the md5 function.

And I would assume you would want to count for “x number of bad passwords, within y seconds”. Make sure you set the session table expiry options to expire the session table entry after y seconds.

Here’s some quick, non-tested pseudocode that should do roughly what you want:

opts = {expire: 60}        // Expire Table if no traffic from client ip in 60 seconds

my_session_entry = Session.lookup(client_ip);

if (my_session_entry) {
    new_count = my_session_entry + 1;

    if (new_count > 5) {
    //Log an event to Syslog or something here if we counted more than x number of brute force attempts within y interval
    }

Session.replace(client_ip, new_count, opts);
}

else {
    Session.add(client_ip, 1, opts)
}

#3

Thanks Tomr, sounds perfect. I’ll give it a bash and see how it goes.


#4

It may be a mess but I have it all working now which is nice. I can get information based on the various stages of a login.

// Events: HTTP_RESPONSE, HTTP_REQUEST
// For given uri(s), on a POST request, log the username.
// and other relevant information.

if (Flow.server.device.hasTrigger){
if ( condition() ) {
action();
}
}

// Only interested in either of the two URIs
function condition(){
return HTTP.uri && (HTTP.uri.indexOf(/specificURI-1/) !== -1 || HTTP.uri.indexOf(/specificURI-2/) !== -1)
}

function action(){

var application_name = “Brute Monitor”;

// Return the referer or display as ‘null_referer’, searchable on the Dash
var referer = HTTP.referer || “null_referer”;

// Process the next step, on HTTP reques and POST look in the payload for the username string

if (event == “HTTP_REQUEST” && HTTP.method == “POST”){
var payload = HTTP.payload;
var client_ip = Flow.client.ipaddr.toString();
Flow.store.uri = HTTP.uri;
Flow.store.ua = HTTP.userAgent;
var username = /username=(.+?)&/.exec(payload) || null;
if (username){
Flow.store.username = username[1];
}

// Collect information regarding multiple attempts

opts = {expire: 60}        // Expire Table if no traffic from client ip in 60 seconds
my_session_entry = Session.lookup(client_ip);

if (my_session_entry) {
new_count = my_session_entry + 1;

if (new_count > 4) {
    
    Application(application_name).metricAddCount("login_count", 1);
    Application(application_name).metricAddDetailCount("login_incremental_count", 'Count: ' + new_count + ' ~ IP: ' + client_ip + ' ~ UA: ' + Flow.store.ua + ' ~ URI: ' + Flow.store.uri, 1);
    
}

Session.replace(client_ip, new_count, opts);

}
else {
Session.add(client_ip, 1, opts)
}
var NotLoggedIn = “ClientIP: " + Flow.client.ipaddr + " ~ Username:” + Flow.store.username + " ~ URI: " + Flow.store.uri + " ~ UA: " + Flow.store.ua + " ~ Referer: " + referer;
Application(application_name).metricAddCount(“notloggedin”, 1);
Application(application_name).metricAddDetailCount(“notloggedin_detail”, NotLoggedIn, 1);
Application(application_name).metricAddDetailCount(“notloggedin_by_client”, Flow.client.ipaddr, 1);

// Process the HTTP response looking for the username

} else if ((event == “HTTP_RESPONSE”) && Flow.store.username){

var cookies = HTTP.cookies;
var cookit = "";
var i;
for (i = 0; i < cookies.length; i++) { 
    cookit += printCookie(cookies[i]);      
}

var detail = "ClientIP: " + Flow.client.ipaddr + " ~ URI: " + Flow.store.uri + " ~ UA: " + Flow.store.ua + " ~ Referer: " + referer;
var details = "Username: " + Flow.store.username + " ~ " + detail;
var count = new_count;
cookit;

// This information at this point is of those accounts that are succesfully logged in.

Application(application_name).commit();
Application(application_name).metricAddCount("login", 1);
Application(application_name).metricAddDetailCount("login_detail", details, 1);
Application(application_name).metricAddDetailCount("login_by_client", Flow.client.ipaddr, 1);
Application(application_name).metricAddDetailCount("login_by_user_agent", Flow.store.ua, 1);
Application(application_name).metricAddDetailCount("login_by_uri", Flow.store.uri, 1);
Application(application_name).metricAddDetailCount("login_by_referer", referer, 1);
Application(application_name).metricAddDetailCount("login_busername", Flow.store.username, 1);

// Send to syslog before we null the Flow Stores

var message="";
message += "Message1: " + details + " ";
message += "Message2: " + count + " ";
Remote.Syslog.info(message);

// Null the flows so they’re not picked up anywhere else once the work is done

Flow.store.username = null;
Flow.store.ua = null;
Flow.store.uri = null;

}
}
function printCookie(cookie) {
var cookie_string = " ~ cookie: ";
for(var c in cookie) {
cookie_string+=(c + “=” + cookie[c] + " ");
}
return(cookie_string);
}

Thanks for your help!