CVE-2015-10008: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: ** UNSUPPORTED WHEN ASSIGNED ** A vulnerability was found in 82Flex WEIPDCRM. It has been classified as critical. This affects an unknown part. The manipulation leads to sql injection. It is possible to initiate the attack remotely. The identifier of the patch is 43bad79392332fa39e31b95268e76fbda9fec3a4. It is recommended to apply a patch to fix this issue. The identifier VDB-217185 was assigned to this vulnerability. NOTE: This vulnerability only affects products that are no longer supported by the maintainer.
CWE description: 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.
CVSS v3 base score: 9.8
Published: 2023-01-02T11:15Z
Repository: https://github.com/82Flex/WEIPDCRM
Language: PHP
Files changed: main/commercial.php, main/index.php, main/install/function.php, main/manage/header.php, main/manage/login.php, main/system/class/db.php, main/system/function/core.php
Commit date: 2015-04-01 21:13:02 +0800
Commit message: IMPORTANT: Some HotFix and some bugs fixed. 重要：一些紧急修复及错误修复。
1. IMPORTANT: Add MySQL safe execution filtering for Commercial Package API.
1. 重要：添加付费软件包API数据库安全执行过滤。
2. IMPORTANT: Add XSS filtering function for Commercial Package API.
2. 重要：添加付费软件包API添加XSS过滤。
3. Suppress errors for Installer.
3. 安装器错误抑制。
4. Fix login fail not auto reset sometimes.
4. 修复有些时候无法自动重置登录失败等待时间。（如：只输错了验证码）

Diff: diff --git a/main/commercial.php b/main/commercial.php
index f96ba63..8f4d2a8 100644
--- a/main/commercial.php
+++ b/main/commercial.php
@@ -16,22 +16,26 @@
  * GNU Affero General Public License for more details.
  * 
  * You should have received a copy of the GNU Affero General Public License
  * along with WEIPDCRM.  If not, see <http://www.gnu.org/licenses/>.
  */
-//This file is vulnerable, PLEASE CHECK IT AT ONCE.
-exit();
+
+
 if(isset($_GET['action'])){
 	switch($_GET['action']){
 		// 支付宝跳转
 		case 'alipay_go':
+			// XSS过滤
+			foreach($_GET as $key => $value){
+				$clan_data[$key] = xss_clean($value);
+			}
 ?>
 <form id="alipay" accept-charset="GBK" method="POST" action="https://shenghuo.alipay.com/send/payment/fill.htm">
-	<?php if(isset($_GET['optEmail'])): ?><input type="hidden" value="<?php echo($_GET['optEmail']); ?>" name="optEmail"><?php endif; ?>
-	<?php if(isset($_GET['payAmount'])): ?><input type="hidden" value="<?php echo($_GET['payAmount']); ?>" name="payAmount"><?php endif; ?>
-	<?php if(isset($_GET['title'])): ?><input id="title" type="hidden" value="<?php echo($_GET['title']); ?>" name="title"><?php endif; ?>
-	<?php if(isset($_GET['memo'])): ?><input name="memo" type="hidden" value="<?php echo($_GET['memo']); ?>" /><?php endif; ?>
+	<?php if(isset($_GET['optEmail'])): ?><input type="hidden" value="<?php echo($clan_data['optEmail']); ?>" name="optEmail"><?php endif; ?>
+	<?php if(isset($_GET['payAmount'])): ?><input type="hidden" value="<?php echo($clan_data['payAmount']); ?>" name="payAmount"><?php endif; ?>
+	<?php if(isset($_GET['title'])): ?><input id="title" type="hidden" value="<?php echo($clan_data['title']); ?>" name="title"><?php endif; ?>
+	<?php if(isset($_GET['memo'])): ?><input name="memo" type="hidden" value="<?php echo($clan_data['memo']); ?>" /><?php endif; ?>
 </form>
 <script type="text/javascript">
 var postForm = document.getElementById('alipay');
 postForm.method = "post" ;   
 postForm.action = 'https://shenghuo.alipay.com/send/payment/fill.htm' ;  
@@ -50,11 +54,11 @@ if (!isset($package_info)) {
 	require_once('system/common.inc.php');
 	if(!isset($detect)){
 		class_loader('Mobile_Detect');
 		$detect = new Mobile_Detect;
 	}
-	$package_info = DB::fetch_first("SELECT `Package`, `Name`, `Tag`, `Level`, `Price`, `Purchase_Link` FROM `".DCRM_CON_PREFIX."Packages` WHERE `Package` = '".$_GET['Package']."' AND `Stat` = '1'");
+	$package_info = DB::fetch_first(DB::prepare("SELECT `Package`, `Name`, `Tag`, `Level`, `Price`, `Purchase_Link` FROM `".DCRM_CON_PREFIX."Packages` WHERE `Package` = '%s' AND `Stat` = '1'", $_GET['Package']));
 	if(!$package_info)
 		exit();
 ?>
 <!DOCTYPE html SYSTEM "about:legacy-compat">
 <html>
@@ -73,11 +77,11 @@ if (!isset($package_info)) {
 }
 if(check_commercial_tag($package_info['Tag'])):
 	$nowip = _ip2long(getIp());
 
 	if(isset($_GET['udid']))
-		$udid_status = DB::fetch_first("SELECT `Packages`, `Level`, `IP` FROM `".DCRM_CON_PREFIX."UDID` WHERE `UDID` = '".$_GET['udid']."' LIMIT 1");
+		$udid_status = DB::fetch_first(DB::prepare("SELECT `Packages`, `Level`, `IP` FROM `".DCRM_CON_PREFIX."UDID` WHERE `UDID` = '%s' LIMIT 1", $_GET['udid']));
 	else
 		$udid_status = DB::fetch_first("SELECT `Packages`, `Level`, `IP` FROM `".DCRM_CON_PREFIX."UDID` WHERE `IP` = '".$nowip."' LIMIT 1");
 	$purchased = false;
 	if(!empty($udid_status)){
 		if(!empty($udid_status['Packages'])) {
diff --git a/main/index.php b/main/index.php
index bb86759..bf41161 100644
--- a/main/index.php
+++ b/main/index.php
@@ -590,11 +590,11 @@ if ($index == 0) {
 				</a>
 			</fieldset>
 <?php
 		}
 		$package_info = $pkg_assoc;
-		//require_once('commercial.php');
+		require_once('commercial.php');
 ?>
 			<fieldset>
 <?php
 		if (DCRM_SCREENSHOTS == 2) {
 ?>
diff --git a/main/install/function.php b/main/install/function.php
index b044dcf..3f1f572 100644
--- a/main/install/function.php
+++ b/main/install/function.php
@@ -22,10 +22,15 @@
 // 设定参数
 define('ABSPATH', dirname(dirname(__FILE__)).'/');
 define('CONF_PATH', ABSPATH.'system/config/');
 define('VERSION', '1.6.15.3.18');
 
+// 错误抑制
+define('DEBUG_ENABLED', isset($_GET['debug']));
+error_reporting(DEBUG_ENABLED ? E_ALL & !E_NOTICE & !E_STRICT : E_ERROR | E_PARSE);
+@ini_set('display_errors', DEBUG_ENABLED);
+
 /* 载入语言 */
 $localetype = 'install';
 include_once ABSPATH . 'system/languages/l10n.php';
 $step_language = localization_load();
 
diff --git a/main/manage/header.php b/main/manage/header.php
index 4f70178..a5c01ea 100644
--- a/main/manage/header.php
+++ b/main/manage/header.php
@@ -25,10 +25,11 @@ if (!defined("DCRM")) {
 
 $localetype = 'manage';
 define('MANAGE_ROOT', dirname(__FILE__).'/');
 define('ABSPATH', dirname(MANAGE_ROOT).'/');
 require_once ABSPATH.'system/common.inc.php';
+header('Content-type: text/html; charset=utf-8');
 
 $sidebars = array(
 	array(
         'title' => 'PACKAGES',
         'type'  => 'title'
diff --git a/main/manage/login.php b/main/manage/login.php
index 29019f6..b0bff6b 100755
--- a/main/manage/login.php
+++ b/main/manage/login.php
@@ -70,25 +70,27 @@ if(isset($_POST['submit'])) {
 			goto endlabel;
 		}
 		if (strtolower($_POST['authcode']) != strtolower($_SESSION['VCODE'])) {
 			unset($_SESSION['VCODE']);
 			$_SESSION['try'] = $_SESSION['try'] + 1;
+			$_SESSION['lasttry'] = time();
 			$error = "authcode";
 			goto endlabel;
 		} else {
 			unset($_SESSION['VCODE']);
 		}
 		if (!preg_match("#^[0-9a-zA-Z\_]*$#i", $_POST['username'])) {
 			$_SESSION['try'] = $_SESSION['try'] + 1;
+			$_SESSION['lasttry'] = time();
 			$error = "badlogin";
 			goto endlabel;
 		}
 		$login_query = DB::query("SELECT * FROM `".DCRM_CON_PREFIX."Users` WHERE `Username` = '".DB::real_escape_string($_POST['username'])."' LIMIT 1");
 		if (DB::affected_rows() > 0) {
 			$login = mysql_fetch_assoc($login_query);
 			if ($login['Username'] === $_POST['username'] AND strtoupper($login['SHA1']) === strtoupper(sha1($_POST['password']))) {
-				$login_query = DB::query("UPDATE `".DCRM_CON_PREFIX."Users` SET `LastLoginTime` = '".date('Y-m-d H:i:s')."' WHERE `ID` = '".$login['ID']."'");
+				$login_query = DB::update(DCRM_CON_PREFIX.'Users', array('LastLoginTime' => date('Y-m-d H:i:s')), array('ID' => $login['ID']));
 				$_SESSION['power'] = $login['Power'];
 				$_SESSION['userid'] = $login['ID'];
 				$_SESSION['username'] = $login['Username'];
 				$_SESSION['token'] = sha1(time()*rand(140,320));
 				$_SESSION['try'] = 0;
diff --git a/main/system/class/db.php b/main/system/class/db.php
index 712b636..2483335 100644
--- a/main/system/class/db.php
+++ b/main/system/class/db.php
@@ -208,10 +208,14 @@ class DB {
 	function &object() {
 		static $db;
 		if (empty($db)) $db = new db_mysql();
 		return $db;
 	}
+	public function escape_by_ref( &$string ) {
+		if ( ! is_float( $string ) )
+			$string = DB::real_escape_string( $string );
+	}
 	/**
 	 * Prepares a SQL query for safe execution. Uses sprintf()-like syntax.
 	 *
 	 * The following directives can be used in the query format string:
 	 *   %d (integer)
@@ -260,9 +264,10 @@ class DB {
 			$args = $args[0];
 		$query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
 		$query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
 		$query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
 		$query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
+		array_walk( $args, "DB::escape_by_ref" );
 		return @vsprintf( $query, $args );
 	}
 }
 ?>
\ No newline at end of file
diff --git a/main/system/function/core.php b/main/system/function/core.php
index 857f9b8..2c6ae42 100755
--- a/main/system/function/core.php
+++ b/main/system/function/core.php
@@ -312,10 +312,41 @@ function add_option( $option, $value = '', $deprecated = '') {
 	if ( ! $result )
 		return false;
 
 	return true;
 }
+function xss_clean($data) {
+	// Fix &entity\n;
+	$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
+	$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
+	$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
+	$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
+
+	// Remove any attribute starting with "on" or xmlns
+	$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
+
+	// Remove javascript: and vbscript: protocols
+	$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
+	$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
+	$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
+
+	// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
+	$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
+	$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
+	$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
+
+	// Remove namespaced elements (we do not need them)
+	$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
+	do{
+		// Remove really unwanted tags
+		$old_data = $data;
+		$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
+	}
+	while ($old_data !== $data);
+	// we are done...
+	return $data;
+}
 // Function link
 function randstr($len = 40) {
 	require_once SYSTEM_ROOT.'./function/manage.php';
 	return _randstr($len);
 }

Vulnerable code: //This file is vulnerable, PLEASE CHECK IT AT ONCE.
exit();
	<?php if(isset($_GET['optEmail'])): ?><input type="hidden" value="<?php echo($_GET['optEmail']); ?>" name="optEmail"><?php endif; ?>
	<?php if(isset($_GET['payAmount'])): ?><input type="hidden" value="<?php echo($_GET['payAmount']); ?>" name="payAmount"><?php endif; ?>
	<?php if(isset($_GET['title'])): ?><input id="title" type="hidden" value="<?php echo($_GET['title']); ?>" name="title"><?php endif; ?>
	<?php if(isset($_GET['memo'])): ?><input name="memo" type="hidden" value="<?php echo($_GET['memo']); ?>" /><?php endif; ?>
	$package_info = DB::fetch_first("SELECT `Package`, `Name`, `Tag`, `Level`, `Price`, `Purchase_Link` FROM `".DCRM_CON_PREFIX."Packages` WHERE `Package` = '".$_GET['Package']."' AND `Stat` = '1'");
		$udid_status = DB::fetch_first("SELECT `Packages`, `Level`, `IP` FROM `".DCRM_CON_PREFIX."UDID` WHERE `UDID` = '".$_GET['udid']."' LIMIT 1");
		//require_once('commercial.php');
				$login_query = DB::query("UPDATE `".DCRM_CON_PREFIX."Users` SET `LastLoginTime` = '".date('Y-m-d H:i:s')."' WHERE `ID` = '".$login['ID']."'");
Fixed code: 

			// XSS过滤
			foreach($_GET as $key => $value){
				$clan_data[$key] = xss_clean($value);
			}
	<?php if(isset($_GET['optEmail'])): ?><input type="hidden" value="<?php echo($clan_data['optEmail']); ?>" name="optEmail"><?php endif; ?>
	<?php if(isset($_GET['payAmount'])): ?><input type="hidden" value="<?php echo($clan_data['payAmount']); ?>" name="payAmount"><?php endif; ?>
	<?php if(isset($_GET['title'])): ?><input id="title" type="hidden" value="<?php echo($clan_data['title']); ?>" name="title"><?php endif; ?>
	<?php if(isset($_GET['memo'])): ?><input name="memo" type="hidden" value="<?php echo($clan_data['memo']); ?>" /><?php endif; ?>
	$package_info = DB::fetch_first(DB::prepare("SELECT `Package`, `Name`, `Tag`, `Level`, `Price`, `Purchase_Link` FROM `".DCRM_CON_PREFIX."Packages` WHERE `Package` = '%s' AND `Stat` = '1'", $_GET['Package']));
		$udid_status = DB::fetch_first(DB::prepare("SELECT `Packages`, `Level`, `IP` FROM `".DCRM_CON_PREFIX."UDID` WHERE `UDID` = '%s' LIMIT 1", $_GET['udid']));
		require_once('commercial.php');
// 错误抑制
define('DEBUG_ENABLED', isset($_GET['debug']));
error_reporting(DEBUG_ENABLED ? E_ALL & !E_NOTICE & !E_STRICT : E_ERROR | E_PARSE);
@ini_set('display_errors', DEBUG_ENABLED);

header('Content-type: text/html; charset=utf-8');
			$_SESSION['lasttry'] = time();
			$_SESSION['lasttry'] = time();
				$login_query = DB::update(DCRM_CON_PREFIX.'Users', array('LastLoginTime' => date('Y-m-d H:i:s')), array('ID' => $login['ID']));
	public function escape_by_ref( &$string ) {
		if ( ! is_float( $string ) )
			$string = DB::real_escape_string( $string );
	}
		array_walk( $args, "DB::escape_by_ref" );
function xss_clean($data) {
	// Fix &entity\n;
	$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
	$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
	$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
	$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

	// Remove any attribute starting with "on" or xmlns
	$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

	// Remove javascript: and vbscript: protocols
	$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
	$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
	$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

	// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
	$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
	$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
	$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

	// Remove namespaced elements (we do not need them)
	$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
	do{
		// Remove really unwanted tags
		$old_data = $data;
		$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
	}
	while ($old_data !== $data);
	// we are done...
	return $data;
}