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.
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 # 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 |
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 filename: /opt/cuckoo3/suricata/suricata-command.socket |
| Location 2 | … # Run Suricata with a specific user-id and group-id: run-as: user: cuckoo group: cuckoo … |
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.
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
/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.
~/.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 |
Save the changes and restart the Cuckoo service. The next time that Suricata produces these alerts they will be displayed on sample submission reports.
