DOCS · HONEYPOT SETUP
Contribute to mikrotik-bruteforce.
Last updated: .
The mikrotik-bruteforce
list is populated by volunteer routers running the script on this
page. If you own a RouterOS device on a public IP — homelab, SOHO,
VPS, anything that gets login-attempt traffic — you can contribute
the attacker IPs you see to the community list. Five-minute setup.
What gets sent
- The attacker's IP address — the source IP that triggered the firewall match. This is what lands in the public list.
- The service that was hit —
winbox,ssh,api,webfig,ftp, ortelnet. Surfaces as thecomment="honeypot: ssh"field on the rendered.rsc. - A timestamp — implicit in the HTTPS POST; not stored in the public list (which only carries the IP + service + comment).
What does NOT get sent
- The attempted username — RouterOS may log this; we don't transmit it.
- Any payload or password attempt — not even hashed.
- The router's own LAN topology, hostname, MAC, or serial.
- Internal IPs — the firewall rules below only tarpit traffic arriving from external IPs hitting the public- facing management ports. A household member typo'ing their password from the LAN never gets reported.
- Documentation / loopback / link-local / CGN / multicast
ranges — the server-side
/api/honeypot/ingestendpoint rejects these with HTTP 422 as defense-in-depth, even if the .rsc collector ever slipped one through.
Prerequisites
- RouterOS v6.43+ or v7.0+ — the collector uses
/tool fetchwith HTTPS + custom headers; older versions don't supporthttp-header-field. - An active supporter subscription — monthly
(A$5/mo) or yearly (A$50/yr) at
/supporter. One-time donations
don't qualify for honeypot ingest even though
they grant the permanent
supporterrole. The server-side gate at/api/honeypot/ingestchecks for an active subscription (statusactiveortrialing) on every POST and returns HTTP 403subscription_requiredwhen missing. Rationale: honeypot data quality benefits from long-term commitment — a router that reports for a week and goes silent contributes mostly noise to the rolling 30-day TTL. - A router on a public IP with at least one management service exposed (Winbox / SSH / API / Webfig). The rules below tarpit on TCP 22 / 8291 / 8728 / 8729 / 80 / 443 — adjust if you've moved services to non-default ports.
Step 1 — Mint a honeypot API key
- Sign in to /account.
-
Scroll to API keys. Set the label to something
you'll recognise later — e.g.
honeypot-home-auorhoneypot-mom-de. The label becomes thelist_sources.namefor attribution. - Pick
Writeas the capability. The honeypot endpoint requiresscope='write'— a read-only key won't work. - Click Create new key. Copy the cleartext immediately — we only store the hash; you can't retrieve it later.
Step 2 — Paste the .rsc onto your router
Replace mtkf_REPLACE_WITH_YOUR_KEY with the cleartext
key from step 1, then paste the whole block into a Terminal window
on the router (Winbox → New Terminal, or SSH). The block creates
firewall rules + an export script + a 5-minute scheduler.
# mikrotikfilters.com honeypot collector — v0.116.0
# Docs: https://mikrotikfilters.com/docs/honeypot-setup
#
# Replace the API key on the next line BEFORE running.
:global mtkfApiKey "mtkf_REPLACE_WITH_YOUR_KEY"
# ─── Firewall: progressive bruteforce-detection on management ports ──
# Three-stage tarpit. An IP that opens a fresh connection to ANY
# listed management port three times within ~5 minutes ends up on
# the `mtkf-honeypot-reported` address-list with a 24h timeout.
# The exporter script (below) reads that address-list and POSTs
# each entry to mikrotikfilters.com.
#
# Ports: 22 (SSH), 8291 (Winbox), 8728 (API), 8729 (API-SSL),
# 80 (Webfig HTTP), 443 (Webfig HTTPS), 21 (FTP), 23 (Telnet).
# Trim ports you don't have listening; rules cost almost nothing
# either way.
#
# IMPORTANT — these rules go BEFORE your accept-established and
# any explicit allow rules for management traffic. The 3-strike
# progression triggers ONLY on connection-state=new, so legitimate
# established sessions are unaffected.
/ip/firewall/filter
add chain=input action=add-src-to-address-list \
protocol=tcp connection-state=new \
dst-port=22,8291,8728,8729,80,443,21,23 \
src-address-list=mtkf-bf-stage2 \
address-list=mtkf-honeypot-reported \
address-list-timeout=24h \
comment="mikrotikfilters honeypot: report-queue (3rd attempt)"
add chain=input action=add-src-to-address-list \
protocol=tcp connection-state=new \
dst-port=22,8291,8728,8729,80,443,21,23 \
src-address-list=mtkf-bf-stage1 \
address-list=mtkf-bf-stage2 \
address-list-timeout=5m \
comment="mikrotikfilters honeypot: stage 2"
add chain=input action=add-src-to-address-list \
protocol=tcp connection-state=new \
dst-port=22,8291,8728,8729,80,443,21,23 \
address-list=mtkf-bf-stage1 \
address-list-timeout=1m \
comment="mikrotikfilters honeypot: stage 1"
# ─── Exporter script ───────────────────────────────────────────
# Reads `mtkf-honeypot-reported`, POSTs each entry, removes them
# from the address-list on success. Runs every 5 minutes via the
# scheduler below. Failures (network, 429, key revoked) leave the
# entry in the address-list for retry next tick.
/system/script
add name=mtkf-honeypot-export source={
:global mtkfApiKey
:if (\$mtkfApiKey = "mtkf_REPLACE_WITH_YOUR_KEY" or \$mtkfApiKey = "") do={
:log warning "mtkf-honeypot-export: API key not set; skipping"
:error "mikrotikfilters honeypot: API key not configured"
}
:local apiUrl "https://mikrotikfilters.com/api/honeypot/ingest"
:local reported [/ip/firewall/address-list find list=mtkf-honeypot-reported]
:foreach entryId in=\$reported do={
:local ip [/ip/firewall/address-list get \$entryId address]
:local body "{\"source_ip\":\"\$ip\",\"service\":\"unknown\"}"
:do {
/tool fetch mode=https url=\$apiUrl http-method=post \
http-header-field="Authorization: Bearer \$mtkfApiKey,Content-Type: application/json" \
http-data=\$body output=none
# On success, remove the entry so we don't re-report next tick.
/ip/firewall/address-list remove \$entryId
:log info ("mtkf-honeypot-export: reported " . \$ip)
} on-error={
:log warning ("mtkf-honeypot-export: POST failed for " . \$ip . " (will retry next tick)")
}
}
}
# ─── Scheduler: every 5 minutes ────────────────────────────────
/system/scheduler
add name=mtkf-honeypot-export-tick \
interval=5m \
on-event="/system/script/run mtkf-honeypot-export" \
comment="mikrotikfilters honeypot: drain report-queue every 5min"
# Done. Watch /log for "mtkf-honeypot-export: reported …" entries
# once the firewall has caught its first 3-strike attacker.
On RouterOS v6 the path syntax is slightly different —
/ip firewall filter instead of
/ip/firewall/filter, etc. Toggle the RouterOS
version control at the top of the page to see the v6
variant.
# mikrotikfilters.com honeypot collector — v0.116.0 (RouterOS v6 syntax)
# Docs: https://mikrotikfilters.com/docs/honeypot-setup
:global mtkfApiKey "mtkf_REPLACE_WITH_YOUR_KEY"
/ip firewall filter
add chain=input action=add-src-to-address-list \
protocol=tcp connection-state=new \
dst-port=22,8291,8728,8729,80,443,21,23 \
src-address-list=mtkf-bf-stage2 \
address-list=mtkf-honeypot-reported \
address-list-timeout=24h \
comment="mikrotikfilters honeypot: report-queue (3rd attempt)"
add chain=input action=add-src-to-address-list \
protocol=tcp connection-state=new \
dst-port=22,8291,8728,8729,80,443,21,23 \
src-address-list=mtkf-bf-stage1 \
address-list=mtkf-bf-stage2 \
address-list-timeout=5m \
comment="mikrotikfilters honeypot: stage 2"
add chain=input action=add-src-to-address-list \
protocol=tcp connection-state=new \
dst-port=22,8291,8728,8729,80,443,21,23 \
address-list=mtkf-bf-stage1 \
address-list-timeout=1m \
comment="mikrotikfilters honeypot: stage 1"
/system script
add name=mtkf-honeypot-export source={
:global mtkfApiKey
:if (\$mtkfApiKey = "mtkf_REPLACE_WITH_YOUR_KEY" or \$mtkfApiKey = "") do={
:log warning "mtkf-honeypot-export: API key not set; skipping"
:error "mikrotikfilters honeypot: API key not configured"
}
:local apiUrl "https://mikrotikfilters.com/api/honeypot/ingest"
:local reported [/ip firewall address-list find list=mtkf-honeypot-reported]
:foreach entryId in=\$reported do={
:local ip [/ip firewall address-list get \$entryId address]
:local body "{\"source_ip\":\"\$ip\",\"service\":\"unknown\"}"
:do {
/tool fetch mode=https url=\$apiUrl http-method=post \
http-header-field="Authorization: Bearer \$mtkfApiKey,Content-Type: application/json" \
http-data=\$body output=none
/ip firewall address-list remove \$entryId
:log info ("mtkf-honeypot-export: reported " . \$ip)
} on-error={
:log warning ("mtkf-honeypot-export: POST failed for " . \$ip . " (will retry next tick)")
}
}
}
/system scheduler
add name=mtkf-honeypot-export-tick \
interval=5m \
on-event="/system script run mtkf-honeypot-export" \
comment="mikrotikfilters honeypot: drain report-queue every 5min"
Step 3 — Verify it's working
-
Run the script once manually:
/system script run mtkf-honeypot-export. If the address-list is empty (no attackers have triggered the progression yet) you'll see no log entries. -
Within a few hours an attacker should trigger the 3-strike
progression. Watch with
/ip firewall address-list print where list=mtkf-honeypot-reported. -
Once an entry lands, the next 5-minute scheduler tick will POST
it. Check the log:
/log print where message~"mtkf-honeypot-export". A successful report logsmtkf-honeypot-export: reported <ip>. - On the server side, /account/usage shows the honeypot key's daily POST count. The key has a 5,000 reports/day cap (UTC midnight reset) as a runaway circuit-breaker; normal traffic is in the single-double-digit range per day.
Common gotchas
- Rules in wrong order — the 3-stage progression
must run BEFORE your
accept established,related,untrackedand any other allow rules. If your input chain accepts the connection before the stage-1 rule sees it, no IPs get tarpitted. Re-order with/ip/firewall/filter move <number> destination=0to put them at the top. - Your own IP gets reported — if you connect to
management from an external IP that you also fail to log in from
(typo, expired session), you may end up on the report queue.
Either remove yourself manually with
/ip/firewall/address-list remove [find list=mtkf-honeypot-reported address=<your-ip>]OR add an explicit allowlist rule BEFORE the stage-1 rule excluding your known-good IPs. - CGN-NAT subscribers — if your ISP puts you behind carrier-grade NAT, your "external" IP is shared with hundreds of other subscribers. The honeypot endpoint rejects CGN-100.64/10 ranges defensively; ISP-side CGN that uses ranges outside of 100.64/10 (rare but exists) would slip through. Don't report from a CGN'd connection if you're not sure.
- Pasting the .rsc fails — the script body uses
double-quotes inside the JSON; some terminal pastes mangle them.
If that happens, save the .rsc to a file
(
/file print) and run/import file-name=mtkf-honeypot.rsc.
Removing the collector
If you want to stop contributing, run this on the router:
/system/scheduler remove [find name=mtkf-honeypot-export-tick]
/system/script remove [find name=mtkf-honeypot-export]
/ip/firewall/filter remove [find comment~"mikrotikfilters honeypot:"]
/ip/firewall/address-list remove [find list~"^mtkf-(bf-stage|honeypot-reported)"]
:global mtkfApiKey ""
Then revoke the honeypot API key on /account so it can't be reused.