// TODO: check number of file additions per dir (hash the entire dir in one operation?) and only read the files if there's a difference global $smd_prognostics_event, $smd_prognostics_checksums, $smd_prognostics_sqlprot; $smd_prognostics_event = 'smd_prognostics'; $smd_prognostics_checksums = rtrim(get_pref('smd_prognostics_dir', txpath, 1), DS) . DS . get_pref('smd_prognostics_prefix', '').'smd_prognostics_checksums.txt'; $hdron = get_pref('smd_prognostics_req_headers', ''); $smd_prognostics_sqlprot = new smd_prog_PhProtector(false); if (@txpinterface == 'admin') { global $smd_prognostics_style, $txp_user, $event; $smd_prognostics_privs = '1,2'; $smd_prognostics_suppress = gps('smd_prognostics_suppress'); $smd_prognostics_style = array( 'msg' => '.smd_prog_warn { margin:0 auto 10px; width:500px; background:#ffc; border:2px dashed red; padding:10px; color:#444; } .smd_prog_warn a { font-weight:bold; color:#963; } .smd_prog_warn span { font-weight:bold; } .smd_prog_warn div { font-weight:bold; padding-bottom:10px; }', 'setup' => '.smd_label { text-align:right!important; vertical-align:middle; } .smd_prog_btns form { display:inline; } .smd_prognostics_setup h3 { margin:25px 0 0; }', 'meter' => '#smd_prog_meter { margin:0 auto; border:1px solid #ccc; width:360px; padding:5px; font-size:120%; } .smd_prog_pass_strength { color:green; font-weight:bold; }', 'advice' => '.smd_prog_advice { width:750px; } #list.smd_prog_advice td { padding:5px; } .smd_prog_btns { width:140px; }', ); $privs = safe_field("privs", "txp_users", "name = '".doSlash($txp_user)."'"); $users = get_pref('smd_prognostics_users', ''); $allow = ($users) ? in_array($txp_user, do_list($users)) : true; if ($allow) { add_privs($smd_prognostics_event, $smd_prognostics_privs); add_privs('plugin_prefs.'.$smd_prognostics_event, $smd_prognostics_privs); register_tab('extensions', $smd_prognostics_event, smd_prognostics_gTxt('smd_prognostics')); register_callback('smd_prognostics_setup', 'plugin_prefs.'.$smd_prognostics_event); register_callback('smd_prognostics_dispatcher', $smd_prognostics_event); } // Password checker goes on the Admin->Users tab for all users if ($event == 'admin') { register_callback('smd_prognostics_chronostrength', 'admin_side', 'head_end'); } if ($hdron) { register_callback('smd_prognostics_request_headers', 'admin_side', 'head_end'); } // Admin side callback for checking files if (!$smd_prognostics_suppress && in_array($privs, do_list($smd_prognostics_privs))) { register_callback('smd_prognostics', 'admin_side', 'pagetop_end'); } } // Public side callbacks if (strpos(get_pref('smd_prognostics_check_where', ''), 'public') !== false) { register_callback('smd_prognostics', 'pretext'); } if ($hdron) { register_callback('smd_prognostics_request_headers', 'pretext'); } if (strpos(get_pref('smd_prognostics_sql_inject', 'smd_no'), 'smd_no') === false) { register_callback('smd_prognostics_sql_inject', 'pretext'); } // ------------------------ function smd_prognostics_dispatcher($evt, $stp) { if(!$stp or !in_array($stp, array( 'smd_prognostics_files', 'smd_prognostics_setup', 'smd_prognostics_advice', 'smd_prognostics_ack', ))) { smd_prognostics_setup(''); } else $stp(); } // Stub to call the verification code from the URL function smd_prognostics($evt, $stp) { return smd_do_prognostics(); } // Verify the file checksums // $mode = 0: normal / 1: no update (return arrays only) / 2: silent update function smd_do_prognostics($mode=0) { global $smd_prognostics_event, $smd_prognostics_checksums, $smd_prognostics_style; $now = time(); $nok = $miss = $added = $allfiles = $hashdown = $hashmod = array(); $timenow = date('H:i:s', $now); list($beg, $end) = do_list(get_pref('smd_prognostics_check_between', '|'), '|'); // Default is pipe so we can guarantee two return vals $tdiff = ($mode==1 || ($now - get_pref('smd_prognostics_lastcheck', 0) > get_pref('smd_prognostics_check_freq', 3600)) && ($timenow>$beg) && ($timenow<$end) ) ? true : false; // Parts shamelessly plagiarised from txp_diag if ($tdiff) { $sumhash = get_pref('smd_prognostics_sumhash', NULL, ($mode==1 ? 1 : 0)); $lookat = get_pref('smd_prognostics_check_for', ''); $adds = (strpos($lookat, 'add') !== false); $dels = (strpos($lookat, 'delete') !== false); $mods = (strpos($lookat, 'modify') !== false); if ($cs = @file($smd_prognostics_checksums)) { $hash = md5(smd_prognostics_prep_file($smd_prognostics_checksums)); if ($hash != $sumhash) { $hashmod[] = $smd_prognostics_checksums; } else { $ctr = 0; $qty_per = (($qty = get_pref('smd_prognostics_check_qty', '')) == '') ? count($cs) : $qty; $so_far = get_pref('smd_prognostics_qty_so_far', 0); $until = $so_far + $qty_per; foreach ($cs as $c) { if (preg_match('@^(\S+): \((.*)\)$@', trim($c), $m)) { list(,$file,$md5) = $m; if ($dels && !file_exists($file)) { $miss[] = $file; } else if ($mods && $md5 != 'NULL') { if ( file_exists($file) && ( (($ctr >= $so_far) && ($ctr < $until) || $mode == 1) ) ) { $content = smd_prognostics_prep_file($file); if ((md5($content) != $md5) && ($file != $smd_prognostics_checksums)) { $nok[] = $file; } } $ctr++; } $allfiles[] = $file; } } // Stash the story so far ready for next time the function is called if ($mode != 1) { set_pref('smd_prognostics_qty_so_far', (($until < $ctr) ? $until : 0), 'smd_prognos', PREF_HIDDEN, 'text_input'); } if ($adds) { $filelist = smd_prognostics_readfiles(); $added = array_diff($filelist, $allfiles); } if ($mode != 1) { set_pref('smd_prognostics_lastcheck', $now, 'smd_prognos', PREF_HIDDEN, 'text_input'); } } } else { // File doesn't exist $hashdown[] = $smd_prognostics_checksums; } } // Assemble message if ($nok || $miss || $added || $hashdown || $hashmod) { if ($mode==1) { return array($nok, $miss, $added, $hashdown, $hashmod); } else { $via = get_pref('smd_prognostics_notify_via', ''); $detect = get_pref('smd_prognostics_lastdetect', ''); $lasts = explode(',', get_pref('smd_prognostics_lastact', 0)); $freqs = explode(',', get_pref('smd_prognostics_alarm_freq', 86400)); if (!isset($lasts[1])) { $lasts[1] = $lasts[0]; } if (!isset($freqs[1])) { $freqs[1] = $freqs[0]; } $lastact_txp = ($mode < 2 && ($now - $lasts[0] > $freqs[0])) ? true : false; $lastact_mail = ($mode < 2 && ($now - $lasts[1] > $freqs[1])) ? true : false; $lastmsg = get_pref('smd_prognostics_lastmsg', ''); $subject = smd_prognostics_gTxt('subject'); $msg = join('|', array_merge($hashdown, $hashmod, $nok, $miss, $added)); if (@txpinterface == 'admin' && strpos($via, 'txp') !== false) { if ($lastact_txp || ($lastmsg != md5($msg))) { $txpdir = get_pref('smd_prognostics_txpdir', hu.smd_prognostics_guess_admin_dir()); $out = '
'.$subject.'
'. (($hashdown) ? '

'.smd_prognostics_gTxt('preamble_hashdown').'

' : ''). (($hashmod) ? '

'.smd_prognostics_gTxt('preamble_hashmod').'

' : ''). (($nok) ? '

'.smd_prognostics_gTxt('preamble_nok').'

' : ''). (($miss) ? '

'.smd_prognostics_gTxt('preamble_miss').'

' : ''). (($added) ? '

'.smd_prognostics_gTxt('preamble_added').'

' : ''). '

'. smd_prognostics_gTxt('postamble').'

'; set_pref('smd_prognostics_lastact', $now.','.$lasts[1], 'smd_prognos', PREF_HIDDEN, 'text_input'); echo $out; } } if (strpos($via, 'email') !== false) { if ($lastact_mail || ($lastmsg != md5($msg))) { $to = get_pref('smd_prognostics_mailto', ''); if ($to) { $hdrs = smd_prognostics_header_info('smd_prognostics'); $body = (($hashdown) ? n.smd_prognostics_gTxt('preamble_hashdown').n.n.join(n,$hashdown) : ''). (($hashmod) ? n.smd_prognostics_gTxt('preamble_hashmod').n.n.join(n,$hashmod) : ''). (($nok) ? n.smd_prognostics_gTxt('preamble_nok').n.n.join(n,$nok) : ''). (($miss) ? n.n.smd_prognostics_gTxt('preamble_miss').n.n.join(n,$miss) : ''). (($added) ? n.n.smd_prognostics_gTxt('preamble_added').n.n.join(n,$added) : ''). n.n.''.smd_prognostics_gTxt('postamble').''; mail($to, $subject, $body, $hdrs['headers']); } set_pref('smd_prognostics_lastact', $lasts[0].','.$now, 'smd_prognos', PREF_HIDDEN, 'text_input'); } } set_pref('smd_prognostics_lastmsg', md5($msg), 'smd_prognos', PREF_HIDDEN, 'text_input'); if ($lastmsg != md5($msg)) { if ($detect == '') { set_pref('smd_prognostics_lastdetect', $now, 'smd_prognos', PREF_HIDDEN, 'text_input'); } else { $detect = explode(',',$detect); set_pref('smd_prognostics_lastdetect', $detect[0].','.$now, 'smd_prognos', PREF_HIDDEN, 'text_input'); } } } } } // ---------- Catch unexpected request headers function smd_prognostics_request_headers($evt, $stp) { $block = explode('|', get_pref('smd_prognostics_req_headers', '')); $hdr = serverSet('REQUEST_METHOD'); if (in_array($hdr, $block)) { $send = (strpos(get_pref('smd_prognostics_rt_forensics'), 'hdr') !== false); // Send the forensics off if necessary $to = get_pref('smd_prognostics_mailto_csi', ''); if ($to && $send) { $subject = smd_prognostics_gTxt('subject_csi'); $hdrs = smd_prognostics_header_info('smd_frognostics'); $body = n.smd_prognostics_gTxt('req_not_allowed', array('{req}' => $hdr)).n; foreach ($_SERVER + $_REQUEST + $_ENV as $key => $var) { $body .= n.$key.': '.$var; } mail($to, $subject, $body, $hdrs['headers']); } //TODO: offer alternative die mechanisms like SQL attacks? exit(1); } } // ---------- SQL injection detection function smd_prognostics_sql_inject() { global $smd_prognostics_sqlprot, $permlink_mode; // Determine comment preview step and ignore if so $is_prevu = false; $com = psa(array( 'parentid', 'preview', 'backpage', )); if ($com['preview']) { $urlparts = explode('/', $com['backpage']); $num = ($permlink_mode == 'messy') ? 1 : count($urlparts); $artic = safe_field('id','textpattern', "ID=".doSlash($com['parentid']).(($num > 1) ? " AND url_title='".doSlash($urlparts[$num-1])."'" : '')); $is_prevu = ($artic) ? true : false; } if(!$is_prevu && $smd_prognostics_sqlprot->isMalicious()) { $opts = do_list(get_pref('smd_prognostics_sql_inject', '|'), '|'); $blok = (strpos($opts[0], 'smd_block') !== false); $send = (strpos(get_pref('smd_prognostics_rt_forensics'), 'sql') !== false); $ver = (defined('txp_version')) ? txp_version : get_pref('version', ''); // Send the forensics off if necessary $to = get_pref('smd_prognostics_mailto_csi', ''); if ($to && $send) { $subject = smd_prognostics_gTxt('subject_csi'); $hdrs = smd_prognostics_header_info('smd_frognostics'); $body = n.smd_prognostics_gTxt('preamble_sql_inject').n; $body .= (($ver) ? 'TXP: ' . $ver .n : '') . 'PHP: ' . phpversion() .n. 'MySQL: ' . mysql_get_server_info() .n. ((is_callable('apache_get_version')) ? 'Apache: ' . apache_get_version().n : ''); foreach ($_SERVER + $_REQUEST + $_ENV as $key => $var) { $body .= n.$key.': '.$var; } mail($to, $subject, $body, $hdrs['headers']); } if (isset($opts[1]) && !empty($opts[1])) { $parts = do_list($opts[1], ':'); if ($parts[0] == 'txp_form') { $msg = parse_form($parts[1]); } else { $msg = $opts[1]; } } else { $msg = ''; } if ($blok) { echo $msg; exit(1); } else { txp_die($msg, $opts[0]); } } } // ----------------- // Admin-side panels // ----------------- // ---------- Alarm acknowledgement function smd_prognostics_ack($msg='') { global $smd_prognostics_event, $smd_prognostics_checksums, $prefs; $submit = gps('submit'); $ignore = gps('ignore'); $csi = gps('csi'); $ack = gps('selected'); $smd_prog_ack = (is_array($ack)) ? $ack : (($ack) ? array($ack) : array()); $out = array(); if ($submit || $ignore) { if ($cs = @file($smd_prognostics_checksums)) { foreach ($cs as $c) { if (preg_match('@^(\S+): \((.*)\)$@', trim($c), $m)) { list(,$file,$md5) = $m; if (($key = array_search($file, $smd_prog_ack)) !== false) { if (file_exists($file)) { $content = smd_prognostics_prep_file($file); $out[] = $file.': ('.( ($ignore) ? 'NULL' : md5($content) ).')'; } // Remove files that already have checksums so we're left with additions unset($smd_prog_ack[$key]); } else { $out[] = trim($c); } } } // Tack on any new files foreach ($smd_prog_ack as $file) { if (file_exists($file) && $file != $smd_prognostics_checksums) { $content = smd_prognostics_prep_file($file); $out[] = $file.': ('.( ($ignore) ? 'NULL' : md5($content) ).')'; } } $fh = fopen($smd_prognostics_checksums, "w"); fwrite($fh, join(n, $out)); fclose($fh); smd_prognostics_self_hash(); $msg = smd_prognostics_gTxt('acked'); } } if ($csi && $smd_prog_ack) { $msg = smd_prognostics_gTxt('csi_sent'); } else if ($csi) { $msg = smd_prognostics_gTxt('none_selected'); } pagetop(smd_prognostics_gTxt('smd_prognostics'), $msg); extract(smd_prognostics_buttons()); list($nok, $miss, $added, $hashdown, $hashmod) = smd_do_prognostics(1); $nok = is_array($nok) ? $nok : array(); $miss = is_array($miss) ? $miss : array(); $added = is_array($added) ? $added : array(); $hashmod = is_array($hashmod) ? $hashmod : array(); $errnum = count(array_merge($nok, $miss, $added, $hashmod)); $forensics = array(); $lform = 'Y-m-d H:i:s'; echo $btnCSS.startTable('list'); echo tr(tda(strong(smd_prognostics_gTxt('ttl_ack')), ' colspan="3"') . tda($btnSetup.$btnFiles.$btnAdvice, $btnStyle) ); echo '
'; if ($errnum > 0) { foreach($hashmod as $naughty) { $sel = in_array($naughty, $smd_prog_ack); echo tr(td(checkbox('selected[]', $naughty, $sel), '', 'multi-edit').tda(smd_prognostics_gTxt('lbl_hashmod')).tda($naughty)); } foreach($nok as $naughty) { $sel = in_array($naughty, $smd_prog_ack); echo tr(td(checkbox('selected[]', $naughty, $sel), '', 'multi-edit').tda(smd_prognostics_gTxt('lbl_changed')).tda($naughty)); if ($sel) { $fi = stat($naughty); $forensics['nok'][] = smd_prognostics_forensic_output($naughty, $fi); $forensics['files'][$naughty] = chunk_split(base64_encode(file_get_contents($naughty))); } } foreach($miss as $naughty) { $sel = in_array($naughty, $smd_prog_ack); echo tr(td(checkbox('selected[]', $naughty, $sel), '', 'multi-edit').tda(smd_prognostics_gTxt('lbl_missing')).tda($naughty)); if ($sel) { $forensics['miss'][] = $naughty; } } foreach($added as $naughty) { $sel = in_array($naughty, $smd_prog_ack); echo tr(td(checkbox('selected[]', $naughty, $sel), '', 'multi-edit').tda(smd_prognostics_gTxt('lbl_added')).tda($naughty)); if ($sel) { $fi = stat($naughty); $forensics['added'][] = smd_prognostics_forensic_output($naughty, $fi); $forensics['files'][$naughty] = chunk_split(base64_encode(file_get_contents($naughty))); } } if ($smd_prog_ack && $prefs['logging'] != 'none') { $detect = explode(',',get_pref('smd_prognostics_lastdetect', time())); if (!isset($detect[1])) { $detect[1] = $detect[0]; } $rs = safe_rows('*', 'txp_log', "time BETWEEN '" . date($lform, ($detect[0] - $prefs['smd_prognostics_check_freq'])) . "' AND '" . date($lform, ($detect[1] + 5)) . "'"); foreach ($rs as $row) { $forensics['txp_log'][] = join(',',$row); } } echo tr(tda( select_buttons() ,' class="multi-edit" colspan="3" style="text-align: right; border: none;"')); echo tr(tda($btnAckIt.$btnIgnore.((get_pref('smd_prognostics_mailto_csi', '')) ? $btnCSI : ''), $btnStyle)); } else { echo tr(td(smd_prognostics_gTxt('no_alarms'))); set_pref('smd_prognostics_lastdetect', '', 'smd_prognos', PREF_HIDDEN, 'text_input'); } echo '
'; echo endTable(); if ($csi && $forensics) { // Send the forensics off $to = get_pref('smd_prognostics_mailto_csi', ''); if ($to) { $subject = smd_prognostics_gTxt('subject_csi'); $hdrs = smd_prognostics_header_info('smd_frognostics'); $body = n.'TXP: ' . txp_version .n. 'PHP: ' . phpversion() .n. 'MySQL: ' . mysql_get_server_info() .n. ((is_callable('apache_get_version')) ? 'Apache: ' . apache_get_version().n : ''). ((isset($forensics['nok'])) ? n.smd_prognostics_gTxt('preamble_nok').n.join(n,$forensics['nok']) : ''). ((isset($forensics['miss'])) ? n.n.smd_prognostics_gTxt('preamble_miss').n.join(n,$forensics['miss']) : ''). ((isset($forensics['added'])) ? n.n.smd_prognostics_gTxt('preamble_added').n.join(n,$forensics['added']) : ''). ((isset($forensics['txp_log'])) ? n.n.smd_prognostics_gTxt('preamble_txplog').n.join(n,$forensics['txp_log']) : n.n.smd_prognostics_gTxt('no_log_entries')); if (isset($forensics['files'])) { $body .= n.n.smd_prognostics_gTxt('preamble_files'); foreach ($forensics['files'] as $fn => $content) { $body .= n.n.$fn.n.n.$content.n; } } mail($to, $subject, $body, $hdrs['headers']); } } } // ---------- File management function smd_prognostics_files($msg='') { global $smd_prognostics_event, $smd_prognostics_checksums; extract(doSlash(gpsa(array('submit')))); $smd_prognostics_files = gps('smd_prognostics_files'); if (!is_array($smd_prognostics_files)) { $smd_prognostics_files = array(); } $adds = (strpos(get_pref('smd_prognostics_check_for'), 'add') !== false); $filelist = smd_prognostics_readfiles(); $allcount = count($filelist); if ($submit) { $outfile = array(); foreach ($smd_prognostics_files as $file) { $content = smd_prognostics_prep_file($file); $outfile[] = $file.': ('.md5($content).')'; } $fh = fopen($smd_prognostics_checksums, "w"); fwrite($fh, join(n, $outfile)); if ($adds) { $additions = array_diff($filelist, $smd_prognostics_files); $added = array(); foreach ($additions as $addition) { $added[] = $addition.': (NULL)'; } fwrite($fh, n.join(n, $added)); } fclose($fh); smd_prognostics_self_hash(); smd_do_prognostics(2); // Silently acknowledge all the files set_pref('smd_prognostics_lastdetect', '', 'smd_prognos', PREF_HIDDEN, 'text_input'); $msg = smd_prognostics_gTxt('files_updated'); } pagetop(smd_prognostics_gTxt('smd_prognostics'), $msg); extract(smd_prognostics_buttons()); $smd_prognostics_files = array(); if ($cs = @file($smd_prognostics_checksums)) { foreach ($cs as $c) { if (preg_match('@^(\S+): \((.*)\)$@', trim($c), $m)) { list(,$file,$md5) = $m; if ($md5 != 'NULL') { $smd_prognostics_files[] = $file; } } } } $moncount = count($smd_prognostics_files); if ($filelist) { $filez = array(); foreach($filelist as $key => $val) { $filez[$val] = $filelist[$key]; } $filesel = smd_prognostics_multisel('smd_prognostics_files', $filez, $smd_prognostics_files); } $showfiles = (isset($filesel) && $filesel); echo $btnCSS.startTable('list'); echo tr(tda(strong(smd_prognostics_gTxt('ttl_files'))) . tda($btnSetup.$btnAck.$btnAdvice, $btnStyle) ); echo tr(tdcs(smd_prognostics_gTxt('currmon', array('{curr}' => $moncount, '{outof}' => $allcount)) .(($showfiles) ? br.br. smd_prognostics_gTxt('monfiles_explain') : ''), 1, 400)); echo '
'; echo ($showfiles) ? tr(tda($filesel)) : tr(tda(smd_prognostics_gTxt('no_files'))); echo tr(tda(fInput('hidden', 'smd_prognostics_suppress', 1).$btnSave, $btnStyle)); echo '
'; echo endTable(); } // ---------- Setup / prefs function smd_prognostics_setup($msg='') { global $smd_prognostics_event, $smd_prognostics_checksums, $prefs; $origloc = get_pref('smd_prognostics_listloc', realpath(txpath.DS.'..'.DS).DS, 1); $origexc = get_pref('smd_prognostics_excludir', 'images, files, tmp', 1); $origdir = rtrim(get_pref('smd_prognostics_dir', realpath(txpath), 1), DS); $origpfx = get_pref('smd_prognostics_prefix', '', 1); $preflist = array( 'smd_prognostics_check_freq', 'smd_prognostics_check_qty', 'smd_prognostics_alarm_freq', 'smd_prognostics_check_where', 'smd_prognostics_mailto', 'smd_prognostics_mailto_csi', 'smd_prognostics_users', 'smd_prognostics_dir', 'smd_prognostics_prefix', 'smd_prognostics_listloc', 'smd_prognostics_excludir', 'smd_prognostics_ignores', 'smd_prognostics_txpdir', ); $warnloc = ''; $notify = gps('smd_prognostics_notify_via'); $chfor = gps('smd_prognostics_check_for'); $reqs = gps('smd_prognostics_req_headers'); $sqlin = gps('smd_prognostics_sql_inject'); $tween = gps('smd_prognostics_check_between'); $rtfor = gps('smd_prognostics_rt_forensics'); // Only one of these valid status codes is allowed to be thrown $throw_codes = array( 'smd_no' => gTxt('no'), 'smd_block' => smd_prognostics_gTxt('block'), '200' => '200 OK', '301' => '301 Moved Permanently', '302' => '302 Found', '307' => '307 Temporary Redirect', '401' => '401 Unauthorized', '403' => '403 Forbidden', '404' => '404 Not Found', '410' => '410 Gone', '414' => '414 Request-URI Too Long', '500' => '500 Internal Server Error', '501' => '501 Not Implemented', ); if (!in_array($throw[0], $throw_codes) ) { $throw[0] = '400'; } foreach ($tween as $idx => $val) { if (empty($val)) { $tween[$idx] = ($idx==0) ? '00:00' : '23:59'; } else { $timeparts = do_list($val, ':'); foreach ($timeparts as $num) { if (!is_numeric($num)) { $tween[$idx] = ($idx==0) ? '00:00' : '23:59'; break; } } } } $smd_prognostics_notify_via = join('|', ((is_array($notify)) ? $notify : array($notify))); $smd_prognostics_check_for = join('|', ((is_array($chfor)) ? $chfor : array($chfor))); $smd_prognostics_req_headers = join('|', ((is_array($reqs)) ? $reqs : array($reqs))); $smd_prognostics_sql_inject = join('|', ((is_array($sqlin)) ? $sqlin : array($sqlin))); $smd_prognostics_check_between = join('|', ((is_array($tween)) ? $tween : array($tween))); $smd_prognostics_rt_forensics = join('|', ((is_array($rtfor)) ? $rtfor : array($rtfor))); // Grab the saved pref values and tack on the array item(s) extract(doSlash(gpsa(array_merge(array('submit'), $preflist)))); $preflist[] = 'smd_prognostics_notify_via'; $preflist[] = 'smd_prognostics_check_for'; $preflist[] = 'smd_prognostics_req_headers'; $preflist[] = 'smd_prognostics_sql_inject'; $preflist[] = 'smd_prognostics_check_between'; $preflist[] = 'smd_prognostics_rt_forensics'; $smd_prognostics_dir = rtrim($smd_prognostics_dir, DS); if ($submit) { if (($smd_prognostics_dir != $origdir) || ($smd_prognostics_prefix != $origpfx)) { if (is_dir($smd_prognostics_dir) && is_writable($smd_prognostics_dir)) { // Everything OK so do nothing for now } else { // Ignore new dir and reset it to what it was before $msg = array(smd_prognostics_gTxt('not_writable', array('{location}' => $smd_prognostics_dir)), E_WARNING); $smd_prognostics_dir = $origdir; } // Room for more config files as and when they are required $filelist[] = $smd_prognostics_checksums; foreach ($filelist as $file) { $filename = $smd_prognostics_prefix.ltrim(basename($file), $origpfx); rename($file, rtrim($smd_prognostics_dir, DS).DS.$filename); } } // Write all the prefs foreach ($preflist as $prefval) { set_pref(doSlash($prefval), doSlash($$prefval), 'smd_prognos', PREF_HIDDEN, 'text_input'); } if ( ($smd_prognostics_listloc != $origloc) || ($smd_prognostics_excludir != $origexc) ) { $msg = array(smd_prognostics_gTxt('warn_loc'), E_WARNING); } if (!$msg) { $msg = gTxt('preferences_saved'); } } pagetop(smd_prognostics_gTxt('smd_prognostics'), $msg); $smd_prognostics_dir = get_pref('smd_prognostics_dir', txpath, 1); $smd_prognostics_prefix = get_pref('smd_prognostics_prefix', '', 1); $smd_prognostics_check_for = get_pref('smd_prognostics_check_for', 'delete|modify', 1); $smd_prognostics_check_where = get_pref('smd_prognostics_check_where', 'admin', 1); $smd_prognostics_check_freq = get_pref('smd_prognostics_check_freq', 10, 1); $smd_prognostics_check_between = get_pref('smd_prognostics_check_between', '00:00|23:59', 1); $smd_prognostics_check_qty = get_pref('smd_prognostics_check_qty', '30', 1); $smd_prognostics_alarm_freq = get_pref('smd_prognostics_alarm_freq', 86400, 1); $smd_prognostics_notify_via = get_pref('smd_prognostics_notify_via', '', 1); $smd_prognostics_mailto = get_pref('smd_prognostics_mailto', '', 1); $smd_prognostics_mailto_csi = get_pref('smd_prognostics_mailto_csi', '', 1); $smd_prognostics_users = get_pref('smd_prognostics_users', '', 1); $smd_prognostics_listloc = get_pref('smd_prognostics_listloc', realpath(txpath.DS.'..'.DS).DS, 1); $smd_prognostics_excludir = get_pref('smd_prognostics_excludir', 'images, files, tmp', 1); $smd_prognostics_ignores = get_pref('smd_prognostics_ignores', 'error_log', 1); $smd_prognostics_req_headers = get_pref('smd_prognostics_req_headers', 'TRACE|PUT|DELETE', 1); $smd_prognostics_sql_inject = get_pref('smd_prognostics_sql_inject', '0|', 1); $smd_prognostics_rt_forensics = get_pref('smd_prognostics_rt_forensics', '1|1', 1); $smd_prognostics_txpdir = get_pref('smd_prognostics_txpdir', hu.smd_prognostics_guess_admin_dir(), 1); extract(smd_prognostics_buttons()); $adds = (strpos($smd_prognostics_check_for, 'add') !== false); $dels = (strpos($smd_prognostics_check_for, 'delete') !== false); $mods = (strpos($smd_prognostics_check_for, 'modify') !== false); $rh_trace = (strpos($smd_prognostics_req_headers, 'TRACE') !== false); $rh_put = (strpos($smd_prognostics_req_headers, 'PUT') !== false); $rh_del = (strpos($smd_prognostics_req_headers, 'DELETE') !== false); $rt_hdr = (strpos($smd_prognostics_rt_forensics, 'hdr') !== false); $rt_sql = (strpos($smd_prognostics_rt_forensics, 'sql') !== false); $tweens = do_list($smd_prognostics_check_between, '|'); $throws = do_list($smd_prognostics_sql_inject, '|'); $helpLink = "?event=plugin&step=plugin_help&name=$smd_prognostics_event#smd_setup"; echo $btnCSS.startTable('list', '', 'smd_prognostics_setup'); echo tr(tdcs(strong(smd_prognostics_gTxt('ttl_setup')).sp.smd_prognostics_gTxt('help_link', array('{link}' => $helpLink)), 2) . tda($btnFiles.$btnAck.$btnAdvice, $btnStyle) ); echo '
'; echo tr(tdcs(hed(smd_prognostics_gTxt('ttl_monopts'), 3) ,2)); echo tr( tda(smd_prognostics_gTxt('check_where'), ' class="smd_label"'). tda(radioSet( array( 'admin' => gTxt('no'), 'admin|public' => gTxt('yes') ), 'smd_prognostics_check_where', $smd_prognostics_check_where), ' id="smd_prognostics_check_where"') ); echo tr( tda(smd_prognostics_gTxt('check_freq'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_check_freq', $smd_prognostics_check_freq, '','','',15).sp.smd_prognostics_gTxt('seconds')) ); echo tr( tda(smd_prognostics_gTxt('check_between'), ' class="smd_label"'). tda( fInput('text', 'smd_prognostics_check_between[]', $tweens[0], '','','',15). smd_prognostics_gTxt('and'). fInput('text', 'smd_prognostics_check_between[]', $tweens[1], '','','',15).sp.smd_prognostics_gTxt('hms') ) ); echo tr( tda(smd_prognostics_gTxt('check_qty'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_check_qty', $smd_prognostics_check_qty, '','','',15)) ); echo tr( tda(smd_prognostics_gTxt('alarm_freq'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_alarm_freq', $smd_prognostics_alarm_freq, '','','',15).sp.smd_prognostics_gTxt('seconds')) ); echo tr( tda(smd_prognostics_gTxt('notify_via'), ' class="smd_label"'). tda( checkbox('smd_prognostics_notify_via[]', 'txp', strpos($smd_prognostics_notify_via, 'txp') !== false) . ''. checkbox('smd_prognostics_notify_via[]', 'email', strpos($smd_prognostics_notify_via, 'email') !== false). '' ) ); echo tr( tda(smd_prognostics_gTxt('mailto'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_mailto', $smd_prognostics_mailto, '','','',60).sp.smd_prognostics_gTxt('csv')) ); echo tr( tda(smd_prognostics_gTxt('mailto_csi'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_mailto_csi', $smd_prognostics_mailto_csi, '','','',60).sp.smd_prognostics_gTxt('csv')) ); echo tr(tdcs(hed(smd_prognostics_gTxt('ttl_realopts'), 3), 2)); echo tr( tda(smd_prognostics_gTxt('req_headers'), ' class="smd_label"'). tda( checkbox('smd_prognostics_req_headers[]', 'TRACE', $rh_trace). ''. checkbox('smd_prognostics_req_headers[]', 'PUT', $rh_put). ''. checkbox('smd_prognostics_req_headers[]', 'DELETE', $rh_del). '' ) ); echo tr( tda(smd_prognostics_gTxt('sql_inject'), ' class="smd_label"'). tda( selectInput('smd_prognostics_sql_inject[]', $throw_codes, $throws[0], 0). smd_prognostics_gTxt('with'). fInput('text', 'smd_prognostics_sql_inject[]', $throws[1], '','','',60) ) ); echo tr( tda(smd_prognostics_gTxt('send_forensics'), ' class="smd_label"'). tda( checkbox('smd_prognostics_rt_forensics[]', 'hdr', $rt_hdr). ''. checkbox('smd_prognostics_rt_forensics[]', 'sql', $rt_sql). '' ) ); echo tr(tdcs(hed(smd_prognostics_gTxt('ttl_fileopts'), 3), 2)); echo tr( tda(smd_prognostics_gTxt('check_for'), ' class="smd_label"'). tda( checkbox('smd_prognostics_check_for[]', 'add', $adds) . ''. checkbox('smd_prognostics_check_for[]', 'delete', $dels). ''. checkbox('smd_prognostics_check_for[]', 'modify', $mods). '' ) ); echo tr( tda(smd_prognostics_gTxt('listloc'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_listloc', $smd_prognostics_listloc, '','','',60).sp.smd_prognostics_gTxt('csv')) ); echo tr( tda(smd_prognostics_gTxt('excludir'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_excludir', $smd_prognostics_excludir, '','','',60).sp.smd_prognostics_gTxt('csv')) ); echo tr( tda(smd_prognostics_gTxt('ignores'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_ignores', $smd_prognostics_ignores, '','','',60).sp.smd_prognostics_gTxt('csv')) ); echo tr(tdcs(hed(smd_prognostics_gTxt('ttl_plugopts'), 3), 2)); echo tr( tda(smd_prognostics_gTxt('auth_users'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_users', $smd_prognostics_users, '','','',60).sp.smd_prognostics_gTxt('csv')) ); echo tr( tda(smd_prognostics_gTxt('txpdir'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_txpdir', $smd_prognostics_txpdir, '','','',60)) ); echo tr( tda(smd_prognostics_gTxt('progloc'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_dir', $smd_prognostics_dir, '','','',60)) ); echo tr( tda(smd_prognostics_gTxt('progpfx'), ' class="smd_label"'). tda(fInput('text', 'smd_prognostics_prefix', $smd_prognostics_prefix, '','','',60)) ); echo tr(tda($btnSave, $btnStyle)); echo '
'; echo endTable(); } // ---------- Security advice function smd_prognostics_advice($msg='') { global $smd_prognostics_event, $smd_prognostics_style, $prefs; require_once txpath.'/lib/IXRClass.php'; pagetop(smd_prognostics_gTxt('smd_prognostics'), $msg); extract(smd_prognostics_buttons()); $checks = array(); // Prognostics dir in docroot? if (strpos(get_pref('smd_prognostics_dir', txpath), $prefs['path_to_site']) !== false) { $checks[] = smd_prognostics_gTxt('docroot_prognostics'); } // Setup still exists? if (@is_dir(txpath . DS. 'setup')) { $checks[] = smd_prognostics_gTxt('setup_exists'); } // RPC still exists? if (@is_dir(realpath(txpath.DS.'..'.DS. 'rpc')) && $prefs['enable_xmlrpc_server'] == 0) { $checks[] = smd_prognostics_gTxt('rpc_exists'); } // New TXP version/branch available? Adapted from txplib_update.php $client = new IXR_Client('http://rpc.textpattern.com'); $uid = get_pref('blog_uid', md5(uniqid(mt_rand(),true))); if ($client->query('tups.getTXPVersion',$uid)) { $response = $client->getResponse(); if (is_array($response)) { ksort($response); $version = get_pref('version', ''); $lversion = explode('.',$version); $branch = substr($version,0,3); foreach ($response as $key => $val) { $rversion = explode('.',$val); if ($key == 'txp_current_version_'.$branch) { if (isset($lversion[2]) && isset($rversion[2]) && (intval($rversion[2])>intval($lversion[2]))) { $most_recent = smd_prognostics_gTxt('avail_branch').': '.$val; } } else { if (intval($rversion[0])>intval($lversion[0]) || intval($rversion[1])>intval($lversion[1])) { $most_recent = smd_prognostics_gTxt('avail_txp').': '.$val; } } } if (isset($most_recent)) { $checks[] = $most_recent; } } } // Files dir in docroot? if (strpos($prefs['file_base_path'], $prefs['path_to_site']) !== false) { $checks[] = smd_prognostics_gTxt('docroot_files'); } // Tmp dir in docroot? if (strpos($prefs['tempdir'], $prefs['path_to_site']) !== false) { $checks[] = smd_prognostics_gTxt('docroot_tmp'); } /* // TODO: check what SHOW GRANTS returns and determine if it could be a security risk $res = safe_query('SHOW GRANTS'); if (numRows($res) > 0) { $checks[] = smd_prognostics_gTxt('show_grants'); } */ // Does this MySQL user have FILES privs? $randfile = $prefs['tempdir'].DS.rand().time().'.sql'; $res = @safe_query('SELECT id INTO OUTFILE "'.$randfile.'" FIELDS TERMINATED BY "\t" LINES TERMINATED BY "\n" FROM txp_image WHERE 1 LIMIT 1'); if (mysql_error() == '') { $checks[] = smd_prognostics_gTxt('sql_file_privs'); if (is_file($randfile)) { @unlink($randfile); } } echo ''.startTable('list', '', 'smd_prog_advice'); echo tr(tda(strong(smd_prognostics_gTxt('ttl_advice'))) . tda($btnSetup.$btnFiles.$btnAck, $btnStyle) ); if ($checks) { foreach($checks as $check) { echo tr(tda($check)); } } else { echo tr(tda(smd_prognostics_gTxt('tight'))); } echo endTable(); } // ---------- Hash the hashfile function smd_prognostics_self_hash() { global $smd_prognostics_checksums; if (file_exists($smd_prognostics_checksums)) { $content = smd_prognostics_prep_file($smd_prognostics_checksums); $hash = md5($content); } else { $hash = NULL; } set_pref('smd_prognostics_sumhash', $hash, 'smd_prognos', PREF_HIDDEN, 'text_input'); } // ---------- Compile list of files to monitor function smd_prognostics_readfiles() { $filelist = array(); $smd_prognostics_listloc = get_pref('smd_prognostics_listloc', ''); $smd_prognostics_excludir = do_list(get_pref('smd_prognostics_excludir', '')); $smd_prognostics_ignores = get_pref('smd_prognostics_ignores', ''); if ($smd_prognostics_listloc) { foreach (do_list($smd_prognostics_listloc) as $loc) { // NOTE: not using GLOB_BRACE to grab regular and dot files, since it's not always available cross-OS $filelist = array_merge($filelist, smd_prognostics_rglob("*", GLOB_MARK, $loc, $smd_prognostics_excludir, $smd_prognostics_ignores), smd_prognostics_rglob(".*", GLOB_MARK, $loc, $smd_prognostics_excludir, $smd_prognostics_ignores)); } } return $filelist; } // ---------- Prepare file contents for md5. Assumes file exists // Checks to see if large files are binary before wasting time stripping newlines and stuff function smd_prognostics_prep_file($file) { $content = file_get_contents($file); $stat = stat($file); $dostrip = true; // Perform the strip regardless on files < 1Kb as it has little impact if ($stat['size'] > 1024000) { $part = substr($content, 0, 1536000); // First 1.5KB if (strpos($part, 0x00) || (strpos($part, 0x0D) !== false) || (strpos($part, 0x0A) !== false)) { // Likely a binary file: leave it be $dostrip = false; } } if ($dostrip) { $content = strtr( $content, array("\r\n" => "\n", "\$HeadURL: http:" => "\$HeadURL: https:") ); } return $content; } // Frankensteined from http://snipplr.com/view/16233/recursive-glob/ function smd_prognostics_rglob($pattern, $flags=0, $path='', $excl=array(), $ign='') { global $smd_prognostics_checksums; // Add any files to permanently exclude here (NOT dirs: they're ignored automatically) $ignarr = ($ign) ? do_list($ign) : array(); // Expand any wildcard filenames $regarr = array(); foreach ($ignarr as $idx => $item) { if ( (strpos($item, '*') !== false) || (strpos($item, '?') !== false) ) { $regarr[] = strtr( preg_quote($item), array("\*" => ".*", "\?" => ".") ); unset($ignarr[$idx]); // Remove the wildcard filename from the ignore list } } $regexclude = ($regarr) ? '/^(' . join('|', $regarr) . ')$/' : ''; $permexclude = array_merge(array(basename($smd_prognostics_checksums)), $ignarr); if (!$path && ($dir = dirname($pattern)) != '.') { if ($dir == '\\' || $dir == DS) $dir = ''; return smd_prognostics_rglob(basename($pattern), $flags, $dir . DS, $excl, $ign); } $paths = glob($path . '*', GLOB_ONLYDIR | GLOB_NOSORT); $files = glob($path . $pattern, $flags); foreach ($paths as $p) { $pinfo = array_pop(explode(DS, $p)); if (!in_array($pinfo, $excl)) { $files = array_merge($files, smd_prognostics_rglob($pattern, $flags, $p . DS, $excl, $ign)); foreach($files as $idx => $theFile) { $fex = array_pop(explode(DS, $theFile)); $rex = ($regexclude) ? preg_match($regexclude, $fex) : false; if($fex=='' || in_array($fex, $permexclude) || $rex) { unset($files[$idx]); } } } } return $files; } // Format forensic data for a file function smd_prognostics_forensic_output($file, $fi) { global $prefs; $dform = $prefs['dateformat']; $sep = n; $out = ''; $out .= $sep . smd_prognostics_gTxt('stat_name') . $file; $out .= $sep . smd_prognostics_gTxt('stat_size') . $fi['size']; $out .= $sep . smd_prognostics_gTxt('stat_mod') . strftime($dform, $fi['mtime']); $out .= $sep . smd_prognostics_gTxt('stat_uid') . $fi['uid']; $out .= $sep . smd_prognostics_gTxt('stat_gid') . $fi['gid']; return $out; } // ---------- Does what it says on the tin // Assumes 'textpattern' is the admin-side directory if server var not set. Must fix in core one day with true constant function smd_prognostics_guess_admin_dir() { $admindir = trim(dirname($_SERVER['PHP_SELF']), '/\\'); $admindir = (empty($admindir)) ? 'textpattern' : $admindir; return $admindir; } // ---------- Get common server info for mail headers, etc function smd_prognostics_header_info($fromname) { $domainparts = do_list(doStrip(serverSet('SERVER_NAME')), '.'); $numparts = count($domainparts); $domain = $domainparts[$numparts-2] . '.' . $domainparts[$numparts-1]; $reply_to = 'noreply@'.$domain; $txpdir = get_pref('smd_prognostics_txpdir', hu.smd_prognostics_guess_admin_dir()); $sep = is_windows() ? "\r\n" : "\n"; $headers = "From: $fromname <$reply_to>". $sep.'Reply-To: '.$reply_to. $sep.'X-Mailer: Textpattern'. $sep.'Content-Transfer-Encoding: 8bit'. $sep.'Content-Type: text/plain; charset="UTF-8"'. $sep; $out = array( 'domain' => $domain, 'reply_to' => $reply_to, 'txpdir' => $txpdir, 'sep' => $sep, 'headers' => $headers, ); return $out; } // Common buttons function smd_prognostics_buttons() { global $smd_prognostics_event, $smd_prognostics_style; $ret = array ( 'btnSave' => fInput('submit', 'submit', gTxt('save'), 'publish'), 'btnAck' => '
'.fInput('submit', 'submit', smd_prognostics_gTxt('pnl_ack'), 'smallerbox').'
', 'btnAckIt' => fInput('submit', 'submit', smd_prognostics_gTxt('pnl_ackit'), 'publish'), 'btnIgnore' => fInput('submit', 'ignore', smd_prognostics_gTxt('pnl_ignore'), 'publish'), 'btnCSI' => fInput('submit', 'csi', smd_prognostics_gTxt('pnl_csi'), 'publish'), 'btnAdvice' => '
'.fInput('submit', 'submit', smd_prognostics_gTxt('pnl_advice'), 'smallerbox').'
', 'btnFiles' => '
'.fInput('submit', 'submit', smd_prognostics_gTxt('pnl_files'), 'smallerbox').'
', 'btnSetup' => '
'.fInput('submit', 'submit', smd_prognostics_gTxt('pnl_setup'), 'smallerbox').'
', 'btnStyle' => ' class="smd_prog_btns" style="border:0;height:25px;"', 'btnCSS' => '', ); return $ret; } // Multi-file dropdown selection function smd_prognostics_multisel($selname='', $tree=array(), $sel=array()) { $out[] = ''; return join('',$out); } // Password strength meter function smd_prognostics_chronostrength($evt, $stp) { global $event, $smd_prognostics_style; echo <<{$smd_prognostics_style['meter']} EOS; } //**************************************************************** // Web page : http://code.google.com/p/phprotector // Autor : Hugo Sousa adamastor666@gmail.com // Date : 2010-03-25 // Version : 0.3.1.1 // //*************************************************************** class smd_prog_PhProtector { var $SHOW_ERRORS; public function smd_prog_PhProtector($show_errors) { $this->SHOW_ERRORS=$show_errors; if ($this->SHOW_ERRORS) { error_reporting(E_ERROR | E_WARNING | E_PARSE); //Show errors ini_set('display_errors', "1"); //display errors } else { ini_set('display_errors', "0"); //display errors ini_set('log_errors', "1"); //log_errors } } /* * Main function to be called in a index page that redirects to other pages * */ public function isMalicious() { $sqli = 0; $sqli = callback_event('smd_prognostics', 'sql_injection', false); if (!$sqli) { $num_bad_words1 = $this->CheckGet(); $num_bad_words2 = $this->CheckPost(); if ($num_bad_words1 > 0) { $sqli = true; } if ($num_bad_words2 > 0) { $sqli = true; } } return (($sqli <= 0) ? false : $sqli); } //check for sql injection and XSS in Post variables private function CheckPost() { $num_bad_words = 0; foreach($_POST as $campo => $input) { $_POST[$campo]= doArray($_POST[$campo], 'htmlentities'); // XSS PROTECTION $num_bad_words = $num_bad_words + $this->wordExists($input); //SQL INJECTION } return $num_bad_words; } //check for sql injection and XSS in GET variables private function CheckGet() { $num_bad_words = 0; foreach($_GET as $campo => $input){ $_GET[$campo]= doArray($_GET[$campo], 'htmlentities'); // XSS PROTECTION if($this->isIdInjection($campo,$input)){ //SQL ID INJECTION $num_bad_words = $num_bad_words + 0.5; } $num_bad_words = $num_bad_words + $this->wordExists($input); //SQL INJECTION } return $num_bad_words; } /** * return true if injection sql word is found. * The input is tested if is equal to a sql injection pattern * \b[^a-z]*?drop[^a-z]*?\b * http://www.pagecolumn.com/tool/regtest.htm **//* "/*","+" */ private function wordExists($input) { $num_bad_words = 0; /* WORD AFTER */ $baddelim1 = "[^a-z]*"; //the delim should be from "a" to "b" anything else is considered sql injection :) $baddelim2 = "[^a-z]+"; $badwords= array("union", "select", "show", "insert", "update", "delete", "drop", "truncate", "create", "load_file", "exec", "#", "--"); //"/*" foreach($badwords as $badword) { $expression = "/".$baddelim1.strtolower($badword).$baddelim2."/"; if (preg_match ($expression, strtolower($input))) { //dmp('*WA*',$badword, $input); //die("sql injection!"); $num_bad_words++; } } /* BEFORE WORD */ $baddelim1 = "[^a-z]+"; //the delim should be from "a" to "b" anything else is considered sql injection :) $baddelim2 = "[^a-z]*"; $badwords= array("@@version", "@@datadir", "user", "version"); foreach($badwords as $badword) { $expression = "/".$baddelim1.strtolower($badword).$baddelim2."/"; if (preg_match ($expression, strtolower($input))) { //dmp('*BW*',$badword, $input); //die("sql injection!"); $num_bad_words++; } } /* BEFORE WORD AFTER */ $baddelim1 = "[^a-z]+"; //the delim should be from "a" to "b" anything else is considered sql injection :) $baddelim2 = "[^a-z]+"; $badwords= array("benchmark", "--", "varchar", "convert", "char", "limit", "information_schema","table_name", "from", "where", "order"); foreach($badwords as $badword) { $expression = "/".$baddelim1.strtolower($badword).$baddelim2."/"; if (preg_match ($expression, strtolower($input))) { //dmp('*B-W-A*',$badword, $input); //die("sql injection!"); $num_bad_words++; } } //dmp($num_bad_words); return $num_bad_words; } /** * return true if an ID is not really an ID * **/ private function isIDInjection($campo,$input) { $reg="/^id/"; if(preg_match($reg, $campo)) { if(!$this->stringIsNumberNotZero($input)) { return true; // if is ID and NOT INTEGER or NULL -> SQL INJECTION!! } } return false; } /** * return true if the string is a number (different from 0, the id could not be zero!) * TODO: check if *all* chars are zero and fail, e.g. id=0000 **/ private function stringIsNumberNotZero( $string ) { if (empty($string)) { return false; } return ctype_digit($string); } } //end class // ------------------------ // Plugin-specific replacement strings - localise as required // TODO: Textpack this function smd_prognostics_gTxt($what, $atts = array()) { global $prefs, $smd_prognostics_event; $lang = array( 'acked' => 'Alarms acknowledged.', 'alarm_freq' => 'Alarm on detection and every: ', 'and' => ' and ', 'auth_users' => 'Restrict prognostic config to: ', 'avail_branch' => 'An update to this Textpattern series is available', 'avail_txp' => 'A new version of Textpattern is available', 'block' => 'Block', 'ch_add' => 'Additions', 'ch_del' => 'Deletions', 'ch_mod' => 'Modifications', 'check_between' => 'Check files between: ', 'check_for' => 'Check files for: ', 'check_freq' => 'Check files (at most) every: ', 'check_qty' => 'Check this many files each time: ', 'check_where' => 'Check files on public side clicks: ', 'csi' => 'Gather forensics and send for analysis', 'csi_sent' => ' Forensics data sent', 'csv' => '(comma-separated)', 'currmon' => 'You are currently monitoring {curr} out of {outof} available files.', 'docroot_files' => 'Consider moving the "files" folder outside of your site root folder. You can do this via the "Admin > Prefs > Advanced > File directory path" setting.', 'docroot_prognostics' => 'Please change the "Prognostics folder" setting to a directory outside your site root folder.', 'docroot_tmp' => 'Consider moving the "tmp" folder outside of your site root folder. You can do this via the "Admin > Prefs > Advanced > Temporary directory path" setting.', 'excludir' => 'Exclude folders: ', 'files_updated' => 'File list updated', 'help_link' => '(Help)', 'hms' => '(hrs:mins:secs)', 'ignores' => 'Ignore files: ', 'lbl_changed' => 'Changed', 'lbl_hashmod' => 'COMPROMISED', 'lbl_missing' => 'Missing', 'lbl_added' => 'Added (not monitored)', 'listloc' => 'File locations: ', 'mailto' => 'Send e-mail to: ', 'mailto_csi' => 'Send forensics to: ', 'monfiles_explain' => 'Select all the files you wish to monitor and click Save. Altering this list will automatically acknowledge any outstanding alarms against the selected files.', 'no_alarms' => 'No alarms to acknowledge at present.', 'no_files' => 'No files to list. Check the plugin setup (and Save it).', 'no_log_entries' => 'No log activity around the time of the differences.', 'none_selected' => 'No files selected', 'not_writable' => '{location} is not a directory or is not writable', 'notify_email' => 'E-mail', 'notify_txp' => 'TXP interface', 'notify_via' => 'Notify via: ', 'preamble_added' => 'These files have been added: ', 'preamble_files' => 'File contents follows: ', 'preamble_hashdown' => 'WARNING! The checksums file is missing.', 'preamble_hashmod' => 'WARNING! The checksums file has been altered: ', 'preamble_miss' => 'These files are missing: ', 'preamble_nok' => 'These files differ from their expected content: ', 'preamble_sql_inject' => 'Possible SQL injection detected', 'preamble_txplog' => 'Log entries prior to this detection: ', 'progloc' => 'Prognostics folder: ', 'progpfx' => 'Unique prefix: ', 'pnl_ack' => 'Alarms', 'pnl_ackit' => 'Acknowledge', 'pnl_advice' => 'Advice', 'pnl_csi' => 'Send Forensics', 'pnl_files' => 'Files', 'pnl_ignore' => 'Ignore', 'pnl_setup' => 'Setup', 'postamble' => 'Acknowledge alarms', 'req_headers' => 'Block request headers: ', 'req_not_allowed' => 'REQUEST_METHOD not allowed: {req}', 'rh_del' => 'DELETE', 'rh_put' => 'PUT', 'rh_trace' => 'TRACE', 'ttl_ack' => 'Prognostic alarm acknowledgement', 'ttl_advice' => 'Prognostic advice', 'ttl_files' => 'Prognostic file monitoring', 'ttl_fileopts' => 'Filesystem options', 'ttl_monopts' => 'Monitoring options', 'ttl_plugopts' => 'Plugin options', 'ttl_realopts' => 'Realtime options', 'ttl_setup' => 'Prognostic setup', 'rpc_exists' => 'The rpc directory is not being used. Consider removing it.', 'rt_hdr' => 'Header violations', 'rt_sql' => 'SQL injections', 'seconds' => '(seconds)', 'send_forensics' => 'Send forensics for: ', 'setup_exists' => 'The setup directory still exists. Please delete it.', 'smd_prognostics' => 'Prognostics', 'show_grants' => 'Your TXP user can access the MySQL privileges in the DB. Consider accessing the DB using a less privileged user.', 'sql_file_privs' => 'Your MySQL user has FILE privileges. Consider revoking this right unless absolutely necessary.', 'sql_inject' => 'Protect against SQL injection: ', 'stat_gid' => 'Group ID: ', 'stat_mod' => 'Modified: ', 'stat_name' => 'Filename: ', 'stat_size' => 'Size: ', 'stat_uid' => 'User ID: ', 'subject' => 'Prognostics ('.$prefs['siteurl'].')', 'subject_csi' => 'Prognostics ('.$prefs['siteurl'].') forensics', 'tight' => 'You run a pretty tight ship. Stay frosty.', 'txpdir' => 'Admin-side URL: ', 'warn_loc' => 'File locations changed. Update your list of files now', 'with' => ' with: ', ); return strtr($lang[$what], $atts); }