I'm not very good with SPL. I currently have Linux application logs that show the IP address, user name, and if the user failed or had a successful login.
I'm interested in finding a successful login after one or more failed login attempts. I currently have the following search. The transaction command is necessary where it is or otherwise, all the events are split up into separate events of varying line counts.
index=honeypot sourcetype=honeypotLogs
| transaction sessionID
| search "SSH2_MSG_USERAUTH_FAILURE" OR "SSH2_MSG_USERAUTH_SUCCESS"
Below is an example event. For clarity, I replaced details/omitted details from the logs below.
[02] Tue 27Aug24 15:20:57 - (143323) Connected to 1.2.3.4
...
...
[30] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_REQUEST: user: bob
[31] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_FAILURE
...
[30] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_REQUEST: user: bob
[02] Tue 27Aug24 15:20:57 - (143323) User "bob" logged in
[31] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_SUCCESS: successful login
Any tips on getting my search to find events like this? Currently I only have field extractions for the IP (1.2.3.4), user (bob), and sessionID (143323). I can possibly create a field extraction for the SSH2 messages but I don't know if that will help or not.
Thanks!
Hi @st1 ,
don't use transaction command because it's very slow, please try something like this, adapting my solution to your use case (e.g. the thresholds in the last row):
index=honeypot sourcetype=honeypotLogs ("SSH2_MSG_USERAUTH_FAILURE" OR "SSH2_MSG_USERAUTH_SUCCESS")
| eval kind=if(searchmatch("SSH2_MSG_USERAUTH_FAILURE", "success","failure")
| stats
dc(kind) AS kind_count)
count(eval(kind="success)) As success_count
count(eval(kind="failure)) As failure_count
BY sessionID
| where kind_count=2 AND success_count>0 AND failure_count>10
Ciao.
Giuseppe
Yes, SSH2 message is key. The actual solution kind of depends on your exact use case/requirement. If you don't particularly care if the user had multiple failures, transaction will do just fine. Assuming your sessionID is unique for each connection and that you don't care if attempted user name is the same, simply add startswith and endswith.
index=honeypot sourcetype=honeypotLogs
| rex "\s(?<action>Connected) to (?<IP>\S+)"
| rex "\sUser \"(?<user>\S+)\" (?<action>logged in)"
| rex "\sSSH2_MSG_(?<ssh2_msg_type>\w+)"
| rex ": (?<ssh2_message>.+)"
| rex field=ssh2_message "user: (?<user>\S+)"
| transaction sessionID startswith=ssh2_msg_type=USERAUTH_FAILURE endswith=ssh2_msg_type=USERAUTH_SUCCESS
The above maybe goes a little overboard in extraction but usually, these semantic elements can be of interest.
If you care about attempted user name, you can add user to transaction. If you care about multiple failed attempts, streamstats could be a better approach.
The following is an extended emulation; it shows that
| makeresults format=csv data="_raw
[02] Tue 27Aug24 15:20:56 - (143323) Connected to 1.2.3.4
[30] Tue 27Aug24 15:20:56 - (143323) SSH2_MSG_USERAUTH_REQUEST: user: bob
[31] Tue 27Aug24 15:20:56 - (143323) SSH2_MSG_USERAUTH_FAILURE
[30] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_REQUEST: user: bob
[31] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_FAILURE
[30] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_REQUEST: user: bob
[02] Tue 27Aug24 15:20:57 - (143323) User \"bob\" logged in
[31] Tue 27Aug24 15:20:57 - (143323) SSH2_MSG_USERAUTH_SUCCESS: successful login
[02] Tue 27Aug24 15:20:58 - (143523) Connected to 1.2.3.4
[30] Tue 27Aug24 15:20:58 - (143523) SSH2_MSG_USERAUTH_REQUEST: user: alice
[02] Tue 27Aug24 15:20:58 - (143523) User \"alice\" logged in
[31] Tue 27Aug24 15:20:58 - (143523) SSH2_MSG_USERAUTH_SUCCESS: successful login"
| rex "^(\S+\s+){2}(?<_time>\S+\s+\S+) - \((?<sessionID>\d+)"
| eval _time = strptime(_time, "%d%b%y %T")
| reverse
``` the above emulates
index=honeypot sourcetype=honeypotLogs
```
Play with the emulation and compare with real data.
Hi @st1 ,
don't use transaction command because it's very slow, please try something like this, adapting my solution to your use case (e.g. the thresholds in the last row):
index=honeypot sourcetype=honeypotLogs ("SSH2_MSG_USERAUTH_FAILURE" OR "SSH2_MSG_USERAUTH_SUCCESS")
| eval kind=if(searchmatch("SSH2_MSG_USERAUTH_FAILURE", "success","failure")
| stats
dc(kind) AS kind_count)
count(eval(kind="success)) As success_count
count(eval(kind="failure)) As failure_count
BY sessionID
| where kind_count=2 AND success_count>0 AND failure_count>10
Ciao.
Giuseppe