# MikroTik Router Security Hardening A repeatable security audit and hardening procedure for RouterOS 7.x routers. Run when onboarding a new router or performing a periodic security review. ## Audit checklist ### 1. IP Services — Restrict listening addresses Check current state: `/ip/service/print` Default state exposes SSH (22), API (8728), Winbox (8291), and API-SSL (8729) to `0.0.0.0/0` (any IP). Tighten each: ``` /ip/service/set ssh address=10.1.0.0/24,10.1.1.0/24,192.168.88.0/24,10.77.0.0/24 /ip/service/set api address=10.1.0.0/24,10.1.1.0/24 /ip/service/set winbox address= # Keep open if user needs Winbox from anywhere /ip/service/disable api-ssl ``` **CRITICAL: Include 10.77.0.0/24 in SSH's allowed-address list when WireGuard tunnel is used for remote management.** If you forget, you will lock yourself out and need WinBox access to recover. **RECOVERY from lockout:** SSH to the router fails with "Connection closed by remote host". The fix via WinBox terminal: `/ip/service/set ssh address=10.77.0.0/24`. Always include this in the set command the first time. ### 2. Firewall — Remove duplicate rules RouterOS config accumulates duplicate rules over time (especially WG tunnel rules). Audit: ``` /ip/firewall/filter/print detail ``` Look for: - Multiple rules with identical comments and action - Rules that are redundant (e.g., same port/protocol accepted more than once) - Orphaned rules with no action (missing `action=accept/drop`) Remove duplicates by matching the comment text and removing all but one: ``` /ip/firewall/filter/remove [find where comment="allow WG tunnel (ITPP)"] /ip/firewall/filter/remove [find where comment="allow ITPP tunnel"] ``` Then re-count: `/ip/firewall/filter/print count`. A clean home router has ~26 rules. ### 3. L2TP/IPsec — Disable weak authentication methods Check current: `/interface/l2tp-server/server/print` Default enables PAP, CHAP, MSCHAP1, MSCHAP2. PAP sends passwords in cleartext. MSCHAP1 is weak. Keep only CHAP + MSCHAP2: ``` /interface/l2tp-server/server/set authentication=chap,mschap2 ``` ### 4. Remove obsolete PPP secrets When WireGuard replaces L2TP for remote management, the `shonuff` user's PPP secret is obsolete. Remove it: ``` /ppp/secret/remove [find where name=shonuff] ``` Leave `gadmin` (the user's primary VPN account) intact. ### 5. Stale user accounts Check: `/user/print` Remove any users that haven't logged in recently or belong to decommissioned services (e.g., a Remote Winbox SSTP user from a defunct third-party service): ``` /user/remove [find where name=] ``` Also check for orphaned SSTP/L2TP client interfaces: `/interface/sstp-client/print` — disable or remove interfaces pointing to dead services. ### 7. SMTP Configuration for Scheduled Emails If the router sends scheduled email backups (logs, config, backup files), these settings are specific to this netcup KVM infrastructure: - **Port: 2525** (NOT 465). Port 465 times out from netcup infrastructure. Only 2525 works. - **TLS: starttls** (NOT yes). Port 465 uses SSL/TLS; port 2525 uses STARTTLS. - **DNS servers:** Must be set explicitly. AT&T DHCP leases don't resolve `mail.germainebrown.com`. Set to internal AdGuard: ``` /ip/dns/set servers=10.1.1.14,10.1.1.10 ``` Apply settings: ``` /tool/e-mail/set port=2525 tls=starttls password="" ``` **Diagnostic chain for SMTP failures:** 1. `DNS resolve failed` → check `/ip/dns/set servers=` — AT&T gateway can't resolve MXroute 2. `timeout occured` → missing established/related input rule (see §8). Also check if the port in use is actually open from the server's IP — try `nc -zv mail.germainebrown.com 2525` from the management box. 3. `AUTH failed` → check password in `/tool/e-mail/print` against current mail provider creds. The mail password may have been changed since the router was configured. 4. `succeeded` → test with `/tool/e-mail/send to="test@domain" subject="test" body="test"` Check status: `/tool/e-mail/print` — look for `last-status: succeeded`. **Known quirk:** When changing SMTP settings or password on RouterOS, the previous error entries in the log buffer (`e-mail,error`) persist — the new test may have succeeded even though old errors are still visible. Always check `last-status` on `/tool/e-mail/print` rather than scroll-back logs. Also fix the scheduler scripts: the filenames created by `/log print file=` and `/export file=` auto-append extensions (.txt / .rsc). Ensure the email `file=` parameter matches what's actually created: | Scheduler creates | Email attaches | Match? | |---|---|---| | `logs.txt` | `home-rtr-logs.txt` | ❌ Fix: use same filename on both sides | | `export.rsc` | `home-rtr-config.rsc` | ❌ Fix: use same filename on both sides | ### 8. Firewall INPUT chain — Add established/related rule RouterOS forwards typically have `connection-state=established,related` but the INPUT chain may lack it. Without this rule, outgoing connections initiated by the router itself (SMTP, DNS) have their return traffic blocked by WAN-DROP. **Symptom:** SMTP shows `timeout occurred` or DNS shows `DNS resolve failed` even though DNS servers are correct and ports are open. Add at position 1 (before WAN-DROP): ``` /ip/firewall/filter/add chain=input action=accept connection-state=established,related place-before=1 comment="Allow established/related input" ``` Verify with: `/ip/firewall/filter/print count where chain=input` ## L2TP server IPSec secret The L2TP server's IPsec PSK (`ipsec-secret`) is in cleartext in the config. Ensure it: - Is a strong random string (12+ characters) - Is stored in the password manager / recovery bundle - Is NOT shared across routers (unique per router) ## Common failure: WireGuard public key mismatch This is the most common cause of "tunnel configured correctly but 0 B received". The router's config export (`/export show-sensitive`) includes the WireGuard private key, but RouterOS may have **regenerated** it since that export was saved. The public key in the export is now stale. **Diagnosis:** Server `wg show` shows TX counts increasing but RX stays at 0, even though the router pingable on WAN IP and UDP port is accessible. **Fix:** Read the router's ACTUAL public key directly: ``` /interface/wireguard/print detail where name=wg-itpp ``` Compare `public-key=` from that output with the server's `wg show` peer public key. If mismatched: 1. Update the server's `/etc/wireguard/wg0.conf` [Peer] section with the correct public key 2. Restart `wg-quick@wg0` 3. Verify handshake appears within seconds **Prevention:** Never trust `public-key=` from a config export file. Always verify against the live router's interface. The export captures the key at export time; it can go stale if the router regenerates its WG keys during a config reset or manual rekey.