diff --git a/packages/backend/src/controller/redirect_uriBypass.ts b/packages/backend/src/controller/redirect_uriBypass.ts index 8b4b436..f77b324 100644 --- a/packages/backend/src/controller/redirect_uriBypass.ts +++ b/packages/backend/src/controller/redirect_uriBypass.ts @@ -1,40 +1,46 @@ import type { Request, Response } from "caido:utils"; - +import type { SDK } from "caido:plugin"; export class RedirectBypassController { isRedirectUri(req: Request): boolean { const query = req.getQuery(); - // redirect_uri 파라미터 정규식으로 추출 const redirectUriMatch = query.match(/redirect_uri=([^&]+)/i); if (!redirectUriMatch) return false; - // redirect_uri 파라미터의 URL 문자열을 디코딩 const redirectUri = decodeURIComponent(redirectUriMatch[1]); - // 우회 키워드 const bypassPatterns = [ "%ff@", "/", "%2f@", "%0a@", "%0d@", "\\", ".evil.com", "@", "%2f..%2f" ]; - return bypassPatterns.some(pattern => redirectUri.includes(pattern)); } - isCodeIssued(res: Response): boolean { const location = res.getHeader("Location") || ""; return location.includes("code="); } - test(req: Request, res: Response): string | false { if (this.isRedirectUri(req) && this.isCodeIssued(res)) { return "redirect_uri bypass detected"; } return false; } + + async testAsync(sdk: SDK, req: Request, res: Response) { + const result = this.test(req, res); + if (result) { + await sdk.findings.create({ + title: "Redirect URI Bypass Detected", + description: result, + request: req, + reporter: "gyu", + }); + } + } } diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 44f817c..43d7516 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -7,6 +7,7 @@ import { PKCECheck } from "./controller/PKCECheck"; import { AccessTokenLeakController } from "./controller/accessTokenDetector"; import { ScopeDetection } from "./controller/scopeDetection"; // import { NonceCheckController } from "./controller/nonceCheck"; +import { RedirectBypassController } from "./controller/redirect_uriBypass"; export type API = DefineAPI<{}>; @@ -15,6 +16,7 @@ const pkceCheckController = new PKCECheck(); const tokenCheck = new AccessTokenLeakController(); const ScopeDetectionController = new ScopeDetection(); // const nonceCheckController = new NonceCheckController(); +const redirectBypassController = new RedirectBypassController(); export function init(sdk: SDK) { sdk.events.onInterceptResponse(async (sdk, req: Request, res: Response) => { @@ -23,6 +25,7 @@ export function init(sdk: SDK) { await tokenCheck.testReq(sdk, req); await tokenCheck.testResp(sdk, res, req); await ScopeDetectionController.scan(sdk, req.getUrl()); + await redirectBypassController.testAsync(sdk, req, res); // if (NonceCheckController.isOidcFlow(req, res)) { // await sdk.findings.create({