Vulnerability: 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.
Vulnerability ID: CVE-2016-4847
CWE: CWE-79
Severity score: 2.9
Project: https://github.com/ossec/ossec-wui
Published: 2017-04-20
File: site/search.php
Commit message: Unanchored regex would allow badness through.  This patch eliminates a
XSS identified by JPCERT Reference number: JVN#58455472
Commit author: Brad Lhotsky

Vulnerable version (before fix):
  * License (version 3) as published by the FSF - Free Software  * Foundation  */         /* OS PHP init */ if (!function_exists('os_handle_start')) { /* Getting search id */ if(isset($_POST['searchid'])) {     if(preg_match('/[a-z0-9]+/', $_POST['searchid']))     {         $USER_searchid = $_POST['searchid'];     } /* 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'])) &&          ($_POST['level'] > 0) &&         ($_POST['level'] < 16))     { /* Getting location */ if(isset($_POST['locationpattern'])) {     $lcpattern = "/^[0-9a-zA-Z.: _|^!>\/\\-]{1,156}$/";         if(preg_match($lcpattern, $_POST['locationpattern']) == true)     {         $LOCATION_pattern = $_POST['locationpattern'];             $ossec_max_alerts_per_page = $_POST['max_alerts_per_page'];         }     } }        <table><tr valign="top">     <td><input type="radio" name="monitoring" value="0" checked="checked"/>     </td>     <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"      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"      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>        <td>Real time monitoring</td></tr>       </table>       <br /> class="formText" /> echo '</select>';  /* Str pattern */ echo '</td></tr><tr><td>         Pattern: </td><td><input type="text" name="strpattern" size="16"                      value="'.$u_pattern.'" class="formText" /></td>';   class="formText" />   /* Srcip pattern */ echo '</td></tr><tr><td>         Srcip: </td><td>     <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"                      value="'.$u_user.'" class="formText" /></td></tr>';  /* Location */ echo '<tr><td>         Location:</td><td>     <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"                      value="'.$u_rule.'" class="formText"/>';  /* Max Alerts  */ class="formText" />     value="'.$ossec_max_alerts_per_page.'" class="formText" /></td></tr>';   /* Agent */     //foreach ($agent_list as $agent)      /* Final form */ echo '     <tr><td>                         <input type="submit" name="search" value="Search" class="button" /> ';  class="formText" /> echo ' <script type="text/javascript"> Calendar.setup({ button          :   "i_trigger",  inputField     :    "i_date_a", ifFormat       :    "%Y-%m-%d %H:%M", showsTime      :    true, timeFormat     :    "24" }); Calendar.setup({ button          :   "f_trigger",  inputField     :    "f_date_a", ifFormat       :    "%Y-%m-%d %H:%M", showsTime      :    true, class="formText" /> {     /* Getting alerts */     $output_list = os_searchalerts($ossec_handle, $USER_searchid,                                    $USER_init, $USER_final,                                     $ossec_max_alerts_per_page,                                    $USER_level,$USER_rule, $LOCATION_pattern,                                    $USER_pattern, $USER_group, class="formText" />     echo '         <input type="submit" name="search" value="<< First" class="button"                class="formText" />                             <input type="submit" name="search" value="< Prev" class="button"                class="formText" />          '; class="formText" />  /* 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="rulepattern" value="'.$u_rule.'" />     <input type="hidden" name="srcippattern" value="'.$u_srcip.'" />     <input type="hidden" name="userpattern" value="'.$u_user.'" /> class="formText" />     <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"                           value="'.$ossec_max_alerts_per_page.'" />';   if($output_list[0]{'pg'} > 1) {     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" />           </form> '; }   /* Checking if page exists */ if(!isset($output_list[0]{$real_page}) ||     (strlen($output_list[$real_page]) < 5) ||    (!file_exists($output_list[$real_page]))) {

Fixed version (after fix):
  * License (version 3) as published by the FSF - Free Software  * Foundation  */  /* OS PHP init */ if (!function_exists('os_handle_start')) { /* Getting search id */ if(isset($_POST['searchid'])) {     if(preg_match('/^[a-z0-9]+$/', $_POST['searchid']))     {         $USER_searchid = $_POST['searchid'];     } /* 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'])) &&         ($_POST['level'] > 0) &&         ($_POST['level'] < 16))     { /* Getting location */ if(isset($_POST['locationpattern'])) {     $lcpattern = "/^[0-9a-zA-Z.: _|^!>\/\\-]{1,156}$/";     if(preg_match($lcpattern, $_POST['locationpattern']) == true)     {         $LOCATION_pattern = $_POST['locationpattern'];             $ossec_max_alerts_per_page = $_POST['max_alerts_per_page'];         }     } }    <table><tr valign="top">     <td><input type="radio" name="monitoring" value="0" checked="checked"/>     </td>     <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"     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"     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>       <td>Real time monitoring</td></tr>       </table>       <br /> class="formText" /> echo '</select>';  /* Str pattern */ echo '</td></tr><tr><td>     Pattern: </td><td><input type="text" name="strpattern" size="16"                     value="'.$u_pattern.'" class="formText" /></td>';   class="formText" />   /* Srcip pattern */ echo '</td></tr><tr><td>     Srcip: </td><td>     <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"                     value="'.$u_user.'" class="formText" /></td></tr>';  /* Location */ echo '<tr><td>     Location:</td><td>     <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"                     value="'.$u_rule.'" class="formText"/>';  /* Max Alerts  */ class="formText" />     value="'.$ossec_max_alerts_per_page.'" class="formText" /></td></tr>';   /* Agent */ //foreach ($agent_list as $agent)  /* Final form */ echo '     <tr><td>     <input type="submit" name="search" value="Search" class="button" /> ';  class="formText" /> echo ' <script type="text/javascript"> Calendar.setup({ button          :   "i_trigger", inputField     :    "i_date_a", ifFormat       :    "%Y-%m-%d %H:%M", showsTime      :    true, timeFormat     :    "24" }); Calendar.setup({ button          :   "f_trigger", inputField     :    "f_date_a", ifFormat       :    "%Y-%m-%d %H:%M", showsTime      :    true, class="formText" /> {     /* Getting alerts */     $output_list = os_searchalerts($ossec_handle, $USER_searchid,                                    $USER_init, $USER_final,                                    $ossec_max_alerts_per_page,                                    $USER_level,$USER_rule, $LOCATION_pattern,                                    $USER_pattern, $USER_group, class="formText" />     echo '         <input type="submit" name="search" value="<< First" class="button"                class="formText" />          <input type="submit" name="search" value="< Prev" class="button"                class="formText" />          '; class="formText" />  /* 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="rulepattern" value="'.$u_rule.'" />     <input type="hidden" name="srcippattern" value="'.$u_srcip.'" />     <input type="hidden" name="userpattern" value="'.$u_user.'" /> class="formText" />     <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"                          value="'.$ossec_max_alerts_per_page.'" />';   if($output_list[0]{'pg'} > 1) { 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" />     </form> '; }   /* Checking if page exists */ if(!isset($output_list[0]{$real_page}) ||    (strlen($output_list[$real_page]) < 5) ||    (!file_exists($output_list[$real_page]))) {

Patch:
patch: @@ -9,7 +9,7 @@
  * License (version 3) as published by the FSF - Free Software
  * Foundation
  */
-       
+
 /* OS PHP init */
 if (!function_exists('os_handle_start'))
 {
@@ -54,7 +54,7 @@
 /* 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'];
     }
@@ -99,24 +99,24 @@
 /* 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))
     {
@@ -151,7 +151,7 @@
 /* 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'];
@@ -231,7 +231,7 @@
             $ossec_max_alerts_per_page = $_POST['max_alerts_per_page'];
         }
     }
-}    
+}
 
 
 
@@ -298,23 +298,23 @@
 <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 />
@@ -374,8 +374,8 @@ class="formText" />
 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>';
 
 
@@ -409,25 +409,25 @@ class="formText" />
 
 
 /* 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  */
@@ -437,12 +437,12 @@ class="formText" />
     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" />
 ';
 
@@ -457,14 +457,14 @@ class="formText" />
 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,
@@ -497,7 +497,7 @@ class="formText" />
 {
     /* 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,
@@ -553,7 +553,7 @@ class="formText" />
     echo '
         <input type="submit" name="search" value="<< First" class="button"
                class="formText" />
-                   
+
         <input type="submit" name="search" value="< Prev" class="button"
                class="formText" />
          ';
@@ -563,10 +563,10 @@ class="formText" />
 
 /* 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.'" />
@@ -575,25 +575,25 @@ class="formText" />
     <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])))
 {
path: site/search.php