banhack233
HOST PROTECTION, MADE PRACTICAL
User guidev0.2.3

fail2ban / sshguard style · Host audits · Keepalive · Notifications · Autostart

banhack233

One-Line Install

Linux / macOS:

curl -fsSL https://raw.githubusercontent.com/neko233-com/banhack233/main/scripts/install.sh | sh

Windows PowerShell as Administrator:

iwr -useb https://raw.githubusercontent.com/neko233-com/banhack233/main/scripts/install.ps1 | iex

Check status after install (Linux/macOS; omit sudo when already root):

sudo banhack233 status

On Windows, run & "$env:ProgramFiles\banhack233\banhack233.exe" status in Administrator PowerShell; the installer does not add the command to PATH.

Default mode is dry_run=true: alert only, no real firewall ban. Installation creates configuration but does not start a new daemon. Review the configuration, install autostart, observe dry-run, then switch to production.

English setup: set notifications.language to "en" and notifications.timezone to "UTC" in the installed configuration. See international setup, English example configuration, and notification setup. Language/time-zone fields require v0.2.3+; an older configuration keeps its existing behavior.

Chinese docs: README.md

Documentation: HTML guide · 中文 HTML · Development and releases · Changelog · Download Release. The website updates only after a stable release passes checks, builds, and publication; its version label identifies what is deployed.

Detailed documentation

Your question Reference
English alerts, time zones, proxies, offline installation, overseas providers International setup
Arguments, permissions, and operations that change the system Commands and side effects
Defaults, rule replacement, password-only detection, notification fields Configuration reference
First deployment, isolated replay, office recovery, upgrades and rollback Operations guide
No bans, duplicate counts, missing notifications, disconnected SSH Troubleshooting and FAQ
Scanning, state versus firewall, platform limits, future work Architecture and limits

Repository docs can include unreleased changes. Online HTML represents the stable version displayed on the page; see the changelog.

Telegram and daily updates

See notification setup and retry semantics and verified updates and rollback. Keep office egress addresses in ignore_ips; public SSH cannot identify a remote NIC MAC address.

The following migrates an existing Linux systemd deployment. For a new installation, follow international setup first.

sudo banhack233 safe-ssh -write
sudo banhack233 config-check
sudo systemctl restart banhack233
sudo banhack233 auto-update -enable
sudo banhack233 auto-update -status

What It Is

banhack233 combines fail2ban / sshguard-style SSH defense, host audits, keepalive, notifications and autostart in one Go tool for Linux, macOS and Windows.

It mainly solves these cases:

  • You need SSH password login, sometimes root password login, but still want brute-force defense.
  • You need failed SSH login scanning and threshold-based IP bans.
  • You need autostart, alerts, host audit, and hourly scheduled audit.
  • You need keepalive for long-idle SSH sessions; actual connectivity still depends on the network and client.
  • You need Linux, macOS, and Windows adaptation.

Password SSH login and root password login are supported use cases. The default baseline keeps them enabled while reducing risk with low retry count, short login grace time, no empty passwords, alerts, whitelist, and automated bans.

Similar Software

banhack233 does not clone one project line by line. It combines common host security capabilities. Similar or related software/capabilities:

  1. fail2ban: log scan, threshold detection, attacker IP ban.
  2. sshguard: SSH brute-force protection.
  3. denyhosts: failed login source detection and blocking ideas.
  4. crowdsec: security event detection, remediation, and alert ecosystem.
  5. ClamAV / rkhunter / chkrootkit: Linux malicious file, rootkit, and compromise indicator checks.
  6. nftables / iptables / PF / Windows Firewall: backends called by this project; ufw is a related management tool without a dedicated adapter here.

Features

  1. Host security audit: SSH policy, firewall backend, update/reboot hints, notification channels.
  2. SSH failed-login scanning: auth.log, secure, Windows OpenSSH event log.
  3. SSH-scoped bans: Linux nft/iptables and Windows local destination ports follow ssh_ports (default [22]); macOS requires administrator-managed PF rules.
  4. Root password login support: root and password login are not forcibly disabled.
  5. SSH security baseline: no empty password, low retry count, short grace time, strong-password use case.
  6. SSH 24-hour keepalive: default changes SSH keepalive only, not system TCP sysctl.
  7. TCP keepalive advanced mode: global TCP keepalive/conntrack settings require explicit -tcp.
  8. Notifications: Telegram, Discord, Slack, Feishu/Lark, generic webhooks and TLS email; independent delivery with a durable retry queue.
  9. TLS SMTP with optional separate username and environment credential; hostname/port presets do not guarantee provider authentication support. See SMTP limits.
  10. Linux malware scan: miner processes, temp-dir execution, LD_PRELOAD, cron/systemd persistence indicators.
  11. Conservative cleanup: manual scans may terminate only recognized intrusion executable names when direct_kill=true or -kill; diagnostics and scheduled audits are read-only.
  12. Autostart: Linux systemd, macOS launchd, Windows schtasks.
  13. Safe defaults: dry_run=true, start_at_end=true, ignore_ips whitelist, direct_kill=false.
  14. Password-only defaults, per-user counting, successful-login reset and a 10-minute grace period. Success anywhere in the current read batch suppresses that IP’s earlier failures. Windows event IDs prevent replay.
  15. Daily verified stable updates, restart checks and rollback backups; update guide.
  16. English/Chinese notifications, per-channel language overrides, UTC/IANA time zones and globally consistent default thresholds.

Can It Be Antivirus?

It can be a lightweight Linux host antivirus and intrusion-triage helper, but it is not a full commercial antivirus or EDR.

It can:

  1. Detect common miner indicators: xmrig, kdevtmpfsi, kinsing, watchbog, stratum+tcp, and similar.
  2. Detect suspicious execution from /tmp, /var/tmp, /dev/shm, /run/user.
  3. Detect LD_PRELOAD hijack traces.
  4. Detect suspicious cron and systemd persistence commands.
  5. Send alerts.
  6. Directly kill suspicious processes only when explicitly enabled.

It cannot guarantee:

  1. Coverage of all malware samples.
  2. Replacement for ClamAV/YARA/commercial EDR.
  3. Repair of every rootkit or kernel-level backdoor.
  4. Zero false positives on business processes.

So default behavior is scan and alert only. Remediation must be explicitly enabled.

Supported Platforms

Platform Arch Installer Autostart
Linux amd64 / arm64 install.sh systemd
macOS amd64 / arm64 install.sh launchd
Windows amd64 / arm64 install.ps1 schtasks

Windows event cursors and local-port enforcement are implemented. macOS still requires PF and log-source setup. Builds and automated tests do not replace target-host acceptance; see platform limits.

Default config paths:

Linux:   /etc/banhack233/config.json
macOS:   /usr/local/etc/banhack233/config.json
Windows: %ProgramData%\banhack233\config.json

Default state paths:

Linux:   /var/lib/banhack233/state.json
macOS:   /usr/local/var/banhack233/state.json
Windows: %ProgramData%\banhack233\state.json

Quick Start

Linux with systemd. First review the generated configuration, set English notifications if desired, and add your real office egress addresses to ignore_ips. Windows/macOS steps use their own service managers.

curl -fsSL https://raw.githubusercontent.com/neko233-com/banhack233/main/scripts/install.sh | sh
sudo banhack233 status
sudo banhack233 doctor
sudo banhack233 keepalive -write
sudo banhack233 install-autostart

Enable real bans after observing dry-run output:

sudo banhack233 enable-production -config /etc/banhack233/config.json
sudo systemctl restart banhack233

enable-production changes only dry_run=false, preserving every other setting; restart the daemon afterward. The optional scripts/enable-production.sh also changes SSH policy and should be reviewed separately. Manual equivalent:

sudo sed -i 's/"dry_run": true/"dry_run": false/' /etc/banhack233/config.json
sudo systemctl restart banhack233

Main Commands

See commands. test is a real scan and can change the firewall in production; config-check, status and doctor do not terminate processes.

sudo banhack233 status
sudo banhack233 doctor
sudo banhack233 test
sudo banhack233 notify-test
sudo banhack233 notify-test -channel feishu,email
sudo banhack233 ban-list
sudo banhack233 unban 203.0.113.10
sudo banhack233 malware-scan
sudo banhack233 malware-scan -kill
sudo banhack233 secure-ssh
sudo banhack233 secure-ssh -write -force
sudo banhack233 enable-production -config /etc/banhack233/config.json
sudo banhack233 keepalive -write
sudo banhack233 install-autostart

doctor checks SSH policy, root login policy, empty password setting, retry limit, login grace time, firewall backend, reboot requirement, dry-run status, and notification channels.

It does not treat Redis, MySQL, custom TCP services, or other business ports as default security issues. Business exposure is a business decision.

Malware / Miner Scan

sudo banhack233 malware-scan

Default mode scans only. It does not kill processes or move files.

Manual one-shot kill:

sudo banhack233 malware-scan -kill

Opt-in manual cleanup policy:

{
  "malware": {
    "direct_kill": true
  }
}

direct_kill is the only cleanup configuration switch, default false. It applies to manual malware-scan; routine audits never kill. A temporary path, mining-tool name or matching command argument alone is insufficient for cleanup; review the report.

Reports:

  • Every malware-scan prints a console report and writes a report file.
  • File name format: {name}.yyyy-MM-dd_HH-mm-ss.txt.
  • Default name: malware-scan.
  • Custom name: banhack233 malware-scan -name ssh-box-1.
  • Default directory: /var/lib/banhack233/reports.
  • Default retention: latest 50 reports, older files pruned by LRU/mod-time.

Config:

{
  "malware": {
    "enabled": true,
    "direct_kill": false,
    "report_dir": "/var/lib/banhack233/reports",
    "report_keep": 50
  }
}

Production hosts should keep direct_kill=false first, review reports, then enable it.

SSH Baseline

Preview:

sudo banhack233 secure-ssh

Apply:

sudo banhack233 secure-ssh -write -force

Default policy:

PasswordAuthentication yes
PermitRootLogin yes
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 20s

Keep an existing SSH session open before applying SSH changes.

SSH 24h Keepalive

sudo banhack233 keepalive -write

By default this writes SSH config only. It does not change system TCP keepalive / conntrack settings, avoiding unexpected impact on TCP long connections, HTTP, database pools, proxies, or other business services.

Writes:

/etc/ssh/sshd_config.d/99-banhack233-keepalive.conf

SSH settings:

PasswordAuthentication yes
PermitRootLogin yes
TCPKeepAlive yes
ClientAliveInterval 60
ClientAliveCountMax 1440
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30s

TCP Keepalive Advanced Mode

System TCP settings are not changed by default. If you explicitly need global TCP keepalive / conntrack tuning, add -tcp:

sudo banhack233 keepalive -write -tcp

This additionally writes:

/etc/sysctl.d/99-banhack233-keepalive.conf

TCP settings:

net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
net.netfilter.nf_conntrack_tcp_timeout_established = 432000

Meaning:

  • SSH sends keepalive every 60 seconds.
  • SSH allows 1440 missed keepalive checks, about 24 hours.
  • TCP keepalive starts after 60 seconds.
  • conntrack established timeout is 5 days.

This can prevent system, NAT, or conntrack layers from cleaning up idle business long connections too early, but it is a global kernel setting and affects TCP/HTTP/database/proxy behavior on the whole host. Review the business connection model before enabling it.

If an application has its own 5-minute idle timeout, fix the application heartbeat or timeout too.

Shared Office IPs and Whitelists

A public SSH server cannot see a client's MAC address: MAC addresses stay on the local link. Behind NAT, counting failures by username still affects everyone if enforcement blocks the shared IP. Use a separate SSH key or certificate for each device when device identity is needed. Password login and root login remain supported.

Defaults count only explicit Failed password lines, with IP+username grouping and successful-login reset/grace. Invalid-user/publickey/connection messages do not count. Shared usernames still share counters; actual enforcement remains source-IP based, so whitelist office egress addresses. No connections-per-minute drop rule is installed.

Existing configurations are preserved. Migrate the named default rule with safe-ssh -write and restart; custom rules need explicit review. The password-only pattern is:

"patterns": ["Failed password for(?: invalid user)? (?P<user>\\S+) from <HOST>"]

Add permanent office exceptions using individual IPv4/IPv6 addresses or CIDR networks:

sudo banhack233 whitelist 203.0.113.10 198.51.100.0/24
sudo systemctl restart banhack233
sudo banhack233 whitelist

The command preserves existing config fields and whitelist entries. For another config, use banhack233 whitelist -config /path/config.json 203.0.113.10. The equivalent setting is "ignore_ips": ["127.0.0.1", "::1", "203.0.113.10"]. After restart, ignored addresses no longer accumulate failures. In production mode, their existing automatic bans recorded in state are removed along with failure counts. Use banhack233 unban 203.0.113.10 for leftover firewall entries missing from state.

Automatic bans are actually removed on the first scan after ban_time expires. If multiple rules block the same IP, all must release it first. Custom commands must implement their own reversal. dry_run=true never modifies existing firewall rules.

To disable IP blocking for a rule, change its "action": "auto" to "action": "notify" and restart. It only alerts at the failure threshold, using ban_time as the alert cooldown. Notifications explicitly say the IP was not blocked. In production mode, existing automatic bans from that rule are also released unless another rule still blocks the IP. Other rules keep their own behavior.

If Fail2ban, SSHGuard, cloud firewalls, or SSH connection rate limits also run, configure their exceptions separately. banhack233 whitelist only manages this application. A rule limiting new SSH connections per shared IP can reject correct passwords and keys too; add a persistent SSH-port exception for trusted office egress addresses.

Config Example

{
  "interval": "30s",
  "audit_interval": "1h",
  "state_path": "/var/lib/banhack233/state.json",
  "dry_run": true,
  "start_at_end": true,
  "ignore_ips": [
    "127.0.0.1",
    "::1"
  ],
  "rules": [
    {
      "name": "ssh-auth-failure",
      "log_paths": [
        "/var/log/auth.log",
        "/var/log/secure"
      ],
      "patterns": [
        "Failed password for(?: invalid user)? (?P<user>\\S+) from <HOST>"
      ],
      "reset_patterns": [
        "Accepted (?:password|publickey|keyboard-interactive) for (?P<user>\\S+) from <HOST>"
      ],
      "max_attempts": 5,
      "find_time": "10m",
      "ban_time": "1h",
      "action": "auto",
      "count_by_user": true,
      "success_grace": "10m"
    }
  ],
  "malware": {
    "enabled": true,
    "direct_kill": false,
    "report_dir": "/var/lib/banhack233/reports",
    "report_keep": 50
  },
  "ssh_ports": [
    22
  ]
}

Important fields:

Field Meaning
dry_run Alert only when true; no real firewall ban
start_at_end Monitor only new logs on first run
ignore_ips IP/CIDR whitelist; releases existing automatic bans after restart in production mode
max_attempts Failure threshold
find_time Detection window
ban_time Automatic ban duration; removal on the next scan after expiry; alert cooldown in notify mode
action auto blocks IPs; notify only alerts; or a custom command
count_by_user When true, count failures per IP+user; requires (?P<user>...) in patterns. Reduces false bans on shared egress IPs
patterns Go regex with <HOST> or named IP group; default counts password failures only
reset_patterns Successful-login regex; clears all failure counters for that IP (fail2ban MLFGAINED semantics) so legit users are not penalized by historical failures
region_rules.max_attempts Override threshold by GeoIP Country/Region/City; keys support Chinese/English (广州/Guangzhou)
malware.enabled Include malware checks in doctor/hourly audit
malware.direct_kill Manual cleanup of recognized intrusion executable names; default false; audits remain read-only
malware.report_dir Report directory
malware.report_keep Report retention count; older files pruned by LRU

Notifications

Set notifications.language="en" for English titles, labels, reasons and durations. notifications.timezone="UTC" is useful for international teams. Each channel can override language; existing configs default to zh-CN and Local. Details and examples: language/time zones, all notification channels.

Supported channels:

Channel Field Payload
Console console stdout / systemd journal
Telegram telegram Bot API plain text; optional forum topic
Feishu / Lark feishu Interactive card (msg_type=interactive)
Discord discord Embed card
Slack slack Block Kit message
Generic webhook webhooks[] text, json, discord, slack, feishu
Email email SMTP

Feishu / Lark

{
  "notifications": {
    "feishu": {
      "enabled": true,
      "url": "https://open.feishu.cn/open-apis/bot/v2/hook/xxxx",
      "secret": "your-feishu-sign-secret",
      "location_language": "zh-CN"
    }
  }
}

Feishu messages use interactive cards (JSON 2.0) with color-coded headers: red for bans, orange for dry-run/audit, blue for tests.

If signature verification is enabled, set secret; the client adds timestamp and sign automatically (HmacSHA256 + Base64 per Feishu docs). Omit secret when verification is off.

All channels share the same alert fields with native wrappers: rule, source IP, location, handling method, ban reason, ban duration, and time.

location_language controls location translation. Chinese channels such as Feishu should use zh-CN; the alert adds a separate Chinese location row. If no translation is available, the original text remains.

Test notifications (sends to all enabled channels):

sudo banhack233 notify-test
sudo banhack233 notify-test -channel feishu,email
sudo banhack233 notify-test -message "custom test text"

banhack233 test executes one real daemon cycle, including state writes and configured actions. Notifications require a triggered event; use isolated replay for matching tests and notify-test for channel delivery.

Discord

{
  "notifications": {
    "discord": {
      "enabled": true,
      "url": "https://discord.com/api/webhooks/xxx/yyy"
    }
  }
}

Slack

{
  "notifications": {
    "slack": {
      "enabled": true,
      "url": "https://hooks.slack.com/services/xxx/yyy/zzz"
    }
  }
}

Generic Webhook

Use this for internal alert gateways, security platforms, or OpenClaw-style notification aggregators.

{
  "notifications": {
    "webhooks": [
      {
        "name": "internal-alert",
        "enabled": true,
        "url": "https://example.com/webhook",
        "format": "json",
        "headers": {
          "Authorization": "Bearer token"
        }
      }
    ]
  }
}

Formats:

Format Payload
text Structured plain text
json Structured JSON (title, kind, time, fields, detail, text)
discord Embed card
slack Block Kit message
feishu / lark Interactive card; set secret for signature verification; set location_language=zh-CN for Chinese location row

Email

{
  "notifications": {
    "email": {
      "enabled": true,
      "from": "alert@qq.com",
      "to": "admin@example.com",
      "password": "smtp-authorization-code",
      "smtp_host": "",
      "smtp_port": 0
    }
  }
}

SMTP auto-detection:

Mail Domain SMTP
@qq.com smtp.qq.com:465
@163.com smtp.163.com:465
@126.com smtp.126.com:465
@gmail.com smtp.gmail.com:587
@outlook.com smtp-mail.outlook.com:587
@hotmail.com smtp-mail.outlook.com:587
@live.com smtp-mail.outlook.com:587

QQ and 163 usually require SMTP authorization codes, not login passwords. Presets only choose the server/port. Gmail needs an eligible app password; this client uses SMTP PLAIN over TLS and does not implement Outlook OAuth2. Use a compatible SMTP relay or another notification channel. See provider authentication and separate SMTP usernames.

Brute-Force Defense Flow

  1. Install in dry-run.
  2. Enable autostart.
  3. Watch logs and alerts.
  4. Add office IPs to ignore_ips.
  5. Switch dry_run=false.
  6. Restart service.
  7. Check ban-list.
sudo banhack233 status
journalctl -u banhack233 -n 100 --no-pager
sudo banhack233 ban-list

TCP Long-Connection Advanced Verification

Default mode does not change TCP sysctl. Only run this after banhack233 keepalive -write -tcp.

sysctl net.ipv4.tcp_keepalive_time \
  net.ipv4.tcp_keepalive_intvl \
  net.ipv4.tcp_keepalive_probes \
  net.netfilter.nf_conntrack_tcp_timeout_established

Expected after -tcp:

net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
net.netfilter.nf_conntrack_tcp_timeout_established = 432000

If clients still disconnect after a few minutes, check application idle timeout, protocol heartbeat, cloud load balancer idle timeout, proxy timeout, gateway timeout, and firewall connection cleanup.

Troubleshooting

Install Is Slow

Use verified offline installation or configure a trusted proxy in the install/update process environment. Check the correct OS/architecture asset against the same Release's SHA256SUMS.txt before execution. Installers allow up to 10 minutes per download; repeated failures retain the previous binary.

No Real Bans

sudo banhack233 status
sudo banhack233 test
sudo banhack233 ban-list

If dry_run=true, bans are not applied.

No Notification

Check webhook URL, email SMTP authorization code, outbound network, and service logs:

journalctl -u banhack233 -n 100 --no-pager

Development

go test ./...
go vet ./...

The repository is pure Go (no Python). Two standalone helpers live under tools/ (own go.mod, not part of the main module build):

cd tools/remotessh && go build     # SSH ops: diag / exec / put (password via SSH_PASS)
cd tools/integration && go build   # Linux firewall integration checks (root + nft; stop the daemon first)

Build all release binaries:

./build-all.sh

The HTML documentation generator is another standalone Go module:

cd tools/docs
go test ./...
go run . -root ../.. -out ../../site -version dev -commit local -serve 127.0.0.1:8088

Branch pushes and PRs do not trigger Actions. After local checks and release notes are ready, push a stable vX.Y.Z tag. One workflow runs CI, builds six binaries, publishes the Release, then deploys GitHub Pages. Older tags cannot replace newer docs, and failed prerequisite jobs never deploy. See Development and releases.