最近再做一个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 代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#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 结果入库模块,代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#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,'http://'+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,扫描模块,这个模块问题较多,就是之前提到的,没有考虑重复扫描和异常终止的问题,贴上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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!


  • 本文固定链接: http://www.nxadmin.com/tools/1228.html
  • 转载 由 阿德马Web安全 发表