1: | <?php
|
2: |
|
3: | |
4: | |
5: |
|
6: | class Protector
|
7: | {
|
8: | public $mydirname;
|
9: |
|
10: | public $_conn;
|
11: | public $_conf = array();
|
12: | public $_conf_serialized = '';
|
13: |
|
14: | public $_bad_globals = array();
|
15: |
|
16: | public $message = '';
|
17: | public $warning = false;
|
18: | public $error = false;
|
19: | public $_doubtful_requests = array();
|
20: | public $_bigumbrella_doubtfuls = array();
|
21: |
|
22: | public $_dblayertrap_doubtfuls = array();
|
23: | public $_dblayertrap_doubtful_needles = array(
|
24: | 'information_schema',
|
25: | 'select',
|
26: | "'",
|
27: | '"');
|
28: |
|
29: | public $_logged = false;
|
30: |
|
31: | public $_done_badext = false;
|
32: | public $_done_intval = false;
|
33: | public $_done_dotdot = false;
|
34: | public $_done_nullbyte = false;
|
35: | public $_done_contami = false;
|
36: | public $_done_isocom = false;
|
37: | public $_done_union = false;
|
38: | public $_done_dos = false;
|
39: |
|
40: | public $_safe_badext = true;
|
41: | public $_safe_contami = true;
|
42: | public $_safe_isocom = true;
|
43: | public $_safe_union = true;
|
44: |
|
45: | public $_spamcount_uri = 0;
|
46: |
|
47: | public $_should_be_banned_time0 = false;
|
48: | public $_should_be_banned = false;
|
49: |
|
50: | public $_dos_stage;
|
51: |
|
52: | public $ip_matched_info;
|
53: |
|
54: | public $last_error_type = 'UNKNOWN';
|
55: |
|
56: | |
57: | |
58: |
|
59: | protected function __construct()
|
60: | {
|
61: | $this->mydirname = 'protector';
|
62: |
|
63: |
|
64: | $this->_conf_serialized = @file_get_contents($this->get_filepath4confighcache());
|
65: | $this->_conf = @unserialize($this->_conf_serialized, array('allowed_classes' => false));
|
66: | if (empty($this->_conf)) {
|
67: | $this->_conf = array();
|
68: | }
|
69: |
|
70: | if (!empty($this->_conf['global_disabled'])) {
|
71: | return;
|
72: | }
|
73: |
|
74: |
|
75: |
|
76: |
|
77: |
|
78: |
|
79: |
|
80: |
|
81: |
|
82: |
|
83: |
|
84: |
|
85: | $this->_bad_globals = array(
|
86: | 'GLOBALS',
|
87: | '_SESSION',
|
88: | 'HTTP_SESSION_VARS',
|
89: | '_GET',
|
90: | 'HTTP_GET_VARS',
|
91: | '_POST',
|
92: | 'HTTP_POST_VARS',
|
93: | '_COOKIE',
|
94: | 'HTTP_COOKIE_VARS',
|
95: | '_SERVER',
|
96: | 'HTTP_SERVER_VARS',
|
97: | '_REQUEST',
|
98: | '_ENV',
|
99: | '_FILES',
|
100: | 'xoopsDB',
|
101: | 'xoopsUser',
|
102: | 'xoopsUserId',
|
103: | 'xoopsUserGroups',
|
104: | 'xoopsUserIsAdmin',
|
105: | 'xoopsConfig',
|
106: | 'xoopsOption',
|
107: | 'xoopsModule',
|
108: | 'xoopsModuleConfig');
|
109: |
|
110: | $this->_initial_recursive($_GET, 'G');
|
111: | $this->_initial_recursive($_POST, 'P');
|
112: | $this->_initial_recursive($_COOKIE, 'C');
|
113: | }
|
114: |
|
115: | |
116: | |
117: | |
118: |
|
119: | protected function _initial_recursive($val, $key)
|
120: | {
|
121: | if (is_array($val)) {
|
122: | foreach ($val as $subkey => $subval) {
|
123: |
|
124: | if (in_array($subkey, $this->_bad_globals, true)) {
|
125: | $this->message .= "Attempt to inject '$subkey' was found.\n";
|
126: | $this->_safe_contami = false;
|
127: | $this->last_error_type = 'CONTAMI';
|
128: | }
|
129: | $this->_initial_recursive($subval, $key . '_' . base64_encode($subkey));
|
130: | }
|
131: | } else {
|
132: |
|
133: | if (isset($this->_conf['san_nullbyte']) && $this->_conf['san_nullbyte'] && false !== strpos($val, chr(0))) {
|
134: | $val = str_replace(chr(0), ' ', $val);
|
135: | $this->replace_doubtful($key, $val);
|
136: | $this->message .= "Injecting Null-byte '$val' found.\n";
|
137: | $this->output_log('NullByte', 0, false, 32);
|
138: |
|
139: | }
|
140: |
|
141: |
|
142: | if (preg_match('?[\s\'"`/]?', $val)) {
|
143: | $this->_doubtful_requests["$key"] = $val;
|
144: | }
|
145: | }
|
146: | }
|
147: |
|
148: | |
149: | |
150: |
|
151: | public static function getInstance()
|
152: | {
|
153: | static $instance;
|
154: | if (!isset($instance)) {
|
155: | $instance = new Protector();
|
156: | }
|
157: |
|
158: | return $instance;
|
159: | }
|
160: |
|
161: | |
162: | |
163: |
|
164: | public function updateConfFromDb()
|
165: | {
|
166: | $constpref = '_MI_' . strtoupper($this->mydirname);
|
167: |
|
168: | if (empty($this->_conn)) {
|
169: | return false;
|
170: | }
|
171: |
|
172: | $result = @mysqli_query($this->_conn, 'SELECT conf_name,conf_value FROM ' . XOOPS_DB_PREFIX . "_config WHERE conf_title like '" . $constpref . "%'");
|
173: | if (!$result || mysqli_num_rows($result) < 5) {
|
174: | return false;
|
175: | }
|
176: | $db_conf = array();
|
177: | while (list($key, $val) = mysqli_fetch_row($result)) {
|
178: | $db_conf[$key] = $val;
|
179: | }
|
180: | $db_conf_serialized = serialize($db_conf);
|
181: |
|
182: |
|
183: | if ($db_conf_serialized != $this->_conf_serialized) {
|
184: | $fp = fopen($this->get_filepath4confighcache(), 'w');
|
185: | fwrite($fp, $db_conf_serialized);
|
186: | fclose($fp);
|
187: | $this->_conf = $db_conf;
|
188: | }
|
189: |
|
190: | return true;
|
191: | }
|
192: |
|
193: | |
194: | |
195: |
|
196: | public function setConn($conn)
|
197: | {
|
198: | $this->_conn = $conn;
|
199: | }
|
200: |
|
201: | |
202: | |
203: |
|
204: | public function getConf()
|
205: | {
|
206: | return $this->_conf;
|
207: | }
|
208: |
|
209: | |
210: | |
211: |
|
212: | public function purge($redirect_to_top = false)
|
213: | {
|
214: | $this->purgeNoExit();
|
215: |
|
216: | if ($redirect_to_top) {
|
217: | header('Location: ' . XOOPS_URL . '/');
|
218: | exit;
|
219: | } else {
|
220: | $ret = $this->call_filter('prepurge_exit');
|
221: | if ($ret == false) {
|
222: | die('Protector detects attacking actions');
|
223: | }
|
224: | }
|
225: | }
|
226: |
|
227: | public function purgeSession()
|
228: | {
|
229: |
|
230: | if (isset($_SESSION)) {
|
231: | foreach ($_SESSION as $key => $val) {
|
232: | $_SESSION[$key] = '';
|
233: | if (isset($GLOBALS[$key])) {
|
234: | $GLOBALS[$key] = '';
|
235: | }
|
236: | }
|
237: | }
|
238: | }
|
239: |
|
240: | public function purgeCookies()
|
241: | {
|
242: | if (!headers_sent()) {
|
243: | $domain = defined(XOOPS_COOKIE_DOMAIN) ? XOOPS_COOKIE_DOMAIN : '';
|
244: | $past = time() - 3600;
|
245: | foreach ($_COOKIE as $key => $value) {
|
246: | setcookie($key, '', $past, '', $domain);
|
247: | setcookie($key, '', $past, '/', $domain);
|
248: | }
|
249: | }
|
250: | }
|
251: |
|
252: | public function purgeNoExit()
|
253: | {
|
254: | $this->purgeSession();
|
255: | $this->purgeCookies();
|
256: | }
|
257: |
|
258: | public function deactivateCurrentUser()
|
259: | {
|
260: |
|
261: | global $xoopsUser;
|
262: |
|
263: | if (is_object($xoopsUser)) {
|
264: |
|
265: | $userHandler = xoops_getHandler('user');
|
266: | $xoopsUser->setVar('level', 0);
|
267: | $actkey = substr(md5(uniqid(mt_rand(), 1)), 0, 8);
|
268: | $xoopsUser->setVar('actkey', $actkey);
|
269: | $userHandler->insert($xoopsUser);
|
270: | }
|
271: | $this->purgeNoExit();
|
272: | }
|
273: |
|
274: | |
275: | |
276: | |
277: | |
278: | |
279: | |
280: | |
281: |
|
282: | public function output_log($type = 'UNKNOWN', $uid = 0, $unique_check = false, $level = 1)
|
283: | {
|
284: | if ($this->_logged) {
|
285: | return true;
|
286: | }
|
287: |
|
288: | if (!($this->_conf['log_level'] & $level)) {
|
289: | return true;
|
290: | }
|
291: |
|
292: | if (empty($this->_conn)) {
|
293: | mysqli_report(MYSQLI_REPORT_OFF);
|
294: | $this->_conn = new mysqli(XOOPS_DB_HOST, XOOPS_DB_USER, XOOPS_DB_PASS);
|
295: | if (0 !== $this->_conn->connect_errno) {
|
296: | die('db connection failed.');
|
297: | }
|
298: | if (!mysqli_select_db($this->_conn, XOOPS_DB_NAME)) {
|
299: | die('db selection failed.');
|
300: | }
|
301: | }
|
302: |
|
303: | $ip = \Xmf\IPAddress::fromRequest()->asReadable();
|
304: | $agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
305: |
|
306: |
|
307: | if ($unique_check) {
|
308: | $result = mysqli_query($this->_conn, 'SELECT ip,type FROM ' . XOOPS_DB_PREFIX . '_' . $this->mydirname . '_log ORDER BY timestamp DESC LIMIT 1');
|
309: | list($last_ip, $last_type) = mysqli_fetch_row($result);
|
310: | if ($last_ip == $ip && $last_type == $type) {
|
311: | $this->_logged = true;
|
312: |
|
313: | return true;
|
314: | }
|
315: | }
|
316: |
|
317: | mysqli_query(
|
318: | $this->_conn,
|
319: | 'INSERT INTO ' . XOOPS_DB_PREFIX . '_' . $this->mydirname . "_log SET ip='"
|
320: | . mysqli_real_escape_string($this->_conn, $ip) . "',agent='"
|
321: | . mysqli_real_escape_string($this->_conn, $agent) . "',type='"
|
322: | . mysqli_real_escape_string($this->_conn, $type) . "',description='"
|
323: | . mysqli_real_escape_string($this->_conn, $this->message) . "',uid='"
|
324: | . (int)$uid . "',timestamp=NOW()"
|
325: | );
|
326: | $this->_logged = true;
|
327: |
|
328: | return true;
|
329: | }
|
330: |
|
331: | |
332: | |
333: | |
334: | |
335: |
|
336: | public function write_file_bwlimit($expire)
|
337: | {
|
338: | $expire = min((int)$expire, time() + 300);
|
339: |
|
340: | $fp = @fopen($this->get_filepath4bwlimit(), 'w');
|
341: | if ($fp) {
|
342: | @flock($fp, LOCK_EX);
|
343: | fwrite($fp, $expire . "\n");
|
344: | @flock($fp, LOCK_UN);
|
345: | fclose($fp);
|
346: |
|
347: | return true;
|
348: | } else {
|
349: | return false;
|
350: | }
|
351: | }
|
352: |
|
353: | |
354: | |
355: |
|
356: | public function get_bwlimit()
|
357: | {
|
358: | list($expire) = @file(Protector::get_filepath4bwlimit());
|
359: | $expire = min((int)$expire, time() + 300);
|
360: |
|
361: | return $expire;
|
362: | }
|
363: |
|
364: | |
365: | |
366: |
|
367: | public static function get_filepath4bwlimit()
|
368: | {
|
369: | return XOOPS_VAR_PATH . '/protector/bwlimit' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
|
370: | }
|
371: |
|
372: | |
373: | |
374: | |
375: | |
376: |
|
377: | public function write_file_badips($bad_ips)
|
378: | {
|
379: | asort($bad_ips);
|
380: |
|
381: | $fp = @fopen($this->get_filepath4badips(), 'w');
|
382: | if ($fp) {
|
383: | @flock($fp, LOCK_EX);
|
384: | fwrite($fp, serialize($bad_ips) . "\n");
|
385: | @flock($fp, LOCK_UN);
|
386: | fclose($fp);
|
387: |
|
388: | return true;
|
389: | } else {
|
390: | return false;
|
391: | }
|
392: | }
|
393: |
|
394: | |
395: | |
396: | |
397: | |
398: | |
399: |
|
400: | public function register_bad_ips($jailed_time = 0, $ip = null)
|
401: | {
|
402: | if (empty($ip)) {
|
403: | $ip = \Xmf\IPAddress::fromRequest()->asReadable();
|
404: | }
|
405: | if (empty($ip)) {
|
406: | return false;
|
407: | }
|
408: |
|
409: | $bad_ips = $this->get_bad_ips(true);
|
410: | $bad_ips[$ip] = $jailed_time ?: 0x7fffffff;
|
411: |
|
412: | return $this->write_file_badips($bad_ips);
|
413: | }
|
414: |
|
415: | |
416: | |
417: | |
418: | |
419: |
|
420: | public function get_bad_ips($with_jailed_time = false)
|
421: | {
|
422: |
|
423: | $filepath4badips = @file(Protector::get_filepath4badips());
|
424: |
|
425: | if (is_array($filepath4badips) && isset($filepath4badips[0])) {
|
426: | list($bad_ips_serialized) = $filepath4badips;
|
427: | }
|
428: | $bad_ips = empty($bad_ips_serialized) ? array() : @unserialize($bad_ips_serialized, array('allowed_classes' => false));
|
429: | if (!is_array($bad_ips) || isset($bad_ips[0])) {
|
430: | $bad_ips = array();
|
431: | }
|
432: |
|
433: |
|
434: | $pos = 0;
|
435: | foreach ($bad_ips as $bad_ip => $jailed_time) {
|
436: | if ($jailed_time >= time()) {
|
437: | break;
|
438: | }
|
439: | ++$pos;
|
440: | }
|
441: | $bad_ips = array_slice($bad_ips, $pos);
|
442: |
|
443: | if ($with_jailed_time) {
|
444: | return $bad_ips;
|
445: | } else {
|
446: | return array_keys($bad_ips);
|
447: | }
|
448: | }
|
449: |
|
450: | |
451: | |
452: |
|
453: | public static function get_filepath4badips()
|
454: | {
|
455: | return XOOPS_VAR_PATH . '/protector/badips' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
|
456: | }
|
457: |
|
458: | |
459: | |
460: | |
461: | |
462: |
|
463: | public function get_group1_ips($with_info = false)
|
464: | {
|
465: |
|
466: | $group1_ips = [];
|
467: |
|
468: | $filepath = Protector::get_filepath4group1ips();
|
469: | if (file_exists($filepath)) {
|
470: | $filepath4group1ips = file($filepath);
|
471: | if ($filepath4group1ips === false) {
|
472: |
|
473: | } else {
|
474: |
|
475: | if (is_array($filepath4group1ips) && isset($filepath4group1ips[0])) {
|
476: | list($group1_ips_serialized) = $filepath4group1ips;
|
477: | }
|
478: |
|
479: | $group1_ips = empty($group1_ips_serialized) ? array() : @unserialize($group1_ips_serialized, array('allowed_classes' => false));
|
480: | if (!is_array($group1_ips)) {
|
481: | $group1_ips = array();
|
482: | }
|
483: |
|
484: | if ($with_info) {
|
485: | $group1_ips = array_flip($group1_ips);
|
486: | }
|
487: | }
|
488: | } else {
|
489: |
|
490: | }
|
491: |
|
492: | return $group1_ips;
|
493: | }
|
494: |
|
495: | |
496: | |
497: |
|
498: | public static function get_filepath4group1ips()
|
499: | {
|
500: | return XOOPS_VAR_PATH . '/protector/group1ips' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
|
501: | }
|
502: |
|
503: | |
504: | |
505: |
|
506: | public function get_filepath4confighcache()
|
507: | {
|
508: | return XOOPS_VAR_PATH . '/protector/configcache' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
|
509: | }
|
510: |
|
511: | |
512: | |
513: | |
514: | |
515: |
|
516: | public function ip_match($ips)
|
517: | {
|
518: | $requestIp = \Xmf\IPAddress::fromRequest()->asReadable();
|
519: | if (false === $requestIp) {
|
520: | $this->ip_matched_info = null;
|
521: | return false;
|
522: | }
|
523: | foreach ($ips as $ip => $info) {
|
524: | if ($ip) {
|
525: | switch (strtolower(substr($ip, -1))) {
|
526: | case '.' :
|
527: | case ':' :
|
528: |
|
529: | if (substr($requestIp, 0, strlen($ip)) == $ip) {
|
530: | $this->ip_matched_info = $info;
|
531: | return true;
|
532: | }
|
533: | break;
|
534: | case '0' :
|
535: | case '1' :
|
536: | case '2' :
|
537: | case '3' :
|
538: | case '4' :
|
539: | case '5' :
|
540: | case '6' :
|
541: | case '7' :
|
542: | case '8' :
|
543: | case '9' :
|
544: | case 'a' :
|
545: | case 'b' :
|
546: | case 'c' :
|
547: | case 'd' :
|
548: | case 'e' :
|
549: | case 'f' :
|
550: |
|
551: | if ($requestIp == $ip) {
|
552: | $this->ip_matched_info = $info;
|
553: | return true;
|
554: | }
|
555: | break;
|
556: | default :
|
557: |
|
558: | if (@preg_match($ip, $requestIp)) {
|
559: | $this->ip_matched_info = $info;
|
560: | return true;
|
561: | }
|
562: | break;
|
563: | }
|
564: | }
|
565: | }
|
566: | $this->ip_matched_info = null;
|
567: | return false;
|
568: | }
|
569: |
|
570: | |
571: | |
572: | |
573: | |
574: |
|
575: | public function deny_by_htaccess($ip = null)
|
576: | {
|
577: | if (empty($ip)) {
|
578: | $ip = \Xmf\IPAddress::fromRequest()->asReadable();
|
579: | }
|
580: | if (empty($ip)) {
|
581: | return false;
|
582: | }
|
583: | if (!function_exists('file_get_contents')) {
|
584: | return false;
|
585: | }
|
586: |
|
587: | $target_htaccess = XOOPS_ROOT_PATH . '/.htaccess';
|
588: | $backup_htaccess = XOOPS_ROOT_PATH . '/uploads/.htaccess.bak';
|
589: |
|
590: | $ht_body = file_get_contents($target_htaccess);
|
591: |
|
592: |
|
593: | if ($ht_body && !file_exists($backup_htaccess)) {
|
594: | $fw = fopen($backup_htaccess, 'w');
|
595: | fwrite($fw, $ht_body);
|
596: | fclose($fw);
|
597: | }
|
598: |
|
599: |
|
600: | if (!$ht_body && file_exists($backup_htaccess)) {
|
601: | $ht_body = file_get_contents($backup_htaccess);
|
602: | }
|
603: |
|
604: |
|
605: | if ($ht_body === false) {
|
606: | $ht_body = '';
|
607: | }
|
608: |
|
609: | if (preg_match("/^(.*)#PROTECTOR#\s+(DENY FROM .*)\n#PROTECTOR#\n(.*)$/si", $ht_body, $regs)) {
|
610: | if (substr($regs[2], -strlen($ip)) == $ip) {
|
611: | return true;
|
612: | }
|
613: | $new_ht_body = $regs[1] . "#PROTECTOR#\n" . $regs[2] . " $ip\n#PROTECTOR#\n" . $regs[3];
|
614: | } else {
|
615: | $new_ht_body = "#PROTECTOR#\nDENY FROM $ip\n#PROTECTOR#\n" . $ht_body;
|
616: | }
|
617: |
|
618: |
|
619: |
|
620: | $fw = fopen($target_htaccess, 'w');
|
621: | @flock($fw, LOCK_EX);
|
622: | fwrite($fw, $new_ht_body);
|
623: | @flock($fw, LOCK_UN);
|
624: | fclose($fw);
|
625: |
|
626: | return true;
|
627: | }
|
628: |
|
629: | |
630: | |
631: |
|
632: | public function getDblayertrapDoubtfuls()
|
633: | {
|
634: | return $this->_dblayertrap_doubtfuls;
|
635: | }
|
636: |
|
637: | |
638: | |
639: | |
640: |
|
641: | protected function _dblayertrap_check_recursive($val)
|
642: | {
|
643: | if (is_array($val)) {
|
644: | foreach ($val as $subval) {
|
645: | $this->_dblayertrap_check_recursive($subval);
|
646: | }
|
647: | } else {
|
648: | if (strlen($val) < 6) {
|
649: | return null;
|
650: | }
|
651: | $val = @get_magic_quotes_gpc() ? stripslashes($val) : $val;
|
652: | foreach ($this->_dblayertrap_doubtful_needles as $needle) {
|
653: | if (false !== stripos($val, $needle)) {
|
654: | $this->_dblayertrap_doubtfuls[] = $val;
|
655: | }
|
656: | }
|
657: | }
|
658: | }
|
659: |
|
660: | |
661: | |
662: | |
663: |
|
664: | public function dblayertrap_init($force_override = false)
|
665: | {
|
666: | if (!empty($GLOBALS['xoopsOption']['nocommon']) || defined('_LEGACY_PREVENT_EXEC_COMMON_') || defined('_LEGACY_PREVENT_LOAD_CORE_')) {
|
667: | return null;
|
668: | }
|
669: |
|
670: | $this->_dblayertrap_doubtfuls = array();
|
671: | $this->_dblayertrap_check_recursive($_GET);
|
672: | $this->_dblayertrap_check_recursive($_POST);
|
673: | $this->_dblayertrap_check_recursive($_COOKIE);
|
674: | if (empty($this->_conf['dblayertrap_wo_server'])) {
|
675: | $this->_dblayertrap_check_recursive($_SERVER);
|
676: | }
|
677: |
|
678: | if (!empty($this->_dblayertrap_doubtfuls) || $force_override) {
|
679: | @define('XOOPS_DB_ALTERNATIVE', 'ProtectorMysqlDatabase');
|
680: | require_once dirname(__DIR__) . '/class/ProtectorMysqlDatabase.class.php';
|
681: | }
|
682: | }
|
683: |
|
684: | |
685: | |
686: |
|
687: | protected function _bigumbrella_check_recursive($val)
|
688: | {
|
689: | if (is_array($val)) {
|
690: | foreach ($val as $subval) {
|
691: | $this->_bigumbrella_check_recursive($subval);
|
692: | }
|
693: | } else {
|
694: | if (preg_match('/[<\'"].{15}/s', $val, $regs)) {
|
695: | $this->_bigumbrella_doubtfuls[] = $regs[0];
|
696: | }
|
697: | }
|
698: | }
|
699: |
|
700: | public function bigumbrella_init()
|
701: | {
|
702: | $this->_bigumbrella_doubtfuls = array();
|
703: | $this->_bigumbrella_check_recursive($_GET);
|
704: | $this->_bigumbrella_check_recursive(isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '');
|
705: |
|
706: |
|
707: | if (!empty($this->_bigumbrella_doubtfuls)) {
|
708: | ob_start(array($this, 'bigumbrella_outputcheck'));
|
709: | }
|
710: | }
|
711: |
|
712: | |
713: | |
714: | |
715: | |
716: |
|
717: | public function bigumbrella_outputcheck($s)
|
718: | {
|
719: | if (defined('BIGUMBRELLA_DISABLED')) {
|
720: | return $s;
|
721: | }
|
722: |
|
723: | if (function_exists('headers_list')) {
|
724: | foreach (headers_list() as $header) {
|
725: | if (false !== stripos($header, 'Content-Type:') && false === stripos($header, 'text/html')) {
|
726: | return $s;
|
727: | }
|
728: | }
|
729: | }
|
730: |
|
731: | if (!is_array($this->_bigumbrella_doubtfuls)) {
|
732: | return 'bigumbrella injection found.';
|
733: | }
|
734: |
|
735: | foreach ($this->_bigumbrella_doubtfuls as $doubtful) {
|
736: | if (false !== strpos($s, $doubtful)) {
|
737: | return 'XSS found by Protector.';
|
738: | }
|
739: | }
|
740: |
|
741: | return $s;
|
742: | }
|
743: |
|
744: | |
745: | |
746: |
|
747: | public function intval_allrequestsendid()
|
748: | {
|
749: | global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
|
750: |
|
751: | if ($this->_done_intval) {
|
752: | return true;
|
753: | } else {
|
754: | $this->_done_intval = true;
|
755: | }
|
756: |
|
757: | foreach ($_GET as $key => $val) {
|
758: | if (substr($key, -2) === 'id' && !is_array($_GET[$key])) {
|
759: | $newval = preg_replace('/[^0-9a-zA-Z_-]/', '', $val);
|
760: | $_GET[$key] = $HTTP_GET_VARS[$key] = $newval;
|
761: | if ($_REQUEST[$key] == $_GET[$key]) {
|
762: | $_REQUEST[$key] = $newval;
|
763: | }
|
764: | }
|
765: | }
|
766: | foreach ($_POST as $key => $val) {
|
767: | if (substr($key, -2) === 'id' && !is_array($_POST[$key])) {
|
768: | $newval = preg_replace('/[^0-9a-zA-Z_-]/', '', $val);
|
769: | $_POST[$key] = $HTTP_POST_VARS[$key] = $newval;
|
770: | if ($_REQUEST[$key] == $_POST[$key]) {
|
771: | $_REQUEST[$key] = $newval;
|
772: | }
|
773: | }
|
774: | }
|
775: | foreach ($_COOKIE as $key => $val) {
|
776: | if (substr($key, -2) === 'id' && !is_array($_COOKIE[$key])) {
|
777: | $newval = preg_replace('/[^0-9a-zA-Z_-]/', '', $val);
|
778: | $_COOKIE[$key] = $HTTP_COOKIE_VARS[$key] = $newval;
|
779: | if ($_REQUEST[$key] == $_COOKIE[$key]) {
|
780: | $_REQUEST[$key] = $newval;
|
781: | }
|
782: | }
|
783: | }
|
784: |
|
785: | return true;
|
786: | }
|
787: |
|
788: | |
789: | |
790: |
|
791: | public function eliminate_dotdot()
|
792: | {
|
793: | global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
|
794: |
|
795: | if ($this->_done_dotdot) {
|
796: | return true;
|
797: | } else {
|
798: | $this->_done_dotdot = true;
|
799: | }
|
800: |
|
801: | foreach ($_GET as $key => $val) {
|
802: | if (is_array($_GET[$key])) {
|
803: | continue;
|
804: | }
|
805: | if (substr(trim($val), 0, 3) === '../' || false !== strpos($val, '/../')) {
|
806: | $this->last_error_type = 'DirTraversal';
|
807: | $this->message .= "Directory Traversal '$val' found.\n";
|
808: | $this->output_log($this->last_error_type, 0, false, 64);
|
809: | $sanitized_val = str_replace(chr(0), '', $val);
|
810: | if (substr($sanitized_val, -2) !== ' .') {
|
811: | $sanitized_val .= ' .';
|
812: | }
|
813: | $_GET[$key] = $HTTP_GET_VARS[$key] = $sanitized_val;
|
814: | if ($_REQUEST[$key] == $_GET[$key]) {
|
815: | $_REQUEST[$key] = $sanitized_val;
|
816: | }
|
817: | }
|
818: | }
|
819: |
|
820: | |
821: | |
822: | |
823: | |
824: | |
825: | |
826: | |
827: | |
828: | |
829: | |
830: | |
831: | |
832: | |
833: | |
834: | |
835: | |
836: | |
837: | |
838: | |
839: | |
840: | |
841: | |
842: | |
843: | |
844: | |
845: | |
846: | |
847: |
|
848: |
|
849: | return true;
|
850: | }
|
851: |
|
852: | |
853: | |
854: | |
855: | |
856: | |
857: |
|
858: | public function &get_ref_from_base64index(&$current, $indexes)
|
859: | {
|
860: | foreach ($indexes as $index) {
|
861: | $index = base64_decode($index);
|
862: | if (!is_array($current)) {
|
863: | return false;
|
864: | }
|
865: | $current =& $current[$index];
|
866: | }
|
867: |
|
868: | return $current;
|
869: | }
|
870: |
|
871: | |
872: | |
873: | |
874: |
|
875: | public function replace_doubtful($key, $val)
|
876: | {
|
877: | global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
|
878: |
|
879: | $index_expression = '';
|
880: | $indexes = explode('_', $key);
|
881: | $base_array = array_shift($indexes);
|
882: |
|
883: | switch ($base_array) {
|
884: | case 'G' :
|
885: | $main_ref =& $this->get_ref_from_base64index($_GET, $indexes);
|
886: | $legacy_ref =& $this->get_ref_from_base64index($HTTP_GET_VARS, $indexes);
|
887: | break;
|
888: | case 'P' :
|
889: | $main_ref =& $this->get_ref_from_base64index($_POST, $indexes);
|
890: | $legacy_ref =& $this->get_ref_from_base64index($HTTP_POST_VARS, $indexes);
|
891: | break;
|
892: | case 'C' :
|
893: | $main_ref =& $this->get_ref_from_base64index($_COOKIE, $indexes);
|
894: | $legacy_ref =& $this->get_ref_from_base64index($HTTP_COOKIE_VARS, $indexes);
|
895: | break;
|
896: | default :
|
897: | exit;
|
898: | }
|
899: | if (!isset($main_ref)) {
|
900: | exit;
|
901: | }
|
902: | $request_ref =& $this->get_ref_from_base64index($_REQUEST, $indexes);
|
903: | if ($request_ref !== false && $main_ref == $request_ref) {
|
904: | $request_ref = $val;
|
905: | }
|
906: | $main_ref = $val;
|
907: | $legacy_ref = $val;
|
908: | }
|
909: |
|
910: | |
911: | |
912: |
|
913: | public function check_uploaded_files()
|
914: | {
|
915: | if ($this->_done_badext) {
|
916: | return $this->_safe_badext;
|
917: | } else {
|
918: | $this->_done_badext = true;
|
919: | }
|
920: |
|
921: |
|
922: | $bad_extensions = array('php', 'phtml', 'phtm', 'php3', 'php4', 'cgi', 'pl', 'asp');
|
923: |
|
924: | $image_extensions = array(
|
925: | 1 => 'gif',
|
926: | 2 => 'jpg',
|
927: | 3 => 'png',
|
928: | 4 => 'swf',
|
929: | 5 => 'psd',
|
930: | 6 => 'bmp',
|
931: | 7 => 'tif',
|
932: | 8 => 'tif',
|
933: | 9 => 'jpc',
|
934: | 10 => 'jp2',
|
935: | 11 => 'jpx',
|
936: | 12 => 'jb2',
|
937: | 13 => 'swc',
|
938: | 14 => 'iff',
|
939: | 15 => 'wbmp',
|
940: | 16 => 'xbm');
|
941: |
|
942: | foreach ($_FILES as $_file) {
|
943: | if (!empty($_file['error'])) {
|
944: | continue;
|
945: | }
|
946: | if (!empty($_file['name']) && is_string($_file['name'])) {
|
947: | $ext = strtolower(substr(strrchr($_file['name'], '.'), 1));
|
948: | if ($ext === 'jpeg') {
|
949: | $ext = 'jpg';
|
950: | } elseif ($ext === 'tiff') {
|
951: | $ext = 'tif';
|
952: | }
|
953: |
|
954: |
|
955: | if (count(explode('.', str_replace('.tar.gz', '.tgz', $_file['name']))) > 2) {
|
956: | $this->message .= "Attempt to multiple dot file {$_file['name']}.\n";
|
957: | $this->_safe_badext = false;
|
958: | $this->last_error_type = 'UPLOAD';
|
959: | }
|
960: |
|
961: |
|
962: | if (in_array($ext, $bad_extensions)) {
|
963: | $this->message .= "Attempt to upload {$_file['name']}.\n";
|
964: | $this->_safe_badext = false;
|
965: | $this->last_error_type = 'UPLOAD';
|
966: | }
|
967: |
|
968: |
|
969: | if (in_array($ext, $image_extensions)) {
|
970: | $image_attributes = @getimagesize($_file['tmp_name']);
|
971: | if ($image_attributes === false && is_uploaded_file($_file['tmp_name'])) {
|
972: |
|
973: | $temp_file = XOOPS_ROOT_PATH . '/uploads/protector_upload_temporary' . md5(time());
|
974: | move_uploaded_file($_file['tmp_name'], $temp_file);
|
975: | $image_attributes = @getimagesize($temp_file);
|
976: | @unlink($temp_file);
|
977: | }
|
978: |
|
979: | if ($image_attributes === false || $image_extensions[(int)$image_attributes[2]] != $ext) {
|
980: | $this->message .= "Attempt to upload camouflaged image file {$_file['name']}.\n";
|
981: | $this->_safe_badext = false;
|
982: | $this->last_error_type = 'UPLOAD';
|
983: | }
|
984: | }
|
985: | }
|
986: | }
|
987: |
|
988: | return $this->_safe_badext;
|
989: | }
|
990: |
|
991: | |
992: | |
993: |
|
994: | public function check_contami_systemglobals()
|
995: | {
|
996: | |
997: |
|
998: |
|
999: | |
1000: | |
1001: | |
1002: | |
1003: | |
1004: | |
1005: |
|
1006: |
|
1007: | return $this->_safe_contami;
|
1008: | }
|
1009: |
|
1010: | |
1011: | |
1012: | |
1013: | |
1014: |
|
1015: | public function check_sql_isolatedcommentin($sanitize = true)
|
1016: | {
|
1017: | if ($this->_done_isocom) {
|
1018: | return $this->_safe_isocom;
|
1019: | } else {
|
1020: | $this->_done_isocom = true;
|
1021: | }
|
1022: |
|
1023: | foreach ($this->_doubtful_requests as $key => $val) {
|
1024: | $str = $val;
|
1025: | while ($str = strstr($str, '/*')) {
|
1026: | $str = strstr(substr($str, 2), '*/');
|
1027: | if ($str === false) {
|
1028: | $this->message .= "Isolated comment-in found. ($val)\n";
|
1029: | if ($sanitize) {
|
1030: | $this->replace_doubtful($key, $val . '*/');
|
1031: | }
|
1032: | $this->_safe_isocom = false;
|
1033: | $this->last_error_type = 'ISOCOM';
|
1034: | }
|
1035: | }
|
1036: | }
|
1037: |
|
1038: | return $this->_safe_isocom;
|
1039: | }
|
1040: |
|
1041: | |
1042: | |
1043: | |
1044: | |
1045: |
|
1046: | public function check_sql_union($sanitize = true)
|
1047: | {
|
1048: | if ($this->_done_union) {
|
1049: | return $this->_safe_union;
|
1050: | } else {
|
1051: | $this->_done_union = true;
|
1052: | }
|
1053: |
|
1054: | foreach ($this->_doubtful_requests as $key => $val) {
|
1055: | $str = str_replace(array('/*', '*/'), '', preg_replace('?/\*.+\*/?sU', '', $val));
|
1056: | if (preg_match('/\sUNION\s+(ALL|SELECT)/i', $str)) {
|
1057: | $this->message .= "Pattern like SQL injection found. ($val)\n";
|
1058: | if ($sanitize) {
|
1059: |
|
1060: | $this->replace_doubtful($key, str_ireplace('union', 'uni-on', $val));
|
1061: | }
|
1062: | $this->_safe_union = false;
|
1063: | $this->last_error_type = 'UNION';
|
1064: | }
|
1065: | }
|
1066: |
|
1067: | return $this->_safe_union;
|
1068: | }
|
1069: |
|
1070: | |
1071: | |
1072: | |
1073: | |
1074: |
|
1075: | public function stopforumspam($uid)
|
1076: | {
|
1077: | if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
1078: | return false;
|
1079: | }
|
1080: |
|
1081: | $result = $this->stopForumSpamLookup(
|
1082: | isset($_POST['email']) ? $_POST['email'] : null,
|
1083: | $_SERVER['REMOTE_ADDR'],
|
1084: | isset($_POST['uname']) ? $_POST['uname'] : null
|
1085: | );
|
1086: |
|
1087: | if (false === $result || isset($result['http_code'])) {
|
1088: | return false;
|
1089: | }
|
1090: |
|
1091: | $spammer = false;
|
1092: | if (isset($result['email']) && isset($result['email']['lastseen'])) {
|
1093: | $spammer = true;
|
1094: | }
|
1095: |
|
1096: | if (isset($result['ip']) && isset($result['ip']['lastseen'])) {
|
1097: | $last = strtotime($result['ip']['lastseen']);
|
1098: | $oneMonth = 60 * 60 * 24 * 31;
|
1099: | $oneMonthAgo = time() - $oneMonth;
|
1100: | if ($last > $oneMonthAgo) {
|
1101: | $spammer = true;
|
1102: | }
|
1103: | }
|
1104: |
|
1105: | if (!$spammer) {
|
1106: | return false;
|
1107: | }
|
1108: |
|
1109: | $this->last_error_type = 'SPAMMER POST';
|
1110: |
|
1111: | switch ($this->_conf['stopforumspam_action']) {
|
1112: | default :
|
1113: | case 'log' :
|
1114: | break;
|
1115: | case 'san' :
|
1116: | $_POST = array();
|
1117: | $this->message .= 'POST deleted for IP:' . $_SERVER['REMOTE_ADDR'];
|
1118: | break;
|
1119: | case 'biptime0' :
|
1120: | $_POST = array();
|
1121: | $this->message .= 'BAN and POST deleted for IP:' . $_SERVER['REMOTE_ADDR'];
|
1122: | $this->_should_be_banned_time0 = true;
|
1123: | break;
|
1124: | case 'bip' :
|
1125: | $_POST = array();
|
1126: | $this->message .= 'Ban and POST deleted for IP:' . $_SERVER['REMOTE_ADDR'];
|
1127: | $this->_should_be_banned = true;
|
1128: | break;
|
1129: | }
|
1130: |
|
1131: | $this->output_log($this->last_error_type, $uid, false, 16);
|
1132: |
|
1133: | return true;
|
1134: | }
|
1135: |
|
1136: | public function stopForumSpamLookup($email, $ip, $username)
|
1137: | {
|
1138: | if (!function_exists('curl_init')) {
|
1139: | return false;
|
1140: | }
|
1141: |
|
1142: | $query = '';
|
1143: | $query .= (empty($ip)) ? '' : '&ip=' . $ip;
|
1144: | $query .= (empty($email)) ? '' : '&email=' . $email;
|
1145: | $query .= (empty($username)) ? '' : '&username=' . $username;
|
1146: |
|
1147: | if (empty($query)) {
|
1148: | return false;
|
1149: | }
|
1150: |
|
1151: | $url = 'http://www.stopforumspam.com/api?f=json' . $query;
|
1152: | $ch = curl_init();
|
1153: | curl_setopt($ch, CURLOPT_URL, $url);
|
1154: | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
1155: | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
1156: | $result = curl_exec($ch);
|
1157: | if (false === $result) {
|
1158: | $result = curl_getinfo($ch);
|
1159: | } else {
|
1160: | $result = json_decode(curl_exec($ch), true);
|
1161: | }
|
1162: | curl_close($ch);
|
1163: |
|
1164: | return $result;
|
1165: | }
|
1166: |
|
1167: | |
1168: | |
1169: | |
1170: | |
1171: | |
1172: |
|
1173: | public function check_dos_attack($uid = 0, $can_ban = false)
|
1174: | {
|
1175: | global $xoopsDB;
|
1176: |
|
1177: | if ($this->_done_dos) {
|
1178: | return true;
|
1179: | }
|
1180: |
|
1181: | $ip = \Xmf\IPAddress::fromRequest();
|
1182: | if (false === $ip->asReadable()) {
|
1183: | return true;
|
1184: | }
|
1185: | $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
|
1186: |
|
1187: | $ip4sql = $xoopsDB->quote($ip->asReadable());
|
1188: | $uri4sql = $xoopsDB->quote($uri);
|
1189: |
|
1190: |
|
1191: | $result = $xoopsDB->queryF(
|
1192: | 'DELETE FROM ' . $xoopsDB->prefix($this->mydirname . '_access')
|
1193: | . ' WHERE expire < UNIX_TIMESTAMP()'
|
1194: | );
|
1195: |
|
1196: |
|
1197: | if ($result === false) {
|
1198: | $this->_done_dos = true;
|
1199: |
|
1200: | return true;
|
1201: | }
|
1202: |
|
1203: |
|
1204: | $sql4insertlog = 'INSERT INTO ' . $xoopsDB->prefix($this->mydirname . '_access')
|
1205: | . " SET ip={$ip4sql}, request_uri={$uri4sql},"
|
1206: | . " expire=UNIX_TIMESTAMP()+'" . (int)$this->_conf['dos_expire'] . "'";
|
1207: |
|
1208: |
|
1209: | if (isset($this->_conf['bwlimit_count']) && $this->_conf['bwlimit_count'] >= 10) {
|
1210: | $sql = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access');
|
1211: | $result = $xoopsDB->query($sql);
|
1212: | if ($xoopsDB->isResultSet($result)) {
|
1213: | list($bw_count) = $xoopsDB->fetchRow($result);
|
1214: | if ($bw_count > $this->_conf['bwlimit_count']) {
|
1215: | $this->write_file_bwlimit(time() + $this->_conf['dos_expire']);
|
1216: | }
|
1217: | }
|
1218: | }
|
1219: |
|
1220: |
|
1221: |
|
1222: | $sql = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . " WHERE ip={$ip4sql} AND request_uri={$uri4sql}";
|
1223: | $result = $xoopsDB->query($sql);
|
1224: | if (!$xoopsDB->isResultSet($result)) {
|
1225: | throw new \RuntimeException(
|
1226: | \sprintf(_DB_QUERY_ERROR, $sql) . $xoopsDB->error(), E_USER_ERROR
|
1227: | );
|
1228: | }
|
1229: | list($f5_count) = $xoopsDB->fetchRow($result);
|
1230: | if ($f5_count > $this->_conf['dos_f5count']) {
|
1231: |
|
1232: |
|
1233: | $xoopsDB->queryF($sql4insertlog);
|
1234: |
|
1235: |
|
1236: |
|
1237: |
|
1238: |
|
1239: | $ret = $this->call_filter('f5attack_overrun');
|
1240: |
|
1241: |
|
1242: | $this->_done_dos = true;
|
1243: | $this->last_error_type = 'DoS';
|
1244: | switch ($this->_conf['dos_f5action']) {
|
1245: | default :
|
1246: | case 'exit' :
|
1247: | $this->output_log($this->last_error_type, $uid, true, 16);
|
1248: | exit;
|
1249: | case 'none' :
|
1250: | $this->output_log($this->last_error_type, $uid, true, 16);
|
1251: |
|
1252: | return true;
|
1253: | case 'biptime0' :
|
1254: | if ($can_ban) {
|
1255: | $this->register_bad_ips(time() + $this->_conf['banip_time0']);
|
1256: | }
|
1257: | break;
|
1258: | case 'bip' :
|
1259: | if ($can_ban) {
|
1260: | $this->register_bad_ips();
|
1261: | }
|
1262: | break;
|
1263: | case 'hta' :
|
1264: | if ($can_ban) {
|
1265: | $this->deny_by_htaccess();
|
1266: | }
|
1267: | break;
|
1268: | case 'sleep' :
|
1269: | sleep(5);
|
1270: | break;
|
1271: | }
|
1272: |
|
1273: | return false;
|
1274: | }
|
1275: |
|
1276: |
|
1277: | if (trim($this->_conf['dos_crsafe']) != '' && isset($_SERVER['HTTP_USER_AGENT']) && preg_match($this->_conf['dos_crsafe'], $_SERVER['HTTP_USER_AGENT'])) {
|
1278: |
|
1279: | $this->_done_dos = true;
|
1280: |
|
1281: | return true;
|
1282: | }
|
1283: |
|
1284: |
|
1285: | $sql = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . " WHERE ip={$ip4sql}";
|
1286: | $result = $xoopsDB->query($sql);
|
1287: | if (!$xoopsDB->isResultSet($result)) {
|
1288: | return false;
|
1289: | }
|
1290: | list($crawler_count) = $xoopsDB->fetchRow($result);
|
1291: |
|
1292: |
|
1293: | $xoopsDB->queryF($sql4insertlog);
|
1294: |
|
1295: | if ($crawler_count > $this->_conf['dos_crcount']) {
|
1296: |
|
1297: |
|
1298: | $ret = $this->call_filter('crawler_overrun');
|
1299: |
|
1300: |
|
1301: | $this->_done_dos = true;
|
1302: | $this->last_error_type = 'CRAWLER';
|
1303: | switch ($this->_conf['dos_craction']) {
|
1304: | default :
|
1305: | case 'exit' :
|
1306: | $this->output_log($this->last_error_type, $uid, true, 16);
|
1307: | exit;
|
1308: | case 'none' :
|
1309: | $this->output_log($this->last_error_type, $uid, true, 16);
|
1310: |
|
1311: | return true;
|
1312: | case 'biptime0' :
|
1313: | if ($can_ban) {
|
1314: | $this->register_bad_ips(time() + $this->_conf['banip_time0']);
|
1315: | }
|
1316: | break;
|
1317: | case 'bip' :
|
1318: | if ($can_ban) {
|
1319: | $this->register_bad_ips();
|
1320: | }
|
1321: | break;
|
1322: | case 'hta' :
|
1323: | if ($can_ban) {
|
1324: | $this->deny_by_htaccess();
|
1325: | }
|
1326: | break;
|
1327: | case 'sleep' :
|
1328: | sleep(5);
|
1329: | break;
|
1330: | }
|
1331: |
|
1332: | return false;
|
1333: | }
|
1334: |
|
1335: | return true;
|
1336: | }
|
1337: |
|
1338: |
|
1339: | |
1340: | |
1341: |
|
1342: | public function check_brute_force()
|
1343: | {
|
1344: | global $xoopsDB;
|
1345: |
|
1346: | $ip = \Xmf\IPAddress::fromRequest();
|
1347: | if (false === $ip->asReadable()) {
|
1348: | return true;
|
1349: | }
|
1350: | $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
|
1351: | $ip4sql = $xoopsDB->quote($ip->asReadable());
|
1352: | $uri4sql = $xoopsDB->quote($uri);
|
1353: |
|
1354: | $victim_uname = empty($_COOKIE['autologin_uname']) ? $_POST['uname'] : $_COOKIE['autologin_uname'];
|
1355: |
|
1356: | if ($victim_uname === 'deleted') {
|
1357: | return null;
|
1358: | }
|
1359: | $mal4sql = $xoopsDB->quote("BRUTE FORCE: $victim_uname");
|
1360: |
|
1361: |
|
1362: | $result = $xoopsDB->queryF(
|
1363: | 'DELETE FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . ' WHERE expire < UNIX_TIMESTAMP()'
|
1364: | );
|
1365: |
|
1366: |
|
1367: | $sql4insertlog = 'INSERT INTO ' . $xoopsDB->prefix($this->mydirname . '_access')
|
1368: | . " SET ip={$ip4sql}, request_uri={$uri4sql}, malicious_actions={$mal4sql}, expire=UNIX_TIMESTAMP()+600";
|
1369: |
|
1370: |
|
1371: | $bf_count = 0;
|
1372: | $sql = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . " WHERE ip={$ip4sql} AND malicious_actions like 'BRUTE FORCE:%'";
|
1373: | $result = $xoopsDB->query($sql);
|
1374: | if ($xoopsDB->isResultSet($result)) {
|
1375: | list($bf_count) = $xoopsDB->fetchRow($result);
|
1376: | } else {
|
1377: | throw new \RuntimeException(
|
1378: | \sprintf(_DB_QUERY_ERROR, $sql) . $xoopsDB->error(), E_USER_ERROR
|
1379: | );
|
1380: | }
|
1381: | if ($bf_count > $this->_conf['bf_count']) {
|
1382: | $this->register_bad_ips(time() + $this->_conf['banip_time0']);
|
1383: | $this->last_error_type = 'BruteForce';
|
1384: | $this->message .= "Trying to login as '" . addslashes($victim_uname) . "' found.\n";
|
1385: | $this->output_log('BRUTE FORCE', 0, true, 1);
|
1386: | $ret = $this->call_filter('bruteforce_overrun');
|
1387: | if ($ret == false) {
|
1388: | exit;
|
1389: | }
|
1390: | }
|
1391: |
|
1392: | $xoopsDB->queryF($sql4insertlog);
|
1393: | return null;
|
1394: | }
|
1395: |
|
1396: | |
1397: | |
1398: |
|
1399: | protected function _spam_check_point_recursive($val)
|
1400: | {
|
1401: | if (is_array($val)) {
|
1402: | foreach ($val as $subval) {
|
1403: | $this->_spam_check_point_recursive($subval);
|
1404: | }
|
1405: | } else {
|
1406: |
|
1407: | $path_array = parse_url(XOOPS_URL);
|
1408: | $http_host = empty($path_array['host']) ? 'www.xoops.org' : $path_array['host'];
|
1409: |
|
1410: |
|
1411: | $count = -1;
|
1412: | foreach (preg_split('#https?\:\/\/#i', $val) as $fragment) {
|
1413: | if (strncmp($fragment, $http_host, strlen($http_host)) !== 0) {
|
1414: | ++$count;
|
1415: | }
|
1416: | }
|
1417: | if ($count > 0) {
|
1418: | $this->_spamcount_uri += $count;
|
1419: | }
|
1420: |
|
1421: |
|
1422: | $this->_spamcount_uri += count(preg_split('/\[url=(?!http|\\"http|\\\'http|' . $http_host . ')/i', $val)) - 1;
|
1423: | }
|
1424: | }
|
1425: |
|
1426: | |
1427: | |
1428: | |
1429: |
|
1430: | public function spam_check($points4deny, $uid)
|
1431: | {
|
1432: | $this->_spamcount_uri = 0;
|
1433: | $this->_spam_check_point_recursive($_POST);
|
1434: |
|
1435: | if ($this->_spamcount_uri >= $points4deny) {
|
1436: | $this->message .= (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '') . " SPAM POINT: $this->_spamcount_uri\n";
|
1437: | $this->output_log('URI SPAM', $uid, false, 128);
|
1438: | $ret = $this->call_filter('spamcheck_overrun');
|
1439: | if ($ret == false) {
|
1440: | exit;
|
1441: | }
|
1442: | }
|
1443: | }
|
1444: |
|
1445: | public function disable_features()
|
1446: | {
|
1447: | global $HTTP_POST_VARS, $HTTP_GET_VARS, $HTTP_COOKIE_VARS;
|
1448: |
|
1449: |
|
1450: | $error_reporting_level = error_reporting(0);
|
1451: |
|
1452: |
|
1453: |
|
1454: |
|
1455: | if ($this->_conf['disable_features'] & 1) {
|
1456: |
|
1457: |
|
1458: | if (isset($_SERVER['SCRIPT_NAME']) && substr($_SERVER['SCRIPT_NAME'], -10) === 'xmlrpc.php') {
|
1459: | $this->output_log('xmlrpc', 0, true, 1);
|
1460: | exit;
|
1461: | }
|
1462: |
|
1463: |
|
1464: | if ((isset($_POST['uname']) && $_POST['uname'] === '0') || (isset($_COOKIE['autologin_pass']) && $_COOKIE['autologin_pass'] === '0')) {
|
1465: | $this->output_log('CRITERIA');
|
1466: | exit;
|
1467: | }
|
1468: | }
|
1469: |
|
1470: |
|
1471: |
|
1472: |
|
1473: | if ($this->_conf['disable_features'] & 1024) {
|
1474: |
|
1475: |
|
1476: | if (isset($_SERVER['SCRIPT_NAME']) && false === stripos($_SERVER['SCRIPT_NAME'], 'modules')) {
|
1477: |
|
1478: | if (substr($_SERVER['SCRIPT_NAME'], -8) === 'misc.php' && ((isset($_GET['type']) && $_GET['type'] === 'debug') || (isset($_POST['type']) && $_POST['type'] === 'debug')) && isset($_GET['file']) && !preg_match('/^dummy_\d+\.html$/', $_GET['file'])) {
|
1479: | $this->output_log('misc debug');
|
1480: | exit;
|
1481: | }
|
1482: |
|
1483: |
|
1484: | if (substr($_SERVER['SCRIPT_NAME'], -8) === 'misc.php' && ((isset($_GET['type']) && $_GET['type'] === 'smilies') || (isset($_POST['type']) && $_POST['type'] === 'smilies')) && isset($_GET['target']) && !preg_match('/^[0-9a-z_]*$/i', $_GET['target'])) {
|
1485: | $this->output_log('misc smilies');
|
1486: | exit;
|
1487: | }
|
1488: |
|
1489: |
|
1490: | if (substr($_SERVER['SCRIPT_NAME'], -12) === 'edituser.php' && isset($_POST['op']) && $_POST['op'] === 'avatarchoose' && isset($_POST['user_avatar']) && false !== strpos($_POST['user_avatar'], '..')) {
|
1491: | $this->output_log('edituser avatarchoose');
|
1492: | exit;
|
1493: | }
|
1494: | }
|
1495: |
|
1496: |
|
1497: | if (isset($_SERVER['SCRIPT_NAME']) && substr($_SERVER['SCRIPT_NAME'], -24) === 'modules/system/admin.php' && ((isset($_GET['fct']) && $_GET['fct'] === 'findusers') || (isset($_POST['fct']) && $_POST['fct'] === 'findusers'))) {
|
1498: | foreach ($_POST as $key => $val) {
|
1499: | if (false !== strpos($key, "'") || false !== strpos($val, "'")) {
|
1500: | $this->output_log('findusers');
|
1501: | exit;
|
1502: | }
|
1503: | }
|
1504: | }
|
1505: |
|
1506: |
|
1507: |
|
1508: | if (isset($_SERVER['SCRIPT_NAME']) && substr($_SERVER['SCRIPT_NAME'], -23) === 'modules/news/submit.php' && isset($_POST['preview']) && isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], XOOPS_URL . '/modules/news/submit.php') !== 0) {
|
1509: | $HTTP_POST_VARS['nohtml'] = $_POST['nohtml'] = 1;
|
1510: | }
|
1511: |
|
1512: | if (isset($_SERVER['SCRIPT_NAME']) && substr($_SERVER['SCRIPT_NAME'], -28) === 'modules/news/admin/index.php' && ($_POST['op'] === 'preview' || $_GET['op'] === 'preview') && isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], XOOPS_URL . '/modules/news/admin/index.php') !== 0) {
|
1513: | $HTTP_POST_VARS['nohtml'] = $_POST['nohtml'] = 1;
|
1514: | }
|
1515: |
|
1516: | if (isset($_POST['com_dopreview']) && isset($_SERVER['HTTP_REFERER']) && false === strpos(substr($_SERVER['HTTP_REFERER'], -16), 'comment_post.php')) {
|
1517: | $HTTP_POST_VARS['dohtml'] = $_POST['dohtml'] = 0;
|
1518: | }
|
1519: |
|
1520: | if (isset($_SERVER['SCRIPT_NAME']) && substr($_SERVER['SCRIPT_NAME'], -24) === 'modules/system/admin.php' && ($_GET['fct'] === 'blocksadmin' || $_POST['fct'] === 'blocksadmin') && isset($_POST['previewblock'])) {
|
1521: | die("Danger! don't use this preview. Use 'altsys module' instead.(by Protector)");
|
1522: | }
|
1523: |
|
1524: | if (isset($_SERVER['SCRIPT_NAME']) && substr($_SERVER['SCRIPT_NAME'], -24) === 'modules/system/admin.php' && ($_GET['fct'] === 'tplsets' || $_POST['fct'] === 'tplsets')) {
|
1525: | if ($_POST['op'] === 'previewpopup' || $_GET['op'] === 'previewpopup' || isset($_POST['previewtpl'])) {
|
1526: | die("Danger! don't use this preview.(by Protector)");
|
1527: | }
|
1528: | }
|
1529: | }
|
1530: |
|
1531: |
|
1532: | error_reporting($error_reporting_level);
|
1533: | }
|
1534: |
|
1535: | |
1536: | |
1537: | |
1538: | |
1539: | |
1540: |
|
1541: | public function call_filter($type, $dying_message = '')
|
1542: | {
|
1543: | require_once __DIR__ . '/ProtectorFilter.php';
|
1544: | $filter_handler = ProtectorFilterHandler::getInstance();
|
1545: | $ret = $filter_handler->execute($type);
|
1546: | if ($ret == false && $dying_message) {
|
1547: | die($dying_message);
|
1548: | }
|
1549: |
|
1550: | return $ret;
|
1551: | }
|
1552: | }
|
1553: | |