/** * @return array|bool */ function b_system_online_show() { global $xoopsUser, $xoopsModule; $online_handler = xoops_getHandler('online'); mt_srand((double) microtime() * 1000000); // set gc probabillity to 10% for now.. if (mt_rand(1, 100) < 11) { $online_handler->gc(300); } if (is_object($xoopsUser)) { $uid = $xoopsUser->getVar('uid'); $uname = $xoopsUser->getVar('uname'); } else { $uid = 0; $uname = ''; } $requestIp = \Xmf\IPAddress::fromRequest()->asReadable(); $requestIp = false === $requestIp ? '0.0.0.0' : $requestIp; if (is_object($xoopsModule)) { $online_handler->write($uid, $uname, time(), $xoopsModule->getVar('mid'), $requestIp); } else { $online_handler->write($uid, $uname, time(), 0, $requestIp); } $onlines = $online_handler->getAll(); if (!empty($onlines)) { $total = count($onlines); $block = array(); $guests = 0; $members = ''; for ($i = 0; $i < $total; ++$i) { if ($onlines[$i]['online_uid'] > 0) { $members .= ' <a href="' . XOOPS_URL . '/userinfo.php?uid=' . $onlines[$i]['online_uid'] . '" title="' . $onlines[$i]['online_uname'] . '">' . $onlines[$i]['online_uname'] . '</a>,'; } else { ++$guests; } } $block['online_total'] = sprintf(_ONLINEPHRASE, $total); if (is_object($xoopsModule)) { $mytotal = $online_handler->getCount(new Criteria('online_module', $xoopsModule->getVar('mid'))); $block['online_total'] .= ' (' . sprintf(_ONLINEPHRASEX, $mytotal, $xoopsModule->getVar('name')) . ')'; } $block['lang_members'] = _MEMBERS; $block['lang_guests'] = _GUESTS; $block['online_names'] = $members; $block['online_members'] = $total - $guests; $block['online_guests'] = $guests; $block['lang_more'] = _MORE; return $block; } else { return false; } }
/** * XoopsCaptchaRecaptcha2::verify() * * @param string|null $sessionName unused for recaptcha * * @return bool */ public function verify($sessionName = null) { $isValid = false; $recaptchaResponse = Request::getString('g-recaptcha-response', ''); $recaptchaVerifyURL = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $this->config['secret_key'] . '&response=' . $recaptchaResponse . '&remoteip=' . IPAddress::fromRequest()->asReadable(); $usedCurl = false; if (function_exists('curl_init') && false !== ($curlHandle = curl_init())) { curl_setopt($curlHandle, CURLOPT_URL, $recaptchaVerifyURL); curl_setopt($curlHandle, CURLOPT_FAILONERROR, true); curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 5); $curlReturn = curl_exec($curlHandle); if (false === $curlReturn) { trigger_error(curl_error($curlHandle)); } else { $usedCurl = true; $recaptchaCheck = json_decode($curlReturn, true); } curl_close($curlHandle); } if (false === $usedCurl) { $recaptchaCheck = file_get_contents($recaptchaVerifyURL); $recaptchaCheck = json_decode($recaptchaCheck, true); } if (isset($recaptchaCheck['success']) && $recaptchaCheck['success'] === true) { $isValid = true; } else { /** @var \XoopsCaptcha $captchaInstance */ $captchaInstance = \XoopsCaptcha::getInstance(); /** @var array $recaptchaCheck */ foreach ($recaptchaCheck['error-codes'] as $msg) { $captchaInstance->message[] = $msg; } } return $isValid; }
/** * Write a session to the database * * @param string $sess_id * @param string $sess_data * * @return bool **/ public function write($sess_id, $sess_data) { $remoteAddress = \Xmf\IPAddress::fromRequest()->asReadable(); $sess_id = $this->db->quoteString($sess_id); $sql = sprintf('UPDATE %s SET sess_updated = %u, sess_data = %s WHERE sess_id = %s', $this->db->prefix('session'), time(), $this->db->quoteString($sess_data), $sess_id); $this->db->queryF($sql); if (!$this->db->getAffectedRows()) { $sql = sprintf('INSERT INTO %s (sess_id, sess_updated, sess_ip, sess_data) VALUES (%s, %u, %s, %s)', $this->db->prefix('session'), $sess_id, time(), $this->db->quote($remoteAddress), $this->db->quote($sess_data)); return $this->db->queryF($sql); } return true; }
/** * @return bool */ function protector_postcommon() { global $xoopsUser, $xoopsModule; // patch for 2.2.x from xoops.org (I know this is not so beautiful...) if (substr(@XOOPS_VERSION, 6, 3) > 2.0 && false !== stripos(@$_SERVER['REQUEST_URI'], 'modules/system/admin.php?fct=preferences')) { $module_handler = xoops_getHandler('module'); $module = $module_handler->get((int) @$_GET['mod']); if (is_object($module)) { $module->getInfo(); } } // configs writable check if (@$_SERVER['REQUEST_URI'] === '/admin.php' && !is_writable(dirname(__DIR__) . '/configs')) { trigger_error('You should turn the directory ' . dirname(__DIR__) . '/configs writable', E_USER_WARNING); } // Protector object require_once dirname(__DIR__) . '/class/protector.php'; $db = XoopsDatabaseFactory::getDatabaseConnection(); $protector = Protector::getInstance(); $protector->setConn($db->conn); $protector->updateConfFromDb(); $conf = $protector->getConf(); if (empty($conf)) { return true; } // not installed yet // phpmailer vulnerability // http://larholm.com/2007/06/11/phpmailer-0day-remote-execution/ if (in_array(substr(XOOPS_VERSION, 0, 12), array('XOOPS 2.0.16', 'XOOPS 2.0.13', 'XOOPS 2.2.4'))) { $config_handler = xoops_getHandler('config'); $xoopsMailerConfig = $config_handler->getConfigsByCat(XOOPS_CONF_MAILER); if ($xoopsMailerConfig['mailmethod'] === 'sendmail' && md5_file(XOOPS_ROOT_PATH . '/class/mail/phpmailer/class.phpmailer.php') === 'ee1c09a8e579631f0511972f929fe36a') { echo '<strong>phpmailer security hole! Change the preferences of mail from "sendmail" to another, or upgrade the core right now! (message by protector)</strong>'; } } // global enabled or disabled if (!empty($conf['global_disabled'])) { return true; } // group1_ips (groupid=1) if (is_object($xoopsUser) && in_array(1, $xoopsUser->getGroups())) { $group1_ips = $protector->get_group1_ips(true); if (implode('', array_keys($group1_ips))) { $group1_allow = $protector->ip_match($group1_ips); if (empty($group1_allow)) { die('This account is disabled for your IP by Protector.<br>Clear cookie if you want to access this site as a guest.'); } } } // reliable ips $reliable_ips = @unserialize(@$conf['reliable_ips']); if (is_array($reliable_ips)) { foreach ($reliable_ips as $reliable_ip) { if (!empty($reliable_ip) && preg_match('/' . $reliable_ip . '/', $_SERVER['REMOTE_ADDR'])) { return true; } } } // user information (uid and can be banned) if (is_object(@$xoopsUser)) { $uid = $xoopsUser->getVar('uid'); $can_ban = count(@array_intersect($xoopsUser->getGroups(), @unserialize(@$conf['bip_except']))) ? false : true; } else { // login failed check if (!empty($_POST['uname']) && !empty($_POST['pass']) || !empty($_COOKIE['autologin_uname']) && !empty($_COOKIE['autologin_pass'])) { $protector->check_brute_force(); } $uid = 0; $can_ban = true; } // CHECK for spammers IPS/EMAILS during POST Actions if (@$conf['stopforumspam_action'] !== 'none') { $protector->stopforumspam($uid); } // If precheck has already judged that he should be banned if ($can_ban && $protector->_should_be_banned) { $protector->register_bad_ips(); } elseif ($can_ban && $protector->_should_be_banned_time0) { $protector->register_bad_ips(time() + $protector->_conf['banip_time0']); } // DOS/CRAWLER skipping based on 'dirname' or getcwd() $dos_skipping = false; $skip_dirnames = explode('|', @$conf['dos_skipmodules']); if (!is_array($skip_dirnames)) { $skip_dirnames = array(); } if (is_object(@$xoopsModule)) { if (in_array($xoopsModule->getVar('dirname'), $skip_dirnames)) { $dos_skipping = true; } } else { foreach ($skip_dirnames as $skip_dirname) { if ($skip_dirname && false !== strpos(getcwd(), $skip_dirname)) { $dos_skipping = true; break; } } } // module can controll DoS skipping if (defined('PROTECTOR_SKIP_DOS_CHECK')) { $dos_skipping = true; } // DoS Attack if (empty($dos_skipping) && !$protector->check_dos_attack($uid, $can_ban)) { $protector->output_log($protector->last_error_type, $uid, true, 16); } // check session hi-jacking $masks = @$conf['session_fixed_topbit']; $maskArray = explode('/', $masks); $ipv4Mask = empty($maskArray[0]) ? 24 : $maskArray[0]; $ipv6Mask = !isset($maskArray[1]) ? 56 : $maskArray[1]; $ip = \Xmf\IPAddress::fromRequest(); $maskCheck = true; if (isset($_SESSION['protector_last_ip'])) { $maskCheck = $ip->sameSubnet($_SESSION['protector_last_ip'], $ipv4Mask, $ipv6Mask); } if (!$maskCheck) { if (is_object($xoopsUser) && count(array_intersect($xoopsUser->getGroups(), unserialize($conf['groups_denyipmove'])))) { $protector->purge(true); } } $_SESSION['protector_last_ip'] = $ip->asReadable(); // SQL Injection "Isolated /*" if (!$protector->check_sql_isolatedcommentin(@$conf['isocom_action'] & 1)) { if ($conf['isocom_action'] & 8 && $can_ban) { $protector->register_bad_ips(); } elseif ($conf['isocom_action'] & 4 && $can_ban) { $protector->register_bad_ips(time() + $protector->_conf['banip_time0']); } $protector->output_log('ISOCOM', $uid, true, 32); if ($conf['isocom_action'] & 2) { $protector->purge(); } } // SQL Injection "UNION" if (!$protector->check_sql_union(@$conf['union_action'] & 1)) { if ($conf['union_action'] & 8 && $can_ban) { $protector->register_bad_ips(); } elseif ($conf['union_action'] & 4 && $can_ban) { $protector->register_bad_ips(time() + $protector->_conf['banip_time0']); } $protector->output_log('UNION', $uid, true, 32); if ($conf['union_action'] & 2) { $protector->purge(); } } if (!empty($_POST)) { // SPAM Check if (is_object($xoopsUser)) { if (!$xoopsUser->isAdmin() && $conf['spamcount_uri4user']) { $protector->spam_check((int) $conf['spamcount_uri4user'], $xoopsUser->getVar('uid')); } } elseif ($conf['spamcount_uri4guest']) { $protector->spam_check((int) $conf['spamcount_uri4guest'], 0); } // filter plugins for POST on postcommon stage $protector->call_filter('postcommon_post'); } // register.php Protection - both core and profile module have a register.php // There should be an event to trigger this check instead of filename sniffing. if (basename($_SERVER['SCRIPT_FILENAME']) == 'register.php') { $protector->call_filter('postcommon_register'); } return null; }
/** * @return bool|null */ public function check_brute_force() { global $xoopsDB; $ip = \Xmf\IPAddress::fromRequest(); if (false === $ip->asReadable()) { return true; } $uri = @$_SERVER['REQUEST_URI']; $ip4sql = $xoopsDB->quote($ip->asReadable()); $uri4sql = $xoopsDB->quote($uri); $victim_uname = empty($_COOKIE['autologin_uname']) ? $_POST['uname'] : $_COOKIE['autologin_uname']; // some UA send 'deleted' as a value of the deleted cookie. if ($victim_uname === 'deleted') { return null; } $mal4sql = $xoopsDB->quote("BRUTE FORCE: {$victim_uname}"); // gargage collection $result = $xoopsDB->queryF('DELETE FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . ' WHERE expire < UNIX_TIMESTAMP()'); // sql for recording access log (INSERT should be placed after SELECT) $sql4insertlog = 'INSERT INTO ' . $xoopsDB->prefix($this->mydirname . '_access') . " SET ip={$ip4sql}, request_uri={$uri4sql}, malicious_actions={$mal4sql}, expire=UNIX_TIMESTAMP()+600"; // count check $result = $xoopsDB->query('SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . " WHERE ip={$ip4sql} AND malicious_actions like 'BRUTE FORCE:%'"); list($bf_count) = $xoopsDB->fetchRow($result); if ($bf_count > $this->_conf['bf_count']) { $this->register_bad_ips(time() + $this->_conf['banip_time0']); $this->last_error_type = 'BruteForce'; $this->message .= "Trying to login as '" . addslashes($victim_uname) . "' found.\n"; $this->output_log('BRUTE FORCE', 0, true, 1); $ret = $this->call_filter('bruteforce_overrun'); if ($ret == false) { exit; } } // delayed insert $xoopsDB->queryF($sql4insertlog); return null; }
/** * Get client IP * * Adapted from PMA_getIp() [phpmyadmin project] * * @param bool $asString requiring integer or dotted string * @return mixed string or integer value for the IP */ public static function getIP($asString = false) { // Gets the proxy ip sent by the user $proxy_ip = ''; if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $proxy_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) { $proxy_ip = $_SERVER['HTTP_X_FORWARDED']; } elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) { $proxy_ip = $_SERVER['HTTP_FORWARDED_FOR']; } elseif (!empty($_SERVER['HTTP_FORWARDED'])) { $proxy_ip = $_SERVER['HTTP_FORWARDED']; } elseif (!empty($_SERVER['HTTP_VIA'])) { $proxy_ip = $_SERVER['HTTP_VIA']; } elseif (!empty($_SERVER['HTTP_X_COMING_FROM'])) { $proxy_ip = $_SERVER['HTTP_X_COMING_FROM']; } elseif (!empty($_SERVER['HTTP_COMING_FROM'])) { $proxy_ip = $_SERVER['HTTP_COMING_FROM']; } if (!empty($proxy_ip)) { $ip = new \Xmf\IPAddress($proxy_ip); if (false === $ip->asReadable()) { $ip = \Xmf\IPAddress::fromRequest(); } } else { $ip = \Xmf\IPAddress::fromRequest(); } // this really should return $ip->asBinary() instead of ip2long, but for IPv6, this will // return false when the ip2long() fails. Callers are not expecting binary strings. $the_IP = $asString ? $ip->asReadable() : ip2long($ip->asReadable()); return $the_IP; }