算法 自动采集列表(基于nginxmirror模块的流量采集方案解密 )

优采云 发布时间: 2021-10-20 14:14

  算法 自动采集列表(基于nginxmirror模块的流量采集方案解密

)

  这里我们以访问为例,可以看到如下信息,代理已经解密了发送的https数据包。

  

  基于nginx镜像模块

  基于nginx镜像模块的flow采集方案基本原理

  当然,不仅可以通过代理流量,也可以通过nginx镜像模块来采集流量。

  在基于nginx镜像模块的流程采集方案中,我们将通过以下步骤实现到目标系统采集的流程:

  1、 配置nginx配置文件,添加镜像服务器,指定后端地址为我们神奇修改的webserver地址。这样nginx会在请求来的时候对原创http请求包进行镜像,并将请求转发到镜像服务器。

  2、在镜像服务器上解析这些http请求包,然后解析明文请求包,然后将这些请求包推送到消息队列进行任务分发。

  实验验证了基于nginx镜像模块进行流量采集的可行性

  为了验证这个想法的可行性,我们来做一个实验。这里需要搭建一个支持mirror模块的nginx服务器,搭建过程不再赘述,读者可以自行搭建。

  现在让我们开始实验。首先,我们在服务器a(192.168.1.10)上安装配置nginx,在服务器192.16上安装配置我们修改的8.1.上的webserver 11.这个修改后的webserver负责解析nginx转发的http数据包,并将解析后的http数据包推送到消息队列中间。

  服务器a中的nginx配置文件如下:

  worker_processes 1;

events {

worker_connections 1024;

}

http {

include mime.types;

default_type application/octet-stream;

sendfile on;

keepalive_timeout 65;

server {

listen 8181;

mirror_request_body on;

access_log /var/log/nginx/test.log;

root html/test;

}

server {

mirror_request_body on;

listen 8282;

access_log /var/log/nginx/mir1.log;

root html/mir1;

}

upstream backend {

server 127.0.0.1:8181;

}

upstream test_backend1 {

server 192.168.1.11:9008;

#如果需要做负载均衡,多配置一些backend

#server 192.168.1.12:9008;

#server 192.168.1.13:9008;

}

server {

listen 80;

server_name localhost;

mirror_request_body on;

location / {

mirror /mirror1;

proxy_pass http://backend;

}

location = /mirror1 {

#internal;

proxy_pass http://test_backend1$request_uri;

}

}

}

  简单解释一下上面的配置信息。在nginx.conf配置中,配置启动三个服务器实例。80端口的服务器负责将原创请求包转发到8181和8282端口,8181端口的http服务负责将原创请求转发到web后端,8282端口的http服务负责转发原创请求向 Web 后端请求。镜像请求包转发到其他webserver(基于python的BaseHTTPRequestHandler修改的webserver)。配置完成后,我们启动nginx,在http服务目录下执行如下命令,创建实验所需的一些文件:

  cd /usr/share/nginx/html/

mkdir test mir1

echo "test page" >test/index.html

  接下来我们执行 curl 命令 curl

  执行该命令后,预期的结果是/var/log/nginx/mir1.log和/var/log/nginx/test.log中都有对应的访问记录,说明nginx成功镜像了一份将流量转发给8282和8181端口对应的http服务,看看实际访问结果

  

  没错,一切都和一开始的预期一样。从访问日志来看,镜像服务器转发的http请求包已经成功接收解析。这里我们举一个简单的例子:

  from http.server import HTTPServer, BaseHTTPRequestHandler

import json

class Resquest(BaseHTTPRequestHandler):

def handler(self):

print("data:", self.rfile.readline().decode())

self.wfile.write(self.rfile.readline())

def do_GET(self):

print(self.requestline)

print(self.headers)

data = {

"status":200,

"info":"test"

}

self.send_response(200)

self.send_header('Content-type', 'application/json')

self.end_headers()

self.wfile.write(json.dumps(data).encode())

def do_POST(self):

print(self.requestline)

print(self.headers)

req_datas = self.rfile.read(int(self.headers['content-length']))

print(req_datas.decode())

data = {

"status":200,

"info":"test"

}

self.send_response(200)

self.send_header('Content-type', 'application/json')

self.end_headers()

self.wfile.write(json.dumps(data).encode('utf-8'))

if __name__ == '__main__':

host = ('0.0.0.0', 9008)

server = HTTPServer(host, Resquest)

print("Starting server, listen at: %s:%s" % host)

server.serve_forever()

  启动服务后,可以接收到镜像服务器转发过来的http请求包。这里我们重写了 do_GET 和 do_POST 函数来解析和打印请求的数据包。实验结果如下:

  

  post数据包效果信息如下(curl -X POST -d'name=张三')

  

  这个过程可以用下图表示:

  

  但是,如果通过nginx镜像模块采集流量,则只能针对企业内部连接nginx的项目。如果要检测没有连接nginx的项目,或者互联网上的一些其他网站,也需要使用代理模式。两者之间存在互补性。Nginx可以解决配置代理和证书的麻烦(当然nginx本身也需要配置https证书),代理模式可以让被动漏洞扫描系统更加有效。但对企业而言,基于nginx镜像模块的流量采集解决方案在自动化上会有比较优势。

  三、分布式漏洞检测框架实现方案

  上面解释了基于http/https代理的流量劫持的基本原理,那么如何基于此开发一个被动的漏洞检测系统呢?以及我们需要考虑哪些问题?在*敏*感*词*被动漏洞扫描的场景下,往往会有大量流量转发到代理服务器。如果没有合理的架构设计,代理服务器很可能会陷入包洪泛的困境,类似于dos Attack(ps:要进行漏洞检测,必须构造请求数据包。试想如果是500漏洞检测插件,那么每个请求的代理服务器至少要转发500个http请求包到目标web服务器,如果没有妥善处理,这是一件很可怕的事情)。那么如何处理这个问题呢?下面是我们设计的基于代理流量的被动漏洞扫描器的*敏*感*词*,我们将在此基础上进一步讨论。

  基于代理流量的分布式漏洞检测框架设计

  

  在基于代理的被动流量采集方案中,用户在chrome端配置https/http代理,让流量先到我们的代理服务器。代理服务器将原创数据包推送到redis消息队列进行任务分发,slave worker监控redis消息队列,通过抢占方式获取任务信息,加载漏洞检测插件,发送带有攻击payload的请求包到服务器进行漏洞检测和分析。另一方面,代理服务器也会将原创请求包转发给服务器,以便客户端获得想要的请求结果。

  在性能优化方面,一方面可以通过适当的sleep方式批量发送这些http攻击数据包,另一方面可以分布式的方式减轻漏洞检测分析服务器的负担。

  基于nginx镜像模块的分布式漏洞检测框架设计

  

  在基于nginx镜像模块的被动流量采集方案中,配置镜像服务器对原创请求流量进行镜像,将镜像流量转发到aeacus服务器分析http流量,并推送解析后的http请求消息信息 到消息队列。然后slave worker*敏*感*词*redis消息队列,通过抢占方式获取任务信息,加载漏洞检测插件,将带有攻击载荷的请求包发送到服务器进行漏洞检测分析。

  在基于nginx镜像模块的被动流量采集方面,可以从以下两个方面进行性能优化。一方面,对于大量并发的请求,可以配置nginx负载均衡,将这些请求平均分配到各个镜像服务器,让各个镜像服务器处理的任务相对较少。镜像可根据实际业务量增减。服务器的数量,另一方面,为了降低每个slave worker的漏洞分析压力,可以根据实际情况扩展分布式任务节点的数量。当然,重点是对数据包进行去重,否则会增加任务节点的检测压力。

  脏数据解决方案讨论

  在被动漏洞分析检测过程中,如果一些post请求数据包具有存储功能,那么大量的攻击性数据包无疑会带来大量的脏数据。这也是很多安全人员在推一些安全测试产品时经常考虑的一个问题。推的时候还担心会因为这个问题受阻,但其实被动漏洞检测系统主要是连接测试环境,脏数据的影响比较小,几乎可以忽略不计。如果测试方觉得大量的脏数据会影响测试的效果,那我们不妨讨论一下如何处理测试过程中产生的脏数据问题。网上有同学的解决办法是过滤一些可能涉及存储的接口,但个人认为这个要慎重考虑,因为不能保证这些接口没有漏洞,容易造成漏报。并且如果不想让脏数据误导考生,可以在payload中插入特定的识别码,供考生识别。但我认为最好的办法是在测试环节之后安排安全测试。在测试链路中,只采集流量,不进行安全测试分析。测试同学确认功能测试没问题后,再发送到测试服务器。安全检查和分析的相应检查说明。因为你不能保证这些接口没有漏洞,容易造成漏报。并且如果不想让脏数据误导考生,可以在payload中插入特定的识别码,供考生识别。但我认为最好的办法是在测试环节之后安排安全测试。在测试链路中,只采集流量,不进行安全测试分析。测试同学确认功能测试没问题后,再发送到测试服务器。安全检查和分析的相应检查说明。因为你不能保证这些接口没有漏洞,容易造成漏报。并且如果不想让脏数据误导考生,可以在payload中插入特定的识别码,让考生识别。但我认为最好的方法是在测试环节之后安排安全测试。在测试链路中,只采集流量,不进行安全测试分析。测试同学确认功能测试没问题后,再发送到测试服务器。安全检查和分析的相应检查说明。可以在payload中插入一个特定的识别码,供考生识别。但我认为最好的办法是在测试环节之后安排安全测试。在测试链路中,只采集流量,不进行安全测试分析。测试同学确认功能测试没问题后,再发送到测试服务器。安全检查和分析的相应检查说明。可以在payload中插入一个特定的识别码,供考生识别。但我认为最好的方法是在测试环节之后安排安全测试。在测试链路中,只采集流量,不进行安全测试分析。测试同学确认功能测试没问题后,再发送到测试服务器。安全检查和分析的相应检查说明。

  四、插件模块设计1、支持动态加载指纹识别模块

  0x1 指纹识别模块加载执行流程图*敏*感*词*

  

  2、支持动态加载漏洞检测模块

  0x0 Aeacus漏洞检测模块动态插件加载原理说明

  插件加载在扫描作业的初始化阶段进行。通过python中的动态导入模块技术,将指定文件中的模块导入到当前进程中,然后检查导入模块的合法性。如果符合预期的模块格式要求,则将该模块保存在模块缓存区。在进行漏洞检测操作时,只需要遍历执行模块缓存区中的插件即可。动态加载的目的是为了支持漏洞检测插件的热更新,即后续插件维护者只需要将编译好的插件放到指定目录下,无需重启系统,让系统支持更多的漏洞检测能力。

  代码

  //python中动态加载指定文件中的模块信息

def module_dynamic_loader(file_path):

if '' not in importlib.machinery.SOURCE_SUFFIXES:

importlib.machinery.SOURCE_SUFFIXES.append('')

try:

module_name = 'plugin_{0}'.format(get_filename(file_path, with_ext=False))

spec = importlib.util.spec_from_file_location(module_name, file_path, loader=PocLoader(module_name, file_path))

mod = importlib.util.module_from_spec(spec)

spec.loader.exec_module(mod)

return mod

except ImportError:

error_msg = "load module failed! '{}'".format(file_path)

print(error_msg)

raise

  0x1漏洞检测模块加载执行流程图*敏*感*词*

  

  五、 爬虫模块与Aeacus被动漏洞分析引擎的结合

  在爬虫方面,可以配置https/http代理与aeacus系统链接,使爬虫爬取的数据包转发到后端被动漏洞分析引擎进行处理。如果使用nginx镜像流量采集方案,则不需要配置代理。直接爬行,aeacus系统可以自动获取相关的请求数据包。

  六、数据包去重存储方案 数据包去重的必要性

  被动的漏洞扫描器在采集流量的过程中难免会采集到大量重复的数据包,重复的数据包会增加后端漏洞分析引擎的负载,所以我们需要去采集到的http/https请求包. 重处理。

  执行

  主要依赖去重算法:Bloom去重算法

  算法库:redisbloom

  算法库安装配置:

  #服务端安装配置

docker pull redislabs/rebloom:latest

docker run -p 5276:6379 --name redis-redisbloom redislabs/rebloom:latest

#客户端处理安装

pip install redisbloom

  算法原理

  基本的

  Bloom filter内部维护一个bitArray(位数组),所有数据一开始都设置为0。当一个元素过来时,可以使用多个hash函数(hash1、hash2、hash3....)来计算不同的hash值,通过hash值找到对应的bitArray下标。里面的值0设置为1。需要注意的是Bloom filter有误判率的概念。误判率越低,阵列越长,占用空间越大。误报率越高,数组越小,占用空间越小。

  初始化

  

  插入,经过3个哈希函数的计算,得到的哈希值分别为1、4、7,然后在bitarray对应的索引处将该位标记为1。

  

  数据包bloom去重代码实现

  这里主要是根据端口、主机名、路径、方法、参数、协议参数对数据包进行签名,示例代码如下:

  #!/usr/bin/env python3

# -*- coding: utf-8 -*-

# desc: 数据包布隆去重

# author: pOny

from redisbloom.client import Client

from configure import bloom_server_address,bloom_server_port

class bloomfilter():

rb = Client(host=bloom_server_address, port=bloom_server_port)

@staticmethod

def add_packet_hash(**kwargs):

'''

添加hash信息

:param kwargs:

datadict={

"method":"post",

"protocal":"http",

"hostname":"pony.com",

"port":"80",

"path":"/docs",

"params":["p1","p2","p3"]

}

:return: None

'''

port,hostname,path,method,params,protocal=kwargs.get("port"),\

kwargs.get("hostname"),kwargs.get("path"),\

kwargs.get("method"),kwargs.get("params"),\

kwargs.get("protocal")

params= "".join(params) if params else ""

if isinstance(port,int):

port=str(port)

data="{}{}{}{}{}{}".format(port,hostname,path,method,params,protocal)

bloomfilter.rb.bfAdd(kwargs.get("projectid"),data)

@staticmethod

def dofilter(**kwargs):

'''

布隆去重复

:param kwargs:

datadict={

"method":"post",

"protocal":"http",

"hostname":"lixiang.com",

"port":"80",

"path":"/docs",

"params":["p1","p2","p3"],

}

:return:Boolean

'''

port,hostname,path,method,params,protocal=kwargs.get("port"),\

kwargs.get("hostname"),kwargs.get("path"),\

kwargs.get("method"),kwargs.get("params"),\

kwargs.get("protocal")

params= params="".join(params) if params else ""

if isinstance(port,int):

port=str(port)

data="{}{}{}{}{}{}".format(port,hostname,path,method,params,protocal)

return bloomfilter.rb.bfExists(kwargs.get("projectid"),data)

  七、Aeacus 被动漏洞扫描器介绍

  在过去的q2季度,理想汽车安全部的devsecops团队一直致力于被动漏洞扫描器的研发,积累了一些被动漏洞扫描器的开发经验。在这里给大家分享一些经验,希望对大家分享后的工作有一定的帮助。

  注:以下涉及的漏洞数据均为模拟数据。

  0x0 整体架构图

  

  0x1 漏洞数据可视化展示面板

  

  0x2 漏洞管理

  漏洞列表

  

  漏洞详情

  

  0x3 项目管理

  项目清单

  

  添加的项目

  

  0x4 插件管理

  插件列表

  

  插件添加页面

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线