CVE-2018-1000870: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: PHPipam version 1.3.2 and earlier contains a CWE-79 vulnerability in /app/admin/users/print-user.php that can result in Execute code in the victims browser. This attack appear to be exploitable via Attacker change theme parameter in user settings. Admin(Victim) views user in admin-panel and gets exploited.. This vulnerability appears to have been fixed in 1.4.
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: 5.4
Published: 2018-12-20T17:29Z
Repository: https://github.com/phpipam/phpipam
Language: PHP
Files changed: app/admin/users/print-user.php, app/tools/user-menu/2fa.php, app/tools/user-menu/2fa_save.php, app/tools/user-menu/account.php, app/tools/user-menu/index.php, app/tools/user-menu/user-edit.php, app/tools/user-menu/user-widgets-set.php, misc/CHANGELOG
Commit date: 2018-12-01 21:02:56 +0000
Commit message: Bugfix: XSS in print-user.php, CSRF in user-edit.php. Fixes #2326

Diff: diff --git a/app/admin/users/print-user.php b/app/admin/users/print-user.php
index b5f53405..2e7134ea 100644
--- a/app/admin/users/print-user.php
+++ b/app/admin/users/print-user.php
@@ -131,11 +131,11 @@ $custom_fields = $Tools->fetch_custom_fields('users');
 <tr>
 	<td colspan="2"><h4><?php print _('Display settings'); ?></h4><hr></td>
 </tr>
 <tr>
 	<td><?php print _('Theme'); ?></td>
-	<td><?php print $user->theme=="" ? _("Default") : $user->theme ?></td>
+	<td><?php print $user->theme=="" ? _("Default") : escape_input($user->theme) ?></td>
 </tr>
 <tr>
 	<td><?php print _('Compress override'); ?></td>
 	<td><?php print $user->compressOverride==1 ? _("Yes") : _("No") ?></td>
 </tr>
diff --git a/app/tools/user-menu/2fa.php b/app/tools/user-menu/2fa.php
index 62fa0cf7..b482de55 100644
--- a/app/tools/user-menu/2fa.php
+++ b/app/tools/user-menu/2fa.php
@@ -47,10 +47,11 @@ $username = strtolower($User->user->username)."@".$User->settings->{'2fa_name'};
 		?>
 	</td>
 	<?php }  ?>
 </tr>
 </table>
+<input type="hidden" name="csrf_cookie" value="<?php print $csrf; ?>">
 </form>
 
 <!-- result -->
 <div id="userModSelf2faResult" style="margin-bottom:90px;display:none"></div>
 
diff --git a/app/tools/user-menu/2fa_save.php b/app/tools/user-menu/2fa_save.php
index 681c7e8a..61d38132 100644
--- a/app/tools/user-menu/2fa_save.php
+++ b/app/tools/user-menu/2fa_save.php
@@ -18,10 +18,13 @@ $Admin          = new Admin ($Database, false);
 $ga 			= new PHPGangsta_GoogleAuthenticator();
 
 # verify that user is logged in
 $User->check_user_session();
 
+# validate csrf cookie
+$User->Crypto->csrf_cookie ("validate", "user-menu", $_POST['csrf_cookie']) === false ? $Result->show("danger", _("Invalid CSRF cookie"), true) : "";
+
 # change ?
 if(@$_POST['2fa']=="1" && $User->user->{'2fa'}=="1") {
 	$Result->show("info", _("No change"), true);
 }
 
diff --git a/app/tools/user-menu/account.php b/app/tools/user-menu/account.php
index bf9523ba..e3c1b3c5 100644
--- a/app/tools/user-menu/account.php
+++ b/app/tools/user-menu/account.php
@@ -214,10 +214,11 @@ if($User->user->authMethod == 1) {
     </td>
     <td></td>
 </tr>
 
 </table>
+<input type="hidden" name="csrf_cookie" value="<?php print $csrf; ?>">
 </form>
 
 
 <!-- result -->
 <div class="userModSelfResult" style="margin-bottom:90px;display:none"></div>
\ No newline at end of file
diff --git a/app/tools/user-menu/index.php b/app/tools/user-menu/index.php
index 8a2c673a..7c092a79 100755
--- a/app/tools/user-menu/index.php
+++ b/app/tools/user-menu/index.php
@@ -5,10 +5,13 @@
  */
 
 # verify that user is logged in
 $User->check_user_session();
 
+# create csrf token
+$csrf = $User->Crypto->csrf_cookie ("create", "user-menu");
+
 # fetch all languages
 $langs = $User->fetch_langs();
 
 /* print hello */
 print "<h4>".$User->user->real_name.", "._('here you can change your account details').":</h4>";
diff --git a/app/tools/user-menu/user-edit.php b/app/tools/user-menu/user-edit.php
index aa2dd08e..c814e179 100755
--- a/app/tools/user-menu/user-edit.php
+++ b/app/tools/user-menu/user-edit.php
@@ -18,10 +18,13 @@ $User           = new User ($Database);
 $Password_check = new Password_check ();
 
 # verify that user is logged in
 $User->check_user_session();
 
+# validate csrf cookie
+$User->Crypto->csrf_cookie ("validate", "user-menu", $_POST['csrf_cookie']) === false ? $Result->show("danger", _("Invalid CSRF cookie"), true) : "";
+
 # verify email
 if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL))							{ $Result->show("danger alert-absolute",  _('Email not valid!'), true); }
 
 # verify lang
 if(!is_numeric($_POST['lang']))                                                 { $Result->show("danger alert-absolute",  _('Invalid language!'), true); }
@@ -33,10 +36,15 @@ if (strlen($_POST['password1']) != 0) {
 	$policy = (json_decode($User->settings->passwordPolicy, true));
 	$Password_check->set_requirements  ($policy, explode(",",$policy['allowedSymbols']));
 	if (!$Password_check->validate ($_POST['password1'])) 						{ $Result->show("danger alert-danger ", _('Password validation errors').":<br> - ".implode("<br> - ", $Password_check->get_errors ()), true); }
 }
 
+# Verify Theme
+if (!empty($_POST['theme'])) {
+	if (!in_array($_POST['theme'], ['default', 'white', 'dark'])) 				{ $Result->show("danger alert-absolute", _('Invalid theme'), true); }
+}
+
 # set override
 $_POST['compressOverride'] = @$_POST['compressOverride']=="Uncompress" ? "Uncompress" : "default";
 
 # Update user
 if (!$User->self_update ($_POST)) 												{ $Result->show("danger alert-absolute",  _('Error updating user account!'), true); }
diff --git a/app/tools/user-menu/user-widgets-set.php b/app/tools/user-menu/user-widgets-set.php
index 8b92f638..e24aa7d4 100755
--- a/app/tools/user-menu/user-widgets-set.php
+++ b/app/tools/user-menu/user-widgets-set.php
@@ -12,9 +12,12 @@ require_once( dirname(__FILE__) . '/../../../functions/functions.php' );
 # initialize required objects
 $Database 	= new Database_PDO;
 $Result		= new Result;
 $User		= new User ($Database);
 
+# verify that user is logged in
+$User->check_user_session();
+
 /* save widgets */
 if (!$User->self_update_widgets ($_POST['widgets'])) 	{ $Result->show("danger", _('Error updating'),true); }
 else 													{ $Result->show("success", _('Widgets updated'),true); }
 ?>
\ No newline at end of file
diff --git a/misc/CHANGELOG b/misc/CHANGELOG
index 8c3d35de..fa0f856c 100755
--- a/misc/CHANGELOG
+++ b/misc/CHANGELOG
@@ -48,10 +48,11 @@
     Security Fixes:
     ----------------------------
     + Hide SNMP community (#2197);
     + Hide LDAP/AD/Radius username / password and secret from logs and syslog (#2006);
     + XSS in phpipamredirect cookie (#2338);
+    + XSS in print-user.php, CSRF in user-edit.php (#2326);
 
 == 1.3.2
 
     Enhancements, changes:
     ----------------------------

Vulnerable code: 	<td><?php print $user->theme=="" ? _("Default") : $user->theme ?></td>
Fixed code: 	<td><?php print $user->theme=="" ? _("Default") : escape_input($user->theme) ?></td>
<input type="hidden" name="csrf_cookie" value="<?php print $csrf; ?>">
# validate csrf cookie
$User->Crypto->csrf_cookie ("validate", "user-menu", $_POST['csrf_cookie']) === false ? $Result->show("danger", _("Invalid CSRF cookie"), true) : "";

<input type="hidden" name="csrf_cookie" value="<?php print $csrf; ?>">
# create csrf token
$csrf = $User->Crypto->csrf_cookie ("create", "user-menu");

# validate csrf cookie
$User->Crypto->csrf_cookie ("validate", "user-menu", $_POST['csrf_cookie']) === false ? $Result->show("danger", _("Invalid CSRF cookie"), true) : "";

# Verify Theme
if (!empty($_POST['theme'])) {
	if (!in_array($_POST['theme'], ['default', 'white', 'dark'])) 				{ $Result->show("danger alert-absolute", _('Invalid theme'), true); }
}

# verify that user is logged in
$User->check_user_session();

    + XSS in print-user.php, CSRF in user-edit.php (#2326);