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 hitwinbox, ssh, api, webfig, ftp, or telnet. Surfaces as the comment="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/ingest endpoint 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 fetch with HTTPS + custom headers; older versions don't support http-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 supporter role. The server-side gate at /api/honeypot/ingest checks for an active subscription (status active or trialing) on every POST and returns HTTP 403 subscription_required when 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

  1. Sign in to /account.
  2. Scroll to API keys. Set the label to something you'll recognise later — e.g. honeypot-home-au or honeypot-mom-de. The label becomes the list_sources.name for attribution.
  3. Pick Write as the capability. The honeypot endpoint requires scope='write' — a read-only key won't work.
  4. 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.

v7 88 lines · 3852 bytes
# 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.

v6 58 lines · 2247 bytes
# 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

  1. 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.
  2. Within a few hours an attacker should trigger the 3-strike progression. Watch with /ip firewall address-list print where list=mtkf-honeypot-reported.
  3. 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 logs mtkf-honeypot-export: reported <ip>.
  4. 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,untracked and 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=0 to 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:

v7 6 lines · 292 bytes
/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.