Diff
14 years ago
.htaccess
14 years ago
Diff.php
14 years ago
IPTraf.php
14 years ago
diffResult.php
14 years ago
dropAll.php
14 years ago
email_genericAlert.php
14 years ago
email_newIssues.php
14 years ago
email_unlockRequest.php
14 years ago
menu_activity.php
14 years ago
menu_blockedIPs.php
14 years ago
menu_config.php
14 years ago
menu_options.php
14 years ago
menu_scan.php
14 years ago
sysinfo.php
14 years ago
viewFullActivityLog.php
14 years ago
wf503.php
14 years ago
wfAPI.php
14 years ago
wfAction.php
14 years ago
wfBrowscap.php
14 years ago
wfBrowscapCache.php
14 years ago
wfConfig.php
14 years ago
wfCrawl.php
14 years ago
wfDB.php
14 years ago
wfDict.php
14 years ago
wfIssues.php
14 years ago
wfLockedOut.php
14 years ago
wfLog.php
14 years ago
wfModTracker.php
14 years ago
wfRate.php
14 years ago
wfScanEngine.php
14 years ago
wfSchema.php
14 years ago
wfUnlockMsg.php
14 years ago
wfUtils.php
14 years ago
wfViewResult.php
14 years ago
wordfenceClass.php
14 years ago
wordfenceConstants.php
14 years ago
wordfenceHash.php
14 years ago
wordfenceScanner.php
14 years ago
wordfenceURLHoover.php
14 years ago
wordfenceURLHoover.php
179 lines
| 1 | <?php |
| 2 | require_once('wfAPI.php'); |
| 3 | class wordfenceURLHoover { |
| 4 | private $debug = false; |
| 5 | private $URLsByID = array(); |
| 6 | public $errorMsg = false; |
| 7 | private $hostKeyCache = array(); |
| 8 | private $api = false; |
| 9 | private $table = ''; |
| 10 | private $dRegex = 'aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|ss|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw|xn--lgbbat1ad8j|xn--fiqs8s|xn--fiqz9s|xn--wgbh1c|xn--j6w193g|xn--h2brj9c|xn--mgbbh1a71e|xn--fpcrj9c3d|xn--gecrj9c|xn--s9brj9c|xn--xkc2dl3a5ee0h|xn--45brj9c|xn--mgba3a4f16a|xn--mgbayh7gpa|xn--mgbc0a9azcg|xn--ygbi2ammx|xn--wgbl6a|xn--p1ai|xn--mgberp4a5d4ar|xn--90a3ac|xn--yfro4i67o|xn--clchc0ea0b2g2a9gcd|xn--3e0b707e|xn--fzc2c9e2c|xn--xkc2al3hye2a|xn--mgbtf8fl|xn--kprw13d|xn--kpry57d|xn--o3cw4h|xn--pgbs0dh|xn--mgbaam7a8h|xn--54b7fta0cc|xn--90ae|xn--node|xn--4dbrk0ce|xn--80ao21a|xn--mgb9awbf|xn--mgbai9azgqp6j|xn--j1amh|xn--mgb2ddes|xn--kgbechtv|xn--hgbk6aj7f53bba|xn--0zwm56d|xn--g6w251d|xn--80akhbyknj4f|xn--11b5bs3a9aj6g|xn--jxalpdlp|xn--9t4b11yi5a|xn--deba0ad|xn--zckzah|xn--hlcj6aya9esc7a'; |
| 11 | public function __construct($apiKey, $wordpressVersion){ |
| 12 | $this->api = new wfAPI($apiKey, $wordpressVersion); |
| 13 | $this->db = new wfDB(); |
| 14 | global $wpdb; |
| 15 | $this->table = $wpdb->base_prefix . 'wfHoover'; |
| 16 | $this->db->query("truncate table $this->table"); |
| 17 | } |
| 18 | public function hoover($id, $data){ |
| 19 | if(strpos($data, '.') === false){ |
| 20 | return; |
| 21 | } |
| 22 | if(! preg_match('/[a-zA-Z0-9\-]+\.(?:' . $this->dRegex . ')/i', $data)){ |
| 23 | return; |
| 24 | } |
| 25 | try { |
| 26 | @preg_replace("/(?<=^|[^a-zA-Z0-9\-])((?:[a-zA-Z0-9\-]+\.)+)(" . $this->dRegex . ")((?:$|[^a-zA-Z0-9\-\.\'\"])[^\r\n\s\t\"\'\$\{\}<>]*)/ie", "\$this->" . "addHost(\$id, '$1$2', '$3')", $data); |
| 27 | } catch(Exception $e){ error_log("Regex error 1: $e"); } |
| 28 | preg_replace("/(?<=[^\d]|^)(\d{8,10}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})([^\d\'\"][^\r\n\s\t\"\'\$\{\}<>]*)/e", "\$this->" . "addIP(\$id, \"$1\",\"$2\")", $data); |
| 29 | } |
| 30 | private function dbg($msg){ if($this->debug){ error_log("DEBUG: $msg\n"); } } |
| 31 | public function addHost($id, $host, $path){ |
| 32 | $path = preg_replace_callback('/([^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,;\=]+)/', 'wordfenceURLHoover::urlenc', $path); |
| 33 | $host = strtolower($host); |
| 34 | $this->intAddHost($id, $host, $path); |
| 35 | } |
| 36 | public function addIP($id, $ipdata, $path){ |
| 37 | $path = preg_replace_callback('/([^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,;\=]+)/', 'wordfenceURLHoover::urlenc', $path); |
| 38 | if(strstr($ipdata, '.') === false && $ipdata >= 16777216 && $ipdata <= 4026531840){ |
| 39 | $ipdata = long2ip($ipdata); |
| 40 | } |
| 41 | $parts = explode('.', $ipdata); |
| 42 | $isValid = true; |
| 43 | if($parts[0] >= 240 || $parts[0] == '10' || $parts[0] == '172' || $parts[0] == '192' || $parts[0] == '127'){ |
| 44 | $isValid = false; |
| 45 | } |
| 46 | if($isValid){ |
| 47 | foreach($parts as $part){ |
| 48 | if($part < 1 || $part > 255){ |
| 49 | $isValid = false; |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | if($isValid && $ipdata){ |
| 54 | $this->intAddHost($id, $ipdata, $path); |
| 55 | } |
| 56 | } |
| 57 | public static function urlenc($m){ |
| 58 | return urlencode($m[1]); |
| 59 | } |
| 60 | private function intAddHost($id, $host, $path){ |
| 61 | if(strpos($path, '/') !== 0){ |
| 62 | $path = '/'; |
| 63 | } |
| 64 | $this->db->query("insert into $this->table (owner, host, path, hostKey) values ('%s', '%s', '%s', '%s')", $id, $host, $path, $this->makeHostKey($host)); |
| 65 | return true; |
| 66 | } |
| 67 | private function makeHostKey($host){ |
| 68 | if(isset($this->hostKeyCache[$host])){ |
| 69 | return $this->hostKeyCache[$host]; |
| 70 | } |
| 71 | $hostParts = explode('.', $host); |
| 72 | $hostKey = ''; |
| 73 | if(sizeof($hostParts) == 2){ |
| 74 | $hostKey = substr(hash('sha256', $hostParts[0] . '.' . $hostParts[1] . '/', true), 0, 4); |
| 75 | } else if(sizeof($hostParts) > 2){ |
| 76 | $hostKey = substr(hash('sha256', $hostParts[sizeof($hostParts) - 3] . '.' . $hostParts[sizeof($hostParts) - 2] . '.' . $hostParts[sizeof($hostParts) - 1] . '/', true), 0, 4); |
| 77 | } |
| 78 | $this->hostKeyCache[$host] = $hostKey; |
| 79 | return $hostKey; |
| 80 | } |
| 81 | public function getBaddies(){ |
| 82 | $allHostKeys = array(); |
| 83 | $stime = microtime(true); |
| 84 | $allHostKeys = array(); |
| 85 | $q1 = $this->db->query("select distinct hostKey as hostKey from $this->table"); |
| 86 | while($hRec = mysql_fetch_assoc($q1)){ |
| 87 | array_push($allHostKeys, $hRec['hostKey']); |
| 88 | } |
| 89 | //Now call API and check if any hostkeys are bad. |
| 90 | //This is a shortcut, because if no hostkeys are bad it saves us having to check URLs |
| 91 | if(sizeof($allHostKeys) > 0){ //If we don't have any hostkeys, then we won't have any URL's to check either. |
| 92 | //Hostkeys are 4 byte sha256 prefixes |
| 93 | //Returned value is 2 byte shorts which are array indexes for bad keys that were passed in the original list |
| 94 | $this->dbg("Checking " . sizeof($allHostKeys) . " hostkeys"); |
| 95 | $resp = $this->api->binCall('check_host_keys', implode('', $allHostKeys)); |
| 96 | $this->dbg("Done hostkey check"); |
| 97 | if($this->api->errorMsg){ |
| 98 | $this->errorMsg = $this->api->errorMsg; |
| 99 | return false; |
| 100 | } |
| 101 | |
| 102 | $badHostKeys = array(); |
| 103 | if($resp['code'] == 200){ |
| 104 | if(strlen($resp['data']) > 0){ |
| 105 | $dataLen = strlen($resp['data']); |
| 106 | if($dataLen % 2 != 0){ |
| 107 | $this->errorMsg = "Invalid data length received from Wordfence server: " . $dataLen; |
| 108 | return false; |
| 109 | } |
| 110 | for($i = 0; $i < $dataLen; $i += 2){ |
| 111 | $idxArr = unpack('n', substr($resp['data'], $i, 2)); |
| 112 | $idx = $idxArr[1]; |
| 113 | if(isset($allHostKeys[$idx]) ){ |
| 114 | array_push($badHostKeys, $allHostKeys[$idx]); |
| 115 | } else { |
| 116 | $this->errorMsg = "Bad allHostKeys index: $idx"; |
| 117 | return false; |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | } else { |
| 122 | $this->errorMsg = "Wordfence server responded with an error. HTTP code " . $resp['code'] . " and data: " . $resp['data']; |
| 123 | return false; |
| 124 | } |
| 125 | if(sizeof($badHostKeys) > 0){ |
| 126 | $urlsToCheck = array(); |
| 127 | //need to figure out which id's have bad hostkeys |
| 128 | //need to feed in all URL's from those id's where the hostkey matches a URL |
| 129 | foreach($badHostKeys as $badHostKey){ |
| 130 | $q1 = $this->db->query("select owner, host, path from $this->table where hostKey='%s'", $badHostKey); |
| 131 | while($rec = mysql_fetch_assoc($q1)){ |
| 132 | $url = 'http://' . $rec['host'] . $rec['path']; |
| 133 | if(! isset($urlsToCheck[$rec['owner']])){ |
| 134 | $urlsToCheck[$rec['owner']] = array(); |
| 135 | } |
| 136 | if(! in_array($url, $urlsToCheck[$rec['owner']])){ |
| 137 | $urlsToCheck[$rec['owner']][] = $url; |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | if(sizeof($urlsToCheck) > 0){ |
| 143 | $this->dbg("Checking " . sizeof($urlsToCheck) . " URLs"); |
| 144 | $badURLs = $this->api->call('check_bad_urls', array(), array( 'toCheck' => json_encode($urlsToCheck)) ); |
| 145 | $this->dbg("Done URL check"); |
| 146 | if($this->api->errorMsg){ |
| 147 | $this->errorMsg = $this->api->errorMsg; |
| 148 | return false; |
| 149 | } |
| 150 | if(is_array($badURLs) && sizeof($badURLs) > 0){ |
| 151 | $finalResults = array(); |
| 152 | foreach($badURLs as $file => $badSiteList){ |
| 153 | if(! isset($finalResults[$file])){ |
| 154 | $finalResults[$file] = array(); |
| 155 | } |
| 156 | foreach($badSiteList as $badSite){ |
| 157 | array_push($finalResults[$file], array( |
| 158 | 'URL' => $badSite[0], |
| 159 | 'badList' => $badSite[1] |
| 160 | )); |
| 161 | } |
| 162 | } |
| 163 | return $finalResults; |
| 164 | } else { |
| 165 | return array(); |
| 166 | } |
| 167 | } else { |
| 168 | return array(); |
| 169 | } |
| 170 | } else { |
| 171 | return array(); |
| 172 | } |
| 173 | } else { |
| 174 | return array(); |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | ?> |
| 179 |