2021-12-27 13:52:26 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
# written by sqall
|
|
|
|
# twitter: https://twitter.com/sqall01
|
|
|
|
# blog: https://h4des.org
|
|
|
|
# github: https://github.com/sqall01
|
|
|
|
#
|
2021-12-30 20:48:17 +01:00
|
|
|
# Licensed under the MIT License.
|
2021-12-27 13:52:26 +01:00
|
|
|
|
|
|
|
"""
|
|
|
|
Short summary:
|
|
|
|
Malware will name itself with [brackets] to impersonate a Linux kernel thread.
|
|
|
|
Any Linux process that looks like a [kernel thread] should have an empty maps file.
|
|
|
|
|
|
|
|
Site note:
|
|
|
|
when using ps auxwf | grep "\[" they are children of [kthreadd]
|
|
|
|
|
|
|
|
Requirements:
|
|
|
|
None
|
|
|
|
|
|
|
|
Reference:
|
|
|
|
https://twitter.com/CraigHRowland/status/1232399132632813568
|
|
|
|
https://www.sandflysecurity.com/blog/detecting-linux-kernel-process-masquerading-with-command-line-forensics/
|
|
|
|
"""
|
|
|
|
|
|
|
|
import os
|
|
|
|
import socket
|
|
|
|
|
|
|
|
# Read configuration and library functions.
|
|
|
|
try:
|
|
|
|
from config.config import ALERTR_FIFO, FROM_ADDR, TO_ADDR
|
|
|
|
from config.search_non_kthreads import NON_KTHREAD_WHITELIST, ACTIVATED
|
|
|
|
from lib.alerts import raise_alert_alertr, raise_alert_mail
|
|
|
|
except:
|
|
|
|
ALERTR_FIFO = None
|
|
|
|
FROM_ADDR = None
|
|
|
|
TO_ADDR = None
|
|
|
|
NON_KTHREAD_WHITELIST = []
|
|
|
|
ACTIVATED = True
|
|
|
|
|
|
|
|
|
|
|
|
def search_suspicious_process():
|
|
|
|
|
|
|
|
# Decide where to output results.
|
|
|
|
print_output = False
|
|
|
|
if ALERTR_FIFO is None and FROM_ADDR is None and TO_ADDR is None:
|
|
|
|
print_output = True
|
|
|
|
|
|
|
|
if not ACTIVATED:
|
|
|
|
if print_output:
|
|
|
|
print("Module deactivated.")
|
|
|
|
return
|
|
|
|
|
|
|
|
# Iterate over all processes that have a "[".
|
|
|
|
fd = os.popen("ps auxw | grep \\\\[ | awk '{print $2}'")
|
|
|
|
pids_raw = fd.read().strip()
|
|
|
|
fd.close()
|
|
|
|
for pid in pids_raw.split("\n"):
|
|
|
|
|
|
|
|
# Get process name of pid.
|
|
|
|
fd = os.popen("ps u -p %s" % pid)
|
|
|
|
ps_output = fd.read().strip()
|
|
|
|
fd.close()
|
|
|
|
|
|
|
|
fd = os.popen("ps u -p %s | awk '{$1=$2=$3=$4=$5=$6=$7=$8=$9=$10=\"\"; print $0}'" % pid)
|
|
|
|
process_name_raw = fd.read().strip()
|
|
|
|
fd.close()
|
|
|
|
for process_name in process_name_raw.split("\n"):
|
|
|
|
process_name = process_name.strip()
|
|
|
|
# Ignore COMMAND since it is part of the headline of ps output.
|
|
|
|
if process_name == "COMMAND":
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Check if we have whitelisted the process
|
|
|
|
# (e.g., [lxc monitor] /var/lib/lxc satellite).
|
|
|
|
elif process_name in NON_KTHREAD_WHITELIST:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Only consider process names that start with a "["
|
|
|
|
# (e.g., "avahi-daemon: running [towelie.local]"" does not)
|
|
|
|
elif process_name.startswith("["):
|
|
|
|
|
|
|
|
if print_output:
|
|
|
|
print("Checking pid: %s (%s) - " % (pid, process_name),
|
|
|
|
end="")
|
|
|
|
|
|
|
|
file_path = "/proc/%s/maps" % pid
|
|
|
|
try:
|
|
|
|
with open(file_path, 'rt') as fp:
|
|
|
|
data = fp.read()
|
|
|
|
if data == "":
|
|
|
|
if print_output:
|
|
|
|
print("ok")
|
|
|
|
continue
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print("Exception")
|
|
|
|
print(e)
|
|
|
|
print("")
|
|
|
|
continue
|
|
|
|
|
|
|
|
if print_output:
|
|
|
|
print("SUSPICIOUS")
|
|
|
|
print(ps_output)
|
|
|
|
print("")
|
|
|
|
|
|
|
|
else:
|
|
|
|
if ALERTR_FIFO is not None:
|
|
|
|
|
|
|
|
hostname = socket.gethostname()
|
|
|
|
optional_data = dict()
|
|
|
|
optional_data["pid"] = pid
|
|
|
|
optional_data["ps_output"] = ps_output
|
|
|
|
optional_data["hostname"] = hostname
|
|
|
|
message = "Process with pid '%s' on host '%s' suspicious.\n\n" % (pid, hostname)
|
|
|
|
message += ps_output
|
|
|
|
optional_data["message"] = message
|
|
|
|
|
|
|
|
raise_alert_alertr(ALERTR_FIFO,
|
|
|
|
optional_data)
|
|
|
|
|
|
|
|
if FROM_ADDR is not None and TO_ADDR is not None:
|
|
|
|
|
|
|
|
hostname = socket.gethostname()
|
|
|
|
subject = "[Security] Suspicious process found on '%s'" % hostname
|
|
|
|
message = "Process with pid '%s' on host '%s' suspicious.\n\n" % (pid, hostname)
|
|
|
|
message += ps_output
|
|
|
|
|
|
|
|
raise_alert_mail(FROM_ADDR,
|
|
|
|
TO_ADDR,
|
|
|
|
subject,
|
|
|
|
message)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
search_suspicious_process()
|