THREAT-C2-CloudflaredQuickTunnelProtocolTunneling Sumo Logic CSE · Sumo

Detect Command and Control via Cloudflare Quick Tunnel (cloudflared trycloudflare.com) Protocol Tunneling in Sumo Logic CSE

cloudflared, Cloudflare's tunnel client, can be launched with `tunnel --url http://localhost:PORT` to create an unauthenticated 'quick tunnel' that publishes a local service on a random *.trycloudflare.com hostname with no account, DNS change or inbound firewall rule. Intruders abuse it to expose RDP, SSH, SMB, web shells or C2 listeners on a compromised host, and to tunnel outbound traffic over TCP/443 (or QUIC/7844) to Cloudflare edge addresses that most egress controls allow. Because the binary is legitimately signed and the traffic is TLS to a reputable provider, signature-based network controls rarely fire. This detection correlates cloudflared process execution carrying quick-tunnel or token command-line arguments, and/or execution from a user-writable path or with a renamed image, with connections to trycloudflare.com or Cloudflare tunnel edge port 7844.

MITRE ATT&CK

Tactic
Command and Control

Sumo Detection Query

Sumo Logic CSE (Sumo)
sql
_sourceCategory=endpoint/sysmon (EventID=1 OR EventID=3 OR EventID=22)
| parse "Image=*," as image nodrop
| parse "CommandLine=*," as cmdline nodrop
| parse "DestinationPort=*," as dest_port nodrop
| parse "QueryName=*," as query_name nodrop
| where (image matches "*cloudflared.exe" and cmdline matches "*tunnel*" and (cmdline matches "*--url*" or cmdline matches "*--token*" or cmdline matches "* run*")) or dest_port = "7844" or query_name matches "*.trycloudflare.com"
| eval is_user_path = if (image matches "*\\Users\\*" or image matches "*\\Temp\\*" or image matches "*\\ProgramData\\*", 1, 0)
| count as Events, sum(is_user_path) as UserPathEvents by host
| where Events >= 1
high severity low confidence

Sumo Logic query over Sysmon Event IDs 1, 3 and 22 matching cloudflared tunnel launches, Cloudflare tunnel port 7844 and trycloudflare.com DNS lookups.

Data Sources

Sysmon Event IDs 1, 3, 22 forwarded to Sumo LogicSumo Logic Cloud SIEMProxy/DNS logs

Required Tables

_sourceCategory=endpoint/sysmon

False Positives & Tuning

  • Developers or SREs using cloudflared quick tunnels to preview a local web app, with a documented ticket or owner
  • Managed Cloudflare Zero Trust deployments where cloudflared runs as a sanctioned service from a standard install path with a named (non-quick) tunnel
  • Red team or purple team exercises using cloudflared as a documented ingress channel

Other platforms for THREAT-C2-CloudflaredQuickTunnelProtocolTunneling


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1 cloudflared Quick Tunnel to Local Web Service (Windows)

    Expected signal: Sysmon 1 / DeviceProcessEvents for cloudflared.exe with tunnel --url; Sysmon 22 / DeviceNetworkEvents for *.trycloudflare.com and port 7844.

  2. Test 2 cloudflared Renamed Copy From Temp (Windows)

    Expected signal: Process creation with OriginalFileName cloudflared.exe running from %TEMP% under a different image name.

  3. Test 3 cloudflared Quick Tunnel (Linux)

    Expected signal: Process exec of cloudflared with tunnel --url from /tmp; outbound connections to Cloudflare edge on 7844.


Response Playbook

Triage

  1. Confirm the host, user and parent process that launched cloudflared; check whether an approved ticket or owner exists for the tunnel.
  2. Extract the full command line: --url shows which local service (3389, 22, 445, 8080) is being exposed; --token indicates an attacker-controlled Cloudflare account.
  3. Check the binary path, hash and OriginalFileName; user-writable paths or renamed images raise severity.
  4. Pull the trycloudflare.com hostname from DNS or proxy logs and query threat intel for prior abuse.
  5. Review the 24 hours before launch on the host for the initial-access vector (phishing, RDP brute force, web shell).
  6. Determine whether the exposed local service was accessed from the tunnel (inbound connections to the local port from 127.0.0.1 by cloudflared).

Containment

  1. Isolate the endpoint via EDR network containment.
  2. Kill the cloudflared process tree and block the binary hash.
  3. Block *.trycloudflare.com and tunnel edge port 7844 egress at DNS, proxy and firewall unless an approved exception exists.
  4. Disable or reset the user account used and rotate credentials exposed on the host.
  5. Hunt fleet-wide for the same hash, command line and trycloudflare hostnames.

Evidence Collection

  1. Memory image and process listing before termination.
  2. The cloudflared binary, any config.yml or credentials JSON, and the token passed on the command line.
  3. Sysmon 1/3/22 and DeviceNetworkEvents for the host covering the tunnel lifetime.
  4. Proxy and DNS logs for trycloudflare.com resolutions and edge connections.
  5. Windows Security logon events (4624 type 3/10) coinciding with the tunnel window.

Escalation Criteria

  • !Tunnel exposes RDP, SSH or SMB on a server or domain-joined host.
  • !Binary was renamed or ran from a user-writable path with no approved owner.
  • !Evidence of inbound sessions through the tunnel or follow-on lateral movement.
  • !Same tunnel hostname or token seen on multiple hosts.
  • !Host holds sensitive data or privileged credentials.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >cloudflared binary and its Prefetch/Amcache/Shimcache entries
  • >%USERPROFILE%\.cloudflared\ (cert.pem, tunnel credentials JSON, config.yml)
  • >Sysmon Event ID 1 command lines containing tunnel --url or --token
  • >DNS cache and resolver logs for *.trycloudflare.com
  • >Firewall/proxy logs for TCP/UDP 7844 to Cloudflare edge
  • >Scheduled task or service entries launching cloudflared for persistence

Tuning Guidance

Inventory sanctioned cloudflared deployments first (named tunnels run as a service from Program Files, launched by a known service account) and exclude them by path and parent process. Quick tunnels (--url) have almost no enterprise justification outside developer subnets; scope any developer exception by device group rather than globally. Keep the TunnelScore >= 2 threshold so a single standard-path run does not alert.


Hunting Queries

Fleet-wide baseline of cloudflared execution to build the allowlist of sanctioned Zero Trust connectors before alerting.

Hunting — KQL
kql
// Hunt: any cloudflared execution fleet-wide
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName =~ "cloudflared.exe" or ProcessVersionInfoOriginalFileName =~ "cloudflared.exe"
| summarize Executions = count(), Paths = make_set(FolderPath, 10), CmdLines = make_set(ProcessCommandLine, 10), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by DeviceName, AccountName
| sort by FirstSeen asc
Hunting — SPL
spl
index=windows sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
| eval ImageLower=lower(coalesce(Image,""))
| where like(ImageLower, "%\\cloudflared.exe") OR like(lower(coalesce(OriginalFileName,"")), "cloudflared.exe")
| stats count as Executions, values(ImageLower) as Paths, values(CommandLine) as CmdLines, min(_time) as FirstSeen, max(_time) as LastSeen by ComputerName, User
| eval FirstSeen=strftime(FirstSeen, "%Y-%m-%d %H:%M:%S"), LastSeen=strftime(LastSeen, "%Y-%m-%d %H:%M:%S")
| sort FirstSeen

Quick-tunnel hostnames are always under trycloudflare.com, so any resolution from an enterprise endpoint is high signal and independent of the binary name.

Hunting — KQL
kql
// Hunt: DNS/network lookups of trycloudflare.com
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl endswith ".trycloudflare.com"
| summarize Connections = count(), Hosts = make_set(RemoteUrl, 10), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by DeviceName, InitiatingProcessFileName
| sort by Connections desc
Hunting — SPL
spl
index=windows sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=22
| where like(lower(QueryName), "%.trycloudflare.com")
| stats count as Lookups, values(QueryName) as Names, values(Image) as Images, min(_time) as FirstSeen, max(_time) as LastSeen by ComputerName
| eval FirstSeen=strftime(FirstSeen, "%Y-%m-%d %H:%M:%S"), LastSeen=strftime(LastSeen, "%Y-%m-%d %H:%M:%S")
| sort - Lookups

Atomic Red Team Tests

Test 1 cloudflared Quick Tunnel to Local Web Service (Windows)
windows

Starts a quick tunnel exposing a local port through trycloudflare.com. Exercises process and edge connection arms.

Command

powershell
$cf = Get-Command cloudflared -ErrorAction SilentlyContinue
if (-not $cf) { Write-Host 'cloudflared not installed; skipping'; exit 0 }
Start-Process -FilePath $cf.Source -ArgumentList 'tunnel','--url','http://localhost:8080','--no-autoupdate' -NoNewWindow
Start-Sleep -Seconds 25
Write-Host 'quick tunnel test complete'

Cleanup

powershell
Get-Process -Name cloudflared -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue

Expected Telemetry

Sysmon 1 / DeviceProcessEvents for cloudflared.exe with tunnel --url; Sysmon 22 / DeviceNetworkEvents for *.trycloudflare.com and port 7844.

Expected Detection

TunnelScore reaches at least 3 (base, --url, edge connection) and the rule fires.

Test 2 cloudflared Renamed Copy From Temp (Windows)
windows

Copies cloudflared to a temp path under a different name and launches a tunnel to exercise the renamed-binary and user-writable-path arms.

Command

powershell
$cf = Get-Command cloudflared -ErrorAction SilentlyContinue
if (-not $cf) { Write-Host 'cloudflared not installed; skipping'; exit 0 }
$dst = Join-Path $env:TEMP 'svchost-update.exe'
Copy-Item $cf.Source $dst
Start-Process -FilePath $dst -ArgumentList 'tunnel','--url','http://localhost:3389' -NoNewWindow
Start-Sleep -Seconds 20

Cleanup

powershell
Get-Process -Name svchost-update -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Remove-Item (Join-Path $env:TEMP 'svchost-update.exe') -Force -ErrorAction SilentlyContinue

Expected Telemetry

Process creation with OriginalFileName cloudflared.exe running from %TEMP% under a different image name.

Expected Detection

KQL/SPL score includes UserWritablePath and RenamedBinary and the alert fires. Name-based rules (EQL/YARA-L/CQL) match on original file name only where the platform records it.

Test 3 cloudflared Quick Tunnel (Linux)
linux

Launches a quick tunnel from /tmp on a Linux host.

Command

bash
command -v cloudflared >/dev/null || { echo 'cloudflared not installed; skipping'; exit 0; }
cp "$(command -v cloudflared)" /tmp/cloudflared
/tmp/cloudflared tunnel --url http://localhost:8080 --no-autoupdate >/tmp/cf.log 2>&1 &
sleep 20; cat /tmp/cf.log | head -20

Cleanup

bash
pkill -f '/tmp/cloudflared tunnel' || true
rm -f /tmp/cloudflared /tmp/cf.log

Expected Telemetry

Process exec of cloudflared with tunnel --url from /tmp; outbound connections to Cloudflare edge on 7844.

Expected Detection

KQL (MDE for Linux), Elastic Defend, CrowdStrike and Chronicle rules match the process launch.

Related Detections

Detection Variants (1)

Different telemetry and tradecraft for the same technique — pick the one that matches the data you collect.