commixapi.yaml
Rama master · réplica de lectura del repositorio original.
openapi: 3.0.3
info:
title: commix REST API
version: "1.0"
description: |
The API served by `commixapi.py`, implemented in `src/utils/api.py`.
A scan is a task: created, given options under the names the command line knows them by,
started, then read while it runs and after it ends. Each task is run as a process of its own,
started from a configuration file - the same file `-c` loads.
Notes for implementers:
* Options are the destinations of commix's own command-line options, with `-` read as `_`:
`url` is `--url`, `flush_session` is `--flush-session`. A name the parser does not know is
refused rather than kept.
* `report_json`, `output_dir` and `batch` are settled by the server, and setting them is
refused rather than ignored.
* Options that act on the host serving the API rather than on the target are refused too:
`--alert`, `-c`, `--save`, `--preprocess`, `--postprocess`, `--install`, `--update`,
`--purge`, and the switches that are not scans at all.
* Something the server understood but would not do answers `200` with `success: false` and a
`message`. Only authentication (`401`), an address that is not served (`404`), one asked for
with the wrong method (`405`) and an unhandled failure (`500`) answer with a code of their
own.
* `/scan/{taskid}/data` hands back the `--report-json` file the run is writing, so a run
started from a command line and one started here cannot answer differently.
license:
name: GNU General Public License v3 (GPLv3)
url: https://github.com/commixproject/commix/blob/master/LICENSE.txt
contact:
name: commix project
url: https://commixproject.com
externalDocs:
description: The API, in the user's manual
url: https://github.com/commixproject/commix/wiki/API
servers:
- url: http://127.0.0.1:8775
description: A local commixapi.py server
security:
- apiToken: []
tags:
- name: Version
description: What the server is
- name: Tasks
description: Making and forgetting tasks
- name: Options
description: Reading and settling a task's options
- name: Scans
description: Running a task, and reading it while it runs
- name: Files
description: What a task produced
- name: Admin
description: Every task at once
paths:
/version:
get:
tags: [Version]
operationId: getVersion
summary: commix's version, and this contract's
description: >-
The one address that is served without a token, so that a client can find out what it is
talking to before it authenticates. `api` is counted apart from `version`, so a client can
tell whether it still knows how to talk to a newer commix.
security: []
responses:
"200":
description: The versions.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
version: { type: string, example: "v4.2.dev219" }
api: { type: string, example: "1.0" }
/task/new:
get:
tags: [Tasks]
operationId: newTask
summary: Make a task
responses:
"200":
description: The task's id.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
taskid: { type: string, example: "93c54d9323c4dcba" }
"401": { $ref: "#/components/responses/Unauthorized" }
/task/{taskid}/delete:
get:
tags: [Tasks]
operationId: deleteTask
summary: Forget a task, ending its scan if one is running
description: >-
What the task produced is left on disk; it is the task that is forgotten, not its output.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200": { $ref: "#/components/responses/Plain" }
"401": { $ref: "#/components/responses/Unauthorized" }
/option/{taskid}/list:
get:
tags: [Options]
operationId: listOptions
summary: Every option of a task, with what it is set to
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200":
description: The options.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
options:
type: object
additionalProperties: true
"401": { $ref: "#/components/responses/Unauthorized" }
/option/{taskid}/get:
post:
tags: [Options]
operationId: getOption
summary: One option, by name
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [option]
properties:
option: { type: string, example: "url" }
responses:
"200":
description: The option, under its own name.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
additionalProperties: true
"401": { $ref: "#/components/responses/Unauthorized" }
/option/{taskid}/set:
post:
tags: [Options]
operationId: setOptions
summary: Set options on a task
description: >-
Every option in the body is settled, in the order given. A name the parser does not know
ends the request, and the ones before it stay set.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Options"
responses:
"200": { $ref: "#/components/responses/Plain" }
"401": { $ref: "#/components/responses/Unauthorized" }
/scan/{taskid}/start:
post:
tags: [Scans]
operationId: startScan
summary: Start the task's scan
description: >-
Options in the body are settled first, which makes a scan two requests rather than three.
One of `url`, `logfile`, `bulkfile`, `requestfile`, `sitemap_url` or `openapi` has to be set
by then, and a scan already running is not started again.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/Options"
responses:
"200":
description: The process the scan is running as.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
engineid: { type: integer, example: 45671 }
"401": { $ref: "#/components/responses/Unauthorized" }
/scan/{taskid}/stop:
get:
tags: [Scans]
operationId: stopScan
summary: Ask the scan to stop
description: >-
The run is asked to end and finishes its report first, so what it found up to then is kept.
Worth preferring to `/kill`, which does not.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200":
description: Whether there was a running scan to stop.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
stopped: { type: boolean }
"401": { $ref: "#/components/responses/Unauthorized" }
/scan/{taskid}/kill:
get:
tags: [Scans]
operationId: killScan
summary: End the scan's process outright
description: >-
The process is given no chance to write anything further, so its report stops where it was.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200":
description: Whether there was a running scan to kill.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
killed: { type: boolean }
"401": { $ref: "#/components/responses/Unauthorized" }
/scan/{taskid}/status:
get:
tags: [Scans]
operationId: scanStatus
summary: Where the run has got to
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200":
description: The status, and the code the process ended on where it has ended.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
status:
type: string
enum: [not started, running, completed, time-limit, terminated, failed, killed]
returncode:
type: integer
nullable: true
"401": { $ref: "#/components/responses/Unauthorized" }
/scan/{taskid}/data:
get:
tags: [Scans]
operationId: scanData
summary: The run's results, as they stand
description: >-
Readable throughout: the report is written as the run goes, so findings appear as they are
confirmed. `error` is what went wrong, which is what tells a run that could not reach its
target from one that reached it and found nothing - both end with no findings.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200":
description: The report.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
data: { $ref: "#/components/schemas/Report" }
error:
type: array
items: { $ref: "#/components/schemas/Issue" }
"401": { $ref: "#/components/responses/Unauthorized" }
/scan/{taskid}/log:
get:
tags: [Scans]
operationId: scanLog
summary: What the run has said
parameters:
- { $ref: "#/components/parameters/TaskId" }
- name: start
in: query
required: false
schema: { type: integer }
description: First line to hand back.
- name: end
in: query
required: false
schema: { type: integer }
description: Line to stop before.
responses:
"200":
description: The lines.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
log:
type: array
items: { $ref: "#/components/schemas/LogLine" }
"401": { $ref: "#/components/responses/Unauthorized" }
/download/{taskid}:
get:
tags: [Files]
operationId: listFiles
summary: Every file the task has to hand
description: >-
The options it was started with, the report, what it printed, and whatever the run itself
wrote - each by a path relative to the task's own directory, which is the path
`/download/{taskid}/{path}` takes.
parameters: [ { $ref: "#/components/parameters/TaskId" } ]
responses:
"200":
description: The files, by path.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
files:
type: array
items:
type: object
properties:
path: { type: string, example: "output/localhost_8081/logs.txt" }
size: { type: integer, example: 2127 }
"401": { $ref: "#/components/responses/Unauthorized" }
/download/{taskid}/{path}:
get:
tags: [Files]
operationId: downloadFile
summary: One of those files, as itself
description: >-
The only address that answers with something other than JSON. A path that resolves outside
the task's own directory is refused, however it is spelled.
parameters:
- { $ref: "#/components/parameters/TaskId" }
- name: path
in: path
required: true
schema: { type: string }
description: The file's path, as the listing above gives it.
responses:
"200":
description: The file.
headers:
Content-Disposition:
schema: { type: string }
description: 'attachment; filename="<the file''s own name>"'
content:
application/octet-stream:
schema: { type: string, format: binary }
"401": { $ref: "#/components/responses/Unauthorized" }
"404":
description: No such task, or no such file in it.
content:
application/json:
schema:
$ref: "#/components/schemas/Failure"
/admin/list:
get:
tags: [Admin]
operationId: listTasks
summary: Every task this server holds
responses:
"200":
description: The tasks, by id.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Success"
- type: object
properties:
count: { type: integer }
tasks:
type: object
additionalProperties:
type: object
properties:
status: { type: string }
returncode: { type: integer, nullable: true }
"401": { $ref: "#/components/responses/Unauthorized" }
/admin/flush:
get:
tags: [Admin]
operationId: flushTasks
summary: Forget every task, ending any scan still running
responses:
"200": { $ref: "#/components/responses/Plain" }
"401": { $ref: "#/components/responses/Unauthorized" }
components:
securitySchemes:
apiToken:
type: apiKey
in: header
name: X-Api-Token
description: >-
The token the server was started with, or the one it made up and printed as it started.
parameters:
TaskId:
name: taskid
in: path
required: true
schema:
type: string
pattern: "^[0-9a-f]+$"
description: The id `/task/new` handed back.
responses:
Plain:
description: Whether what was asked for happened.
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/Success"
- $ref: "#/components/schemas/Failure"
Unauthorized:
description: The token was wrong or missing.
content:
application/json:
schema:
$ref: "#/components/schemas/Failure"
schemas:
Success:
type: object
required: [success]
properties:
success:
type: boolean
enum: [true]
Failure:
type: object
required: [success, message]
properties:
success:
type: boolean
enum: [false]
message:
type: string
example: "Unknown option 'nosuchthing'."
Options:
type: object
description: >-
Options by the destinations of commix's own command-line options, with `-` read as `_`.
additionalProperties: true
example:
url: "http://commix-testbed/scenarios/regular/GET/classic.php?addr=127.0.0.1"
flush_session: true
time_limit: 90
Report:
type: object
description: >-
The `--report-json` report, as it stands. A run over a single target is the object below.
A run over several - `bulkfile`, `logfile`, `sitemap_url` or a crawl - carries one such
object per target under `targets`, with `started`, `status`, `finished` and `requests` for
the run as a whole.
properties:
targets:
type: array
description: Present only where the run covered more than one target.
items:
type: object
target: { type: string }
http_method: { type: string }
command: { type: string }
started: { type: string }
finished: { type: string }
status:
type: string
enum: [running, completed, time-limit, terminated, failed]
requests: { type: integer }
target_os: { type: string }
waf_detected: { type: boolean }
evasion_applied: { type: string }
findings:
type: array
items: { $ref: "#/components/schemas/Finding" }
errors:
type: array
items: { $ref: "#/components/schemas/Issue" }
Finding:
type: object
properties:
parameter: { type: string, example: "addr" }
http_method: { type: string, example: "GET" }
technique: { type: string, example: "Results-based" }
type: { type: string, example: "Classic command injection" }
boundary: { type: string, example: "';' separator, ' ' whitespace" }
payload: { type: string }
reproduce:
type: string
description: The single request that brings the finding back.
reproduce_caveats: { type: string }
Issue:
type: object
properties:
time: { type: string, example: "08:12:05" }
level:
type: string
enum: [error, critical, abort]
message: { type: string }
LogLine:
type: object
properties:
time: { type: string, example: "08:12:01" }
level: { type: string, example: "info" }
message: { type: string, example: "Testing connection to the target URL." }