Repository navigation
08. Guacamole
The lab's web-based remote access portal. Apache Guacamole runs in Docker on a dedicated EC2 host, exposes HTTPS publicly, and brokers SSH / RDP / VNC sessions to every other lab machine. It is the only public SSH endpoint in the deployment.
| At a glance | |
|---|---|
| Hostname | guac |
| Public URL | https://<guac-eip>/guacamole |
| UI login |
guacadmin / lab password (from terraform output deployment_info) |
| Containers |
guacamole/guacamole, guacamole/guacd, postgres:15
|
| Pre-registered connections | Windows (RDP), Mythic / Sliver / Havoc / Redirector / Kali / Guacamole (SSH), Havoc Desktop (VNC), optional Kali (XRDP) |
| TLS | Self-signed cert in front of Nginx; terminates HTTPS, proxies to Guacamole on localhost:8080
|
| Public SSH endpoint |
guac only (port 22 on Guacamole's Elastic IP) |
| SSH user |
admin on every Linux host |
| SSH auth | RSA key from public sources; password from 10.0.0.0/8 and 172.16.0.0/12
|
Three reasons:
- Single public ingress: The redirector exposes only 80/443 (for C2 callbacks); the seven other lab hosts have no public IPs. Without Guacamole you'd need either: (a) a public SSH endpoint on every host (sprawl + risk), or (b) a separate bastion host (extra cost + complexity). Guacamole is the bastion, plus it gives you RDP and VNC for free.
- No client install: Web browser, that's it. Useful when working from a kiosk, a locked-down corporate laptop, an iPad, or any environment where you can't install a full SSH/RDP/VNC client stack.
- Centralized session recording (potential): Guacamole supports session recording natively. Not enabled in redStack by default but can be flipped on for training scenarios where you want to review what an operator did during a session.
- Latency: A web-based RDP session has more latency than a native RDP client because every keystroke and frame goes browser → HTTPS → guacd → RDP. Most operators don't notice for terminal work; you do notice for graphical work like the Havoc Katana client.
-
Single point of failure: If
guacis down, the entire lab is unreachable from the public internet. Mitigation: Guacamole has its own EIP and an SG rule for direct SSH fromlocalPub_ip. This is a break-glass path for advanced users who need headless access when the portal is unavailable. For most issues,terraform apply -replace=aws_instance.guacamoleis the faster fix. -
Public attack surface: HTTPS to
guacadmin/lab_passwordis exposed to the entire internet. The lab password is randomly generated per deploy (16 characters with special characters) but it's still a credential pair on the public internet. ThelocalPub_ipSG restriction is strongly recommended.
Guacamole stores its connection database in Postgres rather than MySQL. Postgres handles the
auto-creation of connections at deploy time cleanly, and psql is more debuggable than the MySQL
alternative. Both work; Postgres was the redStack pick.
Default t3.small (2 vCPU, 2 GB RAM) handles 1-2 concurrent operator sessions cleanly. Bump to
t3.medium if multiple operators will be working simultaneously or if you enable session
recording (which writes captures to disk under /var/lib/guacamole/recordings/).
guac (Debian 12) [t3.small, EBS gp3 20 GB]
├── nginx :443 SSL termination, reverse-proxy to localhost:8080
├── docker
│ ├── guacamole/guacamole :8080 (web UI + REST API)
│ ├── guacamole/guacd :4822 (Guacamole daemon: SSH/RDP/VNC client implementation)
│ └── postgres:15 :5432 (connection database)
└── /etc/hosts pre-populated with all lab hostnames
Cloud-init runs terraform/setup_scripts/guacamole_setup.sh, which after Guacamole boots:
- Logs in to the Guacamole REST API as
guacadmin/ default password - Changes the password to the lab password
- Re-authenticates with the new password to get a fresh token
- Issues
POST /api/session/data/postgresql/connectionsfor each host
This is why the connections appear automatically on first deploy. If you re-deploy, the database is destroyed and recreated, so connections are re-registered.
The HTTPS cert at /etc/nginx/ssl/ is a 4096-bit RSA cert with the public IP as the SAN.
Browsers will show a "not secure" warning on first visit; accept it.
If you want a real Let's Encrypt cert:
- Point a DNS A record at the Guacamole EIP.
- SSH to
guac, runsudo certbot --nginx -d yourdomain.tld. - Re-run on every deploy if you destroy/redeploy.
Operator browser
|
v HTTPS (self-signed, port 443)
nginx (on guac)
|
v HTTP (port 8080, localhost)
guacamole/guacamole container
|
v Guacamole protocol (port 4822, localhost)
guacd container
|
v SSH / RDP / VNC to target (private IPs)
mythic / sliver / havoc / windows / kali / redirector
-
Open the portal URL from
terraform output deployment_info. - Allow clipboard access when prompted. On first connection, Guacamole asks for permission to read and write the system clipboard. Allow it so you can copy and paste between your local machine and any Guacamole session.
-
Login as
guacadmin/ lab password. - Click any connection to open it in a new browser tab.

[Figure 5.1.1: Guacamole portal after login showing all pre-registered connections (Windows RDP, the SSH connections to each lab host, the Havoc Desktop VNC, and the optional Kali XRDP)]
Press Ctrl+Alt+Shift inside any active session to open the Guacamole sidebar. This is the
control panel for everything outside of keyboard input to the session itself.
| Shortcut | Action |
|---|---|
Ctrl+Alt+Shift |
Open / close the sidebar |
Ctrl+Alt+End |
Send Ctrl+Alt+Del to a Windows RDP session |
Shift+Insert |
Paste from system clipboard (after opening sidebar once to enable sync) |
The sidebar contains:
- Home icon (top): Returns to the connection list without closing the active session.
- Clipboard: Paste text to and from the session. Open it once to enable two-way sync.
- Devices: Shows the GuacShare virtual drive (RDP sessions only).
- On-screen keyboard: Useful for special characters on non-standard layouts.
- Zoom: Rescale the session viewport.
Each connection opens in its own browser tab. Open multiple connections in separate tabs to work across machines simultaneously. Guacamole keeps each session alive independently.
From inside any session, press Ctrl+Alt+Shift to open the sidebar, then click the home icon
at the top of the sidebar. This returns you to the connection list without terminating the
session. The session stays alive and reconnects immediately when you click it again.
GuacShare is a virtual drive available only during a Windows (RDP) session. It maps between
your browser and C:\Users\Administrator\GuacShare\ on the Windows operator.
Upload (browser → Windows):
- Open the sidebar (
Ctrl+Alt+Shift) → Devices → GuacShare. - Click the upload icon and select a file from your local machine.
- The file lands in
C:\Users\Administrator\GuacShare\on Windows.
Download (Windows → browser):
- Move or copy the file to
C:\Users\Administrator\GuacShare\on Windows. - Open the sidebar → Devices → GuacShare.
- Click the filename to download it to your local machine.
[!NOTE] GuacShare is only available in RDP sessions with drive mapping enabled. It is not available in SSH or VNC sessions. For SSH-based file transfer, use
scp. See SSH Access below.
By default, the host clipboard and the session clipboard are isolated. To sync:
- Open the sidebar (
Ctrl+Alt+Shift) → Clipboard. - Paste text into the box to send it into the session.
- Text copied inside the session appears in the box automatically once the panel is open.
Two facts make the access pattern simple:
- The same
rs-rsa-key.pem(the AWS key pair from Prerequisites) is authorized on every Linux instance. - sshd on each Linux host has
PasswordAuthentication nofor public sources, but flips toyesfor addresses inside172.16.0.0/12or10.0.0.0/8(the lab's private space).
In practice:
-
ssh -i rs-rsa-key.pem admin@<GUAC_PUBLIC_IP>works (key auth from public) -
admin@guac:~$ ssh admin@mythicworks (password auth from inside the lab) -
ssh admin@<MYTHIC_PUBLIC_IP>fails because Mythic has no public IP
1. Guacamole Web Portal (easiest)
Log in as guacadmin and click any pre-configured SSH connection. No manual auth needed; Guacamole
has the lab password baked into each connection profile.
2. SSH directly to Guacamole (the bastion)
ssh -i rs-rsa-key.pem admin@<GUAC_PUBLIC_IP>You land at admin@guac:~$. From here hop to any internal host by hostname.
3. Jump from your host to any internal box
ssh -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> admin@mythic
ssh -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> admin@sliver
ssh -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> admin@havoc
ssh -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> admin@redirector
ssh -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> admin@kaliThe same key satisfies both hops. No password prompts.
From any lab Linux host, hostnames resolve directly via /etc/hosts:
admin@guac:~$ ssh admin@mythic
admin@guac:~$ ssh admin@sliver
admin@guac:~$ ssh admin@havoc
admin@guac:~$ ssh admin@redirector
admin@guac:~$ ssh admin@kaliFrom PowerShell on Windows:
ssh admin@mythic
ssh admin@kali
scp .\payload.exe admin@havoc:/tmp/# From your host workstation:
scp -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> ./localfile admin@mythic:/tmp/
# From inside the lab:
scp ./localfile admin@mythic:/tmp/Kali: The Kali AMI ships with a kali user. redStack renames it to admin during
provisioning. Don't SSH as kali; that user no longer exists. See Kali.
Redirector (port 22 closed publicly): Use Guacamole > Redirector (SSH), or jump through
Guacamole: ssh -i rs-rsa-key.pem -J admin@<GUAC_PUBLIC_IP> admin@redirector.
Windows operator: No SSH server. Access is RDP only via Guacamole > Windows (RDP). PowerShell on Windows can SSH out to any Linux host once the desktop is loaded.
| Connection | Protocol | Use for | Auth |
|---|---|---|---|
| Windows (RDP) | RDP | Driving the Windows operator workstation: Mythic UI, agent execution, payload work | Auto (Administrator + AWS-decrypted password) |
| Mythic (SSH) | SSH | Shell on Mythic host: mythic-cli operations, Docker container management |
admin + lab password |
| Sliver (SSH) | SSH | Shell on Sliver host: launch sliver-client, manage daemon |
admin + lab password |
| Havoc (SSH) | SSH | Shell on Havoc host: build script, teamserver management, log review |
admin + lab password |
| Havoc Desktop (VNC) | VNC | Run the Havoc Katana GUI client (must use this connection, not SSH) | Lab password |
| Redirector (SSH) | SSH | Shell on the redirector: Apache config, certbot, log review |
admin + lab password |
| Guacamole (SSH) | SSH | Shell on the Guacamole host: container management, nginx config, debugging |
admin + lab password |
| Kali (SSH) | SSH | Shell on Kali: AD tooling, proxychains, install-kali-tools |
admin + lab password |
| Kali (XRDP) | RDP | Kali XFCE desktop (only registered when kali_deployment_mode = "gui") |
admin + lab password |
Nginx is up but can't reach the Guacamole container. Check Docker:
ssh admin@guac
docker psExpected: three containers (guacamole, guacd, postgres_guacamole) all Up. If any are
restarting, check logs:
docker logs guacamole
docker logs guacd
docker logs postgres_guacamoleMost common cause is Postgres taking longer than expected on first deploy. Wait 2-3 minutes and retry.
The default password is changed to the lab password during cloud-init. If cloud-init was
interrupted, try guacadmin/guacadmin. If that works, change the password manually:
- Login as
guacadmin/guacadmin. - Settings → Users → guacadmin → Change password.
- Set it to the lab password from
terraform output deployment_info.
Cloud-init's connection-registration step failed. Query Postgres to confirm:
ssh admin@guac
docker exec -it postgres_guacamole psql -U guacamole_user -d guacamole_db \
-c "SELECT connection_id, connection_name, protocol FROM guacamole_connection;"If empty, re-run the registration script:
sudo bash /opt/redstack/register-connections.sh-
Is the target host up? From
guac:ping mythic -
Is the target port listening?
nc -zv mythic 22/nc -zv windows 3389/nc -zv havoc 5901 -
Is the target service running? SSH into the target:
systemctl status sshd/systemctl status xrdp
The Windows host loads the drive lazily. Open File Explorer → This PC and wait 10-30 seconds. If it still doesn't appear, disconnect and reconnect the RDP session.
TigerVNC sometimes loses its X session after a host restart. SSH to havoc and restart the service:
sudo systemctl restart havoc-vnc.serviceThen reconnect via Guacamole.
The Guacamole protocol is sensitive to round-trip time. If your laptop is far from the AWS region, browser RDP will feel sluggish. Options:
- Deploy to a closer region (
aws_region = "eu-west-1"in tfvars). - Use SSH directly (
ssh -i rs-rsa-key.pem admin@guac) for terminal work, reserve RDP for graphical needs.
The lab password is in Terraform state: terraform output deployment_info. If state is gone:
terraform destroy && terraform apply.
Expected. redStack renames the kali user to admin during provisioning. Use admin on all
Linux hosts.
← Previous: Lab Inventory | Next: Redirector →
"Modern Attackers Don't Break In – They Log In"
Bret Arsenault, Microsoft CISO (~2018)