基于Python的nessus API简析——监听&获取扫描结果

来源:互联网 发布:网络协议教程 pdf 编辑:程序博客网 时间:2024/05/17 14:15

前言

之前的文章中我们完成了登录并发起了一次扫描,接下来我们将继续跟进,监听扫描进度并获取扫描结果。

一、监听扫描状态

扫描开始后,我们需要监听扫描任务来确定任务是否成功发起、结束或意外终止。
这里使用的API为:
GET /scans/{scan_id}
除了路径参数scan_id之外,它还可以接受一个查询字符串history_id这里我们用不着所以就不深入了,有兴趣的同学可以参看:
https://localhost:8834/api#/resources/scans/details

我们来看一下这个API的返回值,这里我省略了很多字段,大家可以在官方文档里看到完整的版本。目前我们感兴趣的信息只有respone[‘info’][‘status’],即本次扫描的状态。

{    "info": {        "status": {string},        ...        "folder_id": {integer},        "targets": {string},        ...        "scanner_name": {string},        ...    },    "hosts": [...],    ...    "vulnerabilities": [...],}

那么监听任务状态也就很简单了,只要我们每隔一段时间发送请求查询任务状态即可,代码如下:

import time# 监听指定任务状态def listen_scan(scan_id):    # 调用/scans/{scan_id}/launch    url = 'https://localhost:8834/scans/{scan_id}'.format(scan_id=scan_id)    while True:        # 每隔60秒发送一次请求        time.sleep(60)        # 发送请求        respon = requests.get(url, headers=header, verify=False)        # 是否请求成功        if respon.status_code == 200:            status = json.loads(respon.text)['info']['status']            print status            if status == 'running':                continue            elif status == 'completed':                return True            else:                break    return False

二、获取扫描结果

当我们监听到任务结束,接下来要做的就是处理本次扫描的结果了,从之前贴出来的返回值中我们可以看到,/scans/{scan_id}接口除了返回扫描任务的状态之外,也返回了一个漏洞列表response[‘vulnerabilities’]和一个主机列表response[‘hosts],漏扫结果的获取就和这里面的信息有关。

1、漏洞总览

首先我们来看一下vulnerabilities’字段中都返回了什么东西。

"vulnerabilities":[        {        "plugin_id": {integer},        "plugin_name": {string},        "plugin_family": {string},        "count": {integer},        "vuln_index": {integer},        "severity_index": {integer}        }    ]

可以看到返回的是一个字典列表,包含的信息是本次漏扫的一个总览,内容为漏洞数目的统计和漏洞的基本信息,其中包括了一个plugin_id,可以用来获取漏洞的详情。

2、漏洞详情

从扫描的详情中我们只能看到本次漏洞的概览,如果想要进一步了解漏洞的详情(注意是漏洞本身的详情,与本次扫描无关)。
漏洞信息详情查询的接口为:
GET /plugins/plugin/{id}
文档位置如下:
https://localhost:8834/api#/resources/plugins/plugin-details
照惯例我们来看一下这个接口的返回值。

{    "id": {integer},    "name": {string},    "family_name": {string},    "attributes": [        {            "attribute_name": {string},            "attribute_value": {string}        }    ]}

乍一看它的返回值似乎有些过于简单了,不过其中有个非常有趣的字典列表attributes,它可以用来表示漏洞各类信息,包括漏洞的CVE编号,危险等级,描述,详情,解决方案等,下面的实例代码可能有助于我们更好的理解它的作用。

# 根据id获取漏洞详情def get_vul_detail(plugin_id):    vul_detail = {        # CVE编号        'cve_number': '',        # 漏洞名称        'vul_name': '',        # 漏洞描述        'vul_intro': '',        # 漏洞详情        'vul_detail': '',        # 漏洞等级        'vul_level': 0,        # 解决方案        'solution': '',        # 漏洞发布时间        'release_time': '',        # 漏洞发现时间        'discover_time': ''    }    url = 'https://localhost:8834/plugins/plugin/{plugin_id}'.format(plugin_id=plugin_id)    respone = requests.get(url, headers=header, verify=False)    if respone is not None:        result = json.loads(respone.text)        # 漏洞名称        vul_detail['vul_name'] = result['name']        # 遍历attributes生成结果        for attr in result['attributes']:            attr_name = attr['attribute_name']            # cve编号            if attr_name == 'cve':                vul_detail['cve_number'] = attr['attribute_value']                continue            # 漏洞描述            elif attr_name == 'synopsis':                vul_detail['vul_intro'] = attr['attribute_value']                continue            # 漏洞详情            elif attr_name == 'description':                vul_detail['vul_detail'] = attr['attribute_value']                continue            # 漏洞等级            elif attr_name == 'risk_factor':                vul_detail['risk_factor'] = attr['attribute_value']                continue            # 漏洞描述            elif attr_name == 'solution':                vul_detail['solution'] = attr['attribute_value']                continue            # 漏洞发布时间            elif attr_name == 'plugin_publication_date':                vul_detail['release_time'] = attr['attribute_value']                continue            # 漏洞发现时间            elif attr_name == 'vuln_publication_date':                vul_detail['discover_time'] = attr['attribute_value']                continue        return vul_detail    return None

这里我采取方法的是遍历attributes,然后根据attribute_name来确定是否是我需要的信息,并将相应的attribute_value取出放入我自己的输出字典中。
当然你也可以利用下面这种方式将所有的值全部取出来。

for attr in result['attributes']:    vul_detail[attr['attribute_name']] = attr['attribute_value']

3、基于主机的漏洞列表

漏洞详情仅是对于漏洞的描述,接下来我们来看一下我们最感兴趣的主机漏洞详情。先看一下scan接口返回的hosts列表里都有什么。

{    "host_id": {integer},    "host_index": {string},    "hostname": {integer},    "progress": {string},    "critical": {integer},    "high": {integer},    "medium": {integer},    "low": {integer},    "info": {integer},    "totalchecksconsidered": {integer},    "numchecksconsidered": {integer},    "scanprogresstotal": {integer},    "scanprogresscurrent": {integer},    "score": {integer}}

其中host_id不用说,接下来我们获取主机漏洞详情的时候肯定用得着,另外还有几个比较有意思的字段,比如high, medium, low, info,顾名思义是对各等级风险的统计。
可以通过下面的接口获取主机漏洞的详情。
GET /scans/{scan_id}/hosts/{host_id}
文档位置为:
https://localhost:8834/api#/resources/scans/host-details
我们先来看一下它的返回值。

{    "info": {        "host_start": {string},        "mac-address": {string},        "host-fqdn": {string},        "host_end": {string},        "operating-system": {string},        "host-ip": {string}    },    "compliance": [        host_compliance Resource    ],    "vulnerabilities": [        host_vulnerability Resource    ]}

其中info是主机的基本信息,compliance是主机合规性的信息,这里我们不用管,最后vulnerabilities就是我们关注的漏洞信息,它以字典列表的形式存放,我们来看一下里面的具体内容。

"vulnerabilities": [   {   "host_id": {integer},   "hostname": {string},   "plugin_id": {integer},   "plugin_name": {string},   "plugin_family": {string},   "count": {integer},   "vuln_index": {integer},   "severity_index": {integer},   "severity": {integer}   }]

其中包括了漏洞的名称(plugin_name),漏洞ID(plugin_id),漏洞等级(severity,0: info, 1: low, 2: medium, 3: high, 4: critical)等信息,我们可以按需来读取。
例子,返回一个主机-漏洞列表:

# 获取扫描结果(基于主机)def get_scan_detail_baseon_host(scan_id):    # 结果,主机漏洞字典列表    result = []    # 主机漏洞字典    host_detail = {}    # 调用    url = 'https://localhost:8834/scans/{scan_id}'.format(scan_id=scan_id)    # 发送请求    respon = requests.get(url, headers=header, verify=False)    # 取出主机列表    host_list = json.loads(respon.text)['hosts']    # 遍历主机列表并生成结果    for host in host_list:        # IP为键名        host_detail[host['hostname']] = get_vul_by_host(scan_id, host['host_id'])        result.append(host_detail)    return result# 获得主机漏洞信息def get_vul_by_host(scan_id, host_id):    # 调用    url = 'https://localhost:8834/scans/{scan_id}/hosts/{host_id}'.\        format(scan_id=scan_id, host_id=host_id)    # 发送请求    respon = requests.get(url, headers=header, verify=False)    return json.loads(respon.text)['vulnerabilities']

日常使用中,基于主机是一个常用的维度,上面的代码,实现了一次简单的基于主机的漏洞结果整理,并将结果以字典列表的形式输出,代码比较简陋,希望对大家有所启发。

阅读全文
0 0
原创粉丝点击