Potential Tunneling via AWS IoT Secure Tunneling Localproxy
Description
Identifies AWS IoT Secure Tunneling localproxy started in destination mode that then resolves and connects to the Secure Tunneling data plane, data.tunneling.iot..amazonaws.com, on TCP/443. Destination mode opens no listener; once the operator joins the tunnel the proxy forwards streams to a local service such as SSH on 127.0.0.1:22. Public red-team research shows this signed, documented binary used as post-exploitation C2 that resembles legitimate IoT device management. OpenTunnel and access tokens live in the operator's AWS account, not the victim's.
Query · eql
sequence by process.entity_id with maxspan=5m
[process where event.type == "start" and event.action in ("exec", "exec_event", "start") and
(
process.args in ("-d", "--destination-app") or
(process.args in ("-m", "--mode") and process.args in ("dst", "destination")) or
process.args like ("--mode=dst", "--mode=destination")
) and
(
/* Official binary, container image path, or Windows original filename */
(
process.name like~ ("localproxy", "localproxy.exe") or
?process.pe.original_file_name like~ "localproxy.exe" or
process.executable like~ "*aws-iot-securetunneling-localproxy*"
) or
/* Renamed binary: dest mode plus AWS region or tunneling endpoint */
(
(
process.args regex """[a-z]{2}(-[a-z]+)+-[0-9]+""" or
process.args in ("-e", "--proxy-endpoint", "-r", "--region") or
process.args like~ "*tunneling.iot*"
) and
process.args in (
"-t", "--access-token",
"-c", "--capath",
"-b", "--local-bind-address",
"-m", "--mode"
) and
not process.name like~ (
"timeout", "time", "env", "nice", "nohup", "stdbuf",
"bash", "dash", "sh", "zsh", "sudo", "sshd", "useradd"
)
)
)]
[network where event.action in ("lookup_requested", "lookup_result") and
dns.question.name like~ (
"data.tunneling.iot.*.amazonaws.com",
"data.tunneling.iot.*.amazonaws.com.cn"
)]
[network where event.action == "connection_attempted" and destination.port == 443]
Investigation fields
Pivot points the source recommends for triage.
@timestamphost.nameuser.nameprocess.nameprocess.executableprocess.command_lineprocess.parent.namedestination.addressdestination.portdns.question.name
Implementation guide
This rule is designed for data generated by Elastic Defend, which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
Setup instructions: https://ela.st/install-elastic-defend
Linux DNS events from Elastic Defend require Elastic Stack 9.3.0 or later.
Known false positives
- Support engineers and IoT operators may run localproxy on field devices or jump hosts that legitimately use AWS IoT Secure Tunneling. Confirm the host is an approved device-management asset, the parent process and binary path are expected, and the destination mapping points at an authorized local service. Allowlist by host, user, or signed install path where that use is documented.
Analyst notes
Investigating Potential Tunneling via AWS IoT Secure Tunneling Localproxy
AWS IoT Secure Tunneling's open-source localproxy creates a bidirectional relay through AWS-managed infrastructure. Destination mode (typical on the victim) makes an outbound connection to data.tunneling.iot.<region>.amazonaws.com on 443 using WebSocket subprotocol aws.iot.securetunneling-3.0 and then connects to a local service (-d localhost:22, -d SSH=localhost:22, or a Unix socket). Source mode opens a loopback listener on the operator workstation, not on the compromised host. OpenTunnel is written to the operator's CloudTrail, not the target's.
This is post-exploitation C2 / remote access after code execution, not initial access. The official binary is the expected implant. This rule requires three events from the same process: a destination-mode start (-d / --destination-app, or -m dst with mappings from --config-dir), DNS to the Secure Tunneling data plane, and TCP/443 egress. Elastic Defend often leaves destination.domain empty on the 443 flow, so the third event keys on port 443. Source mode (-s) is the operator workstation. Hosts that egress through a web proxy (HTTPS_PROXY) resolve and connect via the proxy using HTTP CONNECT, so the DNS and 443 events are not attributed to localproxy and this sequence will not fire there.
Possible investigation steps
- Confirm destination mode from the command line:
-d/--destination-app, or-m/--modewithdst/destination(mappings then come from--config-dir). Short flags are case-sensitive (-dis notsshd -D). - Event 2 is DNS to
data.tunneling.iot.<region>.amazonaws.com. Event 3 is TCP/443 from the sameprocess.entity_id(destination.domainmay be empty). - Check what rode the tunnel: look for
connection_attemptedfrom the sameprocess.entity_idto127.0.0.1or::1(typically port 22) during the process lifetime. An idle tunnel has none; a dummy or expired token stops after the 443 handshake. - Treat
-t/--access-tokenon the command line as a leaked one-time tunnel token.AWSIOT_TUNNEL_ACCESS_TOKENis often passed via the environment and is not present on thelocalproxystart event (process.env_varsis typically empty). - Review the parent process, user, and binary path. The AWS-published proxy is not statically linked and is commonly dropped as
localproxy/localproxy.exe, run from a user-writable directory, or launched frompublic.ecr.aws/aws-iot-securetunneling-localproxy/*. - Hunt for the same hash, path, argument pattern, or tunneling hostname on other hosts. A renamed binary still often carries
-dplus an AWS region or*tunneling.iot*endpoint. If this sequence did not fire, hunt destination-mode localproxy process starts directly; web-proxy hosts will show neither the DNS nor the 443 event from the process. - Do not expect
iotsecuretunneling:OpenTunnelin the victim account. If the host is in AWS, VPC flow logs and resolver query logs may still show egress to the tunneling endpoint.
False positive analysis
- Approved AWS IoT device troubleshooting uses this exact binary and flags. Restrict exceptions to known device fleets or jump hosts rather than the process name alone.
- Lab or red-team use of the aws-samples localproxy will look identical to abuse. Confirm against engagement records.
Response and remediation
- If unauthorized: isolate the host, terminate
localproxy, and block*.tunneling.iot.*.amazonaws.comat DNS or egress. That hostname is specific to Secure Tunneling and does not break IoT Core MQTT, Jobs, or Greengrass. - Remove dropped binaries, container images, config files (
--config,--config-dir), and any persistence that relaunches the proxy. Tokens are one-time and expire with the tunnel (published maximum 12 hours). - Hunt for what rode the tunnel (SSH, other mapped services) using local connection history during the process lifetime.
- Organizations that do not use Secure Tunneling should block the data-plane hostname and keep this rule enabled without exceptions.