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) inweb/guac/consumers.pyhandles the binary Guacamole protocol over TCP toguacd - WebSocket consumer (
GuacConsumer) in the same file forwards browser data toguacdand manages session recordings - Django view (
guac.views.index) inweb/guac/views.pygenerates 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 serviceguac-webcontainer (the HTML5 client) listening on port 8080- Systemd units:
guacd.serviceandguac-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]inconf/web.conf, settingenabled = yes, and defining connection parameters likeguacd_host,vnc_host, andmode. - Installation is automated via
sudo ./installer/cape2.sh guacamole, which creates systemd services forguacdandguac-web. - Usage involves submitting samples with
interactive=1via the web UI or REST API, which triggers the session token generation logic inweb/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →