Appscan的python扩展工具: PyScan 收藏
IBM Rational AppScan 是一个面向 Web 应用安全检测的自动化工具,使用它可以自动化检测 Web 应用的安全漏洞,比如跨站点脚本攻击(Cross Site Scripting Flaws)、注入式攻击(Injection Flaws)、失效的访问控制(Broken Access Control)、缓存溢出问题(Buffer Overflows)等等。这些安全漏洞大多包括在 OWASP(Open Web Application Security Project,开放式 Web 应用程序安全项目)所公布的 Web 应用安全漏洞中.
从 7.5 版本以后,Rational Appscan 提供了扩展机制 —— AppScan eXtension Framework。
利用 Appscan 提供的 eXtension framework,用户可以非常简单的为 AppScan 提供扩展。扩展的内容几乎没有任何限制,可以从一个简单的通知程序到一个非常复杂的安全分析工具,使得用户可以根据自己的需要来客户化 AppScan。AppScan eXtension Framework 支持多种语言,如 Python、C#、C++、J#、Jscript 等等 . 本文主要介绍如何利用python进行扩展--PyScan.
进入Pyscan的方法:在appscan中点击"工具", "扩展“, "PyScan“。如果没有,可下载安装PyScan。
appScan:AppScan SDK 的主接口 IAppScan 的实例对象。IAppScan 接口包含了 AppScan 扫描测试引擎的主要功能对象,通过使用这个接口的实例,就可以调用 AppScan 的主要功能,它一般作为客户端访问 AppScan 的入口。如该接口中的 Scan 属性,它实际上是 IScanManager 的实例对象。上面的类图列举了 IScanManager 中的部分方法,比如 Scan() 方法用来开始对目标网站的同步扫描,ScanAsync() 和 Scan() 方法功能相同,只不过是异步方法,ResetExploereAndTestData() 用来清空网站扫描和安全测试结果等等。
IAppscan接口
属性:
IConfiguration Config; # 配置信息接口
IScanManager Scan; # 扫描管理对象
IConfiguration
包含了Appscan进行扫描的配置信息,如配置扫描的代理, 它有成员变量:
IAppScanProxySettings ProxySettings
如果想获取到Appscan的所有漏洞信息,它有成员变量:
IRules Rules; 它能指向每一条漏洞的接口: IIssueTypeData.
IIssueTypeData的公有属性
Advisory: 漏洞的咨询信息
AdvisoryID:漏洞的咨询ID
AdvisoryName:咨询名
CveId: CVE ID
Description: 漏洞描述
Name:漏洞名
RemediationID: 建议ID
RemediationTitle: 建议标题
Severity:安全分数
ThreatClass:威胁分类
UserDefined:该漏洞是否为用户自定义
VariantTypes:有关漏洞检测的过程信息,如检测所用的URL等
IScanManager
这是一个扫描管理对象,包括
公有属性:
CurrentUrl: 当前扫描的URL
ScanData:保存的扫描数据
ScanExpert:扫描专家对象
Status: 扫描状态,如Test扫描状态, Pretest预扫描状态
公有方法:
ResetScanData():清空扫描数据
ReTest():重新测试一个漏洞
ReTestAsync():异步测试
Scan(): 开启一个扫描任务
ScanAsync():开启一个扫描任务,异步扫描
SendManualTest():开始一个手动测试。
Stop():结束当前任务
IScanData
IScanManager.scanData成员是一个IScanData对象,它保存了一个任务的扫描信息。
公有属性:
AppTreeRoot:URL目录树的根结点
Config:扫描的配置信息
TotalScanDuration: 扫描时间
VisitedUrls:扫描的URL
IScanConfiguration
IScanData.Config成员是一个IScanConfiguration对象,它包含了一个任务的扫描配置信息。
公有属性:
ClientSideCertificate:客户认证设置
CommunicationTimeout:会话超时时间(从发送请求,到接收到响应)
CustomErrorPages:定制错误信息页集合。
CustomParameters:定制参数
DefaultLimit:扫描深度设置
ScanPolicy: 深度优先,还是广度优先
SessionManagement:会话管理器
StartingUrl:起启URL
TestPolicy:扫描策略,它包括了漏洞的集合
例程:
# -*- coding: cp936 -*-
import re
import sys
import string
from urlparse import urlparse, urlunparse
import win32com.client
import __main__
appScan = __main__.appScan
startingUrl = ""
vuls_conn = None
def getStartingUrl():
'''
get the starting url
'''
startingUri = System.Uri(appScan.Scan.ScanData.Config.StartingUrl)
url = startingUri.ToString()
print "Starting url is : ", url
return url
def GetAllIssueTypesCount():
'''
Get the count of all the test rules currently installed with Appscan
'''
rules = appScan.Config.Rules.IssueTypes
print len(rules)
def DisplayAllIssueTypes():
'''
Display all the test rules installed with Appscan
'''
rules = appScan.Config.Rules.IssueTypes
for rule in rules:
# rule is a IIssueTypeData class object
print rule.Description
print rule.AdvisoryID
def GetCurrentIssueTypesCount():
'''
Get the count of current using issue types
'''
issueTypesCount = appScan.Scan.ScanData.Config.TestPolicy.IssueTypes.Dictionary.get_Count()
print "issueTypesCount = ", issueTypesCount
return issueTypesCount
def GetIssueDescription(issueType):
'''
Get the issueType Description of a issueType
'''
rules = appScan.Config.Rules.IssueTypes
for rule in rules:
if rule.AdvisoryID == issueType.AdvisoryID:
return rule.Description
def GetIssueType(issueTypeName):
'''
Gets an IssueType element according to the giving issueTypeName string
The IssueType element can be used with the appScan.Scan.SendManualTest method
'''
# Get all issue types that partially match the name
issueTypes = appScan.Scan.ScanData.Config.TestPolicy.IssueTypes
values = list (issueTypes.Dictionary.Values)
# Iterate over all of them, trying to get a match
foundIssueType = None
for v in values:
# Check if a partial match was found
print v.RulesIssueType.Description
if v.RulesIssueType.Description.__contains__(issueTypeName):
foundIssueType = v.RulesIssueType.ResultsIssueType
# If an exact match was found - use that
if v.RulesIssueType.Description == issueTypeName:
return foundIssueType
return foundIssueType
def DisplayConfigInfo():
'''
Display some configure information
'''
startingUri = System.Uri(appScan.Scan.ScanData.Config.StartingUrl)
if startingUri != None:
print "startingUri:", startingUri
scanLimit = appScan.Scan.ScanData.Config.DepthLimit.Value
print "DepthLimit = ", scanLimit
scanLimit = appScan.Scan.ScanData.Config.NumberOfThreads.__str__;
print "NumberOfThreads = ", scanLimit
timeLimit = appScan.Scan.ScanData.Config.TimeLimit.Value
print "timeLimit = ", timeLimit
def StartScan():
'''
Display current scan info
'''
appScan.Scan.ScanData.Config.StartingUrl = "http://stroke.tw/"
# Set a proxy server
#appScan.Scan.ScanData.Config.ProxyServerConfiguration.IPAddress = "119.70.40.101"
#appScan.Scan.ScanData.Config.ProxyServerConfiguration.Port = 8080
#appScan.Scan.ScanData.Config.ProxyServerConfiguration.Enabled = True
appScan.Scan.Scan(True, True)
totalScanDuration = appScan.Scan.ScanData.TotalScanDuration
print "totalScanDuration = ", totalScanDuration
def GetVisitedUrls():
'''
Get the urls visited
'''
appData = appScan.Scan.ScanData.AppTreeRoot.GetApplicationData()
urls = list(appData.VisitedUrls)
for url in urls:
print url.Request.Uri.ToString()
def showTestUrlsbyId(advisoryid):
'''
show the urls test using
'''
issues = appScan.Scan.ScanData.AppTreeRoot.GetIssues()
issueslist = list(issues)
for issue in issueslist:
if issue.IssueType.AdvisoryID != advisoryid:
continue
print GetIssueDescription(issue.IssueType)
tests = list(issue.Variants)
print len(tests)
for test in tests:
request = test.Request.RawRequest
print request
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
def showAllVuls():
issues = appScan.Scan.ScanData.AppTreeRoot.GetIssues()
issueslist = list(issues)
for issue in issueslist:
print GetIssueDescription(issue.IssueType)
tests = list(issue.Variants)
for test in tests:
request = test.Request.RawRequest
print request
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
break
def insertResult(vultype, request, param):
print "type: ", vultype
print "request: ", request
print "param: ", param
def saveScanResults():
'''
Display the results of current scan
'''
global vuls_conn
issues = appScan.Scan.ScanData.AppTreeRoot.GetIssues()
issueslist = list(issues)
print "ISSUES COUNT = ", len(issueslist)
vuls_conn = win32com.client.Dispatch("ADODB.Connection")
vuls_DSN = r"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=U:\work\vulns.accdb;Persist Security Info=False;"
vuls_conn.Open(vuls_DSN)
for issue in issueslist:
descript = GetIssueDescription(issue.IssueType)
print "Descript = ", descript
# XSS
if issue.IssueType.AdvisoryID == '57':
tests = list(issue.Variants)
print len(tests)
for test in tests:
if test.Vulnerable == True:
request = test.Request.RawRequest
print request
print "~~~~~~~~~~~~~~~~~~~", test.Entity.Name
insertResult('XSS', request, test.Entity.Name)
break
# SQL盲注和SQL注入
if (issue.IssueType.AdvisoryID == '142') or (issue.IssueType.AdvisoryID == '132'):
tests = list(issue.Variants)
for test in tests:
if test.Vulnerable == True:
request = test.Request.RawRequest
insertResult('SQLInject', request, test.Entity.Name)
break
if __name__ == '__main__':
#getStartingUrl()
#GetCurrentIssueTypesCount()
#DisplayAllIssueTypes()
#DisplayConfigInfo()
#GetVisitedUrls()
showAllVuls()
#showTestUrlsbyId('57')