When a host is compromised/infected on your network, an important step in the Incident Handling process is the “containment” to prevent further infections. To place the device into a restricted environment is definitively better than powering off the system and, probably, lose some pieces of evidence.
Endpoint protection solutions are the “in” thing for a while. Instead of using standard AV tools, those solutions implement more control and try to block attackers directly. One of the features they implement is a containment solution to prevent a compromised host to communicate over the network, except with the endpoint management console. An endpoint solution can be expensive if you have a lot of hosts to protect and… it’s (again) a new agent to deploy on them.
I’m a big fan of OSSEC and I already wrote a few diaries about it. Today, I’ll demonstrate how you can implement the function described above without an expensive solution. OSSEC has a feature called ‘Active-Response’ that helps to execute scripts on agents in case of specific alerts or… on demand!
I wrote a Windows command line script that temporarily replaces the existing local firewall rules by a very restricted new set:
- Communication with the OSSEC server is still allowed
- An IP address is allowed on all ports TCP/UDP
- All remaining traffic is blocked
This allows a security team to temporarily isolate a suspicious computer from the network and to start some investigations by allowing a SIFT Workstation to connect to the host.
To configure this, in your ossec.conf file, create the new active-response setup:
<command> <name>contain-host</name> <executable>contain-me.cmd</executable> <expect>srcip</expect> <timeout_allowed>no</timeout_allowed> </command>
Note: It’s important to not configure any timeout to prevent the host to be “unconfined” automatically.
Then, create the active-response action:
<active-response> <command>contain-host</command> <location>local</location> <level>10</level> <rules_id>99999999</rules_id> </active-response>
If you want to automatically contain a host, you may create rules: use ‘rules_group’ or ‘rules_id’. My rule_id ‘99999999’ will never trigger because it looks for something that will never happen! This way, you can prevent an automatic containment of a host.
Finally, deploy the script in the right directory (%OSSECPATH%active-responsebin) on all your OSSEC monitored hosts and you’re good to go!
How to contain a host, manually? OSSEC has a command to achieve this:
[root@ossec bin]# ./agent_control -u 011 -f contain-host0 -b 192.168.254.212
Where ‘011’ is the agent ID you’d like to contain and ‘contain-host0’ is the defined active-response action. In the case above, 192.168.254.212 is the IP address of the incident handler that will investigate the suspicious host.
Here is a copy of the script:
:: Script to block all traffic except interesting hosts: :: - The OSSEC server :: - Incident Handling workstation (ex: a SANS SIFT) :: Parameters: :: - %1 = ADD|DELETE :: - %2 = User (unused) :: - %3 = IP address to whitelist @echo off :: Generate timestamp variables for /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET DAT=%%A %%B for /F "TOKENS=1-3 DELIMS=:" %%A IN ("%TIME%") DO SET TIM=%%A:%%B:%%C :: Extract the OSSEC server IP address from config setlocal EnableDelayedExpansion (for /F "delims=" %%a in ('findstr /R "<server-ip>.*</server-ip>$" "%OSSECPATH%ossec.conf"') do ( set "line=%%a" set "line=!line:*<server-ip>=!" for /F "delims=<" %%b in ("!line!") do set OSSECIP=%%b )) if /I "%OSSECIP%"=="" goto ERROR2 :: Check for required arguments if /I "%1"=="" goto ERROR if /I "%2"=="" goto ERROR if /I "%3"=="" goto ERROR :: Check for a valid IP echo "%3" | %WINDIR%system32findstr.exe /R "." >nul || goto ERROR if /I "%1"=="add" goto ADD if /I "%1"=="delete" goto DEL :ERROR echo Invalid argument(s). echo Usage: contain-me.cmd ^(ADD^|DELETE^) user IP_Address echo Example: contain-me.cmd ADD - 188.8.131.52 exit /B 1 :ERROR2 echo Cannot find OSSEC server IP address in ossec.conf exit /B 1 :ADD :: Save the existing firewall rules del %OSSECPATH%fw-backup.wfw" >nul %WINDIR%system32netsh advfirewall export "%OSSECPATH%fw-backup.wfw" %WINDIR%system32NETSH ADVFIREWALL FIREWALL SET RULE all NEW enable=no :: Allow the OSSEC server IP %WINDIR%system32netsh advfirewall firewall add rule name="Allow ICMP in" dir=in protocol=icmpv4 action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow ICMP out" dir=out protocol=icmpv4 action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow OSSEC Server in" dir=in localport=1514 remoteip=%OSSECIP%/32 protocol=udp action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow OSSEC Server out" dir=out localport=1514 remoteip=%OSSECIP%/32 protocol=udp action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow OSSEC Server in/tcp" dir=in localport=any remoteip=%3/32 protocol=tcp action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow OSSEC Server in/udp" dir=in localport=any remoteip=%3/32 protocol=udp action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow OSSEC Server out/tcp" dir=out localport=any remoteip=%3/32 protocol=tcp action=allow %WINDIR%system32netsh advfirewall firewall add rule name="Allow OSSEC Server out/udp" dir=out localport=any remoteip=%3/32 protocol=udp action=allow %WINDIR%system32netsh advfirewall set allprofiles firewallpolicy blockinbound,blockoutbound echo %DAT%%TIM% %~dp0%0 %1 %2 %3 >> "%OSSECPATH%active-responseactive-responses.log" goto EXIT :DEL :: Restore the saved firewall rules %WINDIR%system32netsh advfirewall import "%OSSECPATH%fw-backup.wfw" echo %DAT%%TIM% %~dp0%0 %1 %2 %3 >> "%OSSECPATH%active-responseactive-responses.log" exit /B 0:
It will automatically extract the OSSEC server IP address from the config file and allow it. It will also backup your existing firewall rules and restore them.
There is no way to automatically restore the connectivity via OSSEC (when it’s not automatic). Once you completed the investigations on the host, just restore the previous firewall settings:
C:Program Files (x86)ossec-agentactive-responsebin>set OSSECPATH=c:Program Files (x86)ossec-agent C:Program Files (x86)ossec-agentactive-responsebin>contain-me.cmd delete - 192.168.254.212
Or you can write a second active-response script to “uncontain” the host…
I implemented this script for Windows endpoints but it’s very easy to implement the same on other operating systems.
Xavier Mertens (@xme)
Senior ISC Handler – Freelance Cyber Security Consultant
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.