CVE-2016-4847: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site scripting (XSS) vulnerability in site/search.php in OSSEC Web UI before 0.9 allows remote attackers to inject arbitrary web script or HTML by leveraging an unanchored regex.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2017-04-20T17:59Z
Repository: https://github.com/ossec/ossec-wui
Language: PHP
Files changed: site/search.php
Commit date: 2015-12-29 11:20:30 -0800
Commit message: Unanchored regex would allow badness through.  This patch eliminates a
XSS identified by JPCERT Reference number: JVN#58455472

Diff: diff --git a/site/search.php b/site/search.php
index ddc852a..87e5c7f 100644
--- a/site/search.php
+++ b/site/search.php
@@ -7,11 +7,11 @@
  * This program is a free software; you can redistribute it
  * and/or modify it under the terms of the GNU General Public
  * License (version 3) as published by the FSF - Free Software
  * Foundation
  */
-       
+
 /* OS PHP init */
 if (!function_exists('os_handle_start'))
 {
     echo "<b class='red'>You are not allowed direct access.</b><br />\n";
     return(1);
@@ -52,11 +52,11 @@ $used_stored = 0;
 
 
 /* Getting search id */
 if(isset($_POST['searchid']))
 {
-    if(preg_match('/[a-z0-9]+/', $_POST['searchid']))
+    if(preg_match('/^[a-z0-9]+$/', $_POST['searchid']))
     {
         $USER_searchid = $_POST['searchid'];
     }
 }
 
@@ -97,28 +97,28 @@ if(isset($_POST['monitoring']) && ($_POST['monitoring'] == 1))
 
 
 /* Reading user input -- being very careful parsing it */
 $datepattern = "/^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2})$/";
 if(isset($_POST['initdate']))
-{             
+{
     if(preg_match($datepattern, $_POST['initdate'], $regs))
     {
         $USER_init = mktime($regs[4], $regs[5], 0,$regs[2],$regs[3],$regs[1]);
         $u_init_time = $USER_init;
     }
 }
 if(isset($_POST['finaldate']))
-{             
+{
     if(preg_match($datepattern, $_POST['finaldate'], $regs) == true)
     {
         $USER_final = mktime($regs[4], $regs[5], 0,$regs[2],$regs[3],$regs[1]);
         $u_final_time = $USER_final;
     }
 }
 if(isset($_POST['level']))
-{             
-    if((is_numeric($_POST['level'])) && 
+{
+    if((is_numeric($_POST['level'])) &&
         ($_POST['level'] > 0) &&
         ($_POST['level'] < 16))
     {
         $USER_level = $_POST['level'];
         $u_level = $USER_level;
@@ -149,11 +149,11 @@ if(isset($_POST['strpattern']))
 
 
 /* Getting location */
 if(isset($_POST['locationpattern']))
 {
-    $lcpattern = "/^[0-9a-zA-Z.: _|^!>\/\\-]{1,156}$/";    
+    $lcpattern = "/^[0-9a-zA-Z.: _|^!>\/\\-]{1,156}$/";
     if(preg_match($lcpattern, $_POST['locationpattern']) == true)
     {
         $LOCATION_pattern = $_POST['locationpattern'];
         $u_location = $LOCATION_pattern;
     }
@@ -229,11 +229,11 @@ if(isset($_POST['max_alerts_per_page']))
            ($_POST['max_alerts_per_page'] < 10000))
         {
             $ossec_max_alerts_per_page = $_POST['max_alerts_per_page'];
         }
     }
-}    
+}
 
 
 
 /* Getting search id  -- should be enough to avoid duplicates */
 if( array_key_exists( 'search', $_POST ) ) {
@@ -296,27 +296,27 @@ echo "<h2>Alert search options:</h2>\n";
 echo '
 <form name="dosearch" method="post" action="index.php?f=s">
 <table><tr valign="top">
     <td><input type="radio" name="monitoring" value="0" checked="checked"/>
     </td>
-    <td>From: &nbsp;<input type="text" name="initdate" 
+    <td>From: &nbsp;<input type="text" name="initdate"
     id="i_date_a" size="17"
-    value="'.date('Y-m-d H:i', $u_init_time).'" maxlength="16" 
+    value="'.date('Y-m-d H:i', $u_init_time).'" maxlength="16"
     class="formText" />
     <img src="img/calendar.gif" id="i_trigger" title="Date selector"
     alt="Date selector" class="formText" />
     </td><td>&nbsp;&nbsp;
     To: &nbsp;<input type="text" name="finaldate" id="f_date_a" size="17"
-    value="'.date('Y-m-d H:i', $u_final_time).'" maxlength="16" 
+    value="'.date('Y-m-d H:i', $u_final_time).'" maxlength="16"
     class="formText" />
     <img src="img/calendar.gif" id="f_trigger" title="Date selector"
     alt="Date selector" class="formText" />
     </td>
     </tr>
 ';
 
-echo '<tr><td><input type="radio" name="monitoring" value="1" '.$rt_sk.'/></td> 
+echo '<tr><td><input type="radio" name="monitoring" value="1" '.$rt_sk.'/></td>
       <td>Real time monitoring</td></tr>
       </table>
       <br />
       <table>
      ';
@@ -372,12 +372,12 @@ foreach($global_categories as $_cat_name => $_cat)
     }
 }
 echo '</select>';
 
 /* Str pattern */
-echo '</td></tr><tr><td>    
-    Pattern: </td><td><input type="text" name="strpattern" size="16" 
+echo '</td></tr><tr><td>
+    Pattern: </td><td><input type="text" name="strpattern" size="16"
                     value="'.$u_pattern.'" class="formText" /></td>';
 
 
 /* Log formats */
 echo '<td>
@@ -407,44 +407,44 @@ foreach($log_categories as $_cat_name => $_cat)
 }
 echo '</select>';
 
 
 /* Srcip pattern */
-echo '</td></tr><tr><td>    
+echo '</td></tr><tr><td>
     Srcip: </td><td>
-    <input type="text" name="srcippattern" size="16" class="formText" 
+    <input type="text" name="srcippattern" size="16" class="formText"
                     value="'.$u_srcip.'"/>&nbsp;&nbsp;';
 
 /* Rule pattern */
 echo '</td><td>
-    User: </td><td><input type="text" name="userpattern" size="8" 
+    User: </td><td><input type="text" name="userpattern" size="8"
                     value="'.$u_user.'" class="formText" /></td></tr>';
 
 /* Location */
-echo '<tr><td>    
+echo '<tr><td>
     Location:</td><td>
-    <input type="text" name="locationpattern" size="16" class="formText" 
+    <input type="text" name="locationpattern" size="16" class="formText"
                     value="'.$u_location.'"/>&nbsp;&nbsp;';
 
 /* Rule pattern */
 echo '</td><td>
-    Rule id: </td><td><input type="text" name="rulepattern" size="8" 
+    Rule id: </td><td><input type="text" name="rulepattern" size="8"
                     value="'.$u_rule.'" class="formText"/>';
 
 /* Max Alerts  */
 echo '</td></tr><tr><td>
     Max Alerts:</td>
     <td><input type="text" name="max_alerts_per_page" size="8"
     value="'.$ossec_max_alerts_per_page.'" class="formText" /></td></tr>';
 
 
-/* Agent */    
+/* Agent */
 //foreach ($agent_list as $agent)
-    
+
 /* Final form */
 echo '
-    <tr><td>                    
+    <tr><td>
     <input type="submit" name="search" value="Search" class="button" />
 ';
 
 
 echo '</td></tr></table>
@@ -455,18 +455,18 @@ echo '</td></tr></table>
 
 /* Java script for date */
 echo '
 <script type="text/javascript">
 Calendar.setup({
-button          :   "i_trigger", 
+button          :   "i_trigger",
 inputField     :    "i_date_a",
 ifFormat       :    "%Y-%m-%d %H:%M",
 showsTime      :    true,
 timeFormat     :    "24"
 });
 Calendar.setup({
-button          :   "f_trigger", 
+button          :   "f_trigger",
 inputField     :    "f_date_a",
 ifFormat       :    "%Y-%m-%d %H:%M",
 showsTime      :    true,
 timeFormat     :    "24"
 });
@@ -495,11 +495,11 @@ if($_POST['search'] != "Search")
 /* Searching for new ones */
 else
 {
     /* Getting alerts */
     $output_list = os_searchalerts($ossec_handle, $USER_searchid,
-                                   $USER_init, $USER_final, 
+                                   $USER_init, $USER_final,
                                    $ossec_max_alerts_per_page,
                                    $USER_level,$USER_rule, $LOCATION_pattern,
                                    $USER_pattern, $USER_group,
                                    $USER_srcip, $USER_user,
                                    $USER_log);
@@ -551,51 +551,51 @@ if($output_list[0]{'pg'} > 1)
 if($output_list[0]{'pg'} > 1)
 {
     echo '
         <input type="submit" name="search" value="<< First" class="button"
                class="formText" />
-                   
+
         <input type="submit" name="search" value="< Prev" class="button"
                class="formText" />
          ';
 
     echo 'Page <b>'.$USER_page.'</b> ('.$output_list[0]{$real_page}.' alerts)';
 }
 
 /* Currently page */
 echo '
-    <input type="hidden" name="initdate" 
-           value="'.date('Y-m-d H:i', $u_init_time).'" /> 
-    <input type="hidden" name="finaldate" 
-           value="'.date('Y-m-d H:i', $u_final_time).'" /> 
+    <input type="hidden" name="initdate"
+           value="'.date('Y-m-d H:i', $u_init_time).'" />
+    <input type="hidden" name="finaldate"
+           value="'.date('Y-m-d H:i', $u_final_time).'" />
     <input type="hidden" name="rulepattern" value="'.$u_rule.'" />
     <input type="hidden" name="srcippattern" value="'.$u_srcip.'" />
     <input type="hidden" name="userpattern" value="'.$u_user.'" />
     <input type="hidden" name="locationpattern" value="'.$u_location.'" />
     <input type="hidden" name="level" value="'.$u_level.'" />
     <input type="hidden" name="page" value="'.$USER_page.'" />
     <input type="hidden" name="searchid" value="'.$USER_searchid.'" />
     <input type="hidden" name="monitoring" value="'.$USER_monitoring.'" />
-    <input type="hidden" name="max_alerts_per_page" 
+    <input type="hidden" name="max_alerts_per_page"
                          value="'.$ossec_max_alerts_per_page.'" />';
 
 
 if($output_list[0]{'pg'} > 1)
-{    
-echo '    
+{
+echo '
     &nbsp;&nbsp;
     <input type="submit" name="search" value="Next >" class="button"
            class="formText" />
      <input type="submit" name="search" value="Last >>" class="button"
-           class="formText" />      
+           class="formText" />
     </form>
 ';
 }
 
 
 /* Checking if page exists */
-if(!isset($output_list[0]{$real_page}) || 
+if(!isset($output_list[0]{$real_page}) ||
    (strlen($output_list[$real_page]) < 5) ||
    (!file_exists($output_list[$real_page])))
 {
     echo "<b class='red'>Nothing returned (or search expired). </b><br />\n";
     return(1);

Vulnerable code:        
    if(preg_match('/[a-z0-9]+/', $_POST['searchid']))
{             
{             
{             
    if((is_numeric($_POST['level'])) && 
    $lcpattern = "/^[0-9a-zA-Z.: _|^!>\/\\-]{1,156}$/";    
}    
    <td>From: &nbsp;<input type="text" name="initdate" 
    value="'.date('Y-m-d H:i', $u_init_time).'" maxlength="16" 
    value="'.date('Y-m-d H:i', $u_final_time).'" maxlength="16" 
echo '<tr><td><input type="radio" name="monitoring" value="1" '.$rt_sk.'/></td> 
echo '</td></tr><tr><td>    
    Pattern: </td><td><input type="text" name="strpattern" size="16" 
echo '</td></tr><tr><td>    
    <input type="text" name="srcippattern" size="16" class="formText" 
    User: </td><td><input type="text" name="userpattern" size="8" 
echo '<tr><td>    
    <input type="text" name="locationpattern" size="16" class="formText" 
    Rule id: </td><td><input type="text" name="rulepattern" size="8" 
/* Agent */    
    
    <tr><td>                    
button          :   "i_trigger", 
button          :   "f_trigger", 
                                   $USER_init, $USER_final, 
                   
    <input type="hidden" name="initdate" 
           value="'.date('Y-m-d H:i', $u_init_time).'" /> 
    <input type="hidden" name="finaldate" 
           value="'.date('Y-m-d H:i', $u_final_time).'" /> 
    <input type="hidden" name="max_alerts_per_page" 
{    
echo '    
           class="formText" />      
if(!isset($output_list[0]{$real_page}) || 
Fixed code: 
    if(preg_match('/^[a-z0-9]+$/', $_POST['searchid']))
{
{
{
    if((is_numeric($_POST['level'])) &&
    $lcpattern = "/^[0-9a-zA-Z.: _|^!>\/\\-]{1,156}$/";
}
    <td>From: &nbsp;<input type="text" name="initdate"
    value="'.date('Y-m-d H:i', $u_init_time).'" maxlength="16"
    value="'.date('Y-m-d H:i', $u_final_time).'" maxlength="16"
echo '<tr><td><input type="radio" name="monitoring" value="1" '.$rt_sk.'/></td>
echo '</td></tr><tr><td>
    Pattern: </td><td><input type="text" name="strpattern" size="16"
echo '</td></tr><tr><td>
    <input type="text" name="srcippattern" size="16" class="formText"
    User: </td><td><input type="text" name="userpattern" size="8"
echo '<tr><td>
    <input type="text" name="locationpattern" size="16" class="formText"
    Rule id: </td><td><input type="text" name="rulepattern" size="8"
/* Agent */

    <tr><td>
button          :   "i_trigger",
button          :   "f_trigger",
                                   $USER_init, $USER_final,

    <input type="hidden" name="initdate"
           value="'.date('Y-m-d H:i', $u_init_time).'" />
    <input type="hidden" name="finaldate"
           value="'.date('Y-m-d H:i', $u_final_time).'" />
    <input type="hidden" name="max_alerts_per_page"
{
echo '
           class="formText" />
if(!isset($output_list[0]{$real_page}) ||