python实现——批量检查渗透测试报告

目录

  • 前言
  • 实现逻辑
  • 代码设计
  • 参考

前言

每次日站,最烦人的就是检查渗透测试报告了,尤其是碰到复测的站点,一不留神可能就写错报告了,导致要多次检查报告内容。就花了点时间学习了下“python-docx库”来实现用python去检查渗透测试报告。

实现逻辑

上交的报告是word版的,首先从文件名中读取出测试站点的名字、网址、测试的版本、测试时间,将其作为一个依据,然后去报告中再次获取相关信息,并进行比对。

这里主要是用到了“python-docx库”的两个功能,一个是读取word文档全文。
代码如下:

from docx import Document

doc = Document(r"C:\Users\asuka\Desktop\test\11.docx")
print(doc.paragraphs)
for paragraph in doc.paragraphs:
    print(paragraph.text)

另一个是读取word中的表格,代码如下:

from docx import Document
from openpyxl import Workbook

doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test2.docx")
t0 = doc.tables[0]

workbook = Workbook()
sheet = workbook.active

for i in range(len(t0.rows)):
    list1 = []
    for j in range(len(t0.columns)):
        list1.append(t0.cell(i,j).text)
    sheet.append(list1)
workbook.save(filename = r"G:\6Tipdm\7python办公自动化\concat_word\来自word中的表.xlsx")

有了上述的两个功能,就足够了。

代码设计

需要安装一下“python-docx库”:pip install python-docx

from docx import Document
from colorama import init, Fore
import os
import re


# 获取word文档封面的日期
def feng_mian():
    print('=========分析1:封面中的内容=========')
    feng_mian_title = word_file.split('渗透测试报告')[0].strip()
    if feng_mian_title == file_web_name:
        print(Fore.GREEN + '[√] 封面标题正确:' + feng_mian_title)
    else:
        print(Fore.RED + '[X] 封面标题与文件名称不一致' + '\t[info] 文件名称:' + file_web_name + ',封面标题:' + feng_mian_title)

    feng_mian_time = word_file.split('公司名字【手动替换不予展示】')[-1].split('文件修订记录')[0].strip()
    if fileyear + '年' + filemonth + '月' + filedata + '日' == feng_mian_time:
        print(Fore.GREEN + '[√] 封面日期正确:' + feng_mian_time)
    else:
        print(Fore.RED + '[X] 封面日期与文件日期不一致' + '\t[info] 文件日期:' + filetime + ',封面日期:' + feng_mian_time)


# 获取文件修订记录的日期
def date_of_revision():
    print('=========分析2:文件修订记录=========')
    tables = doc.tables  # 获取文件中的表格集
    table = tables[1]  # 获取文件中的第2个表格:文件修订记录表格
    # for i in range(1, len(table.rows)):  # 从表格第二行开始循环读取表格数据
    #     result = table.cell(i, 0).text + "" + table.cell(i, 1).text + table.cell(i, 2).text + \
    #              table.cell(i, 3).text + table.cell(i, 4).text
    #     # cell(i,0)表示第(i+1)行第1列数据,以此类推
    #     print(result)
    date_of_revision_time = table.cell(1, 4).text
    if filetime == date_of_revision_time:
        print(Fore.GREEN + '[√] 文件修订记录变更日期正确:' + date_of_revision_time)
    else:
        print(
            Fore.RED + '[X] 文件修订记录变更日期与文件日期不一致' + '\t[info] 文件日期:' + filetime + ',文件修订记录变更日期:' + date_of_revision_time)


# 测试对象与测试结果
def test_objects_and_test_results():
    print('=========分析3:测试对象与测试结果=========')
    tables = doc.tables  # 获取文件中的表格集
    table = tables[2]  # 获取文件中的第2个表格:文件修订记录表格
    # 判断检测日期
    if fileyear in table.cell(2, 1).text and filemonth in table.cell(2, 1).text and filedata in table.cell(2, 1).text:
        print(Fore.GREEN + '[√] 检测时间正确:' + table.cell(2, 1).text)
    else:
        print(Fore.RED + '[X] 检测时间与文件日期不一致' + '\t[info] 文件日期:' + filetime + ',检测时间:' + table.cell(2, 1).text)
    # 判断检测版本
    # print(table.cell(3, 1).text)    # 获取检测结果
    word_content_version = table.cell(3, 1).text.split('通过本次渗透测试工作')[0].strip().split('渗透测试')[0] + '渗透测试'
    if file_version in word_content_version:
        print(Fore.GREEN + '[√] 测试结果中的版本正确:' + word_content_version)
    else:
        print(
            Fore.RED + '[X] 测试结果中的版本与文件的版本不一致' + '\t[info] 文件版本:' + file_version + ',测试结果中的版本:' + word_content_version)
    # 判断测试结果日期
    test_result_time = table.cell(3, 1).text.split('【手动隐藏部门名称】')[-1].strip()
    if fileyear + '年' + filemonth + '月' + filedata + '日' == test_result_time:
        print(Fore.GREEN + '[√] 测试结果中的日期正确:' + test_result_time)
    else:
        print(Fore.RED + '[X] 测试结果中的日期与文件日期不一致' + '\t[info] 文件日期:' + filetime + ',测试结果中的日期:' + test_result_time)
    # 提取测试结果中的漏洞
    risk_all1 = table.cell(3, 1).text.split('共发现')[-1].split('个可能潜在')[0]
    risk_high1 = table.cell(3, 1).text.split('高风险级别的问题有')[-1].split('个,中风险级')[0]
    risk_mid1 = table.cell(3, 1).text.split('中风险级别的问题有')[-1].split('个,低风险')[0]
    risk_low1 = table.cell(3, 1).text.split('低风险为')[-1].split('个')[0]
    if int(risk_all1) == int(risk_low1) + int(risk_mid1) + int(risk_high1):
        print(Fore.GREEN + '[√] 测试结果中的漏洞数量自身吻合:' +
              '漏洞总数:' + risk_all1 + ',高危:' + risk_high1 + ',中危:' + risk_mid1 + ',低危:' + risk_low1)
    else:
        print(Fore.RED + '[X] 测试结果中的漏洞数量自身异常' +
              '\t[info] 漏洞总数:' + risk_all1 + ',高危:' + risk_high1 + ',中危:' + risk_mid1 + ',低危:' + risk_low1)
    return risk_all1, risk_high1, risk_mid1, risk_low1


# 判断测试范围
def test_range():
    print('=========分析4:渗透测试范围=========')
    tables = doc.tables  # 获取文件中的表格集
    table = tables[4]  # 获取文件中的第4个表格:渗透测试范围
    # 判断网站名称
    if file_web_name == table.cell(1, 1).text:
        print(Fore.GREEN + '[√] 渗透测试范围的网站名称正确:' + table.cell(1, 1).text)
    else:
        message = '[X] 渗透测试范围的网站名称与文件中的名称不一致' + \
                  '\t[info] 文件名中的网站名称:' + file_web_name + ',渗透测试范围的网站名称:' + table.cell(1, 1).text
        print(Fore.RED + message)
    # 判断网站地址
    flag = 1
    for i in file_web_path_list:
        if i not in table.cell(1, 2).text:
            message1 = '[X] 渗透测试范围的网站地址与文件中地址不一致' + \
                       '\t[info] 文件名中的网站地址:' + file_web_path + ',渗透测试范围的网站地址:' + table.cell(1, 2).text
            print(Fore.RED + message1)
            flag = 0
            break
    if flag:
        print(Fore.GREEN + '[√] 渗透测试范围的网站地址正确:' + table.cell(1, 2).text)


# 获取渗透测试记录
def word_content_test_records():
    print('=========分析5:渗透测试记录=========')
    tables = doc.tables  # 获取文件中的表格集
    table = tables[5]  # 获取文件中的第5个表格:渗透测试记录
    # print(len(table.rows))  # 获取表格的的行数
    # print(len(table.columns))   # 获取表格的列数
    result = ''
    for i in range(1, len(table.rows)):
        for j in range(1, len(table.columns)):
            result = result + table.cell(i, j).text + '\t'
        result = result + '\n'

    word_content_test_records_version = result.rsplit('P', 1)[-1].split(".")[0].replace("'", '')
    if file_version == word_content_test_records_version:
        print(Fore.GREEN + '[√] 渗透测试记录的次数正确:第' + word_content_test_records_version + '次测试')
    else:
        print(
            Fore.RED + '[X] 渗透测试记录的次数与文件名称中的版本号不符' + '\t[info] 文件名称中的版本号:' + file_version + ',渗透测试记录:' + word_content_test_records_version + '\n' + result)


# 分析风险等级概况
def risk_level_describe():
    print('=========分析6:风险等级概况=========')
    describe_all = word_file.split('在渗透测试范围内共发现')[-1].split('个可能潜在的安全问题')[0]  # 获取漏洞总数
    describe_high = word_file.split('其中高风险级别的问题有')[-1].split('个,中风险级别的问题有')[0]  # 获取高危漏洞
    describe_mid = word_file.split('个,中风险级别的问题有')[-1].split('个,低风险为')[0]  # 获取中危漏洞
    describe_low = word_file.split('个,低风险为')[-1].split('按照风险等级分类如下图所示')[0].split('个。')[0]  # 获取低危漏洞
    if int(describe_all) == int(describe_high) + int(describe_mid) + int(describe_low):
        print(Fore.GREEN + '[√] 风险等级概况中的漏洞数量自身吻合:' +
              '漏洞总数:' + describe_all + ',高危:' + describe_high + ',中危:' + describe_mid + ',低危:' + describe_low)
    else:
        print(Fore.RED + '[X] 测试结果中的漏洞数量自身异常' +
              '\t[info] 漏洞总数:' + describe_all + ',高危:' + describe_high + ',中危:' + describe_mid + ',低危:' + describe_low)

    if describe_all == test_risk_all and test_risk_high == describe_high and describe_mid == test_risk_mid and describe_low == test_risk_low:
        print(Fore.GREEN + '[√] 风险等级概况中的漏洞数量 与 测试结果中的漏洞数量吻合')
    else:
        print(Fore.RED + '[X] 风险等级概况中的漏洞数量 与 测试结果中的漏洞数量不匹配')
        print(
            Fore.RED + '\t测试结果中的漏洞数量:漏洞总数:' + test_risk_all + ',高危:' + test_risk_high + ',中危:' + test_risk_mid + ',低危:' + test_risk_low)
    return describe_all, describe_high, describe_mid, describe_low


# 分析漏洞详细列表
def detailed_list_of_vulnerabilities():
    print('=========分析7:漏洞详细列表=========')
    tables = doc.tables  # 获取文件中的表格集
    table = tables[6]  # 获取文件中的第6个表格:漏洞详细列表
    # print(len(table.rows))  # 获取表格的的行数
    # print(len(table.columns))   # 获取表格的列数

    # 提取出“漏洞详细列表”中的“名称(地址)”中的地址,判断网站名称
    reg = "[^\u4e00-\u9fa5]"  # 提取出所有的中文字符,即可得到目标的名字
    name_and_uri = table.cell(1, 1).text
    target_name = re.sub(reg, '', name_and_uri)
    if file_web_name == target_name:
        print(Fore.GREEN + '[√] 漏洞详细列表的网站名字正确:' + target_name)
    else:
        print(Fore.RED + '[X] 漏洞详细列表的网站名字 与 文件名称中的名字不符' + '\t文件名称中的名字:' + file_web_name + ',漏洞详细列表的网站名字' + target_name)

    # 判断网站地址
    flag = 1
    target_uri = name_and_uri.replace(target_name, '').strip()
    for i in file_web_path_list:
        if i not in target_uri:
            message1 = '[X] 漏洞详细列表的网站地址与文件中地址不一致' + \
                       '\t[info] 文件名中的网站地址:' + file_web_path + ',漏洞详细列表的网站地址:' + target_uri
            print(Fore.RED + message1)
            flag = 0
            break
    if flag:
        print(Fore.GREEN + '[√] 漏洞详细列表的网站地址正确:' + target_uri)

    # 分析漏洞数量与危险级别
    form_all = 0
    form_high = 0
    form_mid = 0
    form_low = 0
    result111 = ''
    for i in range(1, len(table.rows)):
        for j in range(2, len(table.columns)):
            result111 = result111 + table.cell(i, j).text + '\t'  # 用来拼接获取“漏洞详细列表”
            # 判断是否是“危险级别”的那列
            if table.cell(i, j).text == '高':
                form_high = form_high + int(table.cell(i, j - 1).text)
            if table.cell(i, j).text == '中':
                form_mid = form_mid + int(table.cell(i, j - 1).text)
            if table.cell(i, j).text == '低':
                form_low = form_low + int(table.cell(i, j - 1).text)
        result111 = result111 + '\n'
    form_all = form_high + form_mid + form_low
    form_all = str(form_all)
    form_high = str(form_high)
    form_mid = str(form_mid)
    form_low = str(form_low)
    print(Fore.GREEN + '[√] 漏洞详细列表中的漏洞数量:' +
          '漏洞总数:' + form_all + ',高危:' + form_high + ',中危:' + form_mid + ',低危:' + form_low)
    # 比对“漏洞详细列表”和"测试结果中的漏洞数量"
    if form_all == test_risk_all and form_high == test_risk_high and form_mid == test_risk_mid and form_low == test_risk_low:
        print(Fore.GREEN + '[√] 漏洞详细列表中的漏洞数量 与 测试结果中的漏洞数量吻合')
    else:
        print(Fore.RED + '[X] 漏洞详细列表中的漏洞数量 与 测试结果中的漏洞数量不匹配')
        print(
            Fore.RED + '\t漏洞详细列表中的漏洞数量:漏洞总数:' + form_all + ',高危:' + form_high + ',中危:' + form_mid + ',低危:' + form_low)
        print(
            Fore.RED + '\t测试结果中的漏洞数量:漏洞总数:' + test_risk_all + ',高危:' + test_risk_high + ',中危:' + test_risk_mid + ',低危:' + test_risk_low)
    # 比对“漏洞详细列表”和"风险等级概况中的漏洞数量"
    if form_all == out_describe_all and form_high == out_describe_high and form_mid == out_describe_mid and form_low == out_describe_low:
        print(Fore.GREEN + '[√] 漏洞详细列表中的漏洞数量 与 风险等级概况中的漏洞数量吻合')
    else:
        print(Fore.RED + '[X] 漏洞详细列表中的漏洞数量 与 风险等级概况中的漏洞数量不匹配')
        print(
            Fore.RED + '\t漏洞详细列表中的漏洞数量:漏洞总数:' + form_all + ',高危:' + form_high + ',中危:' + form_mid + ',低危:' + form_low)
        print(
            Fore.RED + '\t风险等级概况中的漏洞数量:漏洞总数:' + out_describe_all + ',高危:' + out_describe_high + ',中危:' + out_describe_mid + ',低危:' + out_describe_low)
    print('漏洞详情列表如下:')
    print(result111)


# 检查“安全漏洞详细分析”
# 思路:提取“漏洞详细列表”中的内容,去“安全漏洞详细分析”中检索
def detailed_vulnerability_analysis():
    print('=========分析8:安全漏洞详细分析=========')
    tables = doc.tables  # 获取文件中的表格集
    table = tables[6]  # 获取文件中的第6个表格:漏洞详细列表
    for i in range(1, len(table.rows)):
        vulnerability_information = table.cell(i, 2).text + '(' + table.cell(i, 4).text + ')'
        if vulnerability_information in word_file:
            print(Fore.GREEN + '[√] 漏洞详细列表中的漏洞 在 安全漏洞详细分析中找到:' + vulnerability_information)
        else:
            print(Fore.RED + '[√] 漏洞详细列表中的漏洞 在 安全漏洞详细分析中没找到:' + vulnerability_information)


'''
正文内容
'''
print('''渗透测试报告专用检查脚本(仅支持docx格式文档)
注意事项:
1. 运行脚本时,docx文档最好是关闭状态,否则有可能报错
2. 如果出现报错,建议文件“另存为”或重命名(报错原因多是由于上传VSS导致文件属性变化导致的)
3. 脚本能够穿透目标目录,检查出所有docx文档''')
input_path = input('请输入文件所在目录,或者按回车键选择当前脚本所在路径:')
if len(input_path) == 0:
    input_path = os.getcwd()
else:
    if os.path.isdir(input_path):
        pass
    else:
        pass
        # exit('无效路径,程序自动结束!')

docx_list = []  # 用来存储所有docx后缀的渗透测试报告文档的绝对路劲
init(autoreset=True)

for current_folder, list_folders, files in os.walk(input_path):
    for f in files:  # 用来遍历所有的文件,只取文件名,不取路径名
        if f.endswith('docx'):  # 判断文件是不是docx类型的
            path_f = current_folder + '\\' + f  # 给出文档的的绝对路径
            docx_list.append(path_f)

for file in docx_list:
    print(Fore.YELLOW + '[+] 开始测试:' + os.path.basename(file))
    doc = Document(file)
    word_file = ''  # 用来存储word中的文字内容

    # 从文件名中提取如日期,如:20220427
    matches = re.findall(r"\d{8}", file)
    if len(matches) == 1:
        matches = str(matches).replace("['", '').replace("']", '')
    else:
        exit('文件名称中日期有误:' + str(matches))

    filetime = matches
    fileyear = filetime[0:4]
    filemonth = filetime[4:6]
    filedata = filetime[6:8]

    # 从文件名中提取出测试的版本
    file_version = file.split('(P')[-1].split('.0)')[0]

    # 从文件名中提取出网站名称
    file_web_name = os.path.basename(file).split('(', 1)[0]

    # 从文件名中提取出网站地址
    file_web_path = file.split('(', 1)[-1].split(')', 1)[0]
    file_web_path_list = file_web_path.split('_')
    # print(file_web_path_list)

    # 读取到word文件中的内容,存储到 word_file 中
    for paragraph in doc.paragraphs:
        # print(paragraph.text)
        word_file = word_file + paragraph.text + '\n'

    feng_mian()
    date_of_revision()
    test_risk_all, test_risk_high, test_risk_mid, test_risk_low = test_objects_and_test_results()
    test_range()
    word_content_test_records()
    out_describe_all, out_describe_high, out_describe_mid, out_describe_low = risk_level_describe()
    detailed_list_of_vulnerabilities()
    detailed_vulnerability_analysis()
    print(Fore.YELLOW + '[-] 测试结束'+'\n')
# os.system('pause')  # 在脚本中运行时可以删除此行

实现效果如下:
python实现——批量检查渗透测试报告_第1张图片

参考

参考:python自动化办公——python操作Excel、Word、PDF集合大全

你可能感兴趣的:(python,渗透测试,python)