AbuseIPDBのAPIを使ってみた

# AbuseIPDBって何？

これ　https://www.abuseipdb.com/
世界中のいろいろな人が悪いIPを晒上げるサイトで、怪しげなアクセスがあったときのIP調べるのに使ったする。
1個1個調べたり1個1個晒上げるならサイト上の検索やREPORTで十分だが、自動でブラックリストもらってきたり、まとめて晒上げたい場合WebAPIを使うことになる。
今回はこのサイトのWebAPIを使ってIPブラックリストとってきたり、悪いIPを晒上げてみるまでのことを書く。

# WebAPI使うまでの準備
## まずはアカウント作成

貧乏なのでFREEなアカウントを使う。
下記にアクセスして、INDVIDUALの下のSIGN UPを選択する。
https://www.abuseipdb.com/pricing

![1.png](https://qiita-image-store.s3.amazonaws.com/0/367048/04d67d34-f5db-1cb0-9c79-0708b6224114.png)

適当に入れるもん入れてアカウント作成すると、以下のような画面に遷移する。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/367048/fdd77491-7e57-44b3-6049-979d39af663c.png)

しばらくすると登録したアドレスにメールが来るので、そこに貼ってあるリンクを押すと登録完了。
下記のようにEmailの横がverifiedになる。メールが来ないときはRESEND VERIFICATION EMAILのボタンを押す。（メールが来るの結構おそかったから私は連打してしまった）

![4.png](https://qiita-image-store.s3.amazonaws.com/0/367048/0a3a46c9-9996-8612-205f-e779ea2c5834.png)

## APIキー作成

「APIv2」っていうタブがあるからそこ押して「Create Key」でAPIキー作成。名前は適当でいい。
このキーを使ってWebAPIにアクセスすることになる。
![7.png](https://qiita-image-store.s3.amazonaws.com/0/367048/8080af05-972b-0cf5-fc60-9bdeb3d8cfcf.png)

# IPブラックリスト取得

この辺にcurlを利用した使い方が書いてある。
https://docs.abuseipdb.com/#plaintext-blacklist
とりあえず下記で取得できた。

```bash
$ YOUR_API_KEY="APIキー"
$ curl -G https://api.abuseipdb.com/api/v2/blacklist \
  -d countMinimum=15 \
  -d maxAgeInDays=60 \
  -d confidenceMinimum=90 \
  -H "Key: $YOUR_API_KEY" \
  -H "Accept: text/plain" > blacklist.txt
$  head blacklist.txt
60.29.254.252
118.24.214.107
111.231.88.23
41.33.61.165
128.199.61.227
112.112.102.79
223.111.139.210
36.156.24.99
36.156.24.96
223.111.139.211
$  wc -l blacklist.txt 
9999
```

9999個しかないのはたぶんお金払ってないから。。。Basic Blacklistなるものしか手に入らない。

# 悪いIP報告

## 1個1個報告する場合

ここから報告できる。
https://www.abuseipdb.com/report

API使う場合は以下参照。
https://docs.abuseipdb.com/#report-endpoint

SSHブルートフォースが来た場合の報告例

```bash
$ curl https://api.abuseipdb.com/api/v2/report \
  --data-urlencode "ip=悪いIP" \
  -d categories=18,22 \
  --data-urlencode "comment=SSH login attempts with user root." \
  -H "Key: $YOUR_API_KEY" \
  -H "Accept: application/json"
```

API報告の場合、カテゴリをID（数字）で指定することになる。
下記のカテゴリがある。
https://www.abuseipdb.com/categories

## まとめて報告する場合

CSVに悪いIP情報をまとめて、それをアップすることでバルク報告できる。
https://www.abuseipdb.com/bulk-report


# 一定以上の攻撃を検知してバルクで送信する例

やりたかったのはこれ。
WebApp攻撃が一定以上あったIPを1日1回チェックして、AbuseIPDBにバルクで送信するスクリプト。
WebApp攻撃検知としてModSecurityを使用し、攻撃検知データの蓄積には[waf-fle] (http://www.waf-fle.org/)を使用。
waf-fleのDBつついてIPと攻撃数を取得し、AbuseIPDBに送信する。

```python
#!/usr/bin/python
# -*- coding: utf-8 -*-

import MySQLdb
import datetime
import requests
import sys

tmp_csv = "/tmp/report.csv"

# abuseipdb接続情報
api_url = "https://api.abuseipdb.com/api/v2/bulk-report"
api_key = "APIキー"

# DB接続情報
dbname = "wafdb"
dbuser = "DBユーザ"
dbpass = "DBパスワード"

# 攻撃検知閾値
threshold = 100

# SQL文
dt_now = datetime.datetime.now()
start_day = (dt_now - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
end_day = dt_now.strftime("%Y-%m-%d")
query="SELECT COUNT(a_client_ip), INET_NTOA(a_client_ip), MAX(a_timestamp) FROM events" \
      " WHERE a_timestamp >= \"{0} 00:00:00\" AND a_timestamp < \"{1} 00:00:00\" " \
      " GROUP BY a_client_ip HAVING COUNT(a_client_ip) > {2} ORDER BY COUNT(a_client_ip) DESC;".\
      format(start_day, end_day, threshold)

# DB接続して閾値以上の攻撃IP取得
connect = MySQLdb.connect(host='localhost', port=3306, user=dbuser, passwd=dbpass, db=dbname,
                          charset='utf8')
cursor = connect.cursor()
cursor.execute(query)
result = cursor.fetchall()

if len(result) == 0:
    # 攻撃がなければ終了
    cursor.close()
    connect.close()
    sys.exit(0)

# CSVファイルにに書き出し
f = open(tmp_csv,'w')
f.write('IP,Categories,ReportDate,Comment\n')
for row in result:
    f.write('{0},\"16,21\",{1},\"{2} attacks in a short period.\"\n'.format(row[1], row[2], row[0]))
f.close()

cursor.close()
connect.close()

# AbuseIPDBにバルク送信
fileDataBinary = open(tmp_csv, 'rb').read()
files = {'csv': (tmp_csv, fileDataBinary)}
headers = {'Accept': 'application/json', 'Key': api_key}
response = requests.post(api_url, headers=headers, files=files)
# print(response.status_code)
# print(response.content)

```

このスクリプトをcronで毎日1回実行することにした。
これで自動で悪いIPをAbuseIPDBにさらすことができる。

## 余談

なんかpythonモジュールとしてabuseipdbというのがあったが、バルク送信に対応してないし、正直この程度APIなら普通にrequests使ったほうがいいと思う。
https://pypi.org/project/abuseipdb/