From 78ed771bcb6f980a59719870358903a9623f7719 Mon Sep 17 00:00:00 2001 From: kristuff Date: Thu, 14 May 2020 20:40:32 +0200 Subject: [PATCH] initial commit --- .gitattributes | 8 ++ .gitignore | 3 + LICENSE | 21 +++ README.md | 55 ++++++++ composer.json | 20 +++ lib/ApiDefintion.php | 123 +++++++++++++++++ lib/ApiManager.php | 304 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 534 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 composer.json create mode 100644 lib/ApiDefintion.php create mode 100644 lib/ApiManager.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..2e8592a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +tests/ export-ignore +vendor/ export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.travis.yml export-ignore +composer.* export-ignore +phpunit.xml export-ignore +README.* export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..25d109d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +_* +.old* +vendor/* \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..abe2257 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 kristuff + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed80820 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# kristuff/abuse-ipdb +> A mini library to work with the AbuseIPDB api V2 + +see [kristuff/abuse-ipdb-cli](https://github.com/kristuff/abuse-ipdb-cli) for the CLI version + + +Requirements +------------ +- PHP >= 7.1 +- PHP's cURL +- A valid account to [abuseipdb.com](https://abuseipdb.com) with an API key + +Install +------- + +1. Deploy with composer + +```json +[...] +"require": { + "kristuff/abuseipdb": ">=0.1-stable" + }, +``` + +Usage +----- + +```php +echo ('TODO'); +``` + +License +------- + +The MIT License (MIT) + +Copyright (c) 2020 Kristuff + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..3979348 --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "kristuff/abuseipdb", + "description": "A library to work with the AbuseIPDB api V2", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Kristuff", + "homepage": "https://github.com/kristuff" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { + "Kristuff\\AbuseIPDB\\": "lib/" + } + } +} diff --git a/lib/ApiDefintion.php b/lib/ApiDefintion.php new file mode 100644 index 0000000..2571182 --- /dev/null +++ b/lib/ApiDefintion.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @version 0.1.0 + * @copyright 2020 Kristuff + */ + +namespace Kristuff\AbuseIPDB; + +/** + * Class ApiDefintion + * + * Abstract base class for ApiManager + * Contains main hard coded api settings + */ +abstract class ApiDefintion +{ + /** + * AbuseIPDB API v2 Endpoint + * @var string $api_endpoint + */ + protected $aipdbApiEndpoint = 'https://api.abuseipdb.com/api/v2/'; + + /** + * AbuseIPDB API v2 categories + * @var array $aipdbApiCategories + */ + protected $aipdbApiCategories = [ + + // Altering DNS records resulting in improper redirection. + 'dns-c' => ['1', 'DNS Compromise', true], + + // Falsifying domain server cache (cache poisoning). + 'dns-p' => ['2', 'DNS Poisoning', true], + + // Fraudulent orders. + 'fraud-orders' => ['3', 'Fraud Orders', true], + + // Participating in distributed denial-of-service (usually part of botnet). + 'ddos' => ['4', 'DDoS Attack', true], + + // + 'ftp-bf' => ['5', 'FTP Brute-Force', true], + + // Oversized IP packet. + 'pingdeath' => ['6', 'Ping of Death', true], + + // Phishing websites and/or email. + 'phishing' => ['7', 'Phishing', true], + + // + 'fraudvoip' => ['8', 'Fraud VoIP', true], + + // Open proxy, open relay, or Tor exit node. + 'openproxy' => ['9', 'Open Proxy', true], + + // Comment/forum spam, HTTP referer spam, or other CMS spam. + 'webspam' => ['10', 'Web Spam', true], + + // Spam email content, infected attachments, and phishing emails. Note: Limit comments to only relevent + // information (instead of log dumps) and be sure to remove PII if you want to remain anonymous. + 'emailspam' => ['11', 'Email Spam', true], + + // CMS blog comment spam. + 'blogspam' => ['12', 'Blog Spam', true], + + // Conjunctive category. + 'vpnip' => ['13', 'VPN IP', false], // to check alone ?? + + // Scanning for open ports and vulnerable services. + 'scan' => ['14', 'Port Scan', true], + + // seems to can't be used alone + 'hack' => ['15', 'Hacking', false], + + // Attempts at SQL injection. + 'sql' => ['16', 'SQL Injection'], true, + + // Email sender spoofing. + 'spoof' => ['17', 'Spoofing', true], + + // Credential brute-force attacks on webpage logins and services like SSH, FTP, SIP, SMTP, RDP, etc. + // This category is seperate from DDoS attacks. + 'brute' => ['18', 'Brute-Force', true], + + // Webpage scraping (for email addresses, content, etc) and crawlers that do not honor robots.txt. + // Excessive requests and user agent spoofing can also be reported here. + 'badbot' => ['19', 'Bad Web Bot', true], + + + // Host is likely infected with malware and being used for other attacks or to host malicious content. + // The host owner may not be aware of the compromise. This category is often used in combination + // with other attack categories. + 'explhost' => ['20', 'Exploited Host', true], + + // Attempts to probe for or exploit installed web applications such as a CMS + // like WordPress/Drupal, e-commerce solutions, forum software, phpMyAdmin and + // various other software plugins/solutions. + 'webattack' => ['21', 'Web App Attack', true ], + + // Secure Shell (SSH) abuse. Use this category in combination + // with more specific categories. + 'ssh' => ['22', 'SSH', false], + + // Abuse was targeted at an "Internet of Things" type device. Include + // information about what type of device was targeted in the comments. + 'oit' => ['23', 'IoT Targeted', true], + ]; + +} \ No newline at end of file diff --git a/lib/ApiManager.php b/lib/ApiManager.php new file mode 100644 index 0000000..b90c281 --- /dev/null +++ b/lib/ApiManager.php @@ -0,0 +1,304 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @version 0.1.0 + * @copyright 2020 Kristuff + */ + +namespace Kristuff\AbuseIPDB; + +/** + * Class ApiManager + * + * The main class to work with the AbuseIPDB API v2 + */ +class ApiManager extends ApiDefintion +{ + /** + * AbuseIPDB API key + * + * @access protected + * @var string $aipdbApiKey + */ + protected $aipdbApiKey = null; + + /** + * AbuseIPDB user id + * + * @access protected + * @var string $aipdbUserId + */ + protected $aipdbUserId = null; + + /** + * The ips to remove from message + * Generally you will add to this list yours ipv4 and ipv6, and the hostname + * + * @access protected + * @var array $selfIps + */ + protected $selfIps = []; + + /** + * Constructor + * + * @access public + * @param string $apiKey The AbuseIPDB api key + * @param string $userId The AbuseIPDB user's id + * @param array $myIps The Ips you dont want to report + * + */ + public function __construct(string $apiKey, string $userId, array $myIps = []) + { + $this->aipdbApiKey = $apiKey; + $this->aipdbUserId = $userId; + $this->selfIps = $myIps; + } + + /** + * Get the current configuration in a indexed array + * + * @access public + * @return array + */ + public function getConfig() + { + return array( + 'userId' => $this->aipdbUserId, + 'apiKey' => $this->aipdbApiKey, + 'selfIps' => $this->selfIps, + ); + } + + /** + * Get a new instance of ApiManager with config stored in a Json file + * + * @access public + * @static + * @param string $configPath The configuration file path + * + * @return \Kristuff\AbuseIPDB\ApiManager + */ + public static function fromConfigstring(string $configPath) + { + //todo check file exist + $config = self::loadJsonFile($configPath); + return new ApiManager($config->api_key, $config->user_id, $config->self_ips); + } + + /** + * Get the list of report categories + * + * @access public + * @return array + */ + public function getCategories() + { + return $this->aipdbApiCategories; + } + + /** + * Performs a 'report' api request + * + * Result, in json format will be something like this: + * { + * "data": { + * "ipAddress": "127.0.0.1", + * "abuseConfidenceScore": 52 + * } + * } + * + * @access public + * @param string $ip The ip to report + * @param array $categories The report categories + * @param string $message The report message + * + * @return stdClass|array + * @throws \InvalidArgumentException + */ + public function report(string $ip = '', array $categories = [], $message = '') + { + // ip must be set + if (empty($ip)){ + throw new \InvalidArgumentException('Ip was empty'); + } + + // categories must be set + if (empty($categories)){ + throw new \InvalidArgumentException('categories list was empty'); + } + + // message must be set + if (empty($message)){ + throw new \InvalidArgumentException('report message was empty'); + } + + // TODO valider les cat / seules pas seules... + // TODO clean message ? selfips list + $cats = $this->validateCategories($categories); + + // report AbuseIPDB request + + + //TODO + return $this->apiRequest('report', 'POST', [ + 'ip' => $ip, + 'categories' => 'TODO', '21,15', + 'comment' => $message + ]); + } + + /** + * Check if the category(ies) given is/are valid + * Check for shortname or id, and categories that can't be used alone + * + * @access public + * @param array $categories The report categories list + * + * @return string Formatted string id list ('18,2,3...') + * @throws \InvalidArgumentException + */ + public function validateCategories(array $categories = []) + { + $newList = []; + $needAnother = false; + + foreach ($categories as $cat){ + + } + //todo + + } + + /** + * Perform a 'check' api request + * + * + * TODO OPTION POUR VERBOSE ;;; + * force $maxAge int as parameter ? + * + * @access public + * @param string $ip The ip to check + * @param string $maxAge Max age in days + * + * @return stdObj + * @throws \InvalidArgumentException + */ + public function check(string $ip = null, string $maxAge = '30') + { + + $maxAge = intval($maxAge); + + // max age must less or equal to 365 + if ($maxAge > 365 || $maxAge < 1){ + throw new \InvalidArgumentException('maxAge must be at least 1 and less than 365 (' . $maxAge . ' was given)'); + } + + //ip must be set + if (empty($ip)){ + throw new \InvalidArgumentException('ip argument must be set (null given)'); + } + + // check AbuseIPDB request + return $this->apiRequest('check', 'GET', [ + 'ipAddress' => $ip, + 'maxAgeInDays' => $maxAge, + 'verbose' => true + ]); + } + + /** + * Perform a cURL request TODO: option as array + * + * @access protected + * @param string $path The api end path + * @param string $method The request method. Default is 'GET' + * @param array $data The request data + * + * @return stdObj TODO object ARRAY ;;; + */ + protected function apiRequest(string $path, string $method = 'GET', array $data) + { + // set api url + $url = $this->aipdbApiEndpoint . $path; + + // open curl connection + $ch = curl_init(); + + // set the method and data to send + if ($method == 'POST') { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + } else { + $url .= '?' . http_build_query($data); + } + + // set the url to call + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + // set the AbuseIPDB API Key as a header + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Accept: application/json;', + 'Key: ' . $this->aipdbApiKey, + ]); + + // execute curl call + $result = curl_exec($ch); + + // close connection + curl_close($ch); + + // return response as json object + return json_decode($result); + } + + /** + * Load and returns decoded Json from given file + * + * @access public + * @static + * @param string $filePath The file's full path + * @param bool [$trowError] Throw error on true or silent process. Default is true + * + * @return string|null + * @throws \Exception + * @throws \LogicException + */ + protected static function loadJsonFile(string $filePath, bool $throwError = true) + { + // check file exists + if (!file_exists($filePath) || !is_file($filePath)){ + if ($throwError) { + throw new \Exception('Config file not found'); + } + return null; + } + + // get and parse content + $content = file_get_contents($filePath); + $json = json_decode(utf8_encode($content)); + + // check for errors + if ($json == null && json_last_error() != JSON_ERROR_NONE){ + if ($throwError) { + throw new \LogicException(sprintf("Failed to parse config file Error: '%s'", json_last_error_msg())); + } + } + + return $json; + } +} \ No newline at end of file