This is a technical how-to guide for installing and customising a Cuckoo3 sandbox environment running locally or in cloud infrastructure. I’d like to share two great resources that I used to get my own Cuckoo3 instance off the ground – Hamza Megahed’s guide as well as the official docs. What I am covering in this guide is based on my own experiences of getting additional features working like Suricata IDS and improving system stability. 

The Cuckoo3 project is a work in progress and I would like to share my appreciation for the work being done to bring Cuckoo3 to the point where its predecessor once stood. In time I hope to make contributions toward this project in both documentation and feature development. 

 

Making the Cuckoo launcher

I’ll pick up where Hamza’s guide finished, with the suggestion of creating a “Cuckoo launcher” script.

Create the file below and make sure that /opt/cuckoo3/cuckood.sh is owned by the cuckoo user.

File Path /opt/cuckoo3/cuckood.sh
Content #!/bin/bash
sudo /opt/cuckoo3/venv/bin/vmcloak-qemubridge br0 192.168.30.1/24 &&
source /opt/cuckoo3/venv/bin/activate &&
cuckoo –debug

I created a systemd service named cuckoo3.service which executes cuckood.sh as the cuckoo user. You might notice that cuckoo3.service references other oddly named cuckoo services – we get to that later.

File Path /etc/systemd/system/cuckoo3.service
Service file content [Unit]
Description=Cuckoo Sandbox Service
After=network.target cuckoo3suricata.service
Requires=cuckoo3suricata.service
StartLimitIntervalSec=60
StartLimitBurst=5

[Service]
Type=simple
User=cuckoo
ExecStart=/opt/cuckoo3/cuckood.sh
WorkingDirectory=/opt/cuckoo3
Environment=”PATH=/opt/cuckoo3/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”
Restart=on-failure

[Install]
WantedBy=multi-user.target

Run the following commands to set up the service.

sudo systemctl daemon-reload

sudo systemctl enable cuckoo3.service

Check the service status with the the command sudo systemctl status cuckoo3.service. You should see the service with the status ‘active (running)’. If the service has stopped or has exited then check its logs.

Setting up Cuckoo rooter

We need to enable Cuckoo rooter in cuckoo.yaml.

Make changes to the file ~/.cuckoocwd/conf/cuckoo.yaml and go to the network_routing section (shown below).
Set ‘enabled’ to True and ‘rooter_socket’ to ‘/tmp/cuckoo3-rooter.sock’. This tells Cuckoo where the socket file for interacting with cuckoo rooter is.

A screen shot of a computer

Description automatically generated

Creating a Cuckoo rooter service

The next step is to configure the Cuckoo rooter – the feature that will automatically create routing rules with iptables to allow analysis VMs to reach the public internet. I found using Cuckoo rooter to be seamless and reliable rather than using static routes with less configuration.

First we need to interact with the Cuckoo rooter cmdlet to get us the Cuckoo rooter command we’ll use in a Cuckoo rooter service. Run this command from /opt/cuckoo3 (or wherever your venv is): cuckoorooter -d --sudo --group cuckoo --print-command /tmp/cuckoo3-rooter.sock

The output should look similar to:

/opt/cuckoo3/venv/bin/cuckoorooter /tmp/cuckoo3-rooter.sock --cwd /home/cuckoo/.cuckoocwd --iptables /sbin/iptables --ip /sbin/ip --openvpn /usr/sbin/openvpn --group cuckoo --debug

Create the file /etc/systemd/system/cuckoo3rooter.service with the file content shown below:

File Path /etc/systemd/system/cuckoo3rooter.service
Content [Unit]
Description=Cuckoo3 Rooter Service
Before=cuckoo3.service
Wants=cuckoo3.service

[Service]
Type=simple
ExecStart=/opt/cuckoo3/venv/bin/cuckoorooter /tmp/cuckoo3-rooter.sock –cwd /home/cuckoo/.cuckoocwd –iptables /sbin/iptables –ip /sbin/ip –openvpn /usr/sbin/openvpn –group cuckoo –debug
Restart=on-failure


[Install]
WantedBy=multi-user.target

This service (cuckoo3rooter.service) is configured to run before the main Cuckoo service. You’ll soon find that without this dependency set up, Cuckoo will crash without the rooter service running first.

Run the following commands to set up the service.

sudo systemctl daemon-reload

sudo systemctl enable cuckoo3rooter.service

Check the service status with the the command sudo systemctl status cuckoo3rooter.service. You should see the service with the status ‘active (running)’. If the service has stopped or has exited then check its logs.

Suricata

I used these instructions to install the latest version of Suricata – version 7.0.7. Follow the instructions under the heading ‘Install Suricata from Ubuntu Repository’.

Configuring Suricata

With Suricata installed, we need to configure Cuckoo in a way that it can communicate with Suricata and send/receive data with it. Suricata supports UNIX socket communication which is what Cuckoo leverages.

As the cuckoo user I created the folder ‘/opt/cuckoo3/suricata’ to be used as the socket file path. Ensure that the cuckoo user has read and write permissions on this folder.

I then had to edit two files: suricata.yaml within the Cuckoo working directory and /etc/suricata/suricata.yaml:

Edits to ~/.cuckoocwd/conf/processing/suricata.yaml: Set enabled to True, and set the value of unix_sock_path to /opt/cuckoo3/suricata/suricata-command.socket.

File ~/.cuckoocwd/conf/processing/suricata.yaml
Content # Enable Suricata pcap processing. Suricata must have unix-command enabled in
# its configuration file. Log giles created by Suricata will be owned by the
# user running Suricata. The Cuckoo user has to be able to read and delete
# these files.
enabled: True False

# The Suricata unix socket that Cuckoo can use to send pcap processing
# commands. Pleas ensure the Cuckoo user can read and write to this unix socket.
unix_sock_path: /opt/cuckoo3/suricata/suricata-command.socket
unix_sock_path: /var/run/suricata/suricata-command.socket

Edits to /etc/suricata/suricata.yaml: Under unix-command set the value enabled to yes, and set the value filename to /opt/cuckoo3/suricata/suricata-command.socket. Within the same file, under run-as set the user and group values to cuckoo.

File /etc/suricata/suricata.yaml
Location 1
# Unix command socket that can be used to pass commands to Suricata.
# An external tool can then connect to get information from Suricata
# or trigger some modifications of the engine. Set enabled to yes
# to activate the feature. In auto mode, the feature will only be
# activated in live capture mode. You can use the filename variable to set
# the file name of the socket.
unix-command:
  enabled: yes auto
  filename: /opt/cuckoo3/suricata/suricata-command.socket
Location 2
# Run Suricata with a specific user-id and group-id:
run-as:
  user: cuckoo root
  group: cuckoo root

Creating a Suricata service

The previous installation of Suricata would have created a service named suricata.service. We don’t want to use this one, we need to create our own Suricata service which runs in a specific way.

In this GitHub issue I found that the default suricata.service which is installed does not run in what is called “PCAP processing mode”. A long story short, Suricata can receive PCAP files for processing over a UNIX socket, but the suricata.service doesn’t run in the processing mode that Cuckoo expects resulting in error messages saying commands could not be found. The fix? Our own Suricata service.

Disable the default suricata.service with this command sudo systemctl unmask suricata.service.

Create another service file named cuckoo3suricata.service (this is the name of the suricata service that the main Cuckoo service references). I’ve provided the service file content below:

File /etc/systemd/system/cuckoo3suricata.service
Content [Unit]
Description=Suricata IDS/IPS Service for Cuckoo3
After=network.target

[Service]
ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml –unix socket=/opt/cuckoo3/suricata/suricata-command.socket -vvv
Restart=always
RestartSec=5
User=root
Group=root
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
NoNewPrivileges=true
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

Run the following commands to set up the service.

sudo systemctl daemon-reload

sudo systemctl enable cuckoo3suricata.service

Check the service status with the the command sudo systemctl status cuckoo3suricata.service. You should see the service with the status ‘active (running)’. If the service has stopped or has exited then check its logs.

And thats it. Give the system a restart. With my experience I had to run several restarts for the services to kick in correctly.

Troubleshooting

The first port of call with any service crashing or stopping unexpectedly will be the service logs.

View a service’s log output with this command: sudo journalctl -u <service name>. Add the flag -f onto this command to follow log output live.

A black screen with white text

Description automatically generated

Customising Suricata

When Cuckoo sends Suricata a PCAP file for analysis, Suricata will generate three output files: 

  • eve.json – outputs alerts, anomalies, metadata, file info and protocol specific records through JSON.
  • fast.log – alerts that Suricata has generated in a single line format.
  • stats.log – statistics of the PCAP on a fixed interval (default 8 seconds).

Suricata uses a classification configuration file to describe each classification type:

  • Format: shortname,short description,priority
  • Example: credential-theft,Successful Credential Theft Detected,1

A screenshot of a computer program

Description automatically generated
Screenshot of /etc/suricata/classification.config

By default, Cuckoo sets out some mappings between Suricata classifications and scoring levels. Some classifications are scored lower/higher than others. Scoring levels range between: informational, suspicious, likely malicious, malicious, and known bad.

A computer screen shot of a black screen with white text

Description automatically generated
Extract from ~/.cuckoocwd/conf/processing/suricata.yaml

 

If a mapping does not exist in the configuration shown above then Cuckoo will not render the Suricata IDS alert.

Example 1:

Fast.log alerts
11/20/2024-10:23:04.108374  [**] [1:2027390:5] ET USER_AGENTS Microsoft Device Metadata Retrieval Client User-Agent [**] [Classification: Misc activity] [Priority: 3] {TCP} 192.168.30.20:49697 -> 2.18.86.16:80
11/20/2024-10:23:04.206832  [**] [1:2027390:5] ET USER_AGENTS Microsoft Device Metadata Retrieval Client User-Agent [**] [Classification: Misc activity] [Priority: 3] {TCP} 192.168.30.20:49698 -> 2.18.86.16:80

No. Fast.log classification Suricata ahort name
1 Misc activity  misc-activity

No mapping exists for this under ~/.cuckoocwd/conf/processing/suricata.yaml, nor should there be for most use cases as this could produce a lot of false positives.

 

Example 2:

Fast.log alerts
11/20/2024-14:12:29.328824  [**] [1:2019714:13] ET MALWARE Terse alphanumeric executable downloader high likelihood of being hostile [**] [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 192.168.30.20:49681 -> 185.215.113.16:80
11/20/2024-14:12:29.433755  [**] [1:2018959:6] ET INFO PE EXE or DLL Windows file download HTTP [**] [Classification: Potential Corporate Privacy Violation] [Priority: 1] {TCP} 185.215.113.16:80 -> 192.168.30.20:49681

Here we have two classifications that are not mapped in Cuckoo by default. We can use the Suricata classification config file to find the shortname fields for these classifications.

  • Classification: Potentially Bad Traffic
  • Classification: Potential Corporate Privacy Violation

No. Fast.log classification Suricata ahort name
1 Potentially Bad Traffic bad-unknown
2 Potential Corporate Privacy Violation policy-violation

In ~/.cuckoocwd/conf/processing/suricata.yaml we need to add two lines as shown in the screenshot below:

classtype_scores:
command-and-control: known bad

bad-unknown: suspicious
policy-violation: suspicious

A screenshot of a computer

Description automatically generated

Save the changes and restart the Cuckoo service. The next time that Suricata produces these alerts they will be displayed on sample submission reports.