Subversion Repositories vnag

Rev

Rev 42 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 42 Rev 59
1
<?php /* <ViaThinkSoftSignature>
1
<?php /* <ViaThinkSoftSignature>
2
tnq+qJ0FVMFjtw0VxxXU3yGcuwQtR+YxngRuF612pYRja0m6907iUi6E2uuTAiK6d
2
d5Ch9xyUxv3Bu3N2jbIjfBn2mP062FT5Kdj1z31EUW9w+rJMXfvaeidWQfLapqU7c
3
lCx969+n5MBG0N9yM/vPLKowBodxgEAaE5PlS5cfU2WKqbPbrAI6yWjfMruy5OzOi
3
uIAztDKoRCMsAsvZYSB1zD8+pi0ClJYGbiB+/7ACt1TSVOvtrWxE9lsWXIOjLA0Ft
4
KV2wIIWY+QR9HuNDKvO5TQjFMaLvXdOqNZp+bCP/YDiLJ4oq8s470/z4MZu/jz1ou
4
YeccOh4Mf/JFtLbLyo/xQofsIy+9umKQ1fbhgrcmJfaWY07QeoZVE7HHauTZA+ld6
5
2pLzyjyDdaMAjrphpGrG9BY0eS1j9EQo88Kv9sFJrmOR+QNRawiMSL1Vuy5XxbriO
5
HyjNklTAc9b3tcFQBp9bgB3p4Pt28y6irIqDhaqvBja8F2oCK7FCZQFwE/JF0UKT/
6
VH65ZkZ6hs7NPsojgKM50OQUUmRiMi99S2CCqQHPh2O0VaZMB9hQ4NiWN5wyjExMN
6
PMOJ0VtzC1p72SiOWMg4U0+hMi4Sre48SuSOiUtLaF14GdzfATGOxOqyFvFAFXClh
7
v5vVpWLFDwG20YKNWdfPd/hADcJ+W3E17RuDbRqphzEJlHcgKgLMULmCCT0H7XWb3
7
qUqgxXmQTFJCZzGW2rga9BJw35zTYy/jtWLN8nGFG+S2c7e+IJAqN+iDMD7I+NyRd
8
NP3iKqVJOGnt7SVDXPKsNbjP2oA6/gAOpBZptV/i95f0kplJ69T7AxVmoNg9dWJnA
8
jjZKqDjXDZrIolL6KP2yl4WPtVD8iaJcgrxUQD+TQiJkcjvSEp2DVN0OETDFUzlx2
9
JMOmpteZCmdZQV7vKbPvCLVOTMh9/Q9OFe877kjRaEAQJaPtrdus4Q8uhvghRFiiL
9
Jr9hc14n7z78ebkTgNToAGauBvfyFRCEyRBcXyS9VluTd23g3ICXY0qdWJUhf4zpz
10
yuJbsZgIAnZvliEe9jDBPCFxTC4tMDqoG5rXRltz4J+Ig52L9AWq0bSf9+AywMjdT
10
PJPdgAVmO1X8kPaVB97GI2iQDqIMFLr6PEre6GTaB893B3lrej8sTdAiV8WPlzKmZ
11
c1jS22mBcqC0rx2cmKZl/AWutrBisVeQweAaipRncW85wyZMWgSB3lowbMKZHNqZV
11
LHxxUr2uQdIT2NkLbvvzNSoJKsWXKdmbvWk3Oy+VYGH9LEjw+bRTweubH36gYf4to
12
YCZt7QSxUGPZAIKy51i6QivhJaaQhvnCZW3lkQGZLqruuXU7QJzw6BzW+aMz+kWqM
12
QpoiUcnQ4B1f9GxDUp455aPtN9HmY7dOb4YehyWCFKge/1PUoT3/omz4cRlz5+8QM
13
wMHANFDgw/VusaSWW4a+oaYCyygKRiRkb2YQE8U2EObxkaDDEhquWLHhqEJ8F8kly
13
aYOB1/UgdeCUS674R3tzhr28LhNfJ8J4pyXzOVjVsmBkmMd+he/4MJcXWyDYDWpVl
14
2aZghC94ryvIkMmjUCOhxJ9a429MyDrochi4RLI9OkYF4WmF4AkqFnqYJWf73kRUV
14
AMA700hkscLcwktA25TDd/Qh5vjF4i6dWcNlIbFxdaKyN9PTs/0T+Jza0JaDmZagW
15
mLpohXJGLaRp5e0Q7dxJto9hy/I/6yntTREvnDkm19cY8lHceJPRv3YbuSVybMha4
15
gYD5R4+ei44asrZ37oAg9CjOeDm7FKRuMYiMaw/08LAYGQKFxgIAsMdcKOHya4By/
16
9nf3KgaF4hmAwogIqTcSb5f18uqMC+Pp4sZaChQnpbC+K7StY7lI3dWL/MINHUGRX
16
5yVVEVLihCLKdvdn0u9d1d2BQHZS0n2KNG4cMQxnNKVjjTXDybRbyB2C0pp2S9YXN
17
yM702pX2l/WSbflcWcvHaPoOkfkvJwP+R5BZ/GIB5F5Yv5Q4K4BDNs23u2stvbzuK
17
V9WWzveDY5m8jYrZ9wFjvbHeJHfFNXMrkN1k4U7mYM5Be2Mu2+MYA/Xw2oLtzmmyt
18
6NyheDgjSRF+PckMy8AmIHtGMn4wBTbw+mH+nmBnN6HmQgqM6zHpU1CwVw1Q/c2IP
18
9WxiCO0B4TrEKOJYV1jC7BDWoAAHNnDxFoOJo+dm/hjTU3XOaWSpsxTURYFR/Ltn5
19
xihKexQelORhik6WyUWXR8GPT4PAFUOkIKV3ayKibd2zLDAd3YM3J4uDbEwp3vg/b
19
G1yakcUq18mS5c2BEXpwXaJq5+f3QP5COzEcrvgGqBJRfpy0JxsRtKAzTQpADzRtR
20
neIWy36vzf6xGnPFig0qobZGIisfVMMpvnZkXA9c67K6LFNEx1eOlW6Cx068NZqZW
20
8jI68XrP4y9FrcUazM4RPp+U8dRY2zjMas559t7Xb7RysHRpFxf2SZ+Xj0SVQZEsj
21
l1s/Q8qJ8UjnPurbrQ4k1v62ZHMy3s9LbiNRyMEt5kdjCMFNuc1jWGpLwp2rw5WKC
21
YOATRaQdV+a6haeDvB346iJIjVaNY6SaaMPI5JEhAr79BM6nJCXIu7HT9DCBWvhbG
22
O5yx+62O5GPX+qZpkIjxZwe/3woj5dGiFFdsCo4afv4KitzI3czXMCDgiL4oTanQQ
22
MCePzFjOa4XRB1vaCJo5jolQUWyy0pFLKD5VbimI63wd1a5KqRPmtSFAu+/nQ3aKC
23
g==
23
Q==
24
</ViaThinkSoftSignature> */ ?>
24
</ViaThinkSoftSignature> */ ?>
25
<?php
25
<?php
26
 
26
 
27
/*
27
/*
28
 * VNag - Nagios Framework for PHP
28
 * VNag - Nagios Framework for PHP
29
 * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com>
29
 * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com>
30
 * Licensed under the terms of the Apache 2.0 license
30
 * Licensed under the terms of the Apache 2.0 license
31
 *
31
 *
32
 * Revision 2021-12-23
32
 * Revision 2021-12-23
33
 */
33
 */
34
 
34
 
35
declare(ticks=1);
35
declare(ticks=1);
36
 
36
 
37
class OpenBugBountyCheck extends VNag {
37
class OpenBugBountyCheck extends VNag {
38
        protected $argDomain = null;
38
        protected $argDomain = null;
39
        protected $argPrivateAPI = null;
39
        protected $argPrivateAPI = null;
40
        protected $argIgnoredIds = null;
40
        protected $argIgnoredIds = null;
41
 
41
 
42
        public function __construct() {
42
        public function __construct() {
43
                parent::__construct();
43
                parent::__construct();
44
 
44
 
45
                $this->registerExpectedStandardArguments('Vvht');
45
                $this->registerExpectedStandardArguments('Vvht');
46
 
46
 
47
                $this->getHelpManager()->setPluginName('check_openbugbounty');
47
                $this->getHelpManager()->setPluginName('check_openbugbounty');
48
                $this->getHelpManager()->setVersion('1.1');
48
                $this->getHelpManager()->setVersion('1.1');
49
                $this->getHelpManager()->setShortDescription('This plugin checks if a domain has unfixed vulnerabilities listed at OpenBugBounty.org.');
49
                $this->getHelpManager()->setShortDescription('This plugin checks if a domain has unfixed vulnerabilities listed at OpenBugBounty.org.');
50
                $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.');
50
                $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.');
51
                $this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-d <SingleDomain[,SingleDomain,[...]]> | -d <DomainListFile> | -p <PrivateApiUrl> | -i <IgnoredId,IgnoredId,...> ]');
51
                $this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-d <SingleDomain[,SingleDomain,[...]]> | -d <DomainListFile> | -p <PrivateApiUrl> | -i <IgnoredId,IgnoredId,...> ]');
52
                $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com');
52
                $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com');
53
 
53
 
54
                // Individual (non-standard) arguments:
54
                // Individual (non-standard) arguments:
55
                $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.'));
55
                $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.'));
56
                $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\'.'));
56
                $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\'.'));
57
                $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...)'));
57
                $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...)'));
58
        }
58
        }
59
 
59
 
60
        protected function get_cache_dir() {
-
 
61
                $homedir = @getenv('HOME');
-
 
62
                if ($homedir) {
-
 
63
                        $try = "${homedir}/.vnag_obb_cache";
-
 
64
                        if (is_dir($try)) return $try;
-
 
65
                        if (@mkdir($try)) return $try;
-
 
66
                }
-
 
67
 
-
 
68
                $user = posix_getpwuid(posix_geteuid());
-
 
69
                if (isset($user['dir'])) {
-
 
70
                        $homedir = $user['dir'];
-
 
71
                        $try = "${homedir}/.vnag_obb_cache";
-
 
72
                        if (is_dir($try)) return $try;
-
 
73
                        if (@mkdir($try)) return $try;
-
 
74
                }
-
 
75
 
-
 
76
                if (isset($user['name'])) {
-
 
77
                        $username = $user['name'];
-
 
78
                        $try = "/tmp/vnag_obb_cache";
-
 
79
                        if (is_dir($try)) return $try;
-
 
80
                        if (@mkdir($try)) return $try;
-
 
81
                }
-
 
82
 
-
 
83
                return false; // should usually never happen
-
 
84
        }
-
 
85
 
-
 
86
        function is_ignored($id) {
60
        function is_ignored($id) {
87
                $ids = $this->argIgnoredIds->getValue();
61
                $ids = $this->argIgnoredIds->getValue();
88
                if (empty($ids)) return false;
62
                if (empty($ids)) return false;
89
 
63
 
90
                $ids = explode(',', $ids);
64
                $ids = explode(',', $ids);
91
                foreach ($ids as $test) {
65
                foreach ($ids as $test) {
92
                        if ($id == $test) return true;
66
                        if ($id == $test) return true;
93
                }
67
                }
94
                return false;
68
                return false;
95
        }
69
        }
96
 
70
 
97
        static function extract_id_from_url($url) {
71
        static function extract_id_from_url($url) {
98
                // https://www.openbugbounty.org/reports/1019234/
72
                // https://www.openbugbounty.org/reports/1019234/
99
                $parts = explode('/', $url);
73
                $parts = explode('/', $url);
100
                foreach ($parts as $part) {
74
                foreach ($parts as $part) {
101
                        if (is_numeric($part)) return $part;
75
                        if (is_numeric($part)) return $part;
102
                }
76
                }
103
                return -1;
77
                return -1;
104
        }
78
        }
105
 
79
 
106
        function num_open_bugs_v1($domain, $max_cache_time = 3600) { // TODO: make cache time configurable via config
80
        function num_open_bugs_v1($domain, $max_cache_time = 3600) { // TODO: make cache time configurable via config
107
                //assert(!empty($this->argDomain->getValue()));
81
                //assert(!empty($this->argDomain->getValue()));
108
                //assert(empty($this->argPrivateAPI->getValue()));
82
                //assert(empty($this->argPrivateAPI->getValue()));
109
 
83
 
110
                $fixed = 0;
84
                $fixed = 0;
111
                $unfixed = 0;
85
                $unfixed = 0;
112
                $unfixed_ignored = 0;
86
                $unfixed_ignored = 0;
113
 
87
 
114
                $this->setStatus(VNag::STATUS_OK);
88
                $this->setStatus(VNag::STATUS_OK);
115
 
89
 
116
                $domain = strtolower($domain);
90
                $domain = strtolower($domain);
-
 
91
                $url = 'https://www.openbugbounty.org/api/1/search/?domain='.urlencode($domain);
117
                $cache_file = $this->get_cache_dir() . '/' . md5($domain);
92
                $cache_file = $this->get_cache_dir() . '/' . sha1($url);
118
 
93
 
119
                if (file_exists($cache_file) && (time()-filemtime($cache_file) < $max_cache_time)) {
94
                if (file_exists($cache_file) && (time()-filemtime($cache_file) < $max_cache_time)) {
120
                        $cont = @file_get_contents($cache_file);
95
                        $cont = @file_get_contents($cache_file);
121
                        if (!$cont) throw new Exception("Failed to get contents from $cache_file");
96
                        if (!$cont) throw new Exception("Failed to get contents from $cache_file");
122
                } else {
97
                } else {
123
                        $url = 'https://www.openbugbounty.org/api/1/search/?domain='.urlencode($domain);
-
 
124
                        $cont = @file_get_contents($url);
98
                        $cont = @file_get_contents($url);
125
                        if (!$cont) throw new Exception("Failed to get contents from $url");
99
                        if (!$cont) throw new Exception("Failed to get contents from $url");
126
                        file_put_contents($cache_file, $cont);
100
                        file_put_contents($cache_file, $cont);
127
                }
101
                }
128
 
102
 
129
                $xml = simplexml_load_string($cont);
103
                $xml = simplexml_load_string($cont);
130
                foreach ($xml as $x) {
104
                foreach ($xml as $x) {
131
                        $submission = $x->url;
105
                        $submission = $x->url;
132
 
106
 
133
                        if ($x->fixed == '1') {
107
                        if ($x->fixed == '1') {
134
                                $fixed++;
108
                                $fixed++;
135
                                $this->addVerboseMessage("Fixed issue found at $domain: $submission", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
109
                                $this->addVerboseMessage("Fixed issue found at $domain: $submission", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
136
                                $this->setStatus(VNag::STATUS_OK);
110
                                $this->setStatus(VNag::STATUS_OK);
137
                        } else if ($this->is_ignored($this->extract_id_from_url($submission))) {
111
                        } else if ($this->is_ignored($this->extract_id_from_url($submission))) {
138
                                $unfixed_ignored++;
112
                                $unfixed_ignored++;
139
                                $this->addVerboseMessage("Ignored issue found at $domain: $submission", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
113
                                $this->addVerboseMessage("Ignored issue found at $domain: $submission", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
140
                                $this->setStatus(VNag::STATUS_OK);
114
                                $this->setStatus(VNag::STATUS_OK);
141
                        } else {
115
                        } else {
142
                                $unfixed++;
116
                                $unfixed++;
143
                                $this->addVerboseMessage("Unfixed issue found at $domain: $submission", VNag::VERBOSITY_SUMMARY);
117
                                $this->addVerboseMessage("Unfixed issue found at $domain: $submission", VNag::VERBOSITY_SUMMARY);
144
                                $this->setStatus(VNag::STATUS_WARNING);
118
                                $this->setStatus(VNag::STATUS_WARNING);
145
                                // TODO: Unlike the "private" API, the "normal" API does not show if a bug is disclosed (= critical instead of warning)
119
                                // TODO: Unlike the "private" API, the "normal" API does not show if a bug is disclosed (= critical instead of warning)
146
                                //       But we could check if the report is older than XXX months, and then we know that it must be disclosed.
120
                                //       But we could check if the report is older than XXX months, and then we know that it must be disclosed.
147
                        }
121
                        }
148
 
122
 
149
                }
123
                }
150
 
124
 
151
                return array($fixed, $unfixed, $unfixed_ignored);
125
                return array($fixed, $unfixed, $unfixed_ignored);
152
        }
126
        }
153
 
127
 
154
        function get_privateapi_data($url, $max_cache_time = 3600) { // TODO: make cache time configurable via config
128
        function get_privateapi_data($url, $max_cache_time = 3600) { // TODO: make cache time configurable via config
155
                $url = strtolower($url);
129
                $url = strtolower($url);
156
                $cache_file = $this->get_cache_dir() . '/' . md5($url);
130
                $cache_file = $this->get_cache_dir() . '/' . sha1($url);
157
 
131
 
158
                if (file_exists($cache_file) && (time()-filemtime($cache_file) < $max_cache_time)) {
132
                if (file_exists($cache_file) && (time()-filemtime($cache_file) < $max_cache_time)) {
159
                        $cont = @file_get_contents($cache_file);
133
                        $cont = @file_get_contents($cache_file);
160
                        if (!$cont) throw new Exception("Failed to get contents from $url");
134
                        if (!$cont) throw new Exception("Failed to get contents from $url");
161
                } else {
135
                } else {
162
                        $cont = @file_get_contents($url);
136
                        $cont = @file_get_contents($url);
163
                        if (!$cont) throw new Exception("Failed to get contents from $url");
137
                        if (!$cont) throw new Exception("Failed to get contents from $url");
164
                        file_put_contents($cache_file, $cont);
138
                        file_put_contents($cache_file, $cont);
165
                }
139
                }
166
 
140
 
167
                $ary = @json_decode($cont,true);
141
                $ary = @json_decode($cont,true);
168
                if (!$ary) throw new Exception("This is probably not a correct Private API URL, or the service is down (JSON Decode failed)");
142
                if (!$ary) throw new Exception("This is probably not a correct Private API URL, or the service is down (JSON Decode failed)");
169
                return $ary;
143
                return $ary;
170
        }
144
        }
171
 
145
 
172
        function num_open_bugs_v2($privateapi, $max_cache_time = 3600) { // TODO: make cache time configurable via config
146
        function num_open_bugs_v2($privateapi, $max_cache_time = 3600) { // TODO: make cache time configurable via config
173
                //assert(empty($this->argDomain->getValue()));
147
                //assert(empty($this->argDomain->getValue()));
174
                //assert(!empty($this->argPrivateAPI->getValue()));
148
                //assert(!empty($this->argPrivateAPI->getValue()));
175
 
149
 
176
                $sum_fixed = 0;
150
                $sum_fixed = 0;
177
                $sum_unfixed_pending = 0;
151
                $sum_unfixed_pending = 0;
178
                $sum_unfixed_disclosed = 0;
152
                $sum_unfixed_disclosed = 0;
179
                $sum_unfixed_ignored = 0;
153
                $sum_unfixed_ignored = 0;
180
 
154
 
181
                $this->setStatus(VNag::STATUS_OK);
155
                $this->setStatus(VNag::STATUS_OK);
182
 
156
 
183
                $ary = $this->get_privateapi_data($privateapi, $max_cache_time);
157
                $ary = $this->get_privateapi_data($privateapi, $max_cache_time);
184
                foreach ($ary as $id => $data) {
158
                foreach ($ary as $id => $data) {
185
                        /*
159
                        /*
186
                        [Vulnerability Reported] => 21 September, 2017 05:13
160
                        [Vulnerability Reported] => 21 September, 2017 05:13
187
                        [Vulnerability Verified] => 21 September, 2017 05:14
161
                        [Vulnerability Verified] => 21 September, 2017 05:14
188
                        [Scheduled Public Disclosure] => 21 October, 2017 05:13
162
                        [Scheduled Public Disclosure] => 21 October, 2017 05:13
189
                        [Path Status] => Patched
163
                        [Path Status] => Patched
190
                        [Vulnerability Fixed] => 7 August, 2018 21:47
164
                        [Vulnerability Fixed] => 7 August, 2018 21:47
191
                        [Report Url] => https://openbugbounty.org/reports/.../
165
                        [Report Url] => https://openbugbounty.org/reports/.../
192
                        [Host] => ...
166
                        [Host] => ...
193
                        [Researcher] => https://openbugbounty.org/researchers/.../
167
                        [Researcher] => https://openbugbounty.org/researchers/.../
194
                        */
168
                        */
195
 
169
 
196
                        if (empty($data['Vulnerability Reported'])) throw new Exception("This is probably not a correct Private API URL, or the service is down (Missing fields in structure)");
170
                        if (empty($data['Vulnerability Reported'])) throw new Exception("This is probably not a correct Private API URL, or the service is down (Missing fields in structure)");
197
 
171
 
198
                        $status = isset($data['Patch Status']) ? $data['Patch Status'] : $data['Path Status']; // sic! There is a typo in their API (reported, but not fixed)
172
                        $status = isset($data['Patch Status']) ? $data['Patch Status'] : $data['Path Status']; // sic! There is a typo in their API (reported, but not fixed)
199
 
173
 
200
                        $submission = $data['Report Url'];
174
                        $submission = $data['Report Url'];
201
                        $domain = $data['Host'];
175
                        $domain = $data['Host'];
202
 
176
 
203
                        if ($status == 'Patched') {
177
                        if ($status == 'Patched') {
204
                                $sum_fixed++;
178
                                $sum_fixed++;
205
                                $fixed_date = $data['Vulnerability Fixed'];
179
                                $fixed_date = $data['Vulnerability Fixed'];
206
                                $this->addVerboseMessage("Fixed issue found at $domain: $submission (fixed: $fixed_date)", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
180
                                $this->addVerboseMessage("Fixed issue found at $domain: $submission (fixed: $fixed_date)", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
207
                                $this->setStatus(VNag::STATUS_OK);
181
                                $this->setStatus(VNag::STATUS_OK);
208
                        } else if ($this->is_ignored($this->extract_id_from_url($submission))) {
182
                        } else if ($this->is_ignored($this->extract_id_from_url($submission))) {
209
                                $sum_unfixed_ignored++;
183
                                $sum_unfixed_ignored++;
210
                                $this->addVerboseMessage("Ignored issue found at $domain: $submission", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
184
                                $this->addVerboseMessage("Ignored issue found at $domain: $submission", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
211
                                $this->setStatus(VNag::STATUS_OK);
185
                                $this->setStatus(VNag::STATUS_OK);
212
                        } else {
186
                        } else {
213
                                $disclosure = $data['Scheduled Public Disclosure'];
187
                                $disclosure = $data['Scheduled Public Disclosure'];
214
                                $time = strtotime(str_replace(',', '', $disclosure));
188
                                $time = strtotime(str_replace(',', '', $disclosure));
215
                                if (time() > $time) {
189
                                if (time() > $time) {
216
                                        $sum_unfixed_disclosed++;
190
                                        $sum_unfixed_disclosed++;
217
                                        $this->addVerboseMessage("Disclosed unfixed issue found at $domain: $submission (disclosure: $disclosure)", VNag::VERBOSITY_SUMMARY);
191
                                        $this->addVerboseMessage("Disclosed unfixed issue found at $domain: $submission (disclosure: $disclosure)", VNag::VERBOSITY_SUMMARY);
218
                                        $this->setStatus(VNag::STATUS_CRITICAL);
192
                                        $this->setStatus(VNag::STATUS_CRITICAL);
219
                                } else {
193
                                } else {
220
                                        $sum_unfixed_pending++;
194
                                        $sum_unfixed_pending++;
221
                                        $this->addVerboseMessage("Undisclosed unfixed issue found at $domain: $submission (disclosure: $disclosure)", VNag::VERBOSITY_SUMMARY);
195
                                        $this->addVerboseMessage("Undisclosed unfixed issue found at $domain: $submission (disclosure: $disclosure)", VNag::VERBOSITY_SUMMARY);
222
                                        $this->setStatus(VNag::STATUS_WARNING);
196
                                        $this->setStatus(VNag::STATUS_WARNING);
223
                                }
197
                                }
224
                        }
198
                        }
225
                }
199
                }
226
 
200
 
227
                return array($sum_fixed, $sum_unfixed_pending, $sum_unfixed_disclosed, $sum_unfixed_ignored);
201
                return array($sum_fixed, $sum_unfixed_pending, $sum_unfixed_disclosed, $sum_unfixed_ignored);
228
        }
202
        }
229
 
203
 
230
        protected function cbRun($optional_args=array()) {
204
        protected function cbRun($optional_args=array()) {
231
                $domain = $this->argDomain->getValue();
205
                $domain = $this->argDomain->getValue();
232
                $privateapi = $this->argPrivateAPI->getValue();
206
                $privateapi = $this->argPrivateAPI->getValue();
233
 
207
 
234
                if (empty($domain) && empty($privateapi)) {
208
                if (empty($domain) && empty($privateapi)) {
235
                        throw new Exception("Please specify a domain or subdomain, a list of domains, or a private API Url.");
209
                        throw new Exception("Please specify a domain or subdomain, a list of domains, or a private API Url.");
236
                }
210
                }
237
 
211
 
238
                if (!empty($domain) && !empty($privateapi)) {
212
                if (!empty($domain) && !empty($privateapi)) {
239
                        throw new Exception("You can either use argument '-d' or '-p', but not both.");
213
                        throw new Exception("You can either use argument '-d' or '-p', but not both.");
240
                }
214
                }
241
 
215
 
242
                if (!empty($privateapi)) {
216
                if (!empty($privateapi)) {
243
                        // Possibility 1: Private API (showing all bugs for all of your domains, with detailled information)
217
                        // Possibility 1: Private API (showing all bugs for all of your domains, with detailled information)
244
                        //                https://www.openbugbounty.org/api/2/.../
218
                        //                https://www.openbugbounty.org/api/2/.../
245
                        $sum_fixed = 0;
219
                        $sum_fixed = 0;
246
                        $sum_unfixed_pending = 0;
220
                        $sum_unfixed_pending = 0;
247
                        $sum_unfixed_disclosed = 0;
221
                        $sum_unfixed_disclosed = 0;
248
                        $sum_unfixed_ignored = 0;
222
                        $sum_unfixed_ignored = 0;
249
                        list($sum_fixed, $sum_unfixed_pending, $sum_unfixed_disclosed, $sum_unfixed_ignored) = $this->num_open_bugs_v2($privateapi);
223
                        list($sum_fixed, $sum_unfixed_pending, $sum_unfixed_disclosed, $sum_unfixed_ignored) = $this->num_open_bugs_v2($privateapi);
250
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed_pending + $sum_unfixed_disclosed + $sum_unfixed_ignored)." unfixed ($sum_unfixed_pending pending, $sum_unfixed_disclosed disclosed, $sum_unfixed_ignored ignored) issues found at your domain(s)", true);
224
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed_pending + $sum_unfixed_disclosed + $sum_unfixed_ignored)." unfixed ($sum_unfixed_pending pending, $sum_unfixed_disclosed disclosed, $sum_unfixed_ignored ignored) issues found at your domain(s)", true);
251
                } else if (file_exists($domain)) {
225
                } else if (file_exists($domain)) {
252
                        // Possibility 2: File containing a list of domains
226
                        // Possibility 2: File containing a list of domains
253
                        $domains = file($domain);
227
                        $domains = file($domain);
254
                        $sum_fixed = 0;
228
                        $sum_fixed = 0;
255
                        $sum_unfixed = 0;
229
                        $sum_unfixed = 0;
256
                        $sum_unfixed_ignored = 0;
230
                        $sum_unfixed_ignored = 0;
257
                        $count = 0;
231
                        $count = 0;
258
                        foreach ($domains as $domain) {
232
                        foreach ($domains as $domain) {
259
                                $domain = trim($domain);
233
                                $domain = trim($domain);
260
                                if ($domain == '') continue;
234
                                if ($domain == '') continue;
261
                                if ($domain[0] == '#') continue;
235
                                if ($domain[0] == '#') continue;
262
                                list($fixed, $unfixed, $unfixed_ignored) = $this->num_open_bugs_v1($domain);
236
                                list($fixed, $unfixed, $unfixed_ignored) = $this->num_open_bugs_v1($domain);
263
                                $sum_fixed += $fixed;
237
                                $sum_fixed += $fixed;
264
                                $sum_unfixed += $unfixed;
238
                                $sum_unfixed += $unfixed;
265
                                $sum_unfixed_ignored += $unfixed_ignored;
239
                                $sum_unfixed_ignored += $unfixed_ignored;
266
                                $count++;
240
                                $count++;
267
                                $this->addVerboseMessage("$fixed fixed, $unfixed_ignored ignored, and $unfixed unfixed issues found at $domain", $unfixed > 0 ? VNag::VERBOSITY_SUMMARY : VNag::VERBOSITY_ADDITIONAL_INFORMATION);
241
                                $this->addVerboseMessage("$fixed fixed, $unfixed_ignored ignored, and $unfixed unfixed issues found at $domain", $unfixed > 0 ? VNag::VERBOSITY_SUMMARY : VNag::VERBOSITY_ADDITIONAL_INFORMATION);
268
                        }
242
                        }
269
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed + $sum_unfixed_ignored)." unfixed (including $sum_unfixed_ignored ignored) issues found at $count domains", true);
243
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed + $sum_unfixed_ignored)." unfixed (including $sum_unfixed_ignored ignored) issues found at $count domains", true);
270
                } else if (strpos($domain, ',') !== false) {
244
                } else if (strpos($domain, ',') !== false) {
271
                        // Possibility 3: Domains separated with comma
245
                        // Possibility 3: Domains separated with comma
272
                        $domains = explode(',', $domain);
246
                        $domains = explode(',', $domain);
273
                        $sum_fixed = 0;
247
                        $sum_fixed = 0;
274
                        $sum_unfixed = 0;
248
                        $sum_unfixed = 0;
275
                        $sum_unfixed_ignored = 0;
249
                        $sum_unfixed_ignored = 0;
276
                        $count = 0;
250
                        $count = 0;
277
                        foreach ($domains as $domain) {
251
                        foreach ($domains as $domain) {
278
                                list($fixed, $unfixed, $unfixed_ignored) = $this->num_open_bugs_v1($domain);
252
                                list($fixed, $unfixed, $unfixed_ignored) = $this->num_open_bugs_v1($domain);
279
                                $sum_fixed += $fixed;
253
                                $sum_fixed += $fixed;
280
                                $sum_unfixed += $unfixed;
254
                                $sum_unfixed += $unfixed;
281
                                $sum_unfixed_ignored += $unfixed_ignored;
255
                                $sum_unfixed_ignored += $unfixed_ignored;
282
                                $count++;
256
                                $count++;
283
                                $this->addVerboseMessage("$fixed fixed, $unfixed_ignored ignored,  and $unfixed unfixed issues found at $domain", $unfixed > 0 ? VNag::VERBOSITY_SUMMARY : VNag::VERBOSITY_ADDITIONAL_INFORMATION);
257
                                $this->addVerboseMessage("$fixed fixed, $unfixed_ignored ignored,  and $unfixed unfixed issues found at $domain", $unfixed > 0 ? VNag::VERBOSITY_SUMMARY : VNag::VERBOSITY_ADDITIONAL_INFORMATION);
284
                        }
258
                        }
285
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed + $sum_unfixed_ignored)." unfixed (including $sum_unfixed_ignored ignored) issues found at $count domains", true);
259
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed + $sum_unfixed_ignored)." unfixed (including $sum_unfixed_ignored ignored) issues found at $count domains", true);
286
                } else {
260
                } else {
287
                        // Possibility 4: Single domain
261
                        // Possibility 4: Single domain
288
                        list($sum_fixed, $sum_unfixed, $sum_unfixed_ignored) = $this->num_open_bugs_v1($domain);
262
                        list($sum_fixed, $sum_unfixed, $sum_unfixed_ignored) = $this->num_open_bugs_v1($domain);
289
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed + $sum_unfixed_ignored)." unfixed (including $sum_unfixed_ignored ignored) issues found at $domain", true);
263
                        $this->setHeadline("$sum_fixed fixed and ".($sum_unfixed + $sum_unfixed_ignored)." unfixed (including $sum_unfixed_ignored ignored) issues found at $domain", true);
290
                }
264
                }
291
        }
265
        }
292
}
266
}
293
 
267
 
294
 
268