Skill: jestersimpps/fail2ban-reporter (version 1.0.0)

--- name: fail2ban-reporter description: "Auto-report fail2ban banned IPs to AbuseIPDB and notify via Telegram. Use when monitoring server security, reporting attackers, or checking banned IPs. Watches fail2ban for new bans, reports them to AbuseIPDB, and sends alerts." --- # fail2ban Reporter Monitor fail2ban bans and auto-report attackers to AbuseIPDB. ## Setup 1. Get a free AbuseIPDB API key at https://www.abuseipdb.com/account/api 2. Store it: `pass insert abuseipdb/api-key` 3. Install the monitor: `bash {baseDir}/scripts/install.sh` ## Manual Usage ### Report all currently banned IPs ```bash bash {baseDir}/scripts/report-banned.sh ``` ### Check a specific IP ```bash bash {baseDir}/scripts/check-ip.sh <ip> ``` ### Show ban stats ```bash bash {baseDir}/scripts/stats.sh ``` ## Auto-Reporting The install script sets up a fail2ban action that auto-reports new bans. ```bash bash {baseDir}/scripts/install.sh # install auto-reporting bash {baseDir}/scripts/uninstall.sh # remove auto-reporting ``` ## Heartbeat Integration Add to HEARTBEAT.md to check for new bans periodically: ```markdown - [ ] Check fail2ban stats and report any unreported IPs to AbuseIPDB ``` ## Workflow 1. fail2ban bans an IP → action triggers `report-single.sh` 2. Script reports to AbuseIPDB with SSH brute-force category 3. Sends Telegram notification (if configured) 4. Logs report to `/var/log/abuseipdb-reports.log` ## API Reference See [references/abuseipdb-api.md](references/abuseipdb-api.md) for full API docs.

path: README.md
content: # 🛡️ Clawdbot fail2ban Reporter

Auto-report fail2ban banned IPs to [AbuseIPDB](https://www.abuseipdb.com), protecting the community from brute-force attackers.

Built for [Clawdbot](https://github.com/clawdbot/clawdbot) — works as a standalone tool too.

## Why?

Every server with a public IP gets attacked. fail2ban blocks them locally — but reporting to AbuseIPDB blocks them **globally**. When you report an attacker, every other server using AbuseIPDB's blocklist benefits.

Real stats from a fresh server:

```
Within 60 seconds of enabling fail2ban:
→ 62 failed SSH attempts
→ 9 unique IPs banned  
→ Attacks from 7 countries
```

## Quick Start

### 1. Get an AbuseIPDB API Key (free)

Sign up at [abuseipdb.com](https://www.abuseipdb.com/account/api) — free tier allows 1000 reports/day.

### 2. Store your API key

```bash
# Using pass (recommended)
pass insert abuseipdb/api-key

# Or export directly
export ABUSEIPDB_KEY="your-api-key"
```

### 3. Report currently banned IPs

```bash
bash scripts/report-banned.sh
```

### 4. Enable auto-reporting (optional)

```bash
sudo bash scripts/install.sh
```

Now every new fail2ban ban automatically reports to AbuseIPDB.

## Usage

### Report all banned IPs
```bash
bash scripts/report-banned.sh          # default: sshd jail
bash scripts/report-banned.sh nginx    # custom jail
```

### Check an IP's reputation
```bash
bash scripts/check-ip.sh 1.2.3.4
```

### View stats
```bash
bash scripts/stats.sh
```

### Remove auto-reporting
```bash
sudo bash scripts/uninstall.sh
```

## Clawdbot Skill

If you're using Clawdbot, install as a skill:

```bash
# Copy to skills directory
cp -r . ~/.clawdbot/skills/fail2ban-reporter/
```

Then ask your Clawdbot:
- "Report banned IPs to AbuseIPDB"
- "Check IP 1.2.3.4"
- "Show fail2ban stats"

### Heartbeat Integration

Add to your `HEARTBEAT.md`:

```markdown
- [ ] Check fail2ban for new bans, report unreported IPs to AbuseIPDB
```

## How It Works

```
Attacker → SSH brute-force → fail2ban bans IP → report-single.sh
                                                      ↓
                                              AbuseIPDB API (report)
                                                      ↓
                                              /var/log/abuseipdb-reports.log
```

## Prerequisites

- `fail2ban` — `sudo apt install fail2ban`
- `jq` — `sudo apt install jq`
- `curl` — usually pre-installed
- `pass` (optional) — for secure API key storage

## License

MIT — report those attackers, protect the community! 🛡️


path: references/abuseipdb-api.md
content: # AbuseIPDB API Reference

Base URL: `https://api.abuseipdb.com/api/v2`

## Authentication

```
Key: YOUR_API_KEY
```

Header: `Key: <api-key>`
Accept: `application/json`

## Report an IP

```
POST /report
```

| Parameter | Required | Description |
|-----------|----------|-------------|
| ip | Yes | IP to report |
| categories | Yes | Comma-separated category IDs |
| comment | No | Description of attack |

### Categories (common)

| ID | Category |
|----|----------|
| 18 | Brute-Force |
| 22 | SSH |
| 15 | Hacking |
| 14 | Port Scan |

### Example

```bash
curl -s https://api.abuseipdb.com/api/v2/report \
  -H "Key: $ABUSEIPDB_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "ip=1.2.3.4" \
  -d "categories=18,22" \
  --data-urlencode "comment=SSH brute-force (fail2ban)"
```

## Check an IP

```
GET /check?ipAddress=1.2.3.4
```

| Parameter | Required | Description |
|-----------|----------|-------------|
| ipAddress | Yes | IP to check |
| maxAgeInDays | No | 1-365 (default 30) |

### Example

```bash
curl -s "https://api.abuseipdb.com/api/v2/check?ipAddress=1.2.3.4&maxAgeInDays=90" \
  -H "Key: $ABUSEIPDB_KEY" \
  -H "Accept: application/json"
```

Response includes `abuseConfidenceScore` (0-100), `totalReports`, `countryCode`, `isp`.

## Rate Limits (free tier)

- Check: 1000/day
- Report: 1000/day
- Blacklist: 5/day


path: scripts/check-ip.sh
content: #!/bin/bash
# Check an IP's abuse score on AbuseIPDB
# Usage: check-ip.sh <ip>

set -euo pipefail

IP="${1:?Usage: check-ip.sh <ip>}"
[REDACTED_SECRET] show abuseipdb/api-key 2>/dev/null || echo "")}"

if [ -z "$API_KEY" ]; then
  echo "ERROR: No AbuseIPDB API key found."
  exit 1
fi

RESPONSE=$(curl -sG "https://api.abuseipdb.com/api/v2/check" \
  -H "Key: $API_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "ipAddress=$IP" \
  -d "maxAgeInDays=90")

echo "$RESPONSE" | jq '{
  ip: .data.ipAddress,
  score: .data.abuseConfidenceScore,
  country: .data.countryCode,
  isp: .data.isp,
  domain: .data.domain,
  totalReports: .data.totalReports,
  lastReported: .data.lastReportedAt,
  isWhitelisted: .data.isWhitelisted
}'


path: scripts/install.sh
content: #!/bin/bash
# Install fail2ban action for auto-reporting to AbuseIPDB
# Usage: sudo bash install.sh

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

# Check prerequisites
if ! command -v fail2ban-client &>/dev/null; then
  echo "❌ fail2ban not installed. Run: sudo apt install -y fail2ban"
  exit 1
fi

if ! command -v jq &>/dev/null; then
  echo "❌ jq not installed. Run: sudo apt install -y jq"
  exit 1
fi

# Verify API key exists
[REDACTED_SECRET] show abuseipdb/api-key 2>/dev/null || echo "")}"
if [ -z "$API_KEY" ]; then
  echo "❌ No AbuseIPDB API key found."
  echo "   Get one free at: https://www.abuseipdb.com/account/api"
  echo "   Then run: pass insert abuseipdb/api-key"
  exit 1
fi

# Create fail2ban action
cat > /etc/fail2ban/action.d/abuseipdb.conf << CONF
[Definition]
actionban = bash $SCRIPT_DIR/report-single.sh <ip> "SSH brute-force on <name> jail (fail2ban auto-report)"

[Init]
CONF

# Add action to sshd jail
if ! grep -q "abuseipdb" /etc/fail2ban/jail.local 2>/dev/null; then
  # Check if action line exists
  if grep -q "^action" /etc/fail2ban/jail.local 2>/dev/null; then
    sed -i '/^\[sshd\]/,/^\[/{s/^action.*/& \n         abuseipdb/}' /etc/fail2ban/jail.local
  else
    sed -i '/^\[sshd\]/a action = %(action_)s\n         abuseipdb' /etc/fail2ban/jail.local
  fi
fi

# Restart fail2ban
sudo systemctl restart fail2ban

echo "✅ Auto-reporting installed!"
echo "   New bans will be reported to AbuseIPDB automatically."
echo "   Logs: /var/log/abuseipdb-reports.log"
echo ""
echo "   To report existing bans: bash $SCRIPT_DIR/report-banned.sh"
echo "   To check stats: bash $SCRIPT_DIR/stats.sh"


path: scripts/report-banned.sh
content: #!/bin/bash
# Report all currently banned IPs to AbuseIPDB
# Usage: report-banned.sh [jail_name]

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
JAIL="${1:-sshd}"
LOG="/var/log/abuseipdb-reports.log"

# Get banned IPs
BANNED=$(sudo fail2ban-client status "$JAIL" | grep "Banned IP list" | sed 's/.*Banned IP list:\s*//')

if [ -z "$BANNED" ]; then
  echo "No banned IPs in jail: $JAIL"
  exit 0
fi

# Read already-reported IPs from log
REPORTED_IPS=""
if [ -f "$LOG" ]; then
  REPORTED_IPS=$(grep "REPORTED" "$LOG" | awk '{print $4}' | sort -u)
fi

COUNT=0
SKIPPED=0

for IP in $BANNED; do
  # Skip already reported (within last 15 min to avoid duplicates)
  if echo "$REPORTED_IPS" | grep -q "^${IP}$"; then
    SKIPPED=$((SKIPPED + 1))
    continue
  fi

  echo "Reporting: $IP"
  bash "$SCRIPT_DIR/report-single.sh" "$IP" "SSH brute-force (fail2ban auto-ban on $JAIL jail)"
  COUNT=$((COUNT + 1))

  # Rate limit: small delay between reports
  sleep 1
done

echo ""
echo "Done! Reported: $COUNT | Skipped (already reported): $SKIPPED"


path: scripts/report-single.sh
content: #!/bin/bash
# Report a single IP to AbuseIPDB
# Usage: report-single.sh <ip> [comment]

set -euo pipefail

IP="${1:?Usage: report-single.sh <ip> [comment]}"
COMMENT="${2:-SSH brute-force attack detected by fail2ban}"
LOG="/var/log/abuseipdb-reports.log"
[REDACTED_SECRET] show abuseipdb/api-key 2>/dev/null || echo "")}"

if [ -z "$API_KEY" ]; then
  echo "ERROR: No AbuseIPDB API key found."
  echo "Set ABUSEIPDB_KEY or run: pass insert abuseipdb/api-key"
  exit 1
fi

# Report to AbuseIPDB
RESPONSE=$(curl -s -w "\n%{http_code}" \
  "https://api.abuseipdb.com/api/v2/report" \
  -H "Key: $API_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "ip=$IP" \
  -d "categories=18,22" \
  --data-urlencode "comment=$COMMENT")

HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')

TIMESTAMP=$(date -u '+%Y-%m-%d %H:%M:%S UTC')

if [ "$HTTP_CODE" = "200" ]; then
  SCORE=$(echo "$BODY" | jq -r '.data.abuseConfidenceScore // "unknown"')
  echo "$TIMESTAMP | REPORTED | $IP | score: $SCORE | $COMMENT" >> "$LOG"
  echo "✅ Reported $IP to AbuseIPDB (confidence score: $SCORE)"
else
  ERROR=$(echo "$BODY" | jq -r '.errors[0].detail // "unknown error"' 2>/dev/null || echo "$BODY")
  echo "$TIMESTAMP | FAILED | $IP | HTTP $HTTP_CODE | $ERROR" >> "$LOG"
  echo "❌ Failed to report $IP: $ERROR (HTTP $HTTP_CODE)"
fi


path: scripts/stats.sh
content: #!/bin/bash
# Show fail2ban + AbuseIPDB reporting stats
# Usage: stats.sh [jail_name]

JAIL="${1:-sshd}"
LOG="/var/log/abuseipdb-reports.log"

echo "═══════════════════════════════════════"
echo "  fail2ban Reporter Stats"
echo "═══════════════════════════════════════"
echo ""

# fail2ban stats
echo "📊 fail2ban ($JAIL jail):"
STATUS=$(sudo fail2ban-client status "$JAIL" 2>/dev/null)
if [ $? -eq 0 ]; then
  CURRENTLY_BANNED=$(echo "$STATUS" | grep "Currently banned" | awk '{print $NF}')
  TOTAL_BANNED=$(echo "$STATUS" | grep "Total banned" | awk '{print $NF}')
  CURRENTLY_FAILED=$(echo "$STATUS" | grep "Currently failed" | awk '{print $NF}')
  TOTAL_FAILED=$(echo "$STATUS" | grep "Total failed" | awk '{print $NF}')
  BANNED_LIST=$(echo "$STATUS" | grep "Banned IP list" | sed 's/.*Banned IP list:\s*//')

  echo "  Currently banned: $CURRENTLY_BANNED"
  echo "  Total banned:     $TOTAL_BANNED"
  echo "  Failed attempts:  $TOTAL_FAILED (current: $CURRENTLY_FAILED)"
  echo ""
  echo "  Banned IPs: $BANNED_LIST"
else
  echo "  ⚠️ fail2ban not running or jail not found"
fi

echo ""

# AbuseIPDB reporting stats
echo "📡 AbuseIPDB Reports:"
if [ -f "$LOG" ]; then
  REPORTED=$(grep -c "REPORTED" "$LOG" 2>/dev/null || echo 0)
  FAILED=$(grep -c "FAILED" "$LOG" 2>/dev/null || echo 0)
  LAST=$(tail -1 "$LOG")
  echo "  Total reported: $REPORTED"
  echo "  Failed reports: $FAILED"
  echo "  Last entry:     $LAST"
else
  echo "  No reports yet. Run report-banned.sh to start."
fi

echo ""
echo "═══════════════════════════════════════"


path: scripts/uninstall.sh
content: #!/bin/bash
# Remove fail2ban auto-reporting action
# Usage: sudo bash uninstall.sh

set -euo pipefail

# Remove action file
rm -f /etc/fail2ban/action.d/abuseipdb.conf

# Remove action from jail config
if [ -f /etc/fail2ban/jail.local ]; then
  sed -i '/abuseipdb/d' /etc/fail2ban/jail.local
fi

# Restart fail2ban
sudo systemctl restart fail2ban

echo "✅ Auto-reporting removed."
echo "   Manual reporting still works: bash scripts/report-banned.sh"


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)