Creating a module and accessing an event in another script

Hi all,

I am new to Zeek and would like some help with writing a module and accessing the events in another script.

I created a module called SSHAttempt under /usr/local/bro/share/bro/site and set up the module with local.zeek and main.zeek.

I created a custom log stream based on the result derived from ssh_auth_result in SSHAttempt/main.zeek. I also exported the SSH::Info record as log_sshattempt from main.zeek.

I can see the notice.log when running with sshquess.pcap. However if I try to access the event that has been exported from SSHAttempt/main.zeek inside another script (test.zeek) then I am getting the error that the record values are not initialised. I was expecting auth_fail variable inside SSHAttempt::Info record to be initialised when running .pcap.

Please find all the necessary files for reference. Any help would be much appreciated. :slight_smile:

Kind regards,
Merril

local.zeek|attachment (12 Bytes)

main.zeek (1.95 KB)

test.zeek (205 Bytes)

Hi all,

I figured out why it wasn’t working. I was trying to print rec. newbie mistake. :slight_smile:

But the notice email action does not work though. It generates notice.log but does not email. Any silly mistakes anyone can see?

Kind regards,
Merril.

Are you running against a pcap? emails are not sent when reading pcap files. You should still see ACTION_EMAIL in the actions field in the notice.log.

I created a module called SSHAttempt under /usr/local/bro/share/bro/site and set up the module with __local__.zeek and main.zeek.

The magic filename for loading directories is "__load__.zeek", not
"__local__.zeek".

However if I try to access the event that has been exported from SSHAttempt/main.zeek inside another script (test.zeek) then I am getting the error that the record values are not initialised. I was expecting auth_fail variable inside SSHAttempt::Info record to be initialised when running .pcap.

The event handler in test.zeek was creating an uninitialized record
and printing it instead of printing the one given as an argument like:

event log_sshattempt(rec: Info) &priority=5
    {
    print rec;
    }

- Jon

Do you also have "Notice::mail_dest" set to the email address that
should receive them? Or if you're using ZeekControl / BroControl,
you'd instead edit zeekctl.cfg/broctl.cfg to set the "MailTo" option.

- Jon

Hi Justin,

I can see ACTION_EMAIL on notice.log when running .pcap. But I included the SSHAttempt module with local.zeek file and if I try to call the notice type defined in the module inside test.zeek then it doesn’t work when I ssh into the box. Please find attached the files.

Kind regards,
Merril

local.zeek (3.93 KB)

test.zeek (308 Bytes)

Hi Jon,

Yes I have MailTo option set to my email address in zeekcontrol.

Kind regards,
Merril.

Do you think it might be because I am relying on ssh_auth_result which is exported in module GLOBAL as seen in SSH/main.zeek? rather than log_ssh event?. My understanding was that if exported globally it is available for all scripts which is true when I use it in my own module. But maybe its not triggered when I try to ssh into the box since log_ssh is the only event exported from module SSH?

If so how can I export ssh_auth_result to module SSH as well? also how can I pass two events to a log stream? ie how to edit this line: Log::create_stream(SSHAttempt::LOG, [$columns=Info, $ev=log_sshattempt, $path=“SSHAttempt”]);

Kind regards,
Merril.

If your notice.log shows ACTION_EMAIL then it’s working properly. It will not send emails when reading a .pcap file.

Hi Justin,

I think I figured it out. I don’t think seeing EMAIL_ACTION in notice.log necessarily sends out email or at least was the case in my scenario. So what I changed was to not directly declare notice variable in the module/main.zeek I created but instead redefine and export it in another script and then notify the variable using the module I created. After that I had to set the ACTION_EMAIL from another script when the defined notice variable is available. I maybe completely wrong here as I also found that this code (found from SSH.main.zeek)

event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=20
{
if ( atype == Analyzer::ANALYZER_SSH )
{
set_session(c);
}
}

Is needed for the Log to work and perhaps for Notice as well.

Now I am struggling to pass the right information to this event (protocol_confirmation). How does one return a record from a function? I can see examples of string and count etc… but not record.

Kind regards,
Merril.

Hi Justin,

I think I figured it out. I don’t think seeing EMAIL_ACTION in notice.log necessarily sends out email or at least was the case in my scenario.

If notice.log contains ACTION_EMAIL under actions then it would have sent the email when reading live traffic. If you were not getting the email then you had smtp issues, not zeek issues…

So what I changed was to not directly declare notice variable in the module/main.zeek I created but instead redefine and export it in another script and then notify the variable using the module I created. After that I had to set the ACTION_EMAIL from another script when the defined notice variable is available.

You did not need to make any of those changes, the previously shared files were all perfect.

I maybe completely wrong here as I also found that this code (found from SSH.main.zeek)

event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=20
{
if ( atype == Analyzer::ANALYZER_SSH )
{
set_session(c);
}
}

Is needed for the Log to work and perhaps for Notice as well.

It is not needed. That is code specific to the existing ssh policy to start tracking the ssh session as soon as it is detected. This is not relevant to what you are doing since you only care about authentication attempts.

Now I am struggling to pass the right information to this event (protocol_confirmation).

You don’t pass information to that event. You should not need to do anything with that event.

How does one return a record from a function? I can see examples of string and count etc… but not record.

You return a record exactly the same way you return a string or a count, there is no difference.

Hi Justin,

Thanks. But it did not work for me. Yes everything works fine if I use log_ssh event exported from the SSH module. I can check if its authenticated from the SSH::Info. However what I tried to do was to use ssh_auth_result which is exported globally. Not sure the live traffic on SSH would trigger ssh_auth_result. Thats why I tried to include the SSH analyser and protocol_conformation event with my module. Once I put that in then it generates an email and log. Maybe I am just looking at it completely the wrong way.

With regards to function return this gives me an error:

function set_session(c: connection, auth_fail: string &optional, auth_success: string &optional): record
{
if( ! c?$sshattempt )
{
local info: SSHAttempt::Info;
info$ts = network_time();
info$auth_fail = auth_fail;
info$auth_success = auth_success;
c$sshattempt = info;
return info;
}
}

Kind regards,
Merril.

Did not work how? Did you post the version of the script that didn’t work?

Hi Justin,

I can confirm that attached scripts does not send me email on live traffic or create a log under $PREFIX/logs/current. But it does create notice.log and a SSHAttempt.log when running pcap. I can also confirm that send mail set up is working as I have received emails from zeek from other scripts.

Kind regards,
Merril.

test.zeek (334 Bytes)

main.zeek (1.95 KB)

local.zeek (3.86 KB)

that script should generally work, but it was a lot more complicated than it needed to be to accomplish what you are trying to do. Here is a much simplified version.

The only thing to keep in mind is that since you are using zeek_init to setup the log stream this won’t work on bro or a small number of zeek builds from right after the rename. There are no released versions of zeek so I don’t know when you built it. Using bro_init is backwards compatible and is probably better for now.

main.zeek (1.13 KB)

Hi Justin,

Thank you for the script, much appreciated. Unfortunately it does not seem to solve the problem, now I am starting to think if there is any issue with my zeek installation. Also apologies for the messy code. I am only one week into Zeek(bro) and I will try to improve the code for any future posts. :slight_smile:

Kind regards,
Merril.

Hi All,

I cannot figure out why the Notice doesn’t behave as expected on live traffic. I am now trying to make it work with SSH (log_ssh) event as previous attempt on ssh_auth_result lead me nowhere. If I raise the NOTICE function just after the log_ssh event from a script it sends me email on live traffic. However if I use the NOTICE function inside IF, ELSE IF, ELSE conditionals for auth_success boolean then it does not send me emails. Anyone see what I am doing wrong? I couldn’t figure it out from Notice documentation.

Please find attached the scripts for reference.

Kind regards,
Merril.

alert_ssh_attempt_new.bro (957 Bytes)

email_ssh_attempt.bro (239 Bytes)

email_ssh_attempt.bro is not required at all because you already added Login_Attempted to Notice::emailed_types in the other script.

Your other script is slightly broken because in the case of unknown result the field is not present, so your script needs to look like this.

event log_ssh(rec: Info) &priority=5
{
if(!rec?$auth_success) {
NOTICE([$note=SSH::Login_Attempted, $msg=fmt(“Unknown”)]);
}
else if(rec$auth_success == F) {
NOTICE([$note=SSH::Login_Attempted,
$msg=fmt(“SSH login attempted from %s, %s many times and failed”, rec$client, rec$auth_attempts)]);
} else {
NOTICE([$note=SSH::Login_Attempted,
$msg=fmt(“SSH login attempted from %s, %s many times and succeeded”, rec$client, rec$auth_attempts)]);
}
}

if you look at your reporter.log you should see it filled with errors like this:

Reporter::ERROR field value missing [SSH::rec$auth_success] alert_ssh_attempt_new.bro, line 14

Hi Justin,

Thanks again. I made the changes you sent and I am getting this error on reporter.log. “ 1559839456.472514 Reporter::ERROR field value missing [SSH::rec$auth_success] /usr/local/bro/share/bro/site/alert_ssh_attempt.bro, line 22”

But it definitely returns auth_success=F when running on .pcap. I assume auth_success will be T when I ssh into the box?

Kind regards,
Merril.

What does your current script look like?