diff --git a/packages/workflows/src/http-method-checker/README.md b/packages/workflows/src/http-method-checker/README.md new file mode 100644 index 0000000..b91d035 --- /dev/null +++ b/packages/workflows/src/http-method-checker/README.md @@ -0,0 +1,16 @@ +# HTTP Method Checker + +## Author +- **Name:** [Ads Dawson](https://github.com/GangGreenTemperTatum) + +## Description +This workflow dynamically probes HTTP endpoints by sending an `OPTIONS` request to detect discrepancies between the HTTP methods advertised by the server and the method originally used. It helps identify misconfigured HTTP methods exposed on the target. + +## Features +- Sends `OPTIONS` request to the same host and path as the original request. +- Parses `Allow` and `Access-Control-Allow-Methods` headers. +- Flags requests where the original HTTP method is not listed in the allowed methods. +- Creates findings with detailed metadata for easier triage. + +## Usage +Import this workflow into Caido and run it during your HTTP request analysis. It automatically sends the probe and generates findings if discrepancies are found. diff --git a/packages/workflows/src/http-method-checker/definition.json b/packages/workflows/src/http-method-checker/definition.json new file mode 100644 index 0000000..d41857a --- /dev/null +++ b/packages/workflows/src/http-method-checker/definition.json @@ -0,0 +1,172 @@ +{ + "description": "Passively probes each proxied HTTP request with a subsequent HTTP OPTIONS request and reports when the OPTIONS response includes allowed methods beyond the original request method.", + "edition": 2, + "graph": { + "edges": [ + { + "source": { + "exec_alias": "exec", + "node_id": 2 + }, + "target": { + "exec_alias": "exec", + "node_id": 3 + } + }, + { + "source": { + "exec_alias": "exec", + "node_id": 3 + }, + "target": { + "exec_alias": "exec", + "node_id": 1 + } + }, + { + "source": { + "exec_alias": "exec", + "node_id": 0 + }, + "target": { + "exec_alias": "exec", + "node_id": 5 + } + }, + { + "source": { + "exec_alias": "true", + "node_id": 5 + }, + "target": { + "exec_alias": "exec", + "node_id": 2 + } + } + ], + "nodes": [ + { + "alias": "on_intercept_request", + "definition_id": "caido/on-intercept-request", + "display": { + "x": -10, + "y": -110 + }, + "id": 0, + "inputs": [], + "name": "On intercept request", + "version": "0.1.0" + }, + { + "alias": "passive_end", + "definition_id": "caido/passive-end", + "display": { + "x": -10, + "y": 260 + }, + "id": 1, + "inputs": [], + "name": "Passive End", + "version": "0.1.0" + }, + { + "alias": "javascript", + "definition_id": "caido/http-code-js", + "display": { + "x": -10, + "y": 80 + }, + "id": 2, + "inputs": [ + { + "alias": "request", + "value": { + "data": "$on_intercept_request.request", + "kind": "ref" + } + }, + { + "alias": "code", + "value": { + "data": "", + "kind": "string" + } + } + ], + "name": "OPTIONS Request Probe", + "version": "0.1.0" + }, + { + "alias": "create_finding", + "definition_id": "caido/finding-create", + "display": { + "x": -10, + "y": 170 + }, + "id": 3, + "inputs": [ + { + "alias": "title", + "value": { + "data": "Create Finding", + "kind": "string" + } + }, + { + "alias": "reporter", + "value": { + "data": "HTTP Method Checker", + "kind": "string" + } + }, + { + "alias": "dedupe_key", + "value": { + "data": "`${host}|${path}|${origMethod}|${allowHeader}`, ", + "kind": "string" + } + }, + { + "alias": "request", + "value": { + "data": "$options_probe.data", + "kind": "ref" + } + }, + { + "alias": "description", + "value": { + "data": "$options_probe.data", + "kind": "ref" + } + } + ], + "name": "Create Finding", + "version": "0.1.0" + }, + { + "alias": "in_scope", + "definition_id": "caido/in-scope", + "display": { + "x": -10, + "y": -10 + }, + "id": 5, + "inputs": [ + { + "alias": "request", + "value": { + "data": "$on_intercept_request.request", + "kind": "ref" + } + } + ], + "name": "In Scope", + "version": "0.1.0" + } + ] + }, + "id": "ce244451-262d-4c01-89d0-358b8fc58a2b", + "kind": "passive", + "name": "HTTP Method Checker" +} diff --git a/packages/workflows/src/http-method-checker/javascript.ts b/packages/workflows/src/http-method-checker/javascript.ts new file mode 100644 index 0000000..734dbc3 --- /dev/null +++ b/packages/workflows/src/http-method-checker/javascript.ts @@ -0,0 +1,33 @@ +/** + * @param {HttpInput} input + * @param {SDK} sdk + * @returns {MaybePromise} + */ +export async function run({ request, response }, sdk) { + if (!request) return; + + const orig = request.getMethod(); + const spec = request.toSpec(); + spec.setMethod("OPTIONS"); + + // Send the dynamic OPTIONS probe to the same host/path + const probe = await sdk.requests.send(spec); + + if (probe.response) { + const headers = probe.response.getHeaders(); + const allow = headers["allow"]?.[0] || ""; + const cors = headers["access-control-allow-methods"]?.[0] || ""; + const methods = (allow || cors).split(/\s*,\s*/); + + if (methods.length && !methods.includes(orig)) { + const dedupeKey = `${request.getHost()}|${request.getPath()}|${orig}|${methods.join(",")}`; + await sdk.findings.create({ + title: "Extraneous HTTP methods exposed", + description: `OPTIONS listed methods [${methods.join(", ")}], original: ${orig}`, + request, + response: probe.response, + dedupeKey + }); + } + } +} \ No newline at end of file diff --git a/packages/workflows/src/http-method-checker/manifest.json b/packages/workflows/src/http-method-checker/manifest.json new file mode 100644 index 0000000..0df4ad2 --- /dev/null +++ b/packages/workflows/src/http-method-checker/manifest.json @@ -0,0 +1,10 @@ +{ + "author": { + "name": "Ads Dawson" + }, + "url": "https://github.com/caido-community/workflows/packages/workflows/http-method-checker/README.md", + "description": "Detects HTTP methods exposed by dynamically probing endpoints with OPTIONS requests.", + "id": "http-method-checker", + "name": "HTTP Method Checker", + "version": "0.1.0" +}