CVE-2018-16389 (PHP, published 2018-09-12T16:29Z)
Description: value: e107_admin/banlist.php in e107 2.1.8 allows SQL injection via the old_ip parameter.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
Repository: https://github.com/e107inc/e107
Files changed:
e107_admin/banlist.php
Commit message: Code cleanup


Vulnerable code:
//		'main/banlog'		=> array('caption'=> BANLAN_81, 'perm' => '0'),
		public function transferPage()
			//FIXME Put Import code in here. 
			//FIXME Put Options code in here. 








Fixed code:
	//	'main/banlog'		=> array('caption'=> BANLAN_81, 'perm' => '0'),
		protected function transferPage()

			$ipAdministrator = new banlistManager;

			// Character options for import & export
			$separator_char = array(1 => ',', 2 => '|');
			$quote_char = array(1 => '(none)', 2 => "'", 3 => '"');

			$frm = e107::getForm();
			$mes = e107::getMessage();

			$error = false;

			if(isset($_POST['ban_import']))  // Got a file to import
			{
				require_once(e_HANDLER . 'upload_handler.php');

				if(($files = process_uploaded_files(e_UPLOAD, false, array('overwrite' => true, 'max_file_count' => 1, 'file_mask' => 'csv'))) === false)
				{ // Invalid file
					$error = true;
					$mes->addError(BANLAN_47);
				}

				if(empty($files) || vartrue($files[0]['error']))
				{
					$error = true;
					if(varset($files[0]['message']))
					{
						$mes->addError($files[0]['message']);
					}
				}

				if(!$error) // Got a file of some sort
				{
					$message = process_csv(e_UPLOAD . $files[0]['name'],
						intval(varset($_POST['ban_over_import'], 0)),
						intval(varset($_POST['ban_over_expiry'], 0)),
						$separator_char[intval(varset($_POST['ban_separator'], 1))],
						$quote_char[intval(varset($_POST['ban_quote'], 3))]);
					banlist_adminlog('07', 'File: ' . e_UPLOAD . $files[0]['name'] . '<br />' . $message);
				}

			}

			$text = "
				<form method='post' action='" . e_ADMIN_ABS . "banlist_export.php' id='core-banlist-transfer-form' >
					<fieldset id='core-banlist-transfer-export'>
						<legend>" . BANLAN_40 . "</legend>
						<table class='table adminlist'>
							<colgroup>
								<col style='width:30%' />
								<col style='width:30%' />
								<col style='width:40%' />
							</colgroup>
							<tbody>
								<tr>
									<th colspan='2'>" . BANLAN_36 . "</th>
									<th>&nbsp;</th>
								</tr>
				";


			foreach($ipAdministrator->getValidReasonList() as $i) //FIXME $frm->label()
			{
				$text .= "
								<tr>
								<td colspan='3'>
									" . $frm->checkbox("ban_types[{$i}]", $i) . $frm->label($ipAdministrator->getBanTypeString($i, false), "ban_types[{$i}]", $i) . "
									<span class='field-help'>(" . $ipAdministrator->getBanTypeString($i, true) . ")</span>
								</td></tr>
				";
			}

			$text .= "<tr>
				<td>" . BANLAN_79 . "</td>
				<td>" . $frm->select('ban_separator', $separator_char) . ' ' . BANLAN_37 . "</td>
			<td>" . $frm->select('ban_quote', $quote_char) . ' ' . BANLAN_38 . "</td></tr>";

			$text .= "
	
							</tbody>
						</table>
						<div class='buttons-bar center'>" . $frm->admin_button('ban_export', BANLAN_39, 'export', BANLAN_39) . "</div>
							<input type='hidden' name='e-token' value='" . e_TOKEN . "' />
					</fieldset>
				</form>
			";

			// Now do the import options
			$text .= "
				<form enctype='multipart/form-data' method='post' action='" . e_SELF . "?transfer' id='ban_import_form' >
					<fieldset id='core-banlist-transfer-import'>
						<legend>" . BANLAN_41 . "</legend>
						<table class='table adminlist'>
							<colgroup>
								<col style='width:30%' />
								<col style='width:30%' />
								<col style='width:40%' />
							</colgroup>
							<tbody>
								<tr>
									<th colspan='2'>" . BANLAN_42 . "</th>
									<th>&nbsp;</th>
								</tr>
								<tr>
									<td colspan='3'>" . $frm->checkbox('ban_over_import', 1, '', array('label' => BANLAN_43)) . "</td>
								</tr>
								<tr>
									<td colspan='3'>" . $frm->checkbox('ban_over_expiry', 1, '', array('label' => BANLAN_44)) . "</td>
								</tr>
								<tr>
									<td>" . BANLAN_46 . "</td>
									<td colspan='2'>
										" . $frm->file('file_userfile[]', array('size' => '40')) . "
									</td>
								</tr>
								<tr>
				<td>" . BANLAN_80 . "</td>
				<td>" . $frm->select('ban_separator', $separator_char) . ' ' . BANLAN_37 . "</td>
				<td>" . $frm->select('ban_quote', $quote_char) . ' ' . BANLAN_38 . "</td></tr>
					</tbody>
						</table>
						<div class='buttons-bar center'>
						" . $frm->admin_button('ban_import', BANLAN_45, 'import') . $frm->token(). "
						</div>
	
	
					</fieldset>
				</form>
			";

			return $mes->render() . $text;

		private function drop_box($box_name, $curval)
		{
			$frm = e107::getForm();

			$opts = array(50, 100, 150, 200, 250, 300, 400, 500);
			$ret = $frm->select_open($box_name, array('class' => 'tbox'));
			foreach ($opts as $o)
			{
				$ret .= $frm->option($o, $o, ($curval == $o));
			}
			$ret .= "</select>\n";
			return $ret;
		}

			if (!getperms('0'))
			{
				exit();
			}

			$mes = e107::getMessage();
			$tp = e107::getParser();
			$sql = e107::getDb();
			$frm = e107::getForm();
			$pref = e107::getPref();


			if (isset($_POST['update_ban_options']))
			{
				$pref['enable_rdns']            = intval($_POST['ban_rdns_on_access']);
				$pref['enable_rdns_on_ban']     = intval($_POST['ban_rdns_on_ban']);
				$pref['ban_max_online_access']  = intval($_POST['ban_access_guest']).','.intval($_POST['ban_access_member']);
				$pref['ban_retrigger']          = intval($_POST['ban_retrigger']);
				$pref['ban_date_format']        = $tp->toDB($_POST['ban_date_format']);

				e107::getConfig()->setPref($pref)->save(true,true,true);
			}

			if (isset($_POST['remove_expired_bans']))
			{
				$result = $sql->delete('banlist',"`banlist_bantype` < ".eIPHandler::BAN_TYPE_WHITELIST." AND `banlist_banexpires` > 0 AND `banlist_banexpires` < ".time());
				banlist_adminlog('12', $result);
				$mes->addSuccess(str_replace('[y]', $result, BANLAN_48));
			}

			list($ban_access_guest, $ban_access_member) = explode(',', varset($pref['ban_max_online_access'], '100,200'));
			$ban_access_member = max($ban_access_guest, $ban_access_member);


			$text = "
				<form method='post' action='".e_SELF."?mode=main&action=options'>
					<fieldset id='core-banlist-options'>
						<legend>".BANLAN_72."</legend>
						<table class='table adminform'>
							<colgroup>
								<col class='col-label' />
								<col class='col-control' />
							</colgroup>
							<tbody>
								<tr>
									<td>".BANLAN_63."</td>
									<td>
										<div class='auto-toggle-area autocheck'>
											".$frm->checkbox('ban_rdns_on_access', 1, $pref['enable_rdns'] == 1)."
											<div class='field-help'>".BANLAN_65."</div>
										</div>
									</td>
								</tr>
								<tr>
									<td>".BANLAN_64."</td>
									<td>
										<div class='auto-toggle-area autocheck'>
											".$frm->checkbox('ban_rdns_on_ban', 1, $pref['enable_rdns_on_ban'] == 1)."
											<div class='field-help'>".BANLAN_66."</div>
										</div>
									</td>
								</tr>
								<tr>
									<td>".BANLAN_67."</td>
									<td>
										<div class='field-spacer'>".$this->drop_box('ban_access_guest', $ban_access_guest).BANLAN_70."</div>
										<div class='field-spacer'>".$this->drop_box('ban_access_member', $ban_access_member).BANLAN_69."</div>
										<div class='field-help'>".BANLAN_68."</div>
									</td>
								</tr>
								<tr>
									<td>".BANLAN_71."</td>
									<td>
										<div class='auto-toggle-area autocheck'>
											".$frm->checkbox('ban_retrigger', 1, $pref['ban_retrigger'] == 1)."
											<div class='field-help'>".BANLAN_73."</div>
										</div>
									</td>
								</tr>
	
								<tr>
								  <td>".BANLAN_91."</td>
								  <td>
								  ".$frm->text('ban_date_format', varset($pref['ban_date_format'], '%H:%M %d-%m-%y'), 40)."
								  <div class='field-help'>".BANLAN_92."</div>
								  </td>
								</tr>
							</tbody>
						</table>
						<div class='buttons-bar center'>
							".$frm->admin_button('update_ban_options', LAN_UPDATE, 'update')."
							<input type='hidden' name='e-token' value='".e_TOKEN."' />
						</div>
					</fieldset>
					<fieldset id='core-banlist-options-ban'>
						<legend>".BANLAN_74."</legend>
						<table class='table adminform'>
							<colgroup>
								<col class='col-label' />
								<col class='col-control' />
							</colgroup>
							<tbody>
								<tr>
									<td>".BANLAN_75."</td>
									<td>
										".$frm->admin_button('remove_expired_bans', BANLAN_76, 'delete')."
										<input type='hidden' name='e-token' value='".e_TOKEN."' />
									</td>
								</tr>
							</tbody>
						</table>
					</fieldset>
				</form>
			";

			return $text;
require_once(e_ADMIN.'footer.php');
exit;
// Unused code below, but left here for reference.