主机漏洞扫描告警与nmap指纹

和URL扫描的QPS太高把业务告警打挂相匹配的情况:HOST主机漏洞扫描遇到碰瓷的端口服务。

扫描器经常会遇到内网中的某些端口开放的服务,不接收特定格式外的数据,一收到就会报错甚至挂掉,也不用写poc,浏览器贴上 http://ip: 端口直接导致服务报错。形如碰瓷一般,躺在内网中。
一般的说法是,这一块属于业务或者框架方负责,需要做数据校验,校验到不合规的数据,不进行处理抛弃。
但是在报错的处理上,有的业务可以选择直接忽视掉,比如flume某开源服务,发送如http的数据会直接报错,但报错是dba自己接收,可以选择不要,所以直接捕获不抛出就好了。但是作为服务框架,会据理力争报错不能直接丢弃,使用该服务框架的业务也可能传入不正确的数据,业务正常需求上需要报错。
所以在与某中台框架服务商讨后,采用了另一个方案:
框架上设置指纹功能,当发送特定数据的时候,返回特定指纹。

扫描器需要做的:
1.采用nmap端口扫描的时候,建立起连接后发送的框架指纹检测数据包应该是最高优先级的,也就是最早发的。
2.端口扫描识别到框架后,该端口在正常流程中不进入扫描,不传递给插件,除非插件选择了二级指纹或其他的配资,需要对该框架进行检测。

第二点比较好实现,下面探讨的是第一点的实现方式:采用nmap指纹或端口扫描插件中做处理

(半年一年前采用nmap指纹来做,最近在业务反馈后,花了一天的时间改了端口扫描的代码,更稳定可控。也不是说Nmap本身改探针不好,反复测是第一发包检测出业务的端口,就不会发其他探针了,但-sV偶尔抽一下,发了点别的包,业务拿着报错来找又没法复现,挺打脸的..)

Nmap服务探测 (探针优先级)  https://www.cnblogs.com/rab3it/articles/12020756.html

0X01 nmap指纹编写

指纹探针的编写这里写的挺好挺全的,再抄一遍没什么意义
https://www.cnblogs.com/liun1994/p/6986544.html

顺序上,探针的发送顺序是
NULL -> 端口匹配上的探针 -> 端口不匹配的或者没有ports的探针
且nmap只发送 rarity 重要级别在设置以下的探针(级别越低越重要)
tips: ports不匹配也会进行扫描
所以要想探针在最开始的时候被发送,ports 匹配1-65535,否则还会被端口匹配的探针抢在前面。

这一段放在NULL前(其实NULL的下一个也一样,尽量靠前)

vi /usr/share/nmap/nmap-service-probes


##############################MYSELF my_server NEXT PROBE##############################

Probe TCP MYServer q|\x12\x11\r\n\t|
rarity 1
ports 1-65535

match my_server m|\x00\x00i| p/my_server/

##############################NEXT PROBE##############################

缺点
a) 本身不稳定,可能收到预期外的数据包导致业务方程序报错
b) 每一个节点都需要保证nmap的nmap-service-probes是正确的
优点
a) 用nmap本身的指纹,高端优雅

0x02 python nmap插件中略过服务方指纹

只有加上-sV在,在扫描指纹的情况下,才会发送数据。
所以可以先扫描出存活的端口,筛选出非业务服务的端口,-sV扫描其他端口的指纹,不会对业务方的脆弱碰瓷端口发送预期外的数据。

缺点:比较麻烦
优点:稳定易控易修改

import nmap
import time


def check_server_port(target, port):
    # 业务端口返回True
    # 非业务端口正常返回False
    return False


def scan_port(target):
    portlist_info = dict()
    start = time.time()

    nmap_arguments = '-Pn -sT -max-scan-delay 5 -max-retries 2 -T4 -n --host-timeout 1200 --min-parallelism 100'
    connect_argument = nmap_arguments + " -p 1-65535"
    scanner = nmap.PortScanner()
    scanner.scan(target, arguments=connect_argument)
    if scanner[target].get('tcp'):
        # 扫描存活
        for port in scanner[target]['tcp']:
            if scanner[target].state() == 'up' and scanner[target]['tcp'] and \
                    scanner[target]['tcp'][int(port)]['state'] == 'open':
                portlist_info[port] = ""
        print(time.time() - start)
        # SCF检测,不扫描指纹
        service_port = list(portlist_info.keys())
        for port in service_port:
            if check_server_port(target, port):
                portlist_info[port] = "my_server"
                service_port.remove(port)
        service_port_str = ",".join([str(port) for port in service_port])
        # 扫描指纹
        version_argument = nmap_arguments + " -p %s -sV" % service_port_str
        scanner.scan(target, arguments=version_argument)
        if scanner[target].get('tcp'):
            for port in scanner[target]['tcp']:
                if scanner[target].state() == 'up' and scanner[target]['tcp'] and \
                        scanner[target]['tcp'][int(port)]['state'] == 'open':
                    product = scanner[target]['tcp'][int(port)]['product']
                    portlist_info[port] = product
    end = time.time()
    print(end-start)
    return portlist_info


if __name__ == '__main__':
    print(scan_port("127.0.0.1"))

posted @ 2020-06-11 00:53  huim  阅读(565)  评论(0编辑  收藏  举报