欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

Python实现Awvs自动化扫描

程序员文章站 2022-03-05 13:54:30
最近再做一个python的小程序,主要功能是实现Acuenetix Web Vulnerability Scanner的自动化扫描,批量对一些目标进行扫描,然后对扫描结果写入mys...
最近再做一个python的小程序,主要功能是实现Acuenetix Web Vulnerability Scanner的自动化扫描,批量对一些目标进行扫描,然后对扫描结果写入mysql数据库。写这篇文章,分享一下一些思路。

程序主要分三个功能模块,Url下载、批量扫描、结果入库,

有一个另外独立的程序,在流量镜像服务器上进行抓包,抓取Http协议的包,然后对包进行筛选处理,保留一些带有各种参数的url,然后对url进行入库。url下载功能主要是从mysql数据库中下载url。

批量扫描功能主要调用了Awvs的命令行wvs_console.exe,调研的时候先是尝试用awvs计划任务来实现批量扫描,但是发现在将一些awvs设置发包给计划任务的时候会遇到各种困难,计划任务貌似也不是一个网页,采用的是XML模版,技术有限,最后没实现,只好放弃。

之后发现Awvs支持命令行,wvs_console.exe就是主程序,有很多命令参数,基本能实现Awvs界面操作的所有功能。批量扫描主要是读取下载到本地的url,进行逐一扫描。要将扫描结果保存到本地access数据库文件,需要使用savetodatabase参数。

Awvs会自动将扫描结果保存到本地的access数据库中,具体的表是Wvs_alerts,也可以设置保存到Mssql数据库中,具体的是在Application Setting进行设置。结果入库模块的功能是从access数据库筛选出危害等级为3的漏洞,然后将它们写入到mysql数据库。主要用了正则表达式对request中的host,漏洞文件,get或post提交的请求进行筛选拼凑,获取到完整的漏洞测试url。

贴上代码,很菜,代码各种Bug,最主要的是程序的整个流程设计存在问题,导致后来被大佬给否掉了,没有考虑到重复扫描和程序异常中止的情况,导致我的程序只能一直运行下去 ,否则重新运行又会从头对url进行扫描。

对此很郁闷,某天晚上下班回家想了想,觉得可以通过以下方法来解决以上两个问题:

Awvs扫描结果数据库中有一个Wvs_scans表,保存的都是扫描过的url,以及扫描开始时间和结束时间。可以将当天下载的url保存到一个list中,然后在扫描之前先将之前所有扫描过的URL查询出来,同样保存在list中,读取list中的url,判断是否在扫描过的URL list中,如果存在将之从url list中删除掉;如果不存在则再进行扫描。

异常中止的话貌似只能增加系统计划任务,每天结束再打开,不知道如何时时监视系统进程,通过是否存在wvs的进程来判断。

以上只是一个大概的程序介绍,贴上代码,代码可能存在一些问题,有兴趣的童鞋去完善完善,大佬觉得我的效率和编码能力有待提高,so,让继续学习,所以没再继续跟进这个项目。

downurl.py 代码:

 

#coding:utf-8
import MySQLdb
import os,time,shutil
import hashlib,re

datanow=time.strftime('%Y-%m-%d',time.localtime(time.time()))
#filetype='.txt'
#urlfilename=datanow+filetype
#path="D:\wvscan\url\\"
#newfile=path+urlfilename

datanow=time.strftime('%Y-%m-%d',time.localtime(time.time()))
con=MySQLdb.Connect('10.1.1.1','root','12345678','wvsdb')
cur=con.cursor()
sqlstr='select url from urls where time like %s'

values=datanow+'%'
cur.execute(sqlstr,values)

data=cur.fetchall()

#将当天的URL保存到本地url.txt文件
f=open(r'd:\Wvscan\url.txt','a+')
uhfile=open(r'd:\Wvscan\urlhash.txt','a+')
line=uhfile.readlines()

#保存之前对url进行简单的处理,跟本地的hash文件比对,确保url.txt中url不重复
for i in range(0,len(data)):
    impurl=str(data[i][0]).split('=')[0]
    urlhash=hashlib.new('md5',impurl).hexdigest()
    urlhash=urlhash+'\n'
    if urlhash in line:
        pass
    else:
        uhfile.write(urlhash)
        newurl=str(data[i][0])+'\n'
        f.writelines(newurl)
cur.close()
con.close()

 

抓包程序抓到的url可能重复率较高,而且都是带参数的,保存到本地的时候截取了最前面的域名+目录+文件部分进行了简单的去重。Awvs可能不大适合这样的方式,只需要将全部的域名列出来,然后逐一扫描即可,site Crawler功能会自动爬行。

writeinmysql.py 结果入库模块,代码:

 

#coding:UTF-8
import subprocess
import os,time,shutil,sys
import win32com.client
import MySQLdb
import re,hashlib

reload(sys)
sys.setdefaultencoding('utf-8')

#需要先在win服务器设置odbc源,指向access文件。实际用pyodbc模块可能更好一些
def writeinmysql():
    conn = win32com.client.Dispatch(r'ADODB.Connection')
    DSN = 'PROVIDER=Microsoft Access Driver (*.mdb, *.accdb)'
    conn.Open('awvs')
    cur=conn.cursor()
    rs = win32com.client.Dispatch(r'ADODB.Recordset')

    rs.Open('[WVS_alerts]', conn, 1, 3)
    if rs.recordcount == 0:
        exit()
    #遍历所有的结果,cmp进行筛选危害等级为3的,也就是高危
    while not rs.eof:
        severity = str(rs('severity'))
        if cmp('3', severity):
            rs.movenext
            continue
        vultype = rs('algroup')
        vulfile=rs('affects')
        #由于mysql库中要求的漏洞类型和access的名称有点差别,所以还需要对漏洞类型和危害等级进行二次命名,sql注入和xss为例
        xss='Cross site'
        sqlinject='injection'
        if xss in str(vultype):
            vultype='XSS'
            level='低危'
        elif sqlinject in str(vultype):
            vultype="SQL注入"
            level='高危'
        else:
            level='中危'
        #拼凑出漏洞测试url,用了正则表达式, post和get类型的request请求是不同的
        params = rs('parameter')
        ss = str(rs('request'))
        str1 = ss[0:4]

        if 'POST'== str1:
            requestType = 'POST'
            regex = 'POST (.*?) HTTP/1\.\d+'
            str1 = re.findall(regex, ss);
        else:
            requestType = 'GET'
            regex = 'GET (.*?) HTTP/1\.\d+'
            str1 = re.findall(regex, ss);
        regex = 'Host:(.*?)\r\n'
        host = re.findall(regex, ss);
        if host == []:
            host = ''
        else:
            host = host[0].strip()
        if str1 == []:
            str1 = ''
        else:
            str1 = str1[0]
        url =host + str1
        timex=time.strftime('%Y-%m-%d',time.localtime(time.time()))

        status=0
        scanner='Awvs'
        comment=''
        db = MySQLdb.connect(host="10.1.1.1", user="root", passwd="12345678", db="wvsdb",charset='utf8')
        cursor = db.cursor()
        sql = 'insert into vuls(status,comment,vultype,url,host,params,level,scanner) values(%s,%s,%s,%s,%s,%s,%s,%s)'
        values =[status,comment,vultype,'https://'+url.lstrip(),host,params,level,scanner]
        #入库的时候又进行了去重,确保mysql库中没有存在该条漏洞记录,跟本地保存的vulhash进行比对,感觉这种方法很原始。
        hashvalue=str(values[2])+str(values[4])+str(vulfile)+str(values[5])
        vulhash=hashlib.new('md5',hashvalue).hexdigest()
        vulhash=vulhash+'\n'
        file=open(r'D:\Wvscan\vulhash.txt','a+')
        if vulhash in file.readlines():
            pass
        else:
            file.write(vulhash+'\n')
            cursor.execute(sql, values)
        delsql='delete from vuls where vultype like %s or vultype like %s'
        delvaluea='Slow HTTP%'
        delvalueb='Host header%'
        delinfo=[delvaluea,delvalueb]
        cursor.execute(delsql,delinfo)
        db.commit()
        rs.movenext

    rs.close
    conn.close
    cursor.close()
    db.close()

if __name_=='__main__':
    writeinmysql()
    time.sleep(10)

    #备份每天的扫描数据库,用原始数据库替换,方便第二天继续保存。
    datanow=time.strftime('%Y-%m-%d',time.localtime(time.time()))
    filetype='.mdb'
    urlfilename=datanow+filetype
    path="D:\wvscan\databak\\"
    databakfile=path+urlfilename
    shutil.copyfile(r'D:\Wvscan\data\vulnscanresults.mdb',databakfile)
    shutil.copyfile(r'D:\Wvscan\vulnscanresults.mdb',r'D:\Wvscan\data\vulnscanresults.mdb')

 

 

startwvs.py,扫描模块,这个模块问题较多,就是之前提到的,没有考虑重复扫描和异常终止的问题,贴上代码:

 

#coding:utf-8
import subprocess
import os,time,shutil

file=open(r"D:\Wvscan\url.txt","r")
def wvsscan():

    for readline in file:

        url=readline.strip('\n')
        cmd=r"d:\Wvs\wvs_console.exe /Scan "+url+r" /SavetoDatabase"
        doscan=subprocess.Popen(cmd)
        doscan.wait()             
if __name__=='__main__': 
    wvsscan()

阿德马原创,转载请注明出处,Tks!