FRP (fast reverse proxy) lets a host behind NAT or a firewall expose TCP, UDP or HTTP services through a public server. The client, frpc, keeps a control connection to the server, frps, and the server forwards inbound requests down it. It has been reported in a number of intrusions because a single Go binary and a short config give an operator a durable tunnel.
Signals at a Glance
| Signal | Where | ATT&CK |
|---|---|---|
| frpc or frps process, or any binary run with -c pointing at an frpc config | Sysmon 1, 4688, auditd, EDR | T1572 |
| Creation of frpc.ini, frpc.toml or similar config files | Sysmon 11, EDR file events | T1090 |
| Outbound connection to an external host on port 7000 (default control port) | Firewall, Zeek | T1572 |
| Config contents: serverAddr/server_addr, remotePort, type tcp, token | File content scan | T1090 |
| Server dashboard exposed on default port 7500 | External scan, flow | T1090 |
Config and Process Artifacts
The FRP client reads a config naming the server address, port and one or more proxies to publish. Older versions use INI with a [common] section; recent releases use TOML with serverAddr and [[proxies]]. Because operators rename the binary but rarely rewrite the config grammar, file and content rules are durable:
title: FRP Client Configuration File Created
logsource:
category: file_event
detection:
selection_name:
TargetFilename|endswith:
- 'frpc.ini'
- 'frpc.toml'
- 'frpc_full.ini'
condition: selection_name
level: high
---
title: FRP Client Execution
logsource:
category: process_creation
detection:
selection_img:
Image|endswith:
- '/frpc'
- '\frpc.exe'
- '/frps'
- '\frps.exe'
selection_cfg:
CommandLine|contains:
- 'frpc.ini'
- 'frpc.toml'
- 'frps.ini'
- 'frps.toml'
condition: selection_img or selection_cfg
level: high
# tune/validate: renamed binaries still pass a config path, so the config
# selection keeps firing; add a hash or OriginalFileName match where available.
Control Port and Server Exposure
FRP defaults to TCP 7000 for the control connection and 7500 for the optional dashboard, although operators change both. A workstation holding one persistent connection to an external host on port 7000 is a strong lead, and the server side of an intrusion often responds to the same banner-less probing from scan data:
# Splunk (Zeek conn.log) - persistent connection to default FRP control port
index=zeek sourcetype=bro_conn id.resp_p=7000 proto=tcp
| where duration > 1800 AND NOT cidrmatch("10.0.0.0/8", 'id.resp_h')
| stats count AS sessions, max(duration) AS longest, sum(orig_bytes) AS up,
sum(resp_bytes) AS down BY id.orig_h, id.resp_h
| sort - longest
# tune/validate: port 7000 has other uses; confirm with process telemetry
# and do not rely on the port number once an operator changes it.
- Search endpoints for config files containing
serverAddr,server_addrand atokenvalue. - Review external IPs that accept long connections on 7000 and publish a dashboard on 7500 in internet scan data for your own address space.
- Hunt for a Go binary run with
-cand a config in a temporary or ProgramData path. - Alert when a server that has never made outbound connections on 7000 begins to do so.
Use the FRP project documentation for configuration grammar and default ports, SigmaHQ and Elastic tunneling-tool coverage, Splunk ESCU tool-detection content and your Zeek connection logs. Always baseline your own environment — ports and filenames are trivially changed, so lead with config contents and process behaviour.
Build Detections That Fire
Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.
- Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
- Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
- 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts