处于当下的Web安全领域当中, 辨别目标站点的指纹属于渗透测试里常见的首个步骤;指纹识别的目标在于明确目标站点所运用的技术体系和框架, 进而依据目标框架展开针对性的安全测评;指纹识别的道理实际上挺简单, 当下主流的识别办法有下面这么一些。
这些基于指纹的识别途径, 皆是借助剖析目标网站的特定表征或者行为, 于其中推导所运用的框架或者技术。它们能够助力渗透测试人员知悉目标网站的技术栈以及框架, 进而施行针对性的安全测试以及漏洞扫描。在本节内容当中, 我们会采用第二种方式, 也就是借助哈希鉴定去确定目标指纹信息, 此种办法需要具备完善的特征库, 这些特征库, 我们能自行寻觅制作, 也能够运用已有的库, 经由转换之后获取。
要实现指纹识别, 在此之前, 须先尝试读取目标网站的标题信息, 该功能的实现堪称简易异常, 只需读入页面, 接着依次取出所需的“Date”, “”, “X--By”, “title”字段就行, 鉴于代码颇为简单, 所以在此处直接放出代码部分。
import re,socket,threading,requests import argparse header = {'user-agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) LySharkTools'} def GetIPAddress(domain): try: url = str(domain.split("//")[1]) sock = socket.getaddrinfo(url,None) result = re.findall("(?:[0-9]{1,3}\.){3}[0-9]{1,3}", str(sock[0][4])) return str(result[0]) except Exception: pass def GetServerTitle(url): try: address = GetIPAddress(url) Respon = requests.get(url=url,headers=header,timeout=5) print("--" * 80) print(url + " ",end="") print(address + " ", end="") if Respon.status_code == 200: RequestBody = [item for item in Respon.headers] for item in ["Date","Server","X-Powered-By"]: if item in RequestBody: print(Respon.headers[item] + " ",end="") title = re.findall(".*
", Respon.content.decode("utf-8")) print(title) except Exception: pass if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-f","--file",dest="file",help="") args = parser.parse_args() # 使用方法: main.py -f url.log if args.file: fp = open(args.file,"r") for item in fp.readlines(): url = item.replace("\n","") thread = threading.Thread(target=GetServerTitle,args=(url,)) thread.start() else: parser.print_help()
运行这段代码时, 读者要准备好所需获取的网站列表, 将其按照每行一列的方式放置到 url.log 文件里, 运行如下面图片所展示的命令, 就能依次读取到这些网站的服务器信息。
我们持续达成指纹识别功能, 先是借助库把目标页面读取进字符串之中, 接着调用MD5算法算出该页面的HASH值并予以比对, 鉴于特定框架里总有一些页面不曾变动, 我们进而校准这些页面的HASH值, 便能达成对框架的识别, 代码颇为简易在此直接给出源代码。
import requests import os,sys,hashlib import argparse headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) LySharkTools'} def CheckFinger(url,flag,keyworld): if flag == 0: ret = requests.get(url=url,headers=headers,timeout=1) text = ret.text md5=hashlib.md5() md5.update(text.encode('utf-8')) print("目标网页Hash值: {}".format(md5.hexdigest())) else: fp = open(keyworld,"r") for i in fp.readlines(): path = url + eval(i.replace("\n", ""))["Path"] hash = eval(i.replace("\n", ""))["Hash"] web = eval(i.replace("\n", ""))["WebServer"] ret = requests.get(url=path, headers=headers, timeout=1) if ret.status_code == 200: text = ret.text md5 = hashlib.md5() md5.update(text.encode('utf-8')) if md5.hexdigest() == hash: print("目标Hash:{} CMS页面类型:{} ".format(hash,web)) else: continue if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--mode",dest="mode",help="设置检查类型 [check/get]") parser.add_argument("-u","--url",dest="url",help="指定需要检测的网站地址") parser.add_argument("-f","--file",dest="file",help="指定字典数据库 data.json") args = parser.parse_args() if args.mode == "get" and args.url: CheckFinger(args.url,0,args.file) # 检测目标容器类型: main.py --mode=check -u https://www.xxx.com -f data.json elif args.mode == "check" and args.url and args.file: CheckFinger(args.url,1,args.file) else: parser.print_help()执行如下命令, 这段代码就被用于通过使用get方法, 去获取特定页面的hash值, 比如说获取网站特定路径的hash值。
当把这些特征给获取到手之后, 我们能够去新建一个.db文件, 接着把这些数据按照特定的格式来进行保存, 呈现的情况如下所示。
{"Path":"/about/index.html","Hash": "9e69dd111c6cc873a1f915ca1a331b06","WebServer":"hexo"} {"Path":"/index.php","Hash": "2457dd111c6cc32461f915ca17789b06","WebServer":"typecho"} {"Path":"/index.html","Hash": "7530893af83150dc07461f4bc4cc0de6","WebServer":"oss"}若特征库处于完整状态,那么此刻可以通过使用 -f 去指定特征文档, 接着在循环之中获取是否与特征相匹配, 借由这样的方式进而判断 web 容器运用了哪一种容器组件。