1,26 → 1,26 |
<?php /* <ViaThinkSoftSignature> |
vJ+0x2DUzGuKKU+tOUdLohoPLPnIkH7lNhr7zWbsRowTtzyrkO7I5Cv+5EYNqyqSN |
ValuGLqnaSFCzCfKD/3Q1fDXLtMa4i9oik3wXGqw31JXcWLPaTssxNdVh7eccVcf4 |
nUSGvZTURAHB3tD461buwSHK4x5IeJC8H7UfCgu2xKZmPIxW01tg+6d+JI2VLoZ05 |
p78QgevhWNnDdHAaWXnitERSUsWqQP+ojulO0RpEOm9tWQ/8/vmCP7egfk1fRvkzY |
SDjFxO0A1lNS3ho9fyDkRkh4eNsyo4XpOr4SaE6EJS0ZViTZbgKHfZWxg88M96pO0 |
c2i0upWR6/cK0AA2oD6KkCo12KWw2kjKu5O+Hi8RHHGIy0yxu5GnYHgq0vXevZX3R |
rkYgckOpHbOHL/ynrQYTiKpTKowbc9YsgvYg2GbKCgc8dT72GLp7cvQsb/hS/V+7M |
878z3TK7gSeI0iEZ3rdqawCFacmA/Wf6cn5P1ddLO4qOOdnJfp05c5gP49z/aZI2Q |
zsIz8wQ96U5sBctKO//nlecjUt+/bKR3tZ58UWpvbmk1RkSJOC9zBc9crhYKNyDYy |
fxb2pGajCHQWg3crV/Qx4asZ9ag0Tky3JgQQM97SrlK3ioZezS3YlQSZlq0j1Xhd6 |
sqyUx45j5l9NgRKy5oFt5z6Rtd69BBloPFIoSQuhv0VCp0qENYCKjMpc4J2OFiQj+ |
ZIB/5RI/mie5aVVZJMeHslsScEgB7tTuOiGzNPY6FXHy7Dpmk5/Og4779l9ZAS1x6 |
twrxb0g8vYaoW/w9+HnDXoh4/FiCEup9NtXPDr152klduswpgOQauTLm8Iw1aDVIl |
lNj/iNLTiWrm2CnxAmeTffdu62obSFikpG751wzzyqiWBubKUrCw3AILNuEPPOcts |
5OcNacznrelP5D1CF7Xx7Nds/FDdIB4X1gd1ombEbpBQuaDN2pw7IPub8/ZMmM9fZ |
05fBqLb6lzOK8ku6qOLiKbbst757vcIraINul7zyw8QXKp0fY9Zw16qnWquQAUvdi |
eM1B6HbfXhLQ2FpGc1WhFVTCchSif7zOviMnDc1Dbp1BadJfBCfg7IjtbGEyhItHm |
Eh6U/m/evT3bWK7p1OJZex9Qnnxkp3qKzQ8hzRoZoYU8G4dwSd7EBT7HiFJIhOTAV |
bwSD7zdqXyED2Vy31HlvbdXkF86Id0C69V5jfh23eXUnVs+t3Vjl4GCz6JQiEvlWo |
jY0PNM6PUVfk2GAOnpfI7ocAHAdHjD3kwsiXg4Bu/iPFpIKIKSXrLLI54VA3Uysga |
vUC6Srjjck8Foeug5mBlaEP7O26Bryvs+iQ4tQwut17TZFQTOcl43u2cVi1jvJ1qV |
Q== |
qWEItTVwmWt4bCuj7GpdpdKLH3wLzHxhgQxr8p/AKPM17DRZoAn/i9x4YUloNuiC6 |
ut7naeSIlD/SKCob9Qli9lrbCjlfAsuZUaV1MVuZutycJBp3xSEOLCxLfBWB9DbVq |
pfAmFuS/ukEWAVipyeddB3RPmsAPDnZlNkQyRXXcB/yO31GYANCB5K6qaUPRoHVc+ |
7AbZK3WfZBBaILYXdFDzincJfCyVxVOtFqdbuwyIQiJKAf6fmcWqJeEWCOGDMve+i |
bcRpS8QuWbB6rntnmh0NB6JvjpaSkdh0I5m4Qx505OeB6lFgeAVlmszJvUSi3zqVz |
b2zOvnEfm2+QGjrolHyP4vWAQ5ldwoYCXK/9yLsQ7YjvWM8FmgGIyO+E0Gn+diEMo |
PivhhivcOyxpa3O9o03WenONl0ERYB5zzrqzxfqGo5Az4Wluy+8vtpCneUf1VmtRT |
zTLW0KLe/j6OApYgzgKWOxk6cyZMNCpWwDz5jt75xeysEBJSlVe3Z1uNLkD+XFjFm |
b+0TgAwq1hDS0aHbDBwE5dwO3vCkVOGZoANnNZtU4vzs8Oy9GVHmR8muj563Dex6H |
7TygozGMfzI9WxttN9HIvPiA5ncsgHDoA9h7BT+AE1cmwWX+0Cs5m6sqlZZ4dLNsT |
Cwe7vXisS6Q4WTEX9qsldDXrzTgJm7Vmb9wMxwr85nEpViET4uEPbeG8ZsFF1tPIU |
yJPE+yZUCCgml8AWrAcdNaRfx92QFdsYhSOIcypV3VlSjvWm1NE2dStuTo/dqX5M3 |
fmNt/04tZnX7Mh7MzgvcXncuprAS6qgaOPWo5uFL8nUU4WIOzxYywNqaSpA2VFCz1 |
YewKblZVRJmVMcszKHdpcIWYAqX6UbZ7UGO/B06RoFQ0A7oS3A5aQOuKyjQDIFe5n |
8MZGCBfp+yINGcJe68yBLu853OSxfs34/6MzbdEjdei2+y4OP8yWU0pJ9adj0ZLxc |
Ev2ktdqE10UyiSvdxmCnJ3ti/1aS5IFrXiA4lUzsABnZzIOsc6GmrEjSS/G/64zfl |
eCU3scGGBnD4/YNDtkGoMFOSw5qJUHjaiHWnFHwqov5G8LksPfc7MhZgKqLmadzSA |
uw6ns9crjn/zeppNCaO0RwN/dnRkGS1dIdZ7r7d44zyuxG4HPWeJOi/6a0mtGScrO |
tZRjuLQItoOFAImOgZ3QmQELxUKapDArl/wQDl/J+dg7XGIdocpquWQRqi3gsaiu4 |
LW1T0hDvpqEBsj5wgPLr7f4M0hUNzF6sD3WTuj+wZuo+Z2/52/yEqinYUsR29NdJ+ |
8mb/hZ6T5atmeGnhS8pG7y7sj2NsanxEtvucQHdCWT3Di9B+jnUGVlfPtr+3jwKW0 |
A== |
</ViaThinkSoftSignature> */ ?> |
<?php |
|
29,7 → 29,7 |
* Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com> |
* Licensed under the terms of the Apache 2.0 license |
* |
* Revision 2020-02-18 |
* Revision 2020-03-07 |
*/ |
|
declare(ticks=1); |
37,6 → 37,7 |
class OpenBugBountyCheck extends VNag { |
protected $argDomain = null; |
protected $argPrivateAPI = null; |
protected $argIgnoredIds = null; |
|
public function __construct() { |
parent::__construct(); |
47,12 → 48,13 |
$this->getHelpManager()->setVersion('1.1'); |
$this->getHelpManager()->setShortDescription('This plugin checks if a domain has unfixed vulnerabilities listed at OpenBugBounty.org.'); |
$this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.'); |
$this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-d <SingleDomain[,SingleDomain,[...]]> | -d <DomainListFile> | -p <PrivateApiUrl> ]'); |
$this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-d <SingleDomain[,SingleDomain,[...]]> | -d <DomainListFile> | -p <PrivateApiUrl> | -i <IgnoredId,IgnoredId,...> ]'); |
$this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com'); |
|
// Individual (non-standard) arguments: |
$this->addExpectedArgument($this->argDomain = new VNagArgument('d', 'domain', VNagArgument::VALUE_REQUIRED, 'domainOrFile', 'Domain(s) or subdomain(s), separated by comma, to be checked or a file containing domain names.')); |
$this->addExpectedArgument($this->argPrivateAPI = new VNagArgument('p', 'privateapi', VNagArgument::VALUE_REQUIRED, 'privateApiUrl', 'A link to your private API (https://www.openbugbounty.org/api/2/...../). Cannot be used together with argument \'-d\'.')); |
$this->addExpectedArgument($this->argIgnoredIds = new VNagArgument('i', 'ignoredids', VNagArgument::VALUE_REQUIRED, 'ignoredIds', 'Comma separated list of submission IDs that shall be defined as fixed (because OpenBugBounty often does not mark fixed bugs as fixed, even if you tell them that you have fixed them...)')); |
} |
|
protected function get_cache_dir() { |
81,7 → 83,35 |
return false; // should usually never happen |
} |
|
function num_open_bugs($domain, $max_cache_time = 3600) { // TODO: make cache time configurable via config |
function is_ignored($id) { |
$ids = $this->argIgnoredIds->getValue(); |
if (empty($ids)) return false; |
|
$ids = explode(',', $ids); |
foreach ($ids as $test) { |
if ($id == $test) return true; |
} |
return false; |
} |
|
static function extract_id_from_url($url) { |
// https://www.openbugbounty.org/reports/1019234/ |
$parts = explode('/', $url); |
foreach ($parts as $part) { |
if (is_numeric($part)) return $part; |
} |
return -1; |
} |
|
function num_open_bugs_v1($domain, $max_cache_time = 3600) { // TODO: make cache time configurable via config |
//assert(!empty($this->argDomain->getValue())); |
//assert(empty($this->argPrivateAPI->getValue())); |
|
$fixed = 0; |
$unfixed = 0; |
|
$this->setStatus(VNag::STATUS_OK); |
|
$domain = strtolower($domain); |
$cache_file = $this->get_cache_dir() . '/' . md5($domain); |
|
93,15 → 123,28 |
file_put_contents($cache_file, $cont); |
} |
|
$fixed = 0; |
$unfixed = 0; |
|
$xml = simplexml_load_string($cont); |
foreach ($xml as $x) { |
if ($x->fixed == '1') $fixed++; |
if ($x->fixed == '0') $unfixed++; |
$submission = $x->url; |
|
if ($fake_fix = $this->is_ignored($this->extract_id_from_url($submission))) $x->fixed = '1'; |
|
if ($x->fixed == '0') { |
$unfixed++; |
$this->addVerboseMessage("Unfixed issue found at $domain: $submission", VNag::VERBOSITY_SUMMARY); |
$this->setStatus(VNag::STATUS_WARNING); |
// TODO: Unlike the "private" API, the "normal" API does not show if a bug is disclosed (= critical instead of warning) |
// But we could check if the report is older than XXX months, and then we know that it must be disclosed. |
} |
|
if ($x->fixed == '1') { |
$fixed++; |
$tmp = $fake_fix ? ' (fix asserted by operator)' : ''; |
$this->addVerboseMessage("Fixed issue found at $domain: $submission$tmp", VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
$this->setStatus(VNag::STATUS_OK); |
} |
} |
|
return array($fixed, $unfixed); |
} |
|
121,22 → 164,10 |
return $ary; |
} |
|
protected function cbRun($optional_args=array()) { |
$domain = $this->argDomain->getValue(); |
$privateapi = $this->argPrivateAPI->getValue(); |
function num_open_bugs_v2($privateapi, $max_cache_time = 3600) { // TODO: make cache time configurable via config |
//assert(empty($this->argDomain->getValue())); |
//assert(!empty($this->argPrivateAPI->getValue())); |
|
if (empty($domain) && empty($privateapi)) { |
throw new Exception("Please specify a domain or subdomain, a list of domains, or a private API Url."); |
} |
|
if (!empty($domain) && !empty($privateapi)) { |
throw new Exception("You can either use argument '-d' or '-p', but not both."); |
} |
|
if (!empty($privateapi)) { |
// Possibility 1: Private API (showing all bugs for all of your domains, with detailled information) |
// https://www.openbugbounty.org/api/2/.../ |
|
$sum_fixed = 0; |
$sum_unfixed_pending = 0; |
$sum_unfixed_disclosed = 0; |
143,7 → 174,7 |
|
$this->setStatus(VNag::STATUS_OK); |
|
$ary = $this->get_privateapi_data($privateapi); |
$ary = $this->get_privateapi_data($privateapi, $max_cache_time); |
foreach ($ary as $id => $data) { |
/* |
[Vulnerability Reported] => 21 September, 2017 05:13 |
160,13 → 191,19 |
|
$status = isset($data['Patch Status']) ? $data['Patch Status'] : $data['Path Status']; // sic! There is a typo in their API (reported, but not fixed) |
|
$submission = $data['Report Url']; |
if ($fake_fix = $this->is_ignored($this->extract_id_from_url($submission))) $status = 'Patched'; |
|
$domain = $data['Host']; |
|
if ($status == 'Patched') { |
$sum_fixed++; |
$fixed_date = $fake_fix ? 'asserted by operator' : $data['Vulnerability Fixed']; |
$this->addVerboseMessage("Fixed issue found at $domain: $submission (fixed: $fixed_date)", VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
$this->setStatus(VNag::STATUS_OK); |
} else { |
$disclosure = $data['Scheduled Public Disclosure']; |
$time = strtotime(str_replace(',', '', $disclosure)); |
$domain = $data['Host']; |
$submission = $data['Report Url']; |
if (time() > $time) { |
$sum_unfixed_disclosed++; |
$this->addVerboseMessage("Disclosed unfixed issue found at $domain: $submission (disclosure: $disclosure)", VNag::VERBOSITY_SUMMARY); |
178,6 → 215,29 |
} |
} |
} |
|
return array($sum_fixed, $sum_unfixed_pending, $sum_unfixed_disclosed); |
} |
|
protected function cbRun($optional_args=array()) { |
$domain = $this->argDomain->getValue(); |
$privateapi = $this->argPrivateAPI->getValue(); |
|
if (empty($domain) && empty($privateapi)) { |
throw new Exception("Please specify a domain or subdomain, a list of domains, or a private API Url."); |
} |
|
if (!empty($domain) && !empty($privateapi)) { |
throw new Exception("You can either use argument '-d' or '-p', but not both."); |
} |
|
if (!empty($privateapi)) { |
// Possibility 1: Private API (showing all bugs for all of your domains, with detailled information) |
// https://www.openbugbounty.org/api/2/.../ |
$sum_fixed = 0; |
$sum_unfixed_pending = 0; |
$sum_unfixed_disclosed = 0; |
list($sum_fixed, $sum_unfixed_pending, $sum_unfixed_disclosed) = $this->num_open_bugs_v2($privateapi); |
if ($this->getVerbosityLevel() == VNag::VERBOSITY_SUMMARY) { |
$this->setHeadline(($sum_unfixed_pending + $sum_unfixed_disclosed)." unfixed ($sum_unfixed_pending pending, $sum_unfixed_disclosed disclosed) issues found at your domains", true); |
} else { |
193,14 → 253,12 |
$domain = trim($domain); |
if ($domain == '') continue; |
if ($domain[0] == '#') continue; |
list($fixed, $unfixed) = $this->num_open_bugs($domain); |
list($fixed, $unfixed) = $this->num_open_bugs_v1($domain); |
$sum_fixed += $fixed; |
$sum_unfixed += $unfixed; |
$count++; |
$this->addVerboseMessage("$fixed fixed and $unfixed unfixed issues found at $domain", $unfixed > 0 ? VNag::VERBOSITY_SUMMARY : VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
} |
if ($sum_unfixed == 0) $this->setStatus(VNag::STATUS_OK); |
if ($sum_unfixed > 0) $this->setStatus(VNag::STATUS_WARNING); // TODO: Critical, when some bugs are disclosed |
if ($this->getVerbosityLevel() == VNag::VERBOSITY_SUMMARY) { |
$this->setHeadline("$sum_unfixed unfixed issues found at $count domains", true); |
} else { |
213,14 → 271,12 |
$sum_unfixed = 0; |
$count = 0; |
foreach ($domains as $domain) { |
list($fixed, $unfixed) = $this->num_open_bugs($domain); |
list($fixed, $unfixed) = $this->num_open_bugs_v1($domain); |
$sum_fixed += $fixed; |
$sum_unfixed += $unfixed; |
$count++; |
$this->addVerboseMessage("$fixed fixed and $unfixed unfixed issues found at $domain", $unfixed > 0 ? VNag::VERBOSITY_SUMMARY : VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
} |
if ($sum_unfixed == 0) $this->setStatus(VNag::STATUS_OK); |
if ($sum_unfixed > 0) $this->setStatus(VNag::STATUS_WARNING); // TODO: Critical, when some bugs are disclosed |
if ($this->getVerbosityLevel() == VNag::VERBOSITY_SUMMARY) { |
$this->setHeadline("$sum_unfixed unfixed issues found at $count domains", true); |
} else { |
228,9 → 284,7 |
} |
} else { |
// Possibility 4: Single domain |
list($fixed, $unfixed) = $this->num_open_bugs($domain); |
if ($unfixed == 0) $this->setStatus(VNag::STATUS_OK); |
if ($unfixed > 0) $this->setStatus(VNag::STATUS_WARNING); // TODO: Critical, when bug is disclosed |
list($fixed, $unfixed) = $this->num_open_bugs_v1($domain); |
if ($this->getVerbosityLevel() == VNag::VERBOSITY_SUMMARY) { |
$this->setHeadline("$unfixed unfixed issues found at $domain", true); |
} else { |