Detect Malcious File Uploads With Wazuh and Yara
Protect your web server with Yara powered by Wazuh’s Active Response
Intro
Many web applications allow end users to upload files. While convenient and often times a required feature with modern web applications, security teams must have proper security features set in place to detect and thwart malicious file uploads. Malicious file uploading is a type of attack that involves placing files onto a server or computer in such a way that they contain some form of backdoor code that will allow the attacker to gain access afterward.
Developers can implement protections such as:
- Only allow specific file types
- Verify file types
- Remove embedded threats
- Authenticate users
- Set maximum file length / size
- And more
While these defense mechanisms are highly recommended, it is crucial for systems to scan uploaded files for malware and take action when malicious files are detected.
This post covers how we can take advantage of YARA, Wazuh, and Wazuh’s Active Response capabilities to scan uploaded files to our web server with Yara rules and quarantine folders that have been flagged as malicious within seconds.
What is YARA?
YARA is a tool aimed at (but not limited to) helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns. Each description, a.k.a. rule, consists of a set of strings and a boolean expression which determine its logic.
Before diving into the features of YARA, it may be helpful to see just how simple the rules can be. The following rule is a play on the simple “Hello, World!” applications many developers create when learning a new programming language.
This rule is looking for the text “hello, world!” to appear in a scan, whether it’s a file on disk or something in memory. The text we want to search is defined as $hello in the “strings” section and in the “condition” section we tell YARA that we would like to be alerted if the text is found.
More advanced YARA detection rules look like the below:
rule Codoso_PlugX_3 {
meta:
description = "Detects Codoso APT PlugX Malware"
license = "Detection Rule License 1.1 https://github.com/Neo23x0/signature-base/blob/master/LICENSE"
author = "Florian Roth"
reference = "https://www.proofpoint.com/us/exploring-bergard-old-malware-new-tricks"
date = "2016-01-30"
hash = "74e1e83ac69e45a3bee78ac2fac00f9e897f281ea75ed179737e9b6fe39971e3"
strings:
$s1 = "Cannot create folder %sDCRC failed in the encrypted file %s. Corrupt file or wrong password." fullword wide
$s2 = "mcs.exe" fullword ascii
$s3 = "McAltLib.dll" fullword ascii
$s4 = "WinRAR self-extracting archive" fullword wide
condition:
uint16(0) == 0x5a4d and filesize < 1200KB and all of them
}
Neo23x0 maintains an updated repo of YARA rules that provide high quality and up to date YARA rules to help combat old and new malware: https://github.com/Neo23x0/signature-base.
Building YARA
Let’s first compile YARA onto our webserver so that we can use the YARA binary to scan files.
- Build YARA from source
- Grab YARA rules Git Repo
- Compile YARA rules
Install Dependencies
apt-get install automake jq libtool libssl-dev make gcc pkg-config git libjansson-dev libmagic-dev -y
mkdir /usr/share/yara
cd /usr/share/yara
wget https://github.com/VirusTotal/yara/archive/refs/tags/v4.2.3.tar.gz
Extract and Build
tar xvf v4.2.3.tar.gz --directory /usr/share/yara/
cd yara-4.2.3/
./bootstrap.sh
./configure --enable-cuckoo --enable-magic --enable-dotnet --with-crypto
make
make install
Download Rules
cd /usr/local
git clone https://github.com/Neo23x0/signature-base.git
Update And Compile Rules
nano /usr/share/yara/yara_update_rules.sh
#!/bin/bash
# Yara rules - Compiled file creation
# Copyright (C) SOCFortress, LLP.
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License (version 2) as published by the FSF - Free Software
# Foundation.
#
#------------------------- Aadjust IFS to read files -------------------------#
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
# Static active response parameters
LOCAL=`dirname $0`
#------------------------- Folder where Yara rules (files) will be placed -------------------------#
git_repo_folder="/usr/local/signature-base"
yara_file_extenstions=( ".yar" )
yara_rules_list="/usr/local/signature-base/yara_rules_list.yar"
#------------------------- Main workflow --------------------------#
# Update Github Repo
cd $git_repo_folder
git pull https://github.com/Neo23x0/signature-base.git
# Remove .yar files not compatible with standard Yara package
rm $git_repo_folder/yara/generic_anomalies.yar $git_repo_folder/yara/general_cloaking.yar $git_repo_folder/yara/thor_inverse_matches.yar $git_repo_folder/yara/yara_mixed_ext_vars.yar $git_repo_folder/yara/apt_cobaltstrike.yar $git_repo_folder/yara/apt_tetris.yar $git_repo_folder/yara/gen_susp_js_obfuscatorio.yar $git_repo_folder/yara/configured_vulns_ext_vars.yar $git_repo_folder/yara/gen_webshells_ext_vars.yar
# Create File with rules to be compiled
if [ ! -f $yara_rules_list ]
then
/usr/bin/touch $yara_rules_list
else rm $yara_rules_list
fi
for e in "${yara_file_extenstions[@]}"
do
for f1 in $( find $git_repo_folder/yara -type f | grep -F $e ); do
echo "include \"""$f1"\""" >> $yara_rules_list
done
done
# Compile Yara Rules
/usr/share/yara/yara-4.2.3/yarac $yara_rules_list /usr/local/signature-base/yara_base_ruleset_compiled.yar
IFS=$SAVEIFS
exit 1;
chmod +x /usr/share/yara/yara_update_rules.sh
/usr/share/yara/yara_update_rules.sh
YARA is now installed and our rules are compiled. We can ensure YARA is properly installed by testing on an EICAR file.
wget https://secure.eicar.org/eicar.com
/usr/share/yara/yara-4.2.3/yara -C -w -r -f -m /usr/local/signature-base/yara_base_ruleset_compiled.yar eicar.com
We now see the YARA output:
Wazuh Implementation
In this demo, my web application (I think its safe to assume I have no future in web development :) ) enables end users to upload a file:
The underlying PHP then takes the uploaded file and writes it to /var/www/html/upload/
on the webserver
<?php
/* Get the name of the uploaded file */
$filename = $_FILES['file']['name'];
/* Choose where to save the uploaded file */
$location = "upload/".$filename;
/* Save the uploaded file to the local filesystem */
if ( move_uploaded_file($_FILES['file']['tmp_name'], $location) ) {
echo 'Success';
} else {
echo 'Failure';
}
?>
Wazuh FIM
Let’s first configure Wazuh’s File Integrity Monitoring to detect when files have been added to this directory in real time.
Set FIM real time for /var/www/html/upload
. Open up the ossec.conf
of your web server, or the agent.conf
of the Wazuh group and add the below under the <syscheck>
block.
<!-- PleaseSubscribe FIM -->
<directories check_all="yes" realtime="yes">/var/www/html/upload</directories>
Now add a file to your monitored directory and ensure you receive the Wazuh detection:
Wazuh Active Response
We now need a way to call YARA to scan the newly uploaded file. We will implement Wazuh’s Active Response feature to run a YARA scan when a file has been uploaded to our web server.
- Configure Active Reponses on Manager
- Add script to Wazuh Agent (our web server)
- Add Wazuh Decoder and Rules
- Test
On the Wazuh-Manager, add the below block to the ossec.conf
file. This instructs Wazuh to call our custom yara.sh
script when a file is added to our webserver (rule id 554).
<command>
<name>yara</name>
<executable>yara.sh</executable>
<expect>filename</expect>
<extra_args>-yara_path /usr/share/yara/yara-4.2.3 -yara_rules /usr/local/signature-base/yara_base_ruleset_compiled.yar</extra_args>
<timeout_allowed>no</timeout_allowed>
</command>
<active-response>
<command>yara</command>
<location>local</location>
<rules_id>554</rules_id>
</active-response>
On the webserver, place the below script in the /var/ossec/active-response/bin
directory: Watch the provided video for a script walkthrough
#!/bin/bash
# Wazuh - Yara active response
# Copyright (C) SOCFortress, LLP.
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License (version 2) as published by the FSF - Free Software
# Foundation.
#------------------------- Gather parameters -------------------------#
# Extra arguments
read INPUT_JSON
YARA_PATH=$(echo $INPUT_JSON | jq -r .parameters.extra_args[1])
YARA_RULES=$(echo $INPUT_JSON | jq -r .parameters.extra_args[3])
FILENAME=$(echo $INPUT_JSON | jq -r .parameters.alert.syscheck.path)
QUARANTINE_PATH="/tmp/quarantined"
# Set LOG_FILE path
LOG_FILE="logs/active-responses.log"
size=0
actual_size=$(stat -c %s ${FILENAME})
while [ ${size} -ne ${actual_size} ]; do
sleep 1
size=${actual_size}
actual_size=$(stat -c %s ${FILENAME})
done
#----------------------- Analyze parameters -----------------------#
if [[ ! $YARA_PATH ]] || [[ ! $YARA_RULES ]]
then
echo "wazuh-yara: ERROR - Yara active response error. Yara path and rules parameters are mandatory." >> ${LOG_FILE}
exit 1
fi
#------------------------- Main workflow --------------------------#
# Execute Yara scan on the specified filename
yara_output="$("${YARA_PATH}"/yara -C -w -r -f -m "$YARA_RULES" "$FILENAME")"
if [[ $yara_output != "" ]]
then
# Iterate every detected rule and append it to the LOG_FILE
while read -r line; do
echo "wazuh-yara: INFO - Scan result: $line" >> ${LOG_FILE}
done <<< "$yara_output"
/usr/bin/mv -f $FILENAME ${QUARANTINE_PATH}
FILEBASE=$(/usr/bin/basename $FILENAME)
/usr/bin/chattr -R +i ${QUARANTINE_PATH}/${FILEBASE}
/usr/bin/echo "wazuh-yara: $FILENAME moved to ${QUARANTINE_PATH}" >> ${LOG_FILE}
fi
exit 0;
Create your quarantine directory:
chown root:wazuh yara.sh
chmod 750 yara.sh
mkdir /tmp/quarantined
Add the Wazuh YARA decoders:
<!--
- YARA decoders
- Created by SOCFortress.
- https://www.socfortress.co
- info@socfortress.co.
-->
<decoder name="yara">
<prematch>wazuh-yara:</prematch>
</decoder>
<!-- wazuh-yara: INFO - Scan result: SUSP_Just_EICAR [description="Just an EICAR test file - this is boring but users asked for it",author="Florian Roth",reference="http://2016.eicar.org/85-0-Download.html",date="2019-03-24",score =40,hash1="275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f"] /var/www/html/upload/test.txt -->
<decoder name="yara_decoder1">
<parent>yara</parent>
<regex>wazuh-yara: (\S+) - Scan result: (\S+) [description\p\p(\.*)"\.*] (\S+)</regex>
<order>log_type, yara_rule, yara_description, yara_scanned_file</order>
</decoder>
Add the Wazuh YARA rules:
<!--
- YARA rules
- Created by SOCFortress.
- https://www.socfortress.co
- info@socfortress.co.
-->
<group name="yara,">
<rule id="200100" level="1">
<decoded_as>yara</decoded_as>
<description>YARA rules grouped.</description>
</rule>
<rule id="200101" level="12">
<if_sid>200100</if_sid>
<field name="yara_rule">\.+</field>
<mitre>
<id>T1204</id>
</mitre>
<description>YARA $(yara_rule) detected.</description>
</rule>
</group>
Save and restart the Wazuh-Manager.
Upload our EICAR test file friend and see your detections take place:
You will also notice that the file is moved from our web server upload directory to our /tmp/quarantine
directory:
Our Active Response script also makes the flagged file immutable so that while the file is quarantined, it cannot be granted execution permissions or modified in any way.
Conclusion
Throughout this post we detailed how to build YARA and compile YARA rules to use to scan files, we enabled Wazuh to monitor our /var/www/html/upload
directory in real time, and configured an Active Response
script to be invoked when a file has been uploaded to our web server.
This feature allows us to quickly detect when an end user has uploaded a malicious file to our web server before they are able to progress their attack further. Go protect your own web servers now! Happy Defending 😄.
Need Help?
The functionality discussed in this post, and so much more, are available via SOCFortress’s Professional Services. Let SOCFortress help you and your team keep your infrastructure secure.
Website: https://www.socfortress.co/
Professional Services: https://www.socfortress.co/ps.html