redirect_uri misconfig

This commit is contained in:
caterpii 2025-05-31 11:41:36 +09:00
commit d35af82aae
16 changed files with 2408 additions and 0 deletions

83
packages/backend/dist/index.js vendored Normal file
View 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
};

View 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
View 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': {}

View 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}`);
}
});
}

View file

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["@caido/sdk-backend"],
"lib": ["ESNext", "DOM"]
},
"include": ["./src/**/*.ts"]
}