Lab Guide 5
Lab Guide 5
Lab Guide 5
Lab-Guide - Session 5
Wazuh 4.1.5
Elastic Stack 7.10.0
OpenDistro 1.12.0
Table of Contents
CDB Lists
Lab Exercise 5a - Escalate sshd alerts about known attacker IPs
Lab Exercise 5b - Distinguish between different ssh-watch-list values
Active Response
Active Response
Creating custom Active Commands:
Creating custom Active Response:
Stateful vs stateless command:
Lab Exercise 5c - deploy and test Linux firewall active response
Hacking Wazuh
Tools for Troubleshooting and Debugging Wazuh
Monitoring network communications between the manager and agents using
tcpdump
Monitoring files that are in-use by ossec processes using lsof (lsof)
Example:
Monitoring process communications between the agent and manager using strace
(for ossec-remoted)
Monitoring open sockets of Wazuh processes using netstat (or ss)
Docker Lab
Use cases:
It’s also a convenient way to index databases and perform lookups on them.
CDB lists need to be stored in the directory /var/ossec/etc/lists/ and they need to
have a specific format. For example, file /var/ossec/etc/lists/suspicious could
contain entries like this:
key1:value
key2:value
key3:value
Each key has to be unique and must be followed by a colon and an optional value. The
values between lines can be the same as long as the key is unique.
We need to define it in the ossec.conf file first by adding the following entry to the <rule>
section of the ossec.conf file.
<ruleset>
<list>etc/lists/suspicious</list>
</ruleset>
The last thing to do is to create new rules to trigger alerts whenever an event matches one
of the entries in our new list.
** Alert 1484799474.4188056: -
syslog,sshd,invalid_login,authentication_failed,pci_dss_10.2.4,pci_dss_10.2
.5,pci_dss_10.6.1,
2017 Jan 19 04:17:54 (linux-agent) 10.0.0.20->/var/log/secure
Rule: 5710 (level 5) -> 'Attempt to login using a non-existent user'
Src IP: 45.55.186.244
Jan 19 04:17:54 agent sshd[2365]: Failed password for invalid user blabla
from 55.55.186.244 port 55969 ssh2
We want to make a special rule of higher severity fire if this rule 5710 is tripped by an >
attacker on our special list of IPs of concern (ssh-watch-list)
Feed the example log entries into /var/ossec/bin/ossec-logtest and observe that those
involving a listed IP fire rule 100112 instead of rule 5710. The higher severity of this rule could
be used to trigger a more severe active response action.
Feed the example log entries into ossec-logtest and observe that those involving a listed IP
fire rule 100112 instead of rule 5710, unless they have a value of "terrible", in which case they
fire the even more severe rule 100111.
Lastly, you might like to see how Wazuh is incorporating some lists of its own directly into
the Wazuh Ruleset to make Amazon and audit rules easier to work with. This will get you
started exploring:
find /var/ossec/etc/lists
grep -r "etc/lists" /var/ossec/ruleset/rules
Also, to see a great blog on importing the OSINT list of malicious IPs into a CDB:
https://wazuh.com/blog/cdb-lists
This automated remediation is called “Active response” in Wazuh. Active response allows
you to execute a script whenever a rule is matched by the ruleset. Any number of responses
can be attached to any of the rules, but it is important to be careful.
A bad implementation of the rules and responses, can be dangerous. An attacker could use
the rules against you.
By default the following active response scripts are already implemented with a default
Wazuh installation:
The scripts need a way to be referenced by the ruleset to perform a particular active
response. A command needs to be defined for this. Any script that can receive parameters
from the command line can be used for Active Response.
Command Values:
<command>
<name>mail-test</name>
<executable>mail-test.sh</executable>
<timeout_allowed>no</timeout_allowed>
<expect />
</command>
In this example, the command is called “mail-test” and should execute the
<command>
<name>host-deny</name>
<executable>host-deny.sh</executable>
<expect>srcip</expect>
<timeout_allowed>yes</timeout_allowed>
</command>
In this case the command is called “host-deny”, and should execute the host-deny.sh,
the script needs the srcip and the command is able to timeout.
Now we need to bind the command to one or more rules or a specific severity level, which
<active-response>
<command>mail-test</command>
<location>server</location>
<rules_id>1002</rules_id>
</active-response>
In this case, the mail-test command will be executed on the ossec manager everytime rule
1002 is fired. The rule 1002 description is: “Unknown problem somewhere in the system” and
is matched when a “bad word” is in the logs.
Bad words, is an array that is defined in the syslog_rules.xml and can be one of the
followings: core_dumped, failure, error, attack, bad, illegal, denied, refused,
unauthorized, fatal, failed, Segmentation Fault or Corrupted
They usually indicate that something is seriously wrong on a system.
Another example:
<active-response>
<command>host-deny</command>
<location>local</location>
<level>7</level>
<timeout>600</timeout>
</active-response>
In this example the host-deny command will be executed on the agent that reported the
rule-matching event, with rule levels equals or bigger than 7. This response has 600 seconds
for the timeout.
It’s important to understand the difference between a command being stateful and a
command being stateless. In our examples we saw one of each.
A Stateful command is a command that has the capability to remove the applied action
after a certain period of time.
To configure a command like this, we need to set the timeout_allowed option in the
command to yes, and then configure a timeout value in the active response to indicate how
long to wait until the applied action is automatically reversed.
A Stateless command is that command that doesn’t have the capability of removing the
applied changes that the response applied.
with the following -- Make sure to get rid of the comments lines, too: <!-- and —>
<active-response>
<command>firewall-drop</command>
<location>local</location>
<rules_id>5712</rules_id>
<timeout>120</timeout>
</active-response>
<command>
<name>firewall-drop</name>
<executable>firewall-drop.sh</executable>
<expect>srcip</expect>
<timeout_allowed>yes</timeout_allowed>
</command>
3. From your linux-agent, perform an ssh dictionary attack against your elastic agent
LABSET=#
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
sleep .5
sshpass -p wrongPassWord ssh badguy@elastic$LABSET.lab.wazuh.info &
6. After the 120 second timeout passes, we should also be able to see the record of the
active response being performed and then later reversed on your linux-agent:
Inspect the AR log via Kibana with this search: decoder.name:"ar_log"
7. Confirm that your linux-agent is again able to reach your elastic system.
# ssh wazuh@elastic#.lab.wazuh.info
wazuh@elastic#.lab.wazuh.info's password:
...
8. Check Kibana later today for active response activity (see step 6) and you will probably
see real attackers in the wild being blocked by one or more of your Linux lab systems.
● tcpdump
● lsof
● strace
● netstat
tcpdump(1) is the swiss-army knife when it comes to troubleshooting all sorts of network
issues, e.g if for some reason an agent suddenly loses the connection to the manager and
wouldn’t connect. In a complex environment, with lots of firewalls or NIPS in between,
tcpdump is a very powerful tool. Below is a detailed example on how we can analyze
network traffic to localize a potential bottleneck in the network communication.
lsof(8) is another diagnostic tool that lists all files of processes running on a specific host that
are currently in use.
strace(1) is useful for monitoring system calls between the manager and agents. Since only
the network traffic between the devices is encrypted through the Wazuh message protocol,
we are able to use strace to read those syscalls and exchange messages in plaintext. Below
there is a detailed described example on how we can use strace to debug a problem on the
manager or on the agents.
netstat(8) lets you print open network connections and routing tables. In our case we will
use netstat to display the open sockets to the corresponding processes.
We are going to use the following options for debugging our network issue. With the flag
-nn we specify that we don’t want to resolve hostnames or ports, instead we want to use the
IP address.
The -i flag specifies the interface we want tcpdump to capture data from, in our case we
specify that only traffic from our interface eth0 should be captured. We also want to
configure tcpdump to only listen on the Wazuh port, 1514, by using the -p flag.
By using the -AA (must be all caps) we tell tcpdump to display the content in ASCII (often
used for capturing web pages).
Finally, we also want to specify the size of the whole packet, in our case we select 0 , we do
this by using the -s flag.
We can see that pretty much the entire network communication is some gibberish output
due to the encryption, almost…. We can still extract some useful information. In order to
Looking at the client.keys file, we can see that one agent (indexer) is on a dynamic ip
address (dhcp) therefore it is connected to the manager through “any” and for the Linux
Agent we have a dedicated static IP address, 10.0.0.4
This is essential, because the ossec-remoted process is looking for a key to decrypt the
message. The goal is to find the right corresponding key, therefore the remoted process
opens the client.key files and looks either for an IP address (if specified) or when only “any” is
used, it looks for the agent ID, which displayed between two exclamation marks !001!
The rest of the captured message is useless to us, because its content is encrypted. This
was just to demonstrate what the encrypted network communication between the manager
and the agents looks like.
lsof(8) can be performed on any regular file, directory, library, stream or network file (e.g
internet socket, nfs file, or UNIX domain socket).
In this particular case, we want to take a closer look at various log files which are configured
in our ossec.conf (for log analysis) that are in use by different processes.
Example:
This output shows that the rsyslog daemon, responsible for logging the main system/kernel
events on Linux systems, writes its log messages into the messages file. In the FD (file
descriptor) column this is shown as “w” for write access. Whereas the ossec-logcollector
process is only reading its log messages and sending the content through a unix domain
socket to the analysisd process for normalization and decoding.
strace(1) can be used to trace system calls and signals when trying to diagnose and
troubleshoot problems in the communication between the manager and the agent. In this
particular case we want to take a closer look at the ossec-remoted process.
Each line in the trace contains the system call name, followed by its arguments in
parentheses and its return value. An example from stracing the command ``cat /dev/null”” is:
open("/dev/null", O_RDONLY) = 3
Errors (typically a return value of -1) have the errno symbol and error string appended.
Signals are printed as a signal symbol and a signal string. An excerpt from stracing and
interrupting the command ``sleep 666'' is:
Now we want to trace the process ossec-remoted on the manager, by issuing the following
command:
The flag -o filename will write the output of the trace into a file called log, rather than to
stderr
The flag -ff specifies that each process is written to filename.pid where pid is the numeric
process id of each process.
The flag -s specifies the maximum string size to print, the default value is 32.
The flag -p specifies the process id of the process that we want to trace.
log.30574
log.30579
log.30580
In this trace we see that ossec-remoted is fetching the following information from the
connected agent
netstat(8) or respectively the more modern ss(8) can be used to investigate sockets or
open network connections. We are going to focus on the open sockets, especially the UNIX
domain socket that is used as a message queue to exchange data between the respective
Wazuh processes.
The following commands can be used to display this, by setting the right flags.
respectively
For those more comfortable with netstat, can of course use this, but it shall be noted that it’s
considered deprecated, meaning that it may be dropped by various Linux distributions at
some point. Let’s take a closer look at those flags.
20153/ossec-remoted
/queue/ossec/queue
/queue/alerts/ar
/var/ossec/queue/alerts/execq
users:(("ossec-analysisd",pid=20142,fd=3))
users:(("ossec-remoted",pid=20153,fd=11))
* 0 users:(("ossec-execd",pid=20139,fd=3))
users:(("ossec-analysisd",pid=20142,fd=8))
users:(("ossec-remoted",pid=20153,fd=5))
users:(("ossec-logcollec",pid=20146,fd=4))
users:(("ossec-analysisd",pid=20142,fd=7))
users:(("ossec-monitord",pid=20162,fd=3))
users:(("ossec-syscheckd",pid=20156,fd=4))
users:(("ossec-syscheckd",pid=20156,fd=3))
users:(("ossec-remoted",pid=20153,fd=4))
On elastic instance
<agent_config name="elastic#">
<wodle name="docker-listener">
<disabled>no</disabled>
</wodle>
</agent_config>
On elastic
data.integration:docker