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')