redirect_uri misconfig
This commit is contained in:
commit
d35af82aae
16 changed files with 2408 additions and 0 deletions
83
packages/backend/dist/index.js
vendored
Normal file
83
packages/backend/dist/index.js
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// packages/backend/src/index.ts
|
||||
import { promises as fs } from "fs";
|
||||
import * as path from "path";
|
||||
import os from "os";
|
||||
var requestMap = /* @__PURE__ */ new Map();
|
||||
function init(sdk) {
|
||||
sdk.events.onInterceptRequest(async (sdk2, req) => {
|
||||
try {
|
||||
const urlString = req.getUrl();
|
||||
const url = new URL(urlString);
|
||||
sdk2.console.log(`[OAuthPlugin] Intercepted request: ${urlString}`);
|
||||
if (!url.pathname.includes("/authorize") && !url.pathname.includes("/auth")) return;
|
||||
const params = new URLSearchParams(url.search);
|
||||
const redirectUri = params.get("redirect_uri");
|
||||
if (!redirectUri) return;
|
||||
const reqId = req.getId();
|
||||
requestMap.set(reqId, redirectUri);
|
||||
const clientId = params.get("client_id") ?? "(missing)";
|
||||
const responseType = params.get("response_type") ?? "(missing)";
|
||||
const isScan = params.has("scan");
|
||||
if (isScan) return;
|
||||
const output = {
|
||||
original_url: urlString,
|
||||
client_id: clientId,
|
||||
redirect_uri: redirectUri,
|
||||
response_type: responseType
|
||||
};
|
||||
try {
|
||||
const filePath = path.join(os.tmpdir(), "oauth-fuzz-input.json");
|
||||
await fs.writeFile(filePath, JSON.stringify(output, null, 2));
|
||||
} catch (err) {
|
||||
await sdk2.findings.create({
|
||||
title: "[fs] Write Failed",
|
||||
description: `Could not write to file: ${err}`,
|
||||
request: req,
|
||||
reporter: "oauth-open-redirect-detector"
|
||||
});
|
||||
}
|
||||
await sdk2.findings.create({
|
||||
title: "[ ] OAuth2 Authorization Request Collected",
|
||||
description: `client_id: ${clientId}
|
||||
redirect_uri: ${redirectUri}
|
||||
response_type: ${responseType}`,
|
||||
request: req,
|
||||
reporter: "oauth-open-redirect-detector"
|
||||
});
|
||||
} catch (err) {
|
||||
sdk2.console.error(`Error in onInterceptRequest: ${err}`);
|
||||
}
|
||||
});
|
||||
sdk.events.onInterceptResponse(async (sdk2, req, resp) => {
|
||||
try {
|
||||
const reqId = req.getId();
|
||||
const url = new URL(req.getUrl());
|
||||
const status = resp.getCode();
|
||||
const location = resp.getHeader("location")?.[0];
|
||||
const params = new URLSearchParams(url.search);
|
||||
const isScan = params.has("scan");
|
||||
if (!isScan) {
|
||||
requestMap.delete(reqId);
|
||||
return;
|
||||
}
|
||||
if (status >= 300 && status < 400 && location) {
|
||||
const redirectUri = requestMap.get(reqId) ?? "(unknown)";
|
||||
await sdk2.findings.create({
|
||||
title: "[+] Redirect URI Misconfiguration Detected",
|
||||
description: `Status: ${status}
|
||||
Location: ${location}
|
||||
Original Redirect URI: ${redirectUri}
|
||||
Request URL: ${url.href}`,
|
||||
request: req,
|
||||
reporter: "oauth-open-redirect-detector"
|
||||
});
|
||||
}
|
||||
requestMap.delete(reqId);
|
||||
} catch (err) {
|
||||
sdk2.console.error(`Error in onInterceptResponse: ${err}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
init
|
||||
};
|
||||
10
packages/backend/package.json
Normal file
10
packages/backend/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "backend",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "vite build"
|
||||
}
|
||||
}
|
||||
35
packages/backend/pnpm-lock.yaml
generated
Normal file
35
packages/backend/pnpm-lock.yaml
generated
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
'@caido/sdk-backend':
|
||||
specifier: ^0.46.0
|
||||
version: 0.46.0
|
||||
|
||||
packages:
|
||||
|
||||
'@caido/quickjs-types@0.17.2':
|
||||
resolution: {integrity: sha512-5kcucGORMNEbcdU91yKLYZG/TFDqsO6XmCZ1TnU6V48E61mmqrJg6kjrfOFP1WOugDm+ZcGd/Su3p3XkFXfaPg==}
|
||||
|
||||
'@caido/sdk-backend@0.46.0':
|
||||
resolution: {integrity: sha512-peUKW/4Nrw9WVxIahc+6KrVtxA7vsbpuJqOoBxudxq7tQJ+cV9IEqzvYoFFo8KlnrTkeUQUJvd0W4WsM3HgxEg==}
|
||||
|
||||
'@caido/sdk-shared@0.1.1':
|
||||
resolution: {integrity: sha512-JAV5ajUqxZdXYPTmDEvIKBZon8I5uHq44ATj0Nj3BVpllRDUGY9kcBd+PXMD50+3lv1CvhR3/f6q24T0+4aVJQ==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@caido/quickjs-types@0.17.2': {}
|
||||
|
||||
'@caido/sdk-backend@0.46.0':
|
||||
dependencies:
|
||||
'@caido/quickjs-types': 0.17.2
|
||||
'@caido/sdk-shared': 0.1.1
|
||||
|
||||
'@caido/sdk-shared@0.1.1': {}
|
||||
94
packages/backend/src/index.ts
Normal file
94
packages/backend/src/index.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import type { SDK, DefineAPI } from "caido:plugin";
|
||||
import type { Request, Response } from "caido:utils";
|
||||
import { promises as fs } from "fs";
|
||||
import * as path from "path";
|
||||
import os from "os";
|
||||
|
||||
export type API = DefineAPI<{}>;
|
||||
|
||||
const requestMap = new Map<string, string>();
|
||||
export function init(sdk: SDK<API>) {
|
||||
|
||||
sdk.events.onInterceptRequest(async (sdk, req: Request) => {
|
||||
try {
|
||||
const urlString = req.getUrl();
|
||||
const url = new URL(urlString);
|
||||
sdk.console.log(`[OAuthPlugin] Intercepted request: ${urlString}`);
|
||||
|
||||
if (!url.pathname.includes("/authorize") && !url.pathname.includes("/auth")) return;
|
||||
|
||||
const params = new URLSearchParams(url.search);
|
||||
const redirectUri = params.get("redirect_uri");
|
||||
if (!redirectUri) return;
|
||||
|
||||
const reqId = req.getId();
|
||||
requestMap.set(reqId, redirectUri);
|
||||
|
||||
const clientId = params.get("client_id") ?? "(missing)";
|
||||
const responseType = params.get("response_type") ?? "(missing)";
|
||||
const isScan = params.has("scan");
|
||||
if (isScan) return;
|
||||
|
||||
const output = {
|
||||
original_url: urlString,
|
||||
client_id: clientId,
|
||||
redirect_uri: redirectUri,
|
||||
response_type: responseType,
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
const filePath = path.join(os.tmpdir(), "oauth-fuzz-input.json");
|
||||
await fs.writeFile(filePath, JSON.stringify(output, null, 2));
|
||||
} catch (err) {
|
||||
await sdk.findings.create({
|
||||
title: "[fs] Write Failed",
|
||||
description: `Could not write to file: ${err}`,
|
||||
request: req,
|
||||
reporter: "oauth-open-redirect-detector"
|
||||
});
|
||||
}
|
||||
await sdk.findings.create({
|
||||
title: "[ ] OAuth2 Authorization Request Collected",
|
||||
description: `client_id: ${clientId}\nredirect_uri: ${redirectUri}\nresponse_type: ${responseType}`,
|
||||
request: req,
|
||||
reporter: "oauth-open-redirect-detector"
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
sdk.console.error(`Error in onInterceptRequest: ${err}`);
|
||||
}
|
||||
});
|
||||
|
||||
sdk.events.onInterceptResponse(async (sdk, req: Request, resp: Response) => {
|
||||
try {
|
||||
const reqId = req.getId();
|
||||
const url = new URL(req.getUrl());
|
||||
const status = resp.getCode();
|
||||
const location = resp.getHeader("location")?.[0];
|
||||
|
||||
const params = new URLSearchParams(url.search);
|
||||
const isScan = params.has("scan");
|
||||
|
||||
if (!isScan) {
|
||||
requestMap.delete(reqId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status >= 300 && status < 400 && location) {
|
||||
const redirectUri = requestMap.get(reqId) ?? "(unknown)";
|
||||
|
||||
await sdk.findings.create({
|
||||
title: "[+] Redirect URI Misconfiguration Detected",
|
||||
description: `Status: ${status}\nLocation: ${location}\nOriginal Redirect URI: ${redirectUri}\nRequest URL: ${url.href}`,
|
||||
request: req,
|
||||
reporter: "oauth-open-redirect-detector",
|
||||
});
|
||||
}
|
||||
|
||||
requestMap.delete(reqId);
|
||||
} catch (err) {
|
||||
sdk.console.error(`Error in onInterceptResponse: ${err}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
8
packages/backend/tsconfig.json
Normal file
8
packages/backend/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"types": ["@caido/sdk-backend"],
|
||||
"lib": ["ESNext", "DOM"]
|
||||
},
|
||||
"include": ["./src/**/*.ts"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue