在本系列的前两期中,我们向您展示了如何使用Bash和PowerShell以及Acunetix API来管理Acunetix扫描。在本文中,您将学习如何使用Python进行相同的操作。作为示例,我们将创建一个Python脚本,该脚本使用请求库向Acunetix REST API发出请求。
必须通过在HTTP请求标头中提供API密钥来对每个API调用进行身份验证,因此,每个请求都使用以下标头进行:
Content-Type: application/json X-Auth: 可以从Acunetix配置文件页面检索API密钥。
剧本剖析 该脚本具有以下结构:
首先,我们声明清除功能,该功能是一种恢复功能,用于在检测到无效的扫描状态时删除脚本创建的扫描和目标: 该remove_scan API调用需要我们做出DELETE请求/扫描/ {} SCAN_ID端点; 扫描ID由下面描述的脚本的主要部分检索 该remove_target API调用,需要我们做出一个DELETE请求到/目标/ {} target_id端点; 目标ID由下面描述的脚本的主要部分检索 然后,我们声明将在整个脚本中使用的起始全局变量: MyAXURL是Acunetix API的基本URL,通常为: 本地:https:// :3443 / api / v1 在线:https : //online.acunetix.com/api/v1 MyAPIKEY是API密钥,可以从配置文件页面中检索 MyTargetURL是最终要扫描的目标的URL MyTargetDESC是对目标的友好描述 FullScanProfileID是默认的“完全扫描”的配置文件ID 。此默认扫描配置文件的值始终为11111111-1111-1111-1111-111111111111 MyRequestHeaders是HTTP请求标头的数组(包括使用Acunetix API密钥进行的身份验证) 接下来,我们创建目标: add_target函数的API文档显示: 我们必须向/ targets端点发出POST请求; 主体应采用JSON格式,并至少包含4个键:地址,描述,类型和关键性;在我们的示例中: { "address": " http://testphp.vulnweb.com/", "description": "Test PHP Site - created via ax-python-api.ps1", "type": "default", "criticality": 10 } 响应将为JSON格式;我们要从响应中提取的关键信息是target_id键的值 下一步,我们安排扫描: schedule_scan函数的API文档显示: 我们必须向/ scans端点发出POST请求; 主体应为JSON格式;在我们的示例中: { "profile_id": "11111111-1111-1111-1111-111111111111", "incremental": false, "schedule": { "disable": false, "start_date": null, "time_sensitive": false }, "user_authorized_to_scan": "yes", "target_id": "TargetID_from_previous_step" } 响应将为JSON格式;但是,我们要提取的关键信息(扫描ID)未在响应中传递,而是在称为Location的HTTP响应标头中传递 然后,我们创建一个循环,每30秒检查一次扫描状态,然后等待扫描状态完成: get_scan函数的API文档显示: 我们必须向/ scans / {scan_id}端点发出GET请求,该端点从上一步获得scan_id 响应将为JSON格式;我们要提取的关键信息(扫描状态)是嵌套JSON对象中具有键current_session的状态键的值 如果扫描状态为处理中或已调度,则脚本继续等待;否则,脚本将继续等待。当扫描状态变为完成时,脚本继续处理;如果扫描状态不是这3个值之一,则认为它是无效的,将调用cleanup函数,并且脚本结束 接下来,我们需要获取扫描会话ID;对get_scan API调用的响应还包含扫描会话ID;我们要提取的关键信息是嵌套JSON对象中带有键current_session的scan_session_id键的值 然后,我们需要获取扫描结果ID;要获得它,我们需要执行以下操作: get_scan_result_history API调用的API文档显示: 我们必须向/ scans / {scan_id} / results端点发出GET请求,在该端点上的scan_id是从上一步获得的 响应为JSON格式;我们要提取的关键信息(扫描结果ID)是JSON对象数组之一中的result_id键的值,该数组形成了结果键的值;由于脚本为单个目标创建了单个扫描,因此情况得到了简化,因此我们只希望将单个JSON对象嵌套在结果键中 最后,我们需要获取由扫描生成的漏洞列表: get_scan_vulnerabilities API调用的API文档显示: 我们必须对/ scans / {scan_id} / results / {result_id} / vulnerabilities端点发出GET请求,其中scan_id和result_id是从前面的步骤中获得的 响应为JSON格式,包含2个键: 该漏洞键包含的所有漏洞(高达100)的阵列中发现的扫描先前调度 该分页键包含的页面,以及如何检索的情况下,后续的页数信息漏洞的数量的确超过100 Python脚本
import json, requests, ssl, time, urllib3 def cleanup():
dummy = requests.delete(MyAXURL + '/scans/' + MyScanID, headers = MyRequestHeaders, verify=False)
dummy = requests.delete(MyAXURL + '/targets/' + MyTargetID, headers = MyRequestHeaders, verify=False)
MyAXURL = "https://qgen-004.qgengroup.local:3443/api/v1" MyAPIKEY = "1986ad8c0a5b3df4d7028d5f3c06e936c2a54cb301c8342b8b047b25985b4205f" MyTargetURL = "http://testphp.vulnweb.com/" MyTargetDESC = "Test PHP Site - created via ax-python-api.py" FullScanProfileID = "11111111-1111-1111-1111-111111111111" MyRequestHeaders = {'X-Auth':MyAPIKEY, 'Content-Type':'application/json'}
MyRequestBody = {"address":MyTargetURL,"description":MyTargetDESC,"type":"default","criticality":10} MyTargetIDResponse = requests.post(MyAXURL + '/targets', json=MyRequestBody, headers = MyRequestHeaders, verify=False) MyTargetIDjson=json.loads(MyTargetIDResponse.content) MyTargetID=MyTargetIDjson["target_id"]
MyRequestBody = {"profile_id":FullScanProfileID,"incremental":False,"schedule":{"disable":False,"start_date":None,"time_sensitive":False},"user_authorized_to_scan":"yes","target_id":MyTargetID} MyScanIDResponse = requests.post(MyAXURL + '/scans', json=MyRequestBody, headers = MyRequestHeaders, verify=False) MyScanID = MyScanIDResponse.headers["Location"].replace("/api/v1/scans/","") LoopCondition=True while LoopCondition : MyScanStatusResponse = requests.get(MyAXURL + '/scans/' + MyScanID, headers = MyRequestHeaders, verify=False) MyScanStatusjson = json.loads(MyScanStatusResponse.content) MyScanStatus = MyScanStatusjson["current_session"]["status"] if (MyScanStatus=="processing"): print("Scan Status: Processing - waiting 30 seconds...") elif (MyScanStatus=="scheduled"): print("Scan Status: Scheduled - waiting 30 seconds...") elif (MyScanStatus=="completed"): LoopCondition=False else: print("Invalid Scan Status: Aborting") cleanup exit() MyScanStatus="" time.sleep(30)
MyScanSessionResponse = requests.get(MyAXURL + '/scans/' + MyScanID, headers = MyRequestHeaders, verify=False) MyScanSessionjson = json.loads(MyScanSessionResponse.content) MyScanSessionID = MyScanSessionjson["current_session"]["scan_session_id"]
MyScanResultResponse = requests.get(MyAXURL + '/scans/' + MyScanID + "/results", headers = MyRequestHeaders, verify=False) MyScanResultjson = json.loads(MyScanResultResponse.content) MyScanResultID = MyScanResultjson["results"][0]["result_id"]
MyScanVulnerabilitiesResponse = requests.get(MyAXURL + '/scans/' + MyScanID + '/results/' + MyScanResultID + '/vulnerabilities', headers = MyRequestHeaders, verify=False) print "" print "Target ID: " + MyTargetID print "Scan ID: " + MyScanID print "Scan Session ID: " + MyScanSessionID print "Scan Result ID: " + MyScanResultID print "" print "" print "Scan Vulnerabilities" print "====================" print "" print MyScanVulnerabilitiesResponse.content
更多试用请访问:http://www.51component.com/acunetix/
公司名称:上海道宁信息科技有限公司 地 址:上海浦东新区金桥路1399号(福建天安大厦)2105室 总 机::021-50318395,021-58995797,021-58996110 邮政编码:200122 销售热线:021-50318395 传 真:021-58996110-110 网 址:www.51component.com 电子邮件:sales@51component.com