红日攻防实验室

红日攻防实验室



InsectsAwke|自动化工具源码分析(二)

Screenshot-dashboard.png

红日安全-工具研发小组
博客:http://sec-redclub.com/team/

简介

InsectsAwke是一个比较著名的开源的基于Python开发的漏洞扫描系统。启蒙于Bugscan脱胎于Pocsuite。采用FLASK+MongoDB提供WEB服务。初步具备Por的健壮性。

主要功能

  • 漏洞扫描

    • 通过调用创宇的 Pocsuite 进行扫描,扫描插件通过 Seebug
    • 扫描目标只能是单个 IP 或者 URL,不支持网段扫描(公司是中小型公司,就忘写这块需求了),默认有80余个插件,大多是 Seebug 的免费PoC
    • 任务周期可以选择临时、每日、每周或每月
  • 资产管理

    • 可以通过各资产库创建漏洞扫描任务,同样资产库只能是单个 IP 或者 URL。
    • 开启端口发现功能后,后端会定时调用 nmap 对资产进行端口扫描,需要扫描的端口可以在设置里进行配置
  • 域名发现功能

    • 即子域名爆破功能,但目前功能尚不完善,只能通过配置字典进行暴力猜解,域名字典可以在设置处进行配置,项目 tests 文件夹内提供了一份子域名字典(字典来源 ring04h 的 wydomain 项目)

安装过程

  • 安装虚拟机 16.04
  • 更新为国内源
  • 获取项目源码
 git clone https://github.com/jeffzh3ng/InsectsAwake.git
  • 安装 Python 及 pip
sudo apt update
sudo apt install python python-pip

  • 安装 MongoDB

    • 安装的是企业版MongoDB,普通的MongoDB是无法支持系统运行的
    • 很多人按照freebuf 的安装不成功,是因为载入的是3.4版本的安装源
      可是当我们执行 sudo apt-get install -y mongodb-enterp的时候,如果没有指定版本号的话,apt默认安装最新的即3.6版本,所以mongodb-enterprise在安装的时候就会出现问题。这里我们加载的是3.6版本的安装源,所以可以安装成功
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
echo "deb [ arch=amd64,arm64,ppc64el,s390x ] http://repo.mongodb.com/apt/ubuntu xenial/mongodb-enterprise/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-enterprise.list
sudo apt-get update
sudo apt-get install -y mongodb-enterprise

  • 其他系统安装参考官方手册:

https://docs.mongodb.com/manual/installation/

  • 安装 Python 依赖包
cd InsectsAwake
sudo pip install pip -U
sudo pip install -r requirements.txt
  • 安装nmap
sudo apt install nmap
  • 配置数据库

    • 启动数据库
    sudo mkdir -p  /data/db
    sudo service mongod start
    mongo --host 127.0.0.1:27017

    • 添加用户
    use InsectsAwake
    db.createUser({user:'you username',pwd:'you password',roles:[{role:'dbOwner',db:'InsectsAwake'}]})
    exit

  • 修改扫描器配置

    • 扫描器配置文件路径:InsectsAwake-Project/instance/config.py
    class Config():
        WEB_USER = 'admin'          // 扫描器登录用户
        WEB_PASSWORD = 'whoami'     // 扫描器登录密码
        WEB_HOST = '127.0.0.1'      // 本地访问
        WEB_PORT = 5000             // Web服务端口
        POCSUITE_PATH = basedir + '/../InsectsAwake/views/modules/scanner/pocsuite_plugin/'
    
    class ProductionConfig(Config):
        DB_HOST = '127.0.0.1'       // 数据库地址
        DB_PORT = 27017             // 数据库端口
        DB_USERNAME = 'testuser'    // 数据库用户
        DB_PASSWORD = 'testpwd'     // 数据库密码
        DB_NAME = 'test'            // 数据库名
    
        // 数据库集合名
        PLUGIN_DB = 'test_plugin_info'
        TASKS_DB = 'test_tasks'
        VULNERABILITY_DB = 'test_vuldb'
        ASSET_DB = 'test_asset'
        CONFIG_DB = 'test_config'
        SERVER_DB = 'test_server'
        SUBDOMAIN_DB = 'test_subdomain'
        DOMAIN_DB = 'test_domain'
        WEEKPASSWD_DB = 'test_weekpasswd'

    比较懒,clone下来直接chmod -R 777 然后就可以愉快的修改文件了

  • 初始化数据库
cd /InsectsAwake/migration
python start.py

  • 运行系统
sudo ./run.sh restart
  • run.sh会出现有关nohup的报错可以参考

https://blog.csdn.net/educast/article/details/28273301
进行适当修改

  • 成功
  • 项目默认运行在127.0.0.1:5000 (可以 修改 默认的 WEB_HOST 及 WEB_PORT),无法外网访问,建议配置 Nginx 或者 Caddy 等Web服务代理访问
  • 后记

    • 系统安装后先更新一遍,推荐清华源
    • 安装mongodb-enterprise的时候建议慢慢来一遍成功,否则安装会很麻烦apt各种报错基本等于报废需要重新来过了。。。
    • 刚刚启动run.sh的时候等一下才能看到web页面

工作流程

下图为系统运行简单SDL流程图

项目结构

├── InsectsAwake
│   ├── app.py flask blueprint注册
│   ├── __init__.py
│   ├── static   网页静态文件夹
│   ├── templates 网页html模板文件夹
│   └── views  
│       ├── asset_management.py  flask资产管理处理页面
│       ├── authenticate.py   flask网页认证页面,登录与登出
│       ├── dashboard.py   dashboard页面
│       ├── index.py   主页
│       ├── __init__.py
│       ├── lib
│       │   ├── __init__.py
│       │   ├── mongo_db.py  创建和管理mongo数据库
│       ├── modules
│       │   ├── discovery   资产发现
│       │   │   ├── __init__.py  
│       │   │   ├── port_scanner.py   扫描端口和目标服务信息
│       │   ├── __init__.py
│       │   ├── scanner   漏洞扫描
│       │   │   ├── __init__.py
│       │   │   ├── pocsuite_plugin   存放漏洞扫描poc插件的文件夹
│       │   │   ├── pocsuite_scanner.py  调用pocsuites框架对目标进行漏洞扫描
│       │   │   ├── vulnerability_plugin.py 管理漏洞poc插件,向数据库中加入插件信息
│       │   ├── subdomain  子域名爆破
│       │   │   ├── __init__.py
│       │   │   ├── subdomain.py  子域名爆破
│       │   └── week_passwd
│       │       ├── __init__.py
│       │       └── week_http_passwd_test.py  作者还未实现
│       ├── plugin_management.py  flask poc插件管理页面
│       ├── settings.py   flask 平台参数设置页面,如线程数量,字典
│       ├── sql_injection.py  作者还未实现
│       ├── subdomain_brute.py  flask 子域名爆破页面
│       ├── task_management.py  flask 任务管理页面
│       ├── vulnerability_management.py  flask 漏洞扫描结果管理页面 
│       ├── weak_passwd_test.py   falsk弱口令管理页面
├── InsectsAwake.py  主执行文件
├── instance
│   ├── config.py   flask 配置和数据库配置
│   ├── __init__.py
├── LICENSE
├── logs
│   ├── db.log
│   └── log.log
├── migration
│   ├── DataModels
│   └── start.py  创建数据库
├── requirements.txt
├── run.sh  
├── tests
│   ├── domain.dict 子域名爆破字典

项目思维导图

image.png

主文件分析

def scanner():
    """
    调用漏洞扫描模块
    :return: 
    """
    config_db = db_name_conf()['config_db']
    scanner_time = int(connectiondb(config_db).find_one()['scanner_time'])
    print('Scanner is start...')
    scanner_loop_execute(scanner_time)


def manage():
    """
    调用flask
    :return: 
    """
    app.run(host=flask_app.config.get('WEB_HOST'), port=flask_app.config.get('WEB_PORT'))


def discovery():
    """
    调用资产发现模块
    :return: 
    """
    print('Discovery is start...')
    scheduler = BlockingScheduler()
    try:
        # 函数实现的是每天14:47执行这start_port_scan这个函数 
        scheduler.add_job(MultiProcess().start_port_scan, 'cron', day='1-31', hour=14, minute=47)
        scheduler.start()
    except Exception as e:
        print(e)


def subdomain():
    """
    调用子域名爆破模块
    :return: 
    """
    scanner_time = 30
    print('Subdomain is start...')
    subdomain_loop_execute(scanner_time)


if __name__ == "__main__":
    """
    开启四个线程执行这4个模块
    """
    t1 = threading.Thread(target=scanner, args=())
    t2 = threading.Thread(target=manage, args=())
    t3 = threading.Thread(target=subdomain, args=())
    t4 = threading.Thread(target=discovery, args=())
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()

子域名爆破模块

该模块与服务器Flask是分开的。Flask负责将前端接受的关于子域名破解的信息存储和更新到数据库中,而核心的子域名暴力破解程序则使用调度器每隔一段时间循环检查数据库中的配置文件,当数据库中有数据满足暴力破解程序运行的条件时,就开始执行程序,对目标进行子域名暴力破解,并将结果存储在数据库中。

简介

InsectsAwake/views/subdomain_brute.py  核心文件,用于对目标进行子域名查找
InsectsAwake/views/modules/subdomain/subdomain.py  flask后端文件,用于接受前端的数据并存储在数据库中

执行函数
def subdomain():
    每30s运行一次子域名爆破程序
    scanner_time = 30
    print('Subdomain is start...')
    subdomain_loop_execute(scanner_time)

细节函数分析

class DomainsBrute:
    def __init__(self, target_domain, subdomain_dict, domain_id, domain_name):
        """
        初始化类和成员变量
        :param target_domain:  目标域名host
        :param subdomain_dict: 子域名爆破字典
        :param domain_id: 域名在数据库中所对应的IP
        :param domain_name: 域名的名字,如百度
        """
    def resolver_check(self):
        """
        对随机生成一个域名并进行处理,如果这个随机的域名存在就返回解析的结果
        :return: [] or False

    def handle_domain(self):
        """
        组成新的二级或者三级域名
        :return: <type 'list'>: [u'123.baidu.com', u'2323.baidu.com', u'sds.baidu.com']
        """
    
    def handle_result(self):
        """
        获取处理的结果,如果该二级或者三级域名存在,则存入数据库,
        :return:
        """

    def save_db(self, result):
        """
        将域名爆破结果存储到数据库中test_subdomain
        :param result:
        :return:
        """

    def run_multi(self):
        """
        多进程解析域名
        :return:
        """
        self.handle_domain()  # 生成子域名字典self.domain_list
        scanner_pool = multiprocessing.Pool(processes=100)  # 在进程池中初始化100个进程 
        self.result = scanner_pool.map(ha_resolver_domain, self.domain_list) # 对self.domain_list中的域名进行解析,判断是否存在,返回结果
        scanner_pool.close()
        scanner_pool.join()
        self.handle_result()  # 对self.result结果进行处理(结果中可能含有空字典),顺便解析一下随机的域名,将最后的结果存储到数据库中

def ha_resolver_domain(domain):
    """
    解析域名,返回解析结果
    :param domain:
    :return: {'baidu.com': ['220.181.57.216', '123.125.115.110']} or {}
    """
def start_brute(inc_time):
    """
    
    :param inc_time:
    :return:
    """
    schedule.enter(inc_time, 1, start_brute, (inc_time,)) # 该代码与subdomain_loop_execute函数中的代码一起使用可以达到循环的效果
  # 从数据库中获取需要的数据和配置
    subdomain_list = connectiondb(config_db).find_one()['subdomain'] # <type 'list'>: [u'123', u'2323', u'sds', u'sdss', u'sdszz']
    for domain_text in connectiondb(domain_db).find(): #
        # Preparation
        if domain_text['scan_status'] == "Done":  # 判断域名状态,三种状态Preparation,running,Done
            domain_list = domain_text['domain_text']  # <type 'list'>: [u'baidu.com']
            domain_id = domain_text['_id']  # 5afcfaa1710c6348e9039b5c
            domain_name = domain_text['domain_name']  # u'baidu.com'
            print("++++++++++ Scan Start! ++++++++++")
            start_date = datetime.now()
            # 开始执行爆破动作,修改数据库中的状态
            connectiondb(domain_db).update_one({'_id': ObjectId(domain_id)}, {'$set': {'scan_status': 'Running'}})
            for target in domain_list:
                start = DomainsBrute(target, subdomain_list, domain_id, domain_name)
                start.run_multi()
            # 是否开启三级域名扫描
            if domain_text['scan_option'] == "Enable":
                for result in connectiondb(subdomain_db).find({'domain_id': ObjectId(domain_id)}):
                    next_subdomain = eval(result['result']).keys()[0]  # u'123.baidu.com'
                    start = DomainsBrute(next_subdomain, subdomain_list, domain_id, domain_name)
                    start.run_multi()
         # 将扫描结果更新到数据库中
            connectiondb(domain_db).update_one({'_id': ObjectId(domain_id)}, {'$set': {'scan_status': 'Done'}})
            scan_time = datetime.now() - start_date
            print("++++++++++ Scan Done! ++++++++++", scan_time.total_seconds())

def subdomain_loop_execute(inc,):

    schedule.enter(inc, 0, start_brute, (inc,))  # 做了一个循环
    schedule.run()

稍微修改了一下,现在可以单独使用了
https://github.com/cmustard06/subdomain

端口扫描模块

端口扫描模块依然是与falsk框架分开的,是一个独立运行的模块,数据的交互主要还是通过数据库进行的,循周期性运行程序,通过查看数据库的关于端口扫描模块的配置信息,如果配置满足一定条件时,就开始执行程序。该模块使用使用了第三方模块APScheduler 该模块是一个Python定时任务框架,使用起来十分方便。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务、并以daemon方式运行应用。
函数实现的是每天14:47执行这start_port_scan这个函数

cheduler.add_job(MultiProcess().start_port_scan, 'cron', day='1-31', hour=14, minute=47)
def nmap_scanner(target_host):
    """
    对目标主机的指定断开进行扫描,返回扫描结果
    :param target_host:
    :return: [{'host': '192.168.1.1', 'banner': 'cpe:/o:linux:linux_kernel', 'port': 80, 'port_server': 'BusyBox http'},]
    原函数中存在bug,修改
    port_scanner.scan(target_host, ','.join('%s' % port for port in eval(target_ports))) # 暂时这么改,存在安全问题
    """

class MultiProcess:
    def __init__(self):
        self.target_list = []
        self.server_db = db_name_conf()['server_db']
        self.asset_db = db_name_conf()['asset_db']
        self.processes_count = int(connectiondb(config_db).find_one()['port_thread'])
        self.asset_id = ''
        self.asset_name = ''

    def scan_pool(self):
        """
        不同目标多进程端口扫描,将结果更新到数据库中
        :return: 
        """

    def start_port_scan(self):
        """
        从数据库中取出数据,调用start_pool函数
        :return: 
        """

漏洞扫描模块

漏洞扫描模块使用的是知道创宇的开源扫描框架pocsuite,由于该框架在后期升级维护的过程中修改了很多功能,导致如果使用最新版的pocsuite框架运行程序时可能会出现异常,这里采用的是该框架的2.0.4版。比如在测试的时候由于导入下面模块时出现错误,通过查看原函数发现

from pocsuite.lib.utils.password import genPassword

没有genPassword函数,因此手动修改了password.py文件,修改后文件内容如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Copyright (c) 2014-2016 pocsuite developers (https://seebug.org)
See the file 'docs/COPYING' for copying permission
"""
import string
from pocsuite.lib.core.common import getFileItems
from pocsuite.lib.core.data import paths
from random import choice

def getWeakPassword():
    return getFileItems(paths.WEAK_PASS)


def getLargeWeakPassword():
    return getFileItems(paths.LARGE_WEAK_PASS)

# 增加的函数
def genPassword(length=8, chars=string.letters + string.digits):
    return "".join([choice(chars) for _ in range(length)])

修改完成后继续运行测试程序,运行成功。成果获取到了漏洞扫描结果的数据,如下

('http://demo.**.cn/demo/**/', 'EZ-Oscommerce 31 - Remote File Upload75a8d2e1', '69439', 'Oscommerce', '3.1', (0, 'Internet nothing returned'), '2018-05-20 20:56:25', '{}')

代码分析

函数分析

    def verify_poc(self, target):
        """
        poc验证函数
        :param target:
        :return:

    def start_scan(self):
        """
        使用多线程进行漏洞扫描
        :return:
        """
    def periodic_tasks(self):
        """
        从数剧库中获取任务信息,跟据配置信息周期性扫描目标
        :return:
        """
def scanner_loop_execute(inc):
    """
    主程序循环执行模块
    :param inc: 
    :return: 
    """

数据库模块

数据库结构

# PLUGIN_DB 插件集合
------------------------------------
plugin_appversion       影响版本
plugin_vultype          漏洞名称
plugin_vuldate          漏洞日期
plugin_filename         文件路径
plugin_name             插件名
plugin_appname          应用名称
plugin_author           插件作者
_id                     ObjectId
------------------------------------

# TASKS_DB 任务集合
------------------------------------
task_status             任务状态
end_date                结束时间
scan_target_list        扫描对象(列表)
task_name               任务名称
plugin_id               插件id
_id                     ObjectId
start_date              任务开始时间
task_plan               扫描计划
------------------------------------

# VULNERABILITY_DB 漏洞集合
------------------------------------
scan_result             扫描结果
target                  扫描对象
task_id                 任务ID
appname                 应用名称
scan_date               扫描日期
poc_name                插件名称
vulversion              漏洞影响版本
poc_vultype             漏洞类型
task_name               任务名称
plugin_id               插件ID
_id                     ObjectId
------------------------------------

# ASSET_DB 资产库集合
asset_date              创建日期
scan_option             资产发现
asset_text              资产
asset_name              资产库名称
dept_name               部门名称
admin_name              管理员
_id                     ObjectId
------------------------------------

# CONFIG_DB 配置集合
------------------------------------
port_thread             端口扫描线程
scanner_thread          漏洞检测线程
port_list               端口扫描列表
config_name             配置文件名称
subdomain               子域名字典
------------------------------------


# SERVER_DB 服务集合
------------------------------------
host                    主机
asset_id                资产库ID
port                    端口
port_server             服务
banner                  指纹(cpe)
scan_date               扫描日期
asset_name              所属资产库
------------------------------------


# DOMAIN_DB 服务集合
------------------------------------
domain_text             主域名
scan_option             三级域名扫描
dept_name               域名所属部门
domain_date             创建日期
domain_name             域名名称
_id                     ObjectId
------------------------------------


# SUBDOMAIN_DB 服务集合
------------------------------------
date                    扫描日期
domain                  主域名
_id                     ObjectId
result                  子域名
domain_id               主域名ID
domain_name             域名名称
------------------------------------

# WEEKPASSWD_DB 服务集合
------------------------------------
date                    扫描日期
target                  检测对象
task_name               任务名称
post_data               登录数据包
status                  检测状态
week_passwd_count       弱口令数量
error_data              失败标记
success_data            成功标记
username                账号
password                密码
week_passwd_result      存在弱口令的结果
_id                     ObjectId
------------------------------------
​````
## 数据库详情
* test_asset  :该表collection用于存储资产信息,通过该表中的信息可以在后面调用漏洞扫描模块和nmap模块对资产进行扫描

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-5a04e3f161d8279f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端.png](https://upload-images.jianshu.io/upload_images/6853514-06d97fc9fbbdab62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

* test_config:该表用于存放域名字典,需要扫描的端口,开启的进程数量等数据

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-58a87b04e56a5e16.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端设置界面.png](https://upload-images.jianshu.io/upload_images/6853514-c766589802ddbf22.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

* test_domain:该表用于存放域名信息,通过该表中的数据对表中的域名进行子域名爆破

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-66cb2bc93be61f2e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端界面.png](https://upload-images.jianshu.io/upload_images/6853514-46bb90934e52b988.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



* test_plugin_info:该表用于存放扫描插件信息,包括插件名称,功能,以及插件存放的路径

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-86579c4201f7c6dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端展示.png](https://upload-images.jianshu.io/upload_images/6853514-97186eb4f6f1cb8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


* test_server:该表中存储的是资产信息,包括开放的端口信息以及服务

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-a18c1f45baf3c6bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端展示.png](https://upload-images.jianshu.io/upload_images/6853514-bf4bab98c8fc829f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

* test_subdomain:该表用于存放子域名爆破结果

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-2d682998223c7a64.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端展示.png](https://upload-images.jianshu.io/upload_images/6853514-0b0eb3ce92058201.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

* test_tasks:该表用于存储漏洞扫描任务信息

![数据库.png](https://upload-images.jianshu.io/upload_images/6853514-03dcb898479e5680.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![前端展示.png](https://upload-images.jianshu.io/upload_images/6853514-7a877c0192dd0266.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

# 总结
该系统使用的所有模块之间都是通过数据库进行数据交互的,每个模块都是相对独立的运行,单独拿出来做测试也是没有问题的,在进行代码分析时也很友好,一个槽点就是漏洞扫描模块使用的pocsuite开源框架有一些问题,每一次版本的迭代都有新的功能被添加,旧的功能被删除,导致了官方的pocsuite poc验证插件容易出问题,老版本的poc插件无法在新的框架下运行!!
 标签: none

作者  :  redBu11



关于我

about me

redBu11

联系我