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
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