CMS识别的一些改进想法与实现

0x00 前言

用CMS识别工具,结果网站被扫死了。就想了想CMS识别的一些优化。一般工具就是把CMS指纹一条条扫。都没区别这套CMS是什么语言,然后根据语言选择指纹库,再去扫。扫了很多无用的指纹。

0x01 CMS识别思路

1.主动式扫描,就是前面的方法,一条一套指纹去匹配,但是需要调整一下扫描策略。
比如将指纹库分成ASP,PHP两种类型的,如果目标站是ASP的,则用ASP的指纹库去扫描,如果如果目标站是PHP的,则用PHP的指纹库去扫描。

再比如分析将指纹库分再细分成有favicon.ico,和无favicon.ico指纹库。
首先判断网站是否有favicon.ico,如果没有,则使用无favicon.ico指纹库进行扫描。如果有则获取其MD5值,跟已有指纹库相匹配,匹配到则识别出来,如果没有匹配到,则进入无favicon.ico指纹库扫描。

优化的方法总之就是分类去扫描。

2.被动式扫描,抓取主页的css,js,html,jpg等文件,然后获取其相对路径,然后与搜集到的指纹库进行比较,获取匹配到最多的结果的CMS则为识别结果。
这里的指纹库,就是一套cms里面所有的文件路径。
比如:

1
2
3
4
5
6
7
/0001shop/aboutme.asp:睿拓智能网上商城 1.0
/0001shop/admin/aboutme.asp:睿拓智能网上商城 1.0
/0001shop/admin/ad/adEdit.asp:睿拓智能网上商城 1.0
/0001shop/admin/ad/index.asp:睿拓智能网上商城 1.0
/SD/jqtransformplugin/img/._btn_left.gif:SD留言本
/SD/jqtransformplugin/img/._btn_right.gif:SD留言本
/SD/jqtransformplugin/img/btn_left.gif:SD留言本

如果匹配到aboutme.asp则,睿拓智能网上商城 1.0就增加1,匹配到数量最多的则为识别CMS。

0x02 编程实现

实现被动式扫描的思路。以asp网站为例。

0x00 爬取下载地址

爬去范围:http://www.mycodes.net/5/ ,结束页是http://www.mycodes.net/5/133.htm 。

使用BeautifulSoup进行提取URL下载地址,然后再使用request获取302跳转后的真正下载地址。

脚本:crawl.py

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
#encoding:UTF-8
import urllib.request
import bs4
from bs4 import BeautifulSoup
import re
from urllib.parse import urlparse
def WriteFile(path,str):
    f = open(path,"a+")
    f.write(str+"\n")

for i in range(1,134):
    i = str(i) + ".htm"
    if(i == "1.htm"):
        i = ""
    url = "http://www.mycodes.net/5/" + i
    print(url+"\n")
    
    ##################################################
    #获取列表页中a标签的href内容
    response = urllib.request.urlopen(url).read()
    html = response.decode('gbk','ignore')
    soup = BeautifulSoup(html,"html.parser")
    table = soup.find_all("table",width=re.compile("97%"), border="0")

    for a in table:
        name = a.find("a",target="_blank").string
        print(name)
        print(a.find("a",target="_blank")["href"])
        siteUrl = a.find("a",target="_blank")["href"]
        
        ##################################################
        #获取详情页中下载地址
        response = urllib.request.urlopen(siteUrl).read()
        html = response.decode('gbk','ignore')
        #print(html)
        siteSoup = BeautifulSoup(html,"html.parser")
        jumpTd = siteSoup.find("td",class_="b4")
        jumpA = jumpTd.find("a")
        
        jumpUrl = jumpA['href']
        #print(jumpUrl)
        
        ##################################################
        try:
            #获取302跳转地址
            buff = urllib.request.urlopen(jumpUrl)
            print(buff.geturl())
            
            #获取下载文件名
            parseResult = urlparse(buff.geturl())  
            path = parseResult.path
            regx = re.compile(r"""/.*?/(.*?(?:\.zip|rar))""",re.I)
            regxResult = re.findall(regx,path)
            print(regxResult[0])
            
            #写入文件
            WriteFile('url.txt',buff.geturl())
            WriteFile('match.txt',regxResult[0]+":"+name)
        except:
            pass
0x01 下载压缩包

下载url.txt中的文件。也可以用迅雷下载,下载文件比较多,也比较大,很消耗时间。
文件:download.py

1
2
3
4
5
6
7
8
9
10
11
from urllib import request
f = open(r"url.txt","r")  
lines = f.readlines()#读取全部内容  
for line in lines:
    downUrl = line.replace('\n','')
    print(downUrl)
    filename = downUrl.split('/')[-1
    print(filename)
    with request.urlopen(downUrl) as reponse:
        with open(filename, 'wb'as outFile:
            outFile.write(reponse.read())
0x02 搜集路径

遍历压缩包里面的文件路径,然后记录到cms.txt文件当中去。

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# unzip-gbk.py
import os
import zipfile
import rarfile
import io
import sys  
reload(sys)  
sys.setdefaultencoding('gbk')
info = {
    "Xiao5u_Query_2.3.zip":"校无忧录取查询系统 2.3",
    "wxpay_1.0.zip":"ASP微信支付接口 1.0",
}
def WriteFile(dir):
    f = open("cms.txt""a+")
    f.write(dir + "\n")


for file in os.listdir("./ASP/"):
    flagDir = ''
    dirList = []
    if (os.path.splitext(file)[1] == ".rar"):
        print("\n" + file + "\n")
        
        rFileName = "./ASP/" + file
        r = rarfile.RarFile(rFileName, 'r')
        for filePath in r.namelist():
            filePath = '/' + filePath
            #处理目录路径
            if(filePath.split('/')[-1].find('.')<0 and filePath[-1]!='/'):
                filePath = filePath + '/'
            #添加到路径列表当中去
            dirList.append(filePath)
        
        if(len(dirList)>0):
            for filePath in dirList:
                try:
                    print(filePath.replace(flagDir,'') + ":" + info[file])
                    WriteFile(filePath.replace(flagDir,'') + ":" + info[file])
                except:
                    pass

    #####################################################################################################
    #zip 压缩包
    if (os.path.splitext(file)[1] == ".zip"):
        print("\n" + file + "\n")
        
        zFileName = "./ASP/" + file
        z = zipfile.ZipFile(zFileName, 'r')
        for filePath in z.namelist():
            filePath = '/' + filePath
            #处理目录路径
            if(filePath.split('/')[-1].find('.')<0 and filePath[-1]!='/'):
                filePath = filePath + '/'
            #添加到路径列表当中去
            dirList.append(filePath)
                    
        if(len(dirList)>0):            
            for filePath in dirList:
                try:
                    print(filePath.replace(flagDir,'') + ":" + info[file])
                    WriteFile(filePath.replace(flagDir,'') + ":" + info[file])
                except:
                    pass
0x03 cms识别

抓取目标站的jpg,png,gif,js,css,以及href里面的路径,与cms.txt中的内容去匹配,匹配到最多数量的即为识别CMS。
python3:CmsIdentify.py

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import urllib.request
import re
import sys
from urllib.parse import urlparse

url = "http://www.hut.edu.cn/"
data = urllib.request.urlopen(url).read()
data = data.decode('gbk','ignore')

resultDict = {}
infoDict = {}

regx = re.compile(r"""src=\W(\S*?(?:\.jpg|png|gif))""",re.I)
picList = re.findall(regx,data)

for index in range(len(picList)):
    picList[index] = picList[index].lower()
    
picList = list(set(picList))
picExistList = picList
print(picList)


regx = re.compile(r"""src=\W(\S*?\.js)""",re.I)
jsList = re.findall(regx,data)

for index in range(len(jsList)):
    jsList[index] = jsList[index].lower()
jsList = list(set(jsList))
print(jsList)

regx = re.compile(r"""href=\W(\S*?\.css)""",re.I)
cssList = re.findall(regx,data)

for index in range(len(cssList)):
    cssList[index] = cssList[index].lower()
cssList = list(set(cssList))
print(cssList)


regx = re.compile(r"""a.*?href=\W(\S*?")""",re.I)
pathList = re.findall(regx,data)

for index in range(len(pathList)):
    pathList[index] = pathList[index].lower()
    parseResult = urlparse(pathList[index])  
    path = parseResult.path
    if(path[0:1]=='/'):
        path = path[1:]
    pathList[index] = path

while '' in pathList:
    pathList.remove('')

pathList = list(set(pathList))
print(pathList)

# sys.exit()

print('\n\n\n\n')
f = open("log.txt","r")  

lines = f.readlines()#读取全部内容  
for line in lines: 
    line = line.replace('\n','').lower()
    
    for pic in picList:
        if(line.find(pic)>-1):
            if((infoDict.get(line.split(':')[1])==Noneor (pic not in infoDict.get(line.split(':')[1]))):
                key = line.split(':')[1]
                value = pic
                infoDict.setdefault(key,[]).append(value)
                if(line.split(':')[1in resultDict):
                    resultDict[line.split(':')[1]] = resultDict[line.split(':')[1]] + 1
                else:
                    resultDict[line.split(':')[1]] = 1

    for js in jsList:
        if(line.find(js)>-1):
            if((infoDict.get(line.split(':')[1])==Noneor (js not in infoDict.get(line.split(':')[1]))):
                key = line.split(':')[1]
                value = js
                infoDict.setdefault(key,[]).append(value)
                if(line.split(':')[1in resultDict):
                    resultDict[line.split(':')[1]] = resultDict[line.split(':')[1]] + 1
                else:
                    resultDict[line.split(':')[1]] = 1
                
    for css in cssList:
        if(line.find(css)>-1):
            if((infoDict.get(line.split(':')[1])==Noneor (css not in infoDict.get(line.split(':')[1]))):
                key = line.split(':')[1]
                value = css
                infoDict.setdefault(key,[]).append(value)
                if(line.split(':')[1in resultDict):
                    resultDict[line.split(':')[1]] = resultDict[line.split(':')[1]] + 1
                else:
                    resultDict[line.split(':')[1]] = 1
                    
    for path in pathList:
        if(line.find(path)>-1):
            if((infoDict.get(line.split(':')[1])==Noneor (path not in infoDict.get(line.split(':')[1]))):
                key = line.split(':')[1]
                value = path
                infoDict.setdefault(key,[]).append(value)
                if(line.split(':')[1in resultDict):
                    resultDict[line.split(':')[1]] = resultDict[line.split(':')[1]] + 1
                else:
                    resultDict[line.split(':')[1]] = 1
                

resultDict = sorted(resultDict.items(), key=lambda e:e[1], reverse=True)
print('\n\n\n\n')
print(resultDict)
print('\n\n\n\n')
print(resultDict[0])
print('infoDict[resultDict[0][0]]\n\n\n\n')
print(infoDict[resultDict[0][0]])



0x03 效果图与结语

1.jpg

进一步可以存入数据当中,使用文件去匹配,速度太慢了。

下载地址:
链接: https://pan.baidu.com/s/1o7ATv3G 密码: a8s9