How to Configure and Set Up CAPEv2's Interactive Desktop Feature Utilizing Guacamole

CAPEv2 streams live VNC or RDP sessions from analysis VMs to your browser via Apache Guacamole by enabling the [guacamole] section in conf/web.conf, installing the guacd daemon and guac-web container, and submitting tasks with the interactive=1 flag.

CAPEv2's interactive desktop feature allows malware analysts to remotely control analysis virtual machines directly from their web browser using Apache Guacamole. This guide explains how to configure and set up CAPEv2's interactive desktop feature utilizing Guacamole based on the official source code in the kevoreilly/capev2 repository.

How CAPEv2 Interactive Desktop Works

CAPEv2 leverages a dedicated Django application to proxy WebSocket connections between the analyst's browser and the Guacamole daemon (guacd). When you submit a sample with the interactive flag enabled, the system stores interactive_desktop: true in the task JSON, which web/submission/views.py processes to trigger the Guacamole workflow.

The architecture relies on three core components:

  • Guacamole client library (guacamole.client.GuacamoleClient) in web/guac/consumers.py handles the binary Guacamole protocol over TCP to guacd
  • WebSocket consumer (GuacConsumer) in the same file forwards browser data to guacd and manages session recordings
  • Django view (guac.views.index) in web/guac/views.py generates signed, base64-encoded session tokens containing the task ID, Guacamole label, and guest IP

Prerequisites and Architecture Overview

Before configuring the interactive desktop, ensure your CAPEv2 instance meets these requirements:

Component Source File Purpose
Guacamole client web/guac/consumers.py Binary protocol handler for guacd
WebSocket consumer web/guac/consumers.py Browser-to-guacd proxy and recording writer
Session generator web/guac/views.py Creates signed tokens (guac.views.index)
URL routing web/guac/urls.py Maps /guac/ paths and WebSocket endpoints
Settings module web/guac_settings.py Django config for Guacamole mode
Submission logic web/submission/views.py Sets interactive_desktop flag in task JSON
Startup routine lib/cuckoo/core/startup.py Creates storage/guacrecordings directory
Configuration conf/web.conf Connection parameters and feature toggles

You must use KVM/QEMU as your machinery backend, as CAPEv2's interactive desktop requires VNC access to the guest VMs.

Step-by-Step Configuration Guide

Install Guacamole Services

CAPEv2 provides an automated installer script that deploys the required Docker containers and systemd services. Run the following command as root:

sudo ./installer/cape2.sh guacamole

This installs:

  • guacd (the Guacamole proxy daemon) as a systemd service
  • guac-web container (the HTML5 client) listening on port 8080
  • Systemd units: guacd.service and guac-web.service

Enable Guacamole in CAPEv2 Configuration

Edit conf/web.conf (or copy from conf/default/web.conf.default if the file does not exist) and configure the [guacamole] section:

[guacamole]
enabled = yes
mode = vnc                 # Options: vnc, rdp

username = <optional>
password = <optional>
guacd_host = localhost
guacd_port = 4822
vnc_host = 127.0.0.1      # IP of the host running the VMs

guest_protocol = vnc
guest_width = 1280
guest_height = 1024

The mode parameter determines whether CAPEv2 connects to the guest via VNC or RDP. For KVM/QEMU deployments, vnc is the standard protocol.

Configure the Web Front-End

The Guacamole UI is served under the /guac/ URL prefix. You must proxy WebSocket connections to the guac-web service (port 8080 by default).

Add this location block to your NGINX configuration:

location /guac/ {
    proxy_pass http://127.0.0.1:8080/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

After editing, reload NGINX:

sudo systemctl reload nginx

Enable VNC on Analysis VMs

CAPEv2's interactive desktop requires VNC access to the guest. Ensure your VM XML configuration includes a graphics device:

<graphics type='vnc' port='-1' listen='0.0.0.0'/>

The port='-1' tells QEMU to auto-allocate a port. The VM must be reachable from the host defined in vnc_host (typically the CAPEv2 host IP).

Restart Services and Verify

After completing configuration, restart all related services:

sudo systemctl restart cape-web guacd.service guac-web.service

Verify that guacd is listening on port 4822:

sudo ss -tlnp | grep 4822

Check that the recordings directory exists (created by lib/cuckoo/core/startup.py):

ls -la /opt/CAPEv2/storage/guacrecordings/

Using the Interactive Desktop

Submitting Samples via Web UI

To launch an interactive session, submit a sample through the CAPEv2 web interface and tick the Interactive Desktop checkbox. This sets interactive_desktop: true in the task JSON, which web/submission/views.py processes to trigger the Guacamole workflow.

Submitting via REST API

For automated submissions, include the interactive=1 parameter:

curl -X POST "https://<cape-host>/api/v1/tasks/create" \
     -H "Authorization: Bearer <API_KEY>" \
     -F "file=@/tmp/malware.exe" \
     -F "interactive=1"

The backend checks web_conf.guacamole.enabled before marking the task for interactive access.

Generating Session Tokens Manually

If you need to construct a Guacamole URL manually, generate a signed session token using the same logic found in web/guac/views.py:

from uuid import uuid3, NAMESPACE_DNS
from base64 import urlsafe_b64encode as ub64enc

sid = uuid3(NAMESPACE_DNS, "0000").hex[:16]           # Random session ID

ip = "192.168.2.2"                                   # Guest IP address

vm_name = "win10"                                   # Label from web.conf labels_and_ports

session_data = ub64enc(f"{sid}|{vm_name}|{ip}".encode()).decode()
print(session_data)   # Append to /guac/<task_id>/ in your browser

This base64-encoded string contains the session ID, VM label, and guest IP required by the GuacConsumer in web/guac/consumers.py.

Troubleshooting Common Issues

Connection Refused Errors

If the browser cannot connect to the interactive desktop, verify that the guacd daemon is running and accessible on the configured port (default 4822). Check the service status with sudo systemctl status guacd, review the log file at /opt/CAPEv2/web/guac-server.log, and ensure guacd_host and guacd_port in conf/web.conf match your deployment. Also verify that firewall rules allow TCP traffic on port 4822 between the CAPEv2 web application and the Guacamole daemon.

WebSocket Upgrade Failures

The NGINX configuration must properly handle WebSocket upgrades for the /guac/ path. If you see 400 Bad Request errors or connection drops, confirm that proxy_set_header Upgrade $http_upgrade and proxy_set_header Connection "upgrade" are present in your NGINX location block, and that proxy_http_version 1.1 is specified.

ALLOWED_HOSTS Errors

If Django returns 400 Bad Request with "Invalid HTTP_HOST header", edit web/web/settings.py and add your CAPEv2 hostname to the ALLOWED_HOSTS list. This is required when accessing the interactive desktop through a reverse proxy or load balancer.

VNC Connectivity Issues

Verify that the analysis VM has a VNC server configured in its XML definition with <graphics type='vnc' port='-1' listen='0.0.0.0'/>. The VM must be reachable from the host defined in vnc_host in conf/web.conf. Check network connectivity and firewall rules between the CAPEv2 host and the VM host if they are separate machines.

Summary

  • CAPEv2's interactive desktop uses Apache Guacamole to stream VNC/RDP sessions from analysis VMs to the browser via WebSocket proxies implemented in web/guac/consumers.py.
  • Configuration requires enabling [guacamole] in conf/web.conf, setting enabled = yes, and defining connection parameters like guacd_host, vnc_host, and mode.
  • Installation is automated via sudo ./installer/cape2.sh guacamole, which creates systemd services for guacd and guac-web.
  • Usage involves submitting samples with interactive=1 via the web UI or REST API, which triggers the session token generation logic in web/guac/views.py.

Frequently Asked Questions

What is the difference between VNC and RDP modes in CAPEv2's Guacamole integration?

VNC (Virtual Network Computing) is the default protocol for KVM/QEMU-based analysis machines and provides framebuffer-level access to the guest desktop. RDP (Remote Desktop Protocol) is an alternative that offers better performance on Windows guests but requires the VM to have an RDP server enabled. Configure the mode in conf/web.conf under the [guacamole] section with mode = vnc or mode = rdp.

How do I manually generate a Guacamole session URL for debugging?

You can construct a session token using Python to mimic the logic found in web/guac/views.py. Import uuid3 from the uuid module and urlsafe_b64encode from base64, then encode a string containing a random session ID, the VM label from your web.conf, and the guest IP address. Append this base64 string to https://<cape-host>/guac/<task-id>/ to access the desktop directly.

Why does my browser show "Connection refused" when trying to open an interactive session?

This error typically indicates that the guacd daemon is not running or is unreachable on the configured port (default 4822). Verify the service status with sudo systemctl status guacd, check the log file at /opt/CAPEv2/web/guac-server.log, and ensure guacd_host and guacd_port in conf/web.conf match your deployment. Also confirm that firewall rules allow TCP traffic on port 4822 between the CAPEv2 web application and the Guacamole daemon.

Can I record interactive desktop sessions for later review?

Yes, CAPEv2 automatically records interactive desktop sessions when the feature is enabled. The GuacConsumer class in web/guac/consumers.py writes session recordings to the storage/guacrecordings directory, which is created during startup by lib/cuckoo/core/startup.py. These recordings capture the entire user interaction with the guest VM and can be replayed through the Guacamole interface or accessed directly from the storage path for forensic analysis.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →