安全平台扫描功能关于插件扫描

0x01 需求


openssl漏洞,struts2漏洞,这些都是一些爆发型的事件漏洞。在复查自身是否存在问题,或者说受影响面有多大的时候,谁有好的自动化工具,谁就最快解决问题。当然,针对特殊的人群,定制化的py脚本也能解决问题,只是相对来说,这个过程会比较麻烦,假如,正好你今天请假,没有上班,且目前只有一个实习生在工作岗位上,处理这个问题,可能瞬间他就懵了。这个时候,我们就要考虑有一个完整的一体化的安全自动化插件检测框架。(例如: tangscan之类的)

0x02 开发


最早参考的是sqlmap的开发模型进行研究,因为sqlmap做得很强大,起码我是这么认为的。so,同时想用一些新的东西提高下自己的能力。
先说下整个扫描器应该分为以下两块:

  • web api 模块
  • 执行模块
    从api上,应该跟sqlmap一样,接受任务、执行任务、返回结果之类的。当然,我也是这样设计的。
    截取部分代码,作为样例:
# 默认方法
@route('/',method='GET')
def index():
    if reqIp(request.environ.get('REMOTE_ADDR')):
        return '<div style="font-size: 30px;">欢迎访问SPScanner V3.0</div>\n'
    else:
        return json.dumps({'status':-5})

# 添加任务方法
@route('/scan/add',method='POST')
def addtask(_ip='',_web=''):
    try:
        if reqIp(request.environ.get('REMOTE_ADDR')):
            _type = int(request.forms.get('type'))
            _ip = request.forms.get('ip')
            _web = request.forms.get('web')

            task_id = createHashID()

            insert_task_sql = 'INSERT INTO task(ID,TYPE,TASKVAL,TASKSTATUS,RESPORTID,TASKID)VALUES(null,?,?,?,?,?);'

            if _type == 1:
                for ip in _ip.split(','):
                    report_id = createHashID()
                    dbconn.execute(insert_task_sql,(1,ip,0,report_id,task_id));
                    dbconn.commit()
                return json.dumps({'status':1,'taskid':task_id})
            elif _type == 2:
                for url in _web.split(','):
                    report_id = createHashID()
                    dbconn.execute(insert_task_sql,(2,url,0,report_id,task_id));
                    dbconn.commit()
                return json.dumps({'status':1,'taskid':task_id})
            else:
                return json.dumps({'status':0})
        else:
            return json.dumps({'status':-5})
    except Exception, e:
        return json.dumps({'status':-1})

# 删除任务方法
@route('/scan/del',method='POST')
def deltask():
    try:
        if reqIp(request.environ.get('REMOTE_ADDR')):
            _taskid = request.forms.get('taskid')
            select_task_sql = "SELECT * FROM task where TASKID = '?';"
            data = dbconn.execute(select_task_sql,(_taskid))
            if len(data) > 0:
                delete_task_sql = "DELETE FROM task WHERE TASKID = '?';"
                dbconn.execute(delete_task_sql,(_taskid))
                dbconn.commit()
                return json.dumps({'status':1})
            else:
                return json.dumps({'status':0})
        else:
            return json.dumps({'status':-5})
    except Exception, e:
        return json.dumps({'status':-1})

# 获得任务状态方法
# 返回任务完成的百分比
@route('/scan/status',method='POST')
def getstatus():
    try:
        _taskid = request.forms.get('taskid')
        select_task_sql = "SELECT * FROM task WHERE TASKID = '%s';" % _taskid
        alldata = dbconn.execute(select_task_sql)
        if len(alldata) > 0:
            all_count = len(alldata)
            finish_task_sql = "SELECT * FROM task WHERE TASKSTATUS = '1' AND TASKID = '%s';" % _taskid
            finish_count = dbconn.execute(finish_task_sql)
            penten = int(float(len(finish_count)/len(alldata))*100)
            return json.dumps({'status':1,'penten':penten})
        else:
            return json.dumps({'status':0})
    except Exception, e:
        return json.dumps({'status':-1})

# 读取任务报告
@route('/scan/report',method='POST')
def getreport():
    try:
        reportdict = {}
        _taskid = request.forms.get('taskid')
        select_task_sql = "SELECT RESPORTID FROM task WHERE TASKID = '%s';" % _taskid
        alldata = dbconn.execute(select_task_sql)
        if len(alldata) > 0:
            for taskitem in alldata:
               reportid = taskitem[0]
               select_report_sql = "SELECT * FROM report WHERE RESPORTID = '%s';" % reportid
               reportdata = dbconn.execute(select_report_sql)
               for reportitem in reportdata:
                   reportdict[reportitem[0]] = {
                        'vulname': reportitem[1],
                        'vullevel': reportitem[2],
                        'vulref': reportitem[3],
                        'vulsdesc': reportitem[4],
                        'vulddesc': reportitem[5],
                        'vulrespheader': reportitem[6],
                        'vulresqheader': reportitem[7],
                        'vulresquest': reportitem[8]
                   }
            reportdict['status'] = 1
            return json.dumps(reportdict)
        else:
            return json.dumps({'status':0})
    except Exception, e:
        return json.dumps({'status':-1})

在数据库这块,默认我选择sqlite,因为我觉得用这个做为本地的agent足够了,在后面读取了报告之后,把结果存到redis/MYSQL,其实才是最靠谱的做法。当然,你需要把这个东西做成守护进程执行~

0x03 目录结构


目录结构基本上比较清晰,命名规范都比较标准,之前犯过的一些错误都会尽可能的避免,所以这个版本基本上都是按照标准化来coding,目的在于长久使用和维护。

├── TaskService.py ==> (任务处理service)
├── WebApiService.py ==> (web服务service)
├── conf ==> (配置)
│   ├── Global_Conf.py
│   ├── Http_Request_Conf.py
│   ├── Plugin_Path_Conf.py
├── daemon ==> (守护进程)
│   ├── pscanner_taskservice
│   └── pscanner_webapiservice
├── lib ==> (基础库)
│   ├── common
│   │   ├── Http_Request.py
│   │   ├── coredata.py
│   │   ├── execute.py
│   │   ├── general.py
│   │   └── special.py
│   ├── core
│   │   ├── Scan_Exploit.py
│   │   ├── Scan_Frame.py
│   │   ├── Scan_Print.py
│   └── objects
│       └── task.py
├── log ==> (日志管理)
│   ├── access
│   ├── error
│   └── info
├── plugins ==> (插件库)
│   ├── system
│   │   ├── M_4cc4d9c6fed65e0dc01adcebbf2f2158.py
│   └── website
│       ├── E_514f056a3ff58eb000f1a94fae988b7b.py
│       ├── E_e8773f08f8f10c34dec6ae699ca1b111.py
│       ├── G_29e34bc8c04565ec9b88c26cdb5ebbc8.py
│       ├── O_2e7e01af7a74ccaee996632665d6a6af.py
├── run.py ==> (扫描器console版本入口)
└── setup.py ==> (环境安装脚本)

0x04 关于 Web Service API:


该api主要用于分布式使用,调度器通过发起http请求将任务下发执行,在扫描结束后将任务报告结果提取。

请求类型 请求地址 请求参数 作用说明
GET / 无请求值 默认页面
POST /scan/add 扫描ip:ip,扫描web:web,扫描类型:type 创建一个扫描任务
POST /scan/del 任务id:taskid 删除扫描任务信息
POST /scan/status 任务id:taskid 读取扫描任务状态
POST /scan/report 任务id:taskid 读取扫描任务报告

0x05 next


下一章讲核心功能设计。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容