Sample API client
A sample API client written in Python, which can be used as a starting point for using the API.
#!/usr/bin/python
"""
Sample API client for Pentest-Tools.com.
This client starts a Web Server Scan, queries the output and writes the report in a HTML and a PDF file.
A valid API key is necessary for this program to work.
This client contains sample requests for most API methods
API Reference: https://pentest-tools.com/api-reference
"""
import json
import time
import traceback
import base64
import requests
def start_scan(api_url, tool_id, target, tool_params):
""" Start a scan using the given target name
Specific parameters:
- tool_id -- the ID of the tool to start (check the API documentation for the possible values)
- target -- the target in string format (e.g. "example.org", "https://example.org")
- tool_params -- the parameters of the tool (check the API documentation for the specific formats)
"""
data = {
"op": "start_scan",
"tool_id": tool_id,
"target": target,
"tool_params": tool_params
}
res = requests.post(api_url, data=json.dumps(data))
return res
def start_scan_by_targetid(api_url, tool_id, target_id, tool_params):
""" Start a scan using the given target_id
Specific parameters:
- tool_id -- the ID of the tool to start (check the API documentation for the possible values)
- target_id -- the target in integer format (use `get_targets` for the target list)
- tool_params -- the parameters of the tool (check the API documentation for the specific formats)
"""
data = {
"op": "start_scan_by_targetid",
"tool_id": tool_id,
"target_id": target_id,
"tool_params": tool_params
}
res = requests.post(api_url, data=json.dumps(data))
return res
def get_output(api_url, scan_id, output_format):
""" Get the output of a scan
Specific parameters:
- scan_id -- the scan_id of the requested scan (use `get_scans` for the scan list)
- output_format -- the format in which to get the output of the scan ("html"/"json"/"pdf")
"""
data = {
"op": "get_output",
"scan_id": scan_id,
"output_format": output_format
}
res = requests.post(api_url, data=json.dumps(data))
return res
def stop_scan(api_url, scan_id):
""" Stop a running scan
Specific parameters:
- scan_id -- the scan_id of the requested scan (use `get_scans` for the scan list)
"""
data = {
"op": "stop_scan",
"scan_id": scan_id
}
res = requests.post(api_url, data=json.dumps(data))
return res
def get_scan_status(api_url, scan_id):
""" Get the status of a scan
Specific parameters:
- scan_id -- the scan_id of the requested scan (use `get_scans` for the scan list)
"""
data = {
"op": "get_scan_status",
"scan_id": scan_id
}
res = requests.post(api_url, data=json.dumps(data))
return res
def get_scans(api_url, limit, workspace_id=None, target_id=None):
""" Get a list of scans
Specific parameters:
- limit -- maximum number of returned scans
- workspace_id -- when set, only the scans from this workspace will be returned
(you can get a list of workspaces by using the `get_workspaces` operation)
- target_id -- when set, only the scans run on this target will be returned
(use `get_targets` for the target list)
"""
data = {
"op": "get_scans",
"limit": limit
}
if workspace_id is not None:
data["workspace_id"] = workspace_id
if target_id is not None:
data["target_id"] = target_id
res = requests.post(api_url, data=json.dumps(data))
return res
def get_targets(api_url, limit=0):
""" Get a list of targets
Specific parameters:
- limit -- maximum number of returned targets (up to 1000 will be returned if it is set to 0)
"""
data = {
"op": "get_targets",
"limit": limit
}
res = requests.post(api_url, data=json.dumps(data))
return res
def add_target(api_url, name, description="", workspace_id=None):
""" Add a new target
Specific parameters:
- name -- the name of the target (must be a hostname, IP address or URL)
- description -- a short description of the target (optional)
- workspace_id -- the specific workspace in which to add this target (optional)
"""
data = {
"op": "add_target",
"name": name
}
if len(description) > 0:
data["description"] = description
if workspace_id is not None:
data["workspace_id"] = workspace_id
res = requests.post(api_url, data=json.dumps(data))
return res
def update_target_description(api_url, target_id, description):
""" Update the description of a target
Specific parameters:
- target_id -- the ID of the updated target
- description -- the new description of the target
"""
data = {
"op": "update_target_description",
"target_id": target_id,
"description": description
}
res = requests.post(api_url, data=json.dumps(data))
return res
if __name__ == '__main__':
key = "xxxxxxxxxxxxxx" # <-- Put your API key here
api_url = "https://app.pentest-tools.com/api?key=" + key
# These values are specific to each tool
# In this case we want to use the Web Server Scanner
# See the API Reference for more details
tool_id = 170
tool_params = {
"scan_type": "quick"
}
target = "http://demo.pentest-tools.com/webapp/"
# Start the scan
res = start_scan(api_url, tool_id, target, tool_params)
try:
res_json = json.loads(res.text)
except:
print(traceback.format_exc())
print(res.text)
# Check the status of the operation
if res_json["op_status"] == "success":
# This is the id of the new scan
scan_id = res_json["scan_id"]
print("Started scan %i" % scan_id)
# Poll periodically to check if the scan is finished
while True:
time.sleep(2)
# Get the status of our scan
res = get_scan_status(api_url, scan_id)
res_json = json.loads(res.text)
if res_json["op_status"] == "success":
print("Scan status: %s" % res_json["scan_status"])
if res_json["scan_status"] != "waiting" and res_json["scan_status"] != "running":
# Get the HTML report and write it to a file
print("Getting HTML report")
res = get_output(api_url, scan_id, "html")
res_json = json.loads(res.text)
output_html = res_json["scan_output"]["output_html"]
with open("report.html", "w") as f:
f.write(output_html)
print("HTML report written to file")
# Get the PDF report and write it to a file
print("Getting PDF report")
res = get_output(api_url, scan_id, "pdf")
res_json = json.loads(res.text)
output_pdf = res_json["scan_output"]["output_pdf"]
with open("report.pdf", "wb") as f:
f.write(base64.b64decode(output_pdf))
print("PDF report written to file")
break
else:
print("Operation get_scan_status failed because: %s. %s" % (res_json["error"], res_json["details"]))
break
else:
print("Operation start_scan failed because: %s. %s" % (res_json["error"], res_json["details"]))