Howto: Build a Cuckoo sandbox


(Sean Whalen) #1

Introduction

Note: The previous versions of this guide used Ubuntu server, but since X11 forwarding has been broken in Ubuntu for quite some time now, I’ve updated this guide to use Debian Testing instead.
As a bonus, this way you get the latest stable versions of software with no additional effort! It has actually simplified the Cuckoo installation process a bit.

This tutorial will show you how to create a working malware sandbox, using the fork of Cuckoo developed by Brad Spengler, a former Optiv employee, and others. It contains many improvements over the original Cuckoo project:

  • Fully-normalized file and registry names
  • Handling of WoW64 filesystem redirection
  • Many additional API hooks
  • Service monitoring
  • Correlates API calls to malware call chains
  • Ability to follow APC injection and stealth explorer injection
  • Pretty-printed API flags
  • Per-analysis Tor support
  • Over 120 new signature modules (over 70 developed solely by Optiv)
  • Anti-anti-sandbox and anti-anti-VM techniques built-in
  • More stable hooking
  • Ability to restore removed hooks
  • Greatly improved behavioral analysis and signature module API
  • Ability to post comments about analyses
  • Deep hooks in IE’s JavaScript and DOM engines usable for Exploit Kit identification
  • Automatic extraction and submission of interesting files from ZIPs, RARs, RFC 2822 emails (.eml), and Outlook .msg files
  • Direct submission of AV quarantine files (Forefront, McAfee, Trend Micro, Kaspersky, MalwareBytes, MSE/SCEP, and SEP12 formats currently supported)
  • Automatic malware classification by Malheur
  • Significant contributions from Jeremy Hedges, William Metcalf, and Kevin Ross
  • Hundreds of other bugfixes

A malware sandbox has many components. Building a sandbox requires you to have an understanding of how all these components work together, and how malware might respond. This guide assumes that you have a working, bare metal system, or a large ESX VM with nested virtualization enabled, running Debian Testing with at least 8 GB of RAM (For running analysis tools, and a few windows VMs) and at least 1TB of disk space (for storing samples, analysis results, and possibly memory dumps).

Cuckoo sandbox allows users to choose from a wide variety of different virtualization and networking techniques. While some malware may be able to detect and avoid some technologies used in this guide, these choices provide excellent coverage and analysis with minimal resources. No sandbox is fail-proof.

Preparing the OS

Download the latest Debian Testing ISO

You can use UNetbootin to load the ISO onto a FAT32-formatted USB drive. The Debian installer will give you a warning about possible compatibility issues with UNetbootin, but I did not have any problems.

Choose the default text installer instead of the graphical installer. After the network has been configured (likely via DHCP), you should press Esc and select network configuration to set a static IP address.

When prompted for a root password, leave it blank. This will disable root login, and instead create a standard user account with sudo access, which is safer…

When you get to the software selection stage of the installer, uncheck all graphical options and the print server, and check the SSH server.

Make sure your system is up-to-date:

$ sudo apt-get remove apt-listchanges
$ sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get upgrade -y && sudo apt-get dist-upgrade -y && sudo apt-get autoremove -y

Installing dependencies

Cuckoo is largely written in Python, so you need to install the Python package manager (pip), and some other dependencies and useful tools:

$ sudo apt-get install git mongodb python python-dev python-pip python-m2crypto libmagic1 swig libvirt-dev upx-ucl libssl-dev wget unzip p7zip-full geoip-database libgeoip-dev libjpeg-dev mono-utils yara python-yara ssdeep libfuzzy-dev exiftool curl openjdk-8-jre-headless

By default, Cuckoo uses a SQLite database file to track analysis tasks. That technically works, but it is not as robust and production-ready as a full-featured relational database like PostgreSQL. For example, when SQLite is used, task IDs are recycled after a task is deleted, which can lead to confusion when a new analysis task exists at the same URL as an old one, possibly for a completely different sample!

Install PostgreSQL:

$ sudo apt-get install postgresql postgresql-contrib libpq-dev
$ sudo pip install psycopg2

More Debian packages are needed to generate PDF reports:

$ sudo apt-get install wkhtmltopdf xvfb xfonts-100dpi

tcpdump needs to be installed and configured to generate packet captures (PCAPs):

$ sudo apt-get install tcpdump libcap2-bin
$ sudo chmod +s /usr/sbin/tcpdump

ClamAV is needed assist in identifying malware:

$ sudo apt-get install clamav clamav-daemon clamav-freshclam

Install pydeep, which is used to generate fuzzy hashes:

$ sudo pip install git+https://github.com/kbandla/pydeep.git

Install Malheur, which is used for malware behavior correlation

$ sudo apt-get install uthash-dev libconfig-dev libarchive-dev libtool autoconf automake checkinstall
$ git clone https://github.com/rieck/malheur.git
$ cd malheur
$ ./bootstrap
$ ./configure --prefix=/usr
$ make

Note: The version number checkinstall parses from Malhur doesn’t conform to Debian standard, so you’ll have to specify the correct version number when prompted by checkinstall. Technically, sudo make install will work fine. checkinstall just makes it easier to upgrade and/or remove it just like any other Debian package.

$ sudo checkinstall
$ cd

Install the Volatility memory analysis system:

$ sudo apt-get install python-pil
$ sudo pip install distorm3 pycrypto openpyxl
$ sudo pip install git+https://github.com/volatilityfoundation/volatility.git

Install the PyV8 JavaScript engine, used for analyzing malicious JavaScript:

$ sudo apt-get install libboost-all-dev
$ sudo pip install git+https://github.com/buffer/pyv8 # This can take a long time, and may appear to hang

Install the Suricata IDS:

$ sudo apt-get install suricata

Create a copy of the default Suricata configuration file for Cuckoo:

$ sudo cp /etc/suricata/suricata-debian.yaml /etc/suricata/suricata-cuckoo.yaml

Edit /etc/suricata/suricata-cuckoo.yaml:

$ sudo nano /etc/suricata/suricata-cuckoo.yaml

Disable the fast and unified2 log types; we don’t need those.

Locate file-store: (use ctrl+w to search). Set enabled to yes. Set force-md5 and force-filestore to yes. Enable file-log, which should be located right below it.

Locate reassembly: use ctrl+w to search (You’ll need to do this twice; the first reference is just comment documentation about it, you want is the actual, non-commented reassembly:)

Set depth, to 0 (without a unit of measurement)

Set request-body-limit and response-body-limit to 0 (without any measurement unit), under default-config:

Under the vars: address-groups: section, set EXTERNAL_NET to any.

Download etupdate to update Emerging Threat’s Open IDS rules:

$ git clone https://github.com/seanthegeek/etupdate.git
$ sudo cp etupdate/etupdate /usr/sbin
$ sudo /usr/sbin/etupdate -V

Edit the crontab:

$ sudo crontab -e

Add the line:

42 * * * * /usr/sbin/etupdate

This will run etupdate every 42 minutes after each hour. You should probably change 42 to some other minute, so everyone following this tutorial doesn’t query Emerging Threats for updates at the exact same time.

Install KVM and virt-manager

$ sudo apt-get install qemu-kvm libvirt-clients libvirt-daemon virt-manager

Add your user to the kvm and libvirt groups, so you can manage VMs:

$ sudo usermod -a -G kvm $USER
$ sudo usermod -a -G libvirt $USER

You’ll need to log out and log back in for the group membership to take effect.

Configure virtual networking

Because managing QEMU/KVM/libvirt purely by command line can have a steep, time-consuming learning curve for even experienced Linux administrators, we’ll use the virt-manager GUI. X server forwarding allows clients to access graphical applications running on a server, even when that server is headless (i.e. does not use a graphical environment)

For accessing the actual sandbox VMs remotely, we’ll use VNC, which is much faster than the X protocol, especially when viewing a full desktop.

Linux desktop/laptop clients:

Simply pass the -X argument to ssh, along with an option to tunnel the the local 5900 port to the emote VM VNC port 5900.

$ ssh -X -L 5900:127.0.0.1:5900 user@hostname

Mac clients:

Systems running Mac OS will need XQuartz installed. After a one-time system reboot, the command is the same as Linux.

Simply pass the -X argument to ssh, along with an option to tunnel the the local 5900 port to the emote VM VNC port 5900.

$ ssh -X -L 5900:127.0.0.1:5900 user@hostname

Windows Clients:

The initial setup for windows clients is a little more involved:

Download and install Cygwin. Select the following packages to install:

  • openssh
  • xorg-server
  • xinit

For more details on this process, check out the Cygwin/X install guide.

Open a Cygwin prompt and run

$ startxwin &

You’ll see the X logo appear in your system tray. Right click on it, then select
xterm from the Applications menu. In xterm the ssh command is used very similarly to the other operating systems above, except the -X option should be -Y.

Simply pass the -Y argument to ssh, along with an option to tunnel the the local 5900 port to the emote VM VNC port 5900.

$ ssh -Y -L 5900:127.0.0.1:5900 user@hostname

From here on, the instructions are the same for all client systems.

In the SSH session, run:

$ virt-manager

Those with high-DPI/ 4K displays should prefix this command with GDK_SCALE=2, to scale the UI properly.

You’ll probably one or many warnings in your console, those can be ignored, as long as virt-manager window appears a few seconds later. If you have a long-running SSH session without a GUI running, sometimes the application has trouble making a connection to your X server, especially on Mac OS, If this occurs, try closing your console, and reconnect.

In the View menu of the Virtual Machine Manager window, select Connection Details, then select the Virtual Networks section.

Stop the Default network, then delete it.

Create a new isolated virtual network called cuckoo at 192.168.100.0/24, using the wizard.

Create the cuckoo user

Create a user named cuckoo on the system. This user will run a few services that Cuckoo needs, as well as Cuckoo itself.

$ sudo adduser cuckoo
$ sudo usermod -L cuckoo

Add the cuckoo user to the right groups to manage VMs

$ sudo usermod -a -G kvm cuckoo
$ sudo usermod -a -G libvirt cuckoo

Download Cuckoo

$ sudo su cuckoo
$ cd
$ wget https://bitbucket.org/mstrobel/procyon/downloads/procyon-decompiler-0.5.30.jar
$ git clone https://github.com/spender-sandbox/cuckoo-modified.git
$ mkdir vmshared
$ cp cuckoo-modified/agent/agent.py vmshared/agent.pyw
$ exit
$ sudo chmod ug=rwX,o=rX ~cuckoo/vmshared
$ sudo mv ~cuckoo/cuckoo-modified /opt/cuckoo
$ sudo pip install -r /opt/cuckoo/requirements.txt
$ sudo su cuckoo
$ cd /opt/cuckoo/utils
$ ./community.py -afw
$ exit

Configure web services

In this guide we’ll be using the nginx web server as a secure reverse proxy for Cuckoo.

$ sudo apt-get install nginx apache2-utils

Add yourself to the cuckoo group:

$ sudo usermod -a -G cuckoo $USER

Create a SSL certificate

It is very important that communications between the sandbox and its users are secure for a couple of reasons:

  • Prevents credentials from being sniffed
  • Prevents triggering IDS alarms in your network while uploading malware

You can use a self-signed certificate, or one that has been signed by an internal or external Certificate Authority (CA). Using a CA will allow browsers and other HTTPS clients that trust the CA to trust that the connection is secure. Self signed certificates will generate browser warnings.

If you are accessing your sandbox directly via in internal/private IP address, you must use a self signed certificate.

Create a directory to store the certificates and keys:

$ mkdir ~/ssl
$ cd ~/ssl

To create a self-signed certificate, run:

$ openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout cuckoo.key -out cuckoo.crt

Or, to create a Certificate Signing Request (CSR) for a CA, run:

$ openssl req -newkey rsa:4096-nodes -keyout cuckoo.key -out cuckoo.csr

Fill in the prompts. Watch out for Common Name (e.g. server FQDN or YOUR domain name), which is the IP address or domain name that you will be hosting Cuckoo web services on. it is the most important field.

Remove the CSR after you have your certs

$ rm cuckoo.csr

Generate Diffie-Hellman (DH) parameters This takes a long time.

$ openssl dhparam -out dhparam.pem 4096

Move the keys into place:

$ cd
$ sudo mv ssl /etc/nginx

Secure the keys:

$ sudo chown -R root:www-data /etc/nginx/ssl
$ sudo chmod -R u=rX,g=rX,o= /etc/nginx/ssl

Configuring nginx

Disable the default nginx configuration:

$ sudo rm /etc/nginx/sites-enabled/default

Create the Cuckoo web server configuration

$ sudo nano /etc/nginx/sites-available/cuckoo
server {
    listen IP_Address:443 ssl http2;
    ssl_certificate /etc/nginx/ssl/cuckoo.crt;
    ssl_certificate_key /etc/nginx/ssl/cuckoo.key;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off; # Requires nginx >= 1.5.9
    # Uncomment this next line if you are using a signed, trusted cert
    #add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    root /usr/share/nginx/html;
    index index.html index.htm;
    client_max_body_size 101M;
    auth_basic "Login required";
    auth_basic_user_file /etc/nginx/htpasswd;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /storage/analysis {
       alias /opt/cuckoo/storage/analyses/;
       autoindex on;
       autoindex_exact_size off;
       autoindex_localtime on;
    }

    location /static {
      alias /opt/cuckoo/web/static/;
    }
}

server {
    listen IP_Address:80;
    return 301 https://$server_name$request_uri;
}


server {
  listen 192.168.100.1:8080;

    root /home/cuckoo/vmshared;

     location / {
           try_files $uri $uri/ =404;
           autoindex on;
           autoindex_exact_size off;
           autoindex_localtime on;
     }
}

# Host the upstream legacy API 
server {
    listen IP_Address:4343 ssl http2;
    ssl_certificate /etc/nginx/ssl/cuckoo.crt;
    ssl_certificate_key /etc/nginx/ssl/cuckoo.key;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off; # Requires nginx >= 1.5.9
   # Uncomment this next line if you are using a signed, trusted cert
    #add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    root /usr/share/nginx/html;
    index index.html index.htm;
    client_max_body_size 101M;

    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # Restrict access
       allow IP_Address;
      #allow 192.168.1.0/24;
      deny all;
    }
}

In both the SSL and non-SSL server blocks, replace IP_Address with the IP address of the interface you will access web services through.

Enable the nginx Cuckoo configuration:

$ sudo ln -s /etc/nginx/sites-available/cuckoo /etc/nginx/sites-enabled/cuckoo 

Setup basic authentication:

Cuckoo’s web interface has no authentication mechanism of its own, so we’ll use use nginx's basic auth. To create a user, use

$ sudo htpasswd -c /etc/nginx/htpasswd exampleuser 

Where exampleuser is the name of the user you want to add.

Secure the permissions of the httpasswd file:

$ sudo chown root:www-data /etc/nginx/htpasswd
$ sudo chmod u=rw,g=r,o= /etc/nginx/htpasswd

Restart nginx:

$ sudo service nginx restart

Inetsim

Inetsim is an internet simulator. It has a bunch of fake network services. It can be configured to respond to all DNS requests with it’s own address, which drives traffic to itself, where it can establish fake connections.

It usually provides just enough to allow malware to beacon once, before it becomes confused by the unexpected response. This is useful if you want to see what an initial beacon looks like, but don’t want to allow the sample to access the internet at all, possibly for OPSEC reasons.

To install inetsim:

$ wget http://www.inetsim.org/debian/binary/inetsim_1.2.5-1_all.deb
$ sudo apt-get install gdebi-core
$ sudo gdebi inetsim_1.2.5-1_all.deb

Edit the configuration:

$ sudo nano /etc/inetsim/inetsim.conf

Set service_bind_address and dns_default_ip to 192.168.100.1

Unfortunately libvirt is already running a DNS server in the virbr0 interface as a part of its process, so inetsim’s fake DNS server will need to run on a different port. Set dns_bind_port to 5342. We’ll redirect VM DNS requests to this port using our startup script, which we’ll create later in this guide.

Edit /etc/default/inetsim:

$ sudo nano /etc/default/inetsim

Set ENABLED to 1

Start inetsim:

$ sudo service inetsim restart

Tor

Tor (The Onion Router) is a great way to give your sandbox VM a pseudo-annonymous, live internet connection. If you’d like to use Tor with your sandbox, here are a few things to keep in mind:

  • Most corporate, university, and other shared networks have policies prohibiting the use of Tor for security reasons. Tor can help keep what you are doing hidden, but it will be very obvious to most network administrators when you use Tor. Get permission if necessary.

  • Only DNS and TCP traffic can be routed through Tor; the rest will be blocked if configured properly. As a result, malware might not behave the same way over Tor as it would over a normal internet connection. However, most malware makes use of TCP.

  • It is possible for a server operator (i.e. malware operator) to recognize that a client is using Tor by checking the IP address against the public list of exit nodes, which may warn attackers that a sample is being analyzed. The fork of Cuckoo provides a per-analysis toggle for Tor. Use it wisely.

  • Although Tor may keep your connection anonymous, the content and configuration of your VM may reveal your identity.

For more on what Tor is, and how it works, view the overview.

Install Tor:

$ sudo apt-get install tor

Once Tor is installed, edit its config file

$ sudo nano /etc/tor/torrc

Add the following lines to the bottom:

TransListenAddress 192.168.100.1
TransPort 9040
DNSListenAddress 192.168.100.1
DNSPort 5353

Then restart Tor:

$ sudo service tor restart

Install Privoxy:

$ sudo apt-get install privoxy

Edit the Privoxy configuration:

$ sudo nano /etc/privoxy/config

Locate, and uncomment the following line:

#        forward-socks5t             /     127.0.0.1:9050 .

Restart Privoxy:

$ sudo service privoxy restart

Install the scripts that Cuckoo will use to enable and disable Tor routing per analysis:

$ git clone https://github.com/seanthegeek/routetor.git
$ cd routetor
$ sudo cp *tor* /usr/sbin
$ cd

routetor uses a UNIX socket client/server model, so that root can take privileged actions on behalf of the cuckoo user which runs the client scripts.

Schedule routetor to run at system boot by running:

$ sudo crontab -e

And adding the following line to the crontab file:

@reboot /usr/sbin/routetor

Start routetor for the first time:

$ sudo /usr/sbin/routetor &

vsftpd

We will use nginx to serve static files like installers from the host to the VMs. But what if you wanted to copy a file from a VM to the host? The simplest way is to use vsftpd as an anonymous FTP server. That way, the VM can send files without being able to overwrite the installers hosted by nginx.

First, create a publicly accessible folder:

$ sudo mkdir /home/cuckoo/vmshared/pub
$ sudo chown cuckoo:cuckoo /home/cuckoo/vmshared/pub
$ sudo chmod 777 /home/cuckoo/vmshared/pub

Install vsftpd:

$ sudo apt-get install vsftpd

By default, it runs on port 21, which is already is use by inetsim to run its fake FTP server, so we need to change the port it listens on, among other things:

$ sudo nano /etc/vsftpd.conf

Make the following changes:

listen=YES
listen_ipv6=NO
anonymous_enable=YES
local_enable=NO

Uncomment the following lines:

write_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES

Add the lines:

listen_address=192.168.100.1
listen_port=2121
anon_root=/home/cuckoo/vmshared
anon_umask=000
chown_upload_mode=0666
pasv_enable=Yes
pasv_min_port=10090
pasv_max_port=10100

Restart the service:

$ sudo service vsftpd restart

The VMs can now read /home/cuckoo/vmshared and write to /home/cuckoo/vmshared/pub.

You can access the FTP server in Windows natively by typing ftp://192.168.100.1:2121 into any Explorer window.

Create your first sandbox VM

The software in the VM should be as plain and bare-bones as possible. Many first-time sandbox builders make the mistake of using a production image for their sandbox. This can cause many problems:

  • Attackers may learn who you are, and what’s in your image
  • Security controls in the image may interfere with sandboxing
  • It can be more difficult to determine why a sample behaved the way it did

Upload your plain Windows ISOs, and the latest vnet drivers ISO to your server

In order to maintain anonymity, the VM must never touch your LAN or WAN connections. By following this guide, the VM will only be able to communicate with the host, and other VMs, unless you enable Tor.

This part of the guide will assume that you have a Windows 7 Professional 64bit ISO and a valid license. If you are using a different version of windows, the setup steps may be slightly different.

Note to volume license users: Do not use KMS keys with Windows, Office, or any other Microsoft product. KMS clients require regular check-ins for the license to remain activated, which is not possible for isolated VMs. Use MAK instead. Those keys can be used for independent activation.

Start virt-manager. Create a new Windows virtual machine.

Watch out for an error like this:

Warning: KVM is not available. This may mean the KVM package is not installed, or the KVM kernel modules are not loaded. your virtual machine may preform poorly.

KVM Error Screenshot

If you see this error, it means that virtualization support is not enabled or your host system’s CPU settings. Check your host system’s BIOS/UEFI settings, or, if you are running Cuckoo in a virtualization platform like ESXi, ensure nested virtualization is enabled for the Cuckoo VM. Restart the host system, and try creating the sandbox VM again.

Name the sandbox VM something reasonable, like sandbox-win7-01, you’ll use this name later. Avoid spaces.

Before completing the last stage of the wizard, make the following changes:

  • Make sure number of CPUs are 2
  • Check Customize configuration before install
  • Set the network selection to the cuckoo isolated virtual network you created earlier

Click Finish.

In the VM Installation that comes up, select the NIC, and set the Device Model to virtio for the best performance. the virtio storage bus is also a lot faster than the default IDE bus, but the Windows can’t be installed on a virtio storage bus.

To work around this issue, click the Add Hardware button, then add a storage device, with a VirtIO bus type, and a cache mode of writeback (under advanced options). Leave the default size of 8.0 GB. Windows can’t be installed to VirtIO device, but it can use them once the driver has been installed manually in Device Manager. We’re only using this new drive as a temporary dummy drive of sorts, so that Windows knows how to work with VirtIO drives after it is installed. We’ll go into detail about installing the drivers later on.

Change the display type to VNC VNC. Leave the port on Auto this means that the VM will take the first port it can once it starts, starting with the port we forwarded, 5900, and incrementing each time another VM with VNC enabled with an Auto port is selected. We only forwarded one port through SSH when we connected (5900), so we can access one VM at a time via VNC. To forward more ports, add more -L options.

To access another VM via VNC, you can shut down the VM you were using, freeing up the port for the next one to start. Or, you can add multiple -L options and different ports when connecting over SSH, to forward multiple VNC ports, and use multiple VMs over VNC at once.

Once all that is done, click on begin installation to start the VM for the first time. The window that opens will be too small, so resize it so you can see the full display. If you are working on the same LAN as the server, this console will probably be responsive enough for you. If you find that it is slow, use a VNC client and connect to 127.0.0.1 with the password that you set earlier. and it will be much faster.

Most Linux Distributions come with a “Remote Desktop” viewer that can connect over VNC. On Mac OS, use the built-in “Screen Sharing” app (find with Spotlight), and for Windows, use TightVNC

Choose a custom Windows install, then click next.

After Windows is installed create a username and computer name that is fictitious, but realistic for your industry. Leave the password blank.

When you get to a screen that says “Help protect your computer and improve Windows automatically”, click “Ask me later”.

Configuring the VM

Once Windows has been installed, and you are at the desktop:

  • Set the theme to Classic
  • Set the screen resolution to 1024x768

This will make the VM easier to work with, and consume less resources.

Installing the VirtIO drivers

Open the VM in virt-manager and click on the blue information button in the toolbar to edit the hardware info.

Select the IDE CD-ROM drive, and disconnect the windows ISO. Then, connect the VirtIO drivers ISO that you downloaded earlier.

In the VM, right click on Computer in the Start Menu, then click Properties. In the upper-left of the System window, click Device Manager.

Follow these steps for each of the “Other devices”:

  1. Right-click on the device, and click Update Driver Software
  2. Click browse my computer manually
  3. Select the root of the D drive

Windows will automatically locate the proper driver on the disk.

After all of the drivers have been installed, shut down the system.

Edit the VM hardware options again, and disconnect the ISO from the CD-ROM drive.

Now that the driver for the VirtIO storage bus has been installed in Windows, the dummy drive isn’t needed any more, and you can configure your primary drive to use VirtIO for much-improved performance.

Remove the dummy VirtIO disk.

Edit the IDE disk. Under advanced options, set the bus to VirtIO Under performance, set the cache mode to writeback.

Start the VM.

Configure the IP settings:

  1. Open the Network and Sharing Center, located in the control panel.
  2. Click on the Local Area Connection
  3. Click Proprieties
  4. Double click on the IPv4 protocol

Configure:

IP Address: 192.168.100.101
Subnet Mask: 255.255.255.0
Default Gateway: 192.168.100.1

Primary DNS: 192.168.100.1
Secondary DNS: Blank

Ensure that Windows Updates are completely disabled, then activate the Tor transparent proxy for the VM, so you can activate Windows anonymously.

 $ sudo torstart 192.168.100.101

Activate windows.

Install and activate your copy of Office (32-bit only, even in a 64-bit OS, due to a bug in Cuckoo). For privacy reasons, do not use Office365, or at least sign out after install if you have no other choice. Remember to disable all update checking when Office prompts you about it.

If your installer is in file format rather than an ISO, zip up the files, and upload the zip to /home/cuckoo/vmshared. It can then be download by the VM from http://192.168.100.1:8080/

Stop the Tor transparent proxy:

$ sudo torstop 192.168.100.101 

Shut down the VM.

Take a snapshot at this point, in case you ever need a fresh VM. Click on the snapshots button on the toolbar.

Then click on the plus button in the bottom left. Name it something like installed.

Start the VM back up. Use the reg files in this zip to disable security features and noisy network services that will interfere with analysis. Run the reg file for your Windows version and Office version, then reboot the VM.

In order to work with Cuckoo, the sandbox VM will need the following installed on it:

For convince, I have bundled all the files listed below in one zip file, organized by guest OS version, and common files required on all guests. You can upload this file, or or the individual files to /home/cuckoo/vmshared. They can be download by the VM from http://192.168.100.1:8080/ This is much more secure than downloading EXEs over Tor, which may be tampered with.

Install all of the latest supported Microsoft Visual C++ Redistributables, which as of this writing are:

To analyze files that use a newer .NET framework, install Microsoft .NET framework 4.6.1.

To analyze more than PE files, the following also need to be installed (older versions are greatly preferred for exploitability and corporate realism):

As you install each of these programs, change their configuration to disable update checks, which can create noisy PCAPs.

Run Adobe Reader, Accept the Terms and Conditions, and maximize the window, so PDFs will open in the future.

Configure Adobe Reader (in preferences) and Java (in the Control Panel) to not check for updates.

To add some realism, find some non-sensitive and non-identifying documents, music, pictures and other files to put into the Windows user’s folder, so you can see how malware might interact with them. Let it seem “lived in”. Be careful to remove or replace any identifying metadata before you send it to the VM. Use Flickr, Jamendo, and Archive.org, to find pictures, music, and more under Creative Commons license. Then, do what you would normally do with those kinds of files, open a few of those files, open them, edit edit them, and import music into Windows Media Player. Browse some known safe, ad-free sites like Wikipedia and secure government sites over SSL/TLS, that way, you build up some browsing history, with minimal risk of your sandbox being popped prematurely in the process. Some malware checks for things like this this sort of activity on the system as a way of evading sandboxes.

Copy the agent.pyw script from the shared folder to the the Windows user’s Startup folder, which is located in the Start Menu, under All Programs.

Click Start and type msconfig, and press enter. Disable all items in the Startup tab except agent.pyw. In the Services tab, check the box to hid all of the Microsoft services, then disable all of the 3rd party update services.

Restart the system when prompted.

If all is well, you should see pythonw.exe in the list of processes in the task manager.

Shut down the VM.

VM Detection countermeasures

In order to make it hardware for malware to detect that it is running in a VM/sandbox, we must edit the VM’s CPU settings

First, dump the VM’s XML configuration

$ virsh dumpxml win7-sandbox-01 > /tmp/win7-sandbox.01.xml

Edit the dumped configuration:

$ nano /tmp/win7-sandbox.01.xml

KVM by default will pass through a feature flag, viewable in ECX as the 31st bit
after executing the CPUID instruction with EAX set to 1. Some malware will use this
unprivileged instruction to detect its execution in a VM. One way to avoid this is to modify
your VM definition as follows: find the following line::

<domain type='kvm'>

Change it to:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>

Then within the domain element, add the following:

<qemu:commandline>
      <qemu:arg value='-cpu'/>
      <qemu:arg value='host,-hypervisor'/>
</qemu:commandline>

Instead of using “host”, you can also choose a number of other CPU models from the
list displayed with the “qemu-system-i386 -cpu help” command (SandyBridge, Haswell, etc).

Save the XML file, and then import (i.e. define) it:

$ virsh define /tmp/win7-sandbox.01.xml

Create a new snapshot called cuckoo you’ll use this for recovering state and cloning VMs.

Start the VM, wait for windows to fully load, then wait another five seconds.

Take a snapshot; call it running

Power off the VM, then restore the cuckoo snapshot

Your sandbox VM is now ready for Cuckoo.

Set up PostgreSQL

Replace somePassword with a password of your choice. It can be random. You only need to use it in the cuckoo config

$ sudo su postgres
$ psql
# CREATE USER cuckoo WITH PASSWORD 'somePassword';
# CREATE DATABASE cuckoo;
# GRANT ALL PRIVILEGES ON DATABASE cuckoo to cuckoo;

Type \q to exit

Exit the postgres bash shell:

$ exit 

Configure Cuckoo

$ sudo su cuckoo
$ cd /opt/cuckoo
$ nano conf/cuckoo.conf

Change the machinery option to kvm

Change the terminate_processes option to yes. This will make Cuckoo gracefully request the termination of the process that is being analyzed prior to shutting down the VM. This is useful for things like some Office macros that launch on close.

Warning! By default, Cuckoo is configured to do post-analysis DNS lookups using the host! This is to allow comparisons with what the VM resolved. However, it could also potentially tip off an attacker and/or deanonymize you, even if your VM isn’t connected to the internet! To disable this feature, set resolve_dns to off in cuckoo.conf.

Set ip to 192.168.100.1.

Set the connection setting to use PostgreSQL:

connection = postgresql://cuckoo:password@localhost:5432/cuckoo

Where password is the password you set in PostgreSQL for the cuckoo user.

$ nano conf/processing.conf

Under static, uncomment the line with the procyon_path variable, including any leading whitespace.

Set Suricata enabled to yes.

Change the Suricata conf option to /etc/suricata/suricata-cuckoo.yaml

$ nano conf/reporting.conf

Set reporthtmlsummary enabled to yes.

Set reportpdf enabled to yes.

Set mongodb enabled to yes.

Set resubmitexe enabled to yes.

Set malhur enabled to yes.

Edit the Cuckoo KVM configuration file:

$ sudo nano conf/kvm.conf

Set machines to the name of your sandbox VM, such as sandbox-win7-01

Replace cuckoo1 in brackets with the name of your sandbox VM, such as sandbox-win7-01

Set label to the name of your sandbox VM, such as sandbox-win7-01

Uncomment the snapshot option by deleting the # and any leading white space, then set it to the name of your running snapshot, running.

Uncomment the tags option, by deleting the # and any leading white space. Make sure it includes either 32_bit or 64_bit to match the VM OS architecture, so Cuckoo knows which VMs can process 64-bit samples. Add other tags of your choice to describe the VMs, for your own convince. For example:

windows_7,64_bit,acrobat_reader_11,java_6

Finally, uncomment the correct mem_profile for the VM OS, by deleting the # and any leading white space.

Install the community modules

$ sudo su cuckoo
$ cd utils
$ ./community.py -afw
$ exit

Hardening your sandbox host

You should take some basic steps to secure your system, especially when running live malware. Even something simple as strings can have security vulnerabilities

Set up automatic security updates:

$ sudo apt-get install unattended-upgrades apt-listchanges

Prevent outsiders from accessing services through brute force:

$ sudo apt-get install fail2ban

Configure the firewall (replace enp3s0 with your primary network interface, if needed. Use sudo ip a for a list):

$ sudo apt-get install ufw
# Allow access to services from the primary NIC
sudo ufw allow in on enp3s0 to any port 80 proto tcp # HTTP
sudo ufw allow in on enp3s0 to any port 443 proto tcp # HTTPS
sudo ufw allow in on enp3s0 to any port 22 proto tcp # SSH
sudo ufw allow in on enp3s0 to any port 4343 proto tcp # Legacy upstream API

# Allow VMs to access cuckoo/inetsim services
sudo ufw allow in on virbr0 to any port 8080 proto tcp # vmshared files
sudo ufw allow in on virbr0 to any port 2042 proto tcp # Cuckoo result server
sudo ufw allow in on virbr0 to any port 5353 proto udp # TOR DNS
sudo ufw allow in on virbr0 to any port 9040 proto tcp # TOR TCP
sudo ufw allow in on virbr0 to any port 53 proto udp # DNS
sudo ufw allow in on virbr0 to any port 5342 proto udp # inetsim DNS
sudo ufw allow in on virbr0 to any port 80 proto tcp # HTTP
sudo ufw allow in on virbr0 to any port 443 proto tcp # HTTPS
sudo ufw allow in on virbr0 to any port 25 proto tcp # SMTP
sudo ufw allow in on virbr0 to any port 465 proto tcp # SMTPS
sudo ufw allow in on virbr0 to any port 110 proto tcp # POP3
sudo ufw allow in on virbr0 to any port 995 proto tcp # POP3S
sudo ufw allow in on virbr0 to any port 69 proto udp # TFTP
sudo ufw allow in on virbr0 to any port 21 proto tcp # FTP
sudo ufw allow in on virbr0 to any port 2121 proto tcp # Shared FTP
sudo ufw allow in on virbr0 to any port 10090:10100 proto tcp # Shared FTP passive ports
sudo ufw allow in on virbr0 to any port 990 proto tcp # FTPS
sudo ufw allow in on virbr0 to any port 123 proto udp # NTP
sudo ufw allow in on virbr0 to any port 6667 proto tcp # IRC
sudo ufw enable

Startup script

As you have seen, there are a lot of services working behind-the-scenes to make Cuckoo work. This script will help you start and restart all of them:

$ sudo pip install gunicorn
$ sudo nano /usr/sbin/cuckooboot
#!/bin/bash

CUCKOO_USER="cuckoo"
CUCKOO_PATH="/opt/cuckoo"
VIRBR_IP="192.168.100.1"
INETSIM_DNS_PORT="5342"
VIRBR_DEV="virbr0"

su $CUCKOO_USER -c "pkill gunicorn" >/dev/null 2>&1
su $CUCKOO_USER -c "pkill python" > /dev/null 2>&1

/usr/bin/curl -s http://$VIRBR_IP:8080/ > /dev/null

# Wait for the virtual bridge to become active before (re)starting services
while [ $? -ne 0 ]
do
sleep 5
/usr/sbin/service nginx restart
/usr/bin/curl -s http://$VIRBR_IP:8080/ > /dev/null
done

# Restart services that bind to the bridge
/usr/sbin/service tor restart
/usr/sbin/service inetsim restart
/usr/sbin/service vsftpd restart

# Start Cuckoo
cd $CUCKOO_PATH
su $CUCKOO_USER -c "./cuckoo.py &"

# Start the Cuckoo web UI
cd web
su $CUCKOO_USER -c "gunicorn --reload -D -w 4 -b 127.0.0.1:8000 web.wsgi"

# Start the legacy upstream API
cd ../utils
su $CUCKOO_USER -c "gunicorn --reload -D -w 4 -b 127.0.0.1:8001 api"

# Redirect libvirt VM DNS quires to inetsim's DNS port
/sbin/iptables -t nat -C  PREROUTING -d $VIRBR_IP -p udp --dport 53 -j REDIRECT --to-ports $INETSIM_DNS_PORT >/dev/null 2>&1
if [ $? -ne 0 ]; then
    /sbin/iptables -t nat -I PREROUTING -d $VIRBR_IP -p udp --dport 53 -j REDIRECT --to-ports $INETSIM_DNS_PORT
fi

# Allow inetsim to accept traffic for any IP address
/sbin/iptables -t nat -C PREROUTING -i $VIRBR_DEV -j REDIRECT >/dev/null 2>&1
if [ $? -ne 0 ]; then
    /sbin/iptables -t nat -A PREROUTING -i $VIRBR_DEV -j REDIRECT
fi
$ sudo chmod +x  /usr/sbin/cuckooboot

Schedule the cuckooboot server to run at system boot

$ sudo crontab -e

Add the line:

@reboot /usr/sbin/cuckooboot > /dev/null 2>&1

Run cuckooboot for the first time:

$ sudo /usr/sbin/cuckooboot

You should now be able to access the Cuckoo web interface at the root of your web server, and upload your first sample. Congratulations!

Updating Cuckoo

Commits are made to the project repositories regularly. It is recommended to follow the cuckoo-modified and community-modified repositories on GitHub to stay advised of the latest bugs and updates.

$ cd /opt/cuckoo
$ git pull

Occasionally there will be conflict between your configuration files and new configuration files.

To view the differences, run:

$ git diff

Make notes on your original configuration settings (in red), especially the connection setting if cuckoo.conf changed, it has your database password!

Once you have made note of your configuration settings, delete the conflicting files:

$ rm conf/example.conf

Run git pull again.

$ git pull

This will replace the files you deleted with the updated version.

Edit each file, and restore your configuration changes.

Then update the Cuckoo community modules.

Warning : This command will overwrite any existing signature files. If you have made any changes, back them up, and consider creating a pull request for the community repository.

$ cd utils
$ ./community.py -afw

Restart services:

$ sudo /usr/sbin/cuckooboot

Scaling Cuckoo

To allow to allow Cuckoo to analyze more than one sample at the same time, you’ll need to create more VMs.

  1. Restore the cuckoo snapshot on your original VM to get it to a malware-free state.
    Clone the VM by right-clicking its name in the list. Name it something like sandbox-win7-02, and so on
  2. Start the VM
  3. Connect to it using VNC
  4. Change the IP address to something else in the 192.168.100.102-192.168.100.254 range
  5. Change the hostname to match the new VM name, and avoid conflict with existing domain
  6. Start the VM. Wait a couple of minutes.
  7. Crate a snapshot called running
  8. Shut down the VM.

Edit the KVM configuration file:

$ sudo nano conf/kvm.conf

Add the VM name to to the machines list, separated by a comma (no spaces).

Copy and paste from [sandbox-win7-01] on down

Replace the name in brackets with the name of the new VM. Do the same with the label variable.

Repeat these steps for each VM. You can build different VMs containing different software or windows versions, and them group them by setting tags in this file. You can specify a tag to use when submitting a sample.

Restart services:

$ sudo /usr/sbin/cuckooboot

Adding YARA rules

Cuckoo looks for YARA rules three sub directories in data/yara, by the type of data to match:

  • binaries
  • memory
  • urls

Place your .yar rule files in the appropriate directories, and then restart Cuckoo.

$ sudo /usr/sbin/cuckooboot

YARA rule indexes will be automatically generated.

Warning! Cuckoo shows the matching strings from memory rules (but not filesystem rules), this may be in violation of sharing rules of groups such as the YARA exchange.

Working with the web APIs

There are two web APIs that are distributed with the cuckoo-modified project:

Legacy upstream web API

This API comes from the original upstream Cuckoo project as utils/api.py It is a Bottle webapp that is designed to run on its own port, on the same box as Cuckoo most applications that integrate with Cuckoo expect to work with this API, as they we made with the mainstream Cuckoo project in mind. Even them, some changes need to be made to make the fork respond like the upstream project. I’m working on a configuration option for that.

The downside to this is those applications also don’t do any form of authentication. To get around this problem, the nginx server as configured in this guide will act as a only allow the specified IP addresses access to this API.

Next-gen web API

The next-gen web API is built into the web app of cuckoo-modified. Currently, not many third party applications support it, but if you are writing a new integration, use this API, which can support reate limits.

I have put together a repository that contains a module for working with this API, and several utility scripts for submitting samples from various sources:

https://github.com/seanthegeek/cuckoo-modified-utils


Feedback welcome

If you have found this guide useful, spot a mistake, or have other suggestions, please contact me on Twitter @SeanTheGeek.