Skip to content

Commit 79df868

Browse files
authored
Add Tracee eBPF threat detection for Linux Dynamic Analysis (#2235)
1 parent 2794fe7 commit 79df868

File tree

12 files changed

+1756
-2
lines changed

12 files changed

+1756
-2
lines changed
+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import json
2+
import logging
3+
import os
4+
import subprocess
5+
import time
6+
from datetime import datetime
7+
from threading import Thread
8+
9+
from lib.common.abstracts import Auxiliary
10+
from lib.common.exceptions import CuckooPackageError
11+
from lib.common.results import NetlogFile, append_buffer_to_host
12+
13+
# Set up logging
14+
log = logging.getLogger(__name__)
15+
16+
__author__ = "jonisworking,theoleecj2"
17+
__version__ = "1.0.0"
18+
19+
# Constants for Docker configuration
20+
DOCKER_LOG_NAME = "tracee.data"
21+
DOCKER_CONTAINER_NAME = "tracee" # Name of the Docker container to monitor
22+
TRACEE_VERSION = "latest"
23+
24+
25+
def is_docker_installed() -> bool:
26+
"""
27+
Check if Docker is installed on the system.
28+
"""
29+
# Docker must be installed manually on the VM
30+
# Check if Docker is installed
31+
completed_process = subprocess.run(["dpkg-query", "-l", "docker"], capture_output=True)
32+
if b"no packages found" in completed_process.stdout:
33+
return False
34+
else:
35+
return True
36+
37+
38+
def is_docker_container_running(container_name):
39+
"""
40+
Check if the Docker container is currently running.
41+
"""
42+
try:
43+
# Check if the container is running
44+
completed_process = subprocess.run(
45+
["docker", "inspect", "-f", "{{.State.Running}}", container_name], capture_output=True, text=True
46+
)
47+
return completed_process.stdout.strip() == "true"
48+
except Exception as e:
49+
log.error(f"Error checking container status: {e}")
50+
return False
51+
52+
53+
def start_docker_container(container_name, tracee_version):
54+
"""
55+
Start the Docker container.
56+
"""
57+
try:
58+
# Checks
59+
tracee_cmd = [
60+
"sudo docker run --name tracee -d --pid=host --cgroupns=host --privileged "
61+
+ f"-v /etc/os-release:/etc/os-release-host:ro -v {os.getcwd()}/tracee-artifacts/:/tmp/tracee/out/host -v /var/run:/var/run:ro -v {os.getcwd()}/modules/auxiliary/tracee:/policy "
62+
+ "aquasec/tracee:latest --output json --output option:parse-arguments,exec-env,exec-hash --policy /policy/policy.yml --cache cache-type=mem --cache mem-cache-size=1024 "
63+
+ "--capture bpf --capture module"
64+
][0]
65+
66+
log.debug(tracee_cmd)
67+
68+
# Run Docker cmd to start the container
69+
result = subprocess.run(
70+
tracee_cmd,
71+
shell=True,
72+
capture_output=True,
73+
text=True,
74+
)
75+
log.debug(f"Docker container started: {result.stdout}")
76+
77+
# Health check to wait until Tracee begins recording events
78+
health_check_failed = True
79+
80+
while health_check_failed:
81+
time.sleep(10)
82+
result = subprocess.run("strace echo tracee-health-check-1903ae", shell=True, capture_output=True, text=True)
83+
log.info(result.stdout)
84+
health_check_log = subprocess.run("docker logs tracee", shell=True, capture_output=True, text=True)
85+
log.info(health_check_log.stdout)
86+
if "1903ae" in health_check_log.stdout:
87+
health_check_failed = False
88+
89+
except subprocess.CalledProcessError as e:
90+
log.error(f"Error starting Docker container '{container_name}': {e}")
91+
92+
93+
def stop_docker_container(container_name):
94+
"""
95+
Stop the Docker container.
96+
"""
97+
try:
98+
# Run the Docker command to stop the container
99+
result = subprocess.run(["sudo", "docker", "stop", container_name], check=True, capture_output=True, text=True)
100+
log.debug(f"Docker container stopped: {result.stdout}")
101+
102+
except subprocess.CalledProcessError as e:
103+
log.error(f"Error stopping Docker container '{container_name}': {e}")
104+
105+
106+
class Docker(Thread, Auxiliary):
107+
"""
108+
Class for managing Docker operations.
109+
"""
110+
111+
def __init__(self, options, config):
112+
"""
113+
Initialize Docker instance.
114+
"""
115+
log.info("docker start")
116+
self.enabled = config.tracee_linux
117+
log.info(self.enabled)
118+
log.info("Tracee")
119+
Auxiliary.__init__(self, options, config)
120+
self.start_time = None
121+
self.end_time = None
122+
123+
def thread_send_docker_buffer(self):
124+
time.sleep(3)
125+
log.info(self.nc)
126+
result = subprocess.run("sudo docker ps", shell=True, capture_output=True, text=True)
127+
log.info(result.stdout)
128+
result = subprocess.run("sudo docker inspect tracee", shell=True, capture_output=True, text=True)
129+
container_details = json.loads(result.stdout)[0]
130+
logpath = container_details["LogPath"]
131+
132+
cmd = f"sudo tail +1f {logpath}"
133+
log.info(cmd)
134+
135+
try:
136+
proc = subprocess.Popen(
137+
cmd,
138+
stdout=subprocess.PIPE,
139+
stderr=subprocess.PIPE,
140+
shell=True,
141+
env={"XAUTHORITY": "/root/.Xauthority", "DISPLAY": ":0"},
142+
)
143+
144+
for line in proc.stdout:
145+
# log.info(line)
146+
append_buffer_to_host(line, self.nc)
147+
except Exception as e:
148+
log.info(e)
149+
150+
def start(self):
151+
"""
152+
Start Docker container.
153+
"""
154+
if not self.enabled:
155+
return False # result.stdout
156+
157+
if not is_docker_installed():
158+
raise CuckooPackageError("Your VM needs to have Docker installed in order to use Docker functionality (tracee).")
159+
160+
# Check if the Docker container is already running
161+
if not is_docker_container_running(DOCKER_CONTAINER_NAME):
162+
# Start Docker container if it's not running
163+
log.debug("Starting docker container")
164+
start_docker_container(DOCKER_CONTAINER_NAME, TRACEE_VERSION)
165+
else:
166+
log.debug("Docker container is already running.")
167+
168+
log.info("Try to stream")
169+
170+
# stream
171+
self.nc = NetlogFile()
172+
self.nc.init("logs/tracee.log", False)
173+
log.info(self.nc)
174+
self.thread = Thread(target=self.thread_send_docker_buffer)
175+
self.thread.start()
176+
177+
log.info("Streamstart")
178+
179+
self.start_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
180+
181+
def collect_logs(self):
182+
"""
183+
Collect Docker container logs.
184+
"""
185+
186+
log.debug("Tracee module skips log collection as it uses streaming")
187+
188+
def stop(self) -> bool:
189+
"""
190+
Stop Docker container.
191+
"""
192+
log.debug("Tracee module instructed to stop")
193+
if self.enabled:
194+
log.debug("Tracee module instructed to stop + was enabled")
195+
self.end_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
196+
self.collect_logs()
197+
198+
# Stop the Docker container
199+
stop_docker_container(DOCKER_CONTAINER_NAME)
200+
201+
return True
202+
return False

0 commit comments

Comments
 (0)