IP Bulk Reporter

Instead of reporting IPs individually, you may compile a CSV of reports. This helps reduce bandwidth on both sides.

The CSV file must be under 8 MB and less than or equal to 10,000 lines, including the headings. These limits may increase in the future as we optimize software and beef up hardware.

CSV Format Strict ordering, Strict headings

  1. IP — A valid IPv4 or IPv6 IP address.
  2. Categories — At least one category ID. Comma separated for multiple categories. See: Report Categories
  3. ReportDate — Date and time of the attack or earliest observance of attack. Any format that strtotime() can process is permitted. However, we recommend a timezoned format such ISO 8601 e.g. 2017-09-08T10:00:37-04:00. A time lacking a timezone will assumed to be in our server timezone (EST).
  4. Comment — A description of the attack. 1,024 characters (bytes). NOTE: The values of this column are entirely optional. However, you must have the Comment header.

Here is a sample of a valid bulk IP file:

IP,Categories,ReportDate,Comment,"18,22",2017-09-08T10:00:37-04:00,Failed password for invalid user odoo from port 39121 ssh2,2017-09-08T11:25:11-04:00,Did not receive identification string from port 57192

Max Filesize: 2 MB

Collecting the Data

Attacks can easily be harvested from /var/log/secure/ or wherever you store security logs. Take a gander at a sample bash script we provide that can run daily. (We're no shell gurus, so shoot us an email if you can beef up the script). Run the script with your log file as the first operand and your API key as the second. The -d may be set to perform a dry run, where the generated file will not be uploaded to our server.


$ ./parse-logs.sh secure.log &YOUR_API_KEY

By default, you should receive a JSON response listing which reports were accepted and which were rejected. Pipe the output into jq if you'd like to peruse the response.

$ ./parse-logs.sh secure.log &YOUR_API_KEY | jq



# by default, this is not a dry run

# options, a while loop will allow us to add more options in the future
while getopts "d" opt; do
	case $opt in
		d) echo "Performing dry run. Results will not submitted to AbuseIPDB"; dryRun=1 ;;
		\?) echo "Invalid option: -$OPTARG" >&2 ;;

# skip over the processed options
shift $((OPTIND-1))

# operand: the file to parse
# operand: the API key of the AbuseIPDB user

# standard operand checking
if [ -z $1 ]; then
	echo "Missing input file. Aborting." >&2
	exit 1;
elif [ ! -r $1 ]; then
	echo "File does not exist or is not readable. Aborting." >&2
	exit 1;
elif [ -z $2 ] && [ $dryRun -eq 0 ]; then
	echo "Missing API Key" >&2
	exit 1;

# pcregrep is not preinstalled on many linux distros
if [ ! -x "$(command -v pcregrep)" ]; then
	echo "Command 'pcregrep' required but it's not installed. Aborting." >&2
	exit 1;

# find the pattern matches for an invalid user
pcregrep -o1 -o2 -o3 --om-separator=";" -e '([a-zA-Z]+ [0-9]+ [0-9]+:[0-9]+:[0-9]+) .* (Invalid user [a-zA-Z0-9]+ from (([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})) port [0-9]+)' $secureLogFile > matches.txt

# rearrange the order of the fields for our bulk uploader
gawk --field-separator=";" 'BEGIN {print "IP,Categories,ReportDate,Comment"} {print $3","22","$1","$2}' matches.txt > report.csv

# clean up
rm matches.txt

# check dry run option
if [ $dryRun -eq 0 ]; then
	# report to AbuseIPDB
	curl -F [email protected] -F key=$key --output - https://www.abuseipdb.com/bulk

exit 0;
** This Document Provided By AbuseIPDB **
Source: https://www.abuseipdb.com/bulk-report