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

前言

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

一、监听扫描状态

扫描开始后,我们需要监听扫描任务来确定任务是否成功发起、结束或意外终止。
这里使用的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
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值