Update redirect_uriBypass.ts
This commit is contained in:
parent
78042ef305
commit
979dda299a
1 changed files with 29 additions and 16 deletions
|
|
@ -2,42 +2,55 @@ import type { Request, Response } from "caido:utils";
|
||||||
import type { SDK } from "caido:plugin";
|
import type { SDK } from "caido:plugin";
|
||||||
|
|
||||||
export class RedirectBypassController {
|
export class RedirectBypassController {
|
||||||
isRedirectUri(req: Request): boolean {
|
// redirect_uri를 확인하는 함수
|
||||||
|
isRedirectUri(req: Request): { detected: boolean; redirectUri?: string } {
|
||||||
|
// ? 뒤에 오는 파라미터 모두 가져오고, 정규표현식으로 redirect_uri= 이후 주소만 뽑음(없으면 null)
|
||||||
const query = req.getQuery();
|
const query = req.getQuery();
|
||||||
|
|
||||||
// redirect_uri 파라미터 정규식으로 추출
|
|
||||||
const redirectUriMatch = query.match(/redirect_uri=([^&]+)/i);
|
const redirectUriMatch = query.match(/redirect_uri=([^&]+)/i);
|
||||||
if (!redirectUriMatch) return false;
|
|
||||||
|
|
||||||
// redirect_uri 파라미터의 URL 문자열을 디코딩
|
// redirectUriMatch[1]은 ()로 감싼 부분
|
||||||
|
// redirect_uri 파라미터가 없거나 있어도 주소가 문자열이 아니면 false
|
||||||
|
if (!redirectUriMatch || typeof redirectUriMatch[1] !== "string") {
|
||||||
|
return { detected: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 인코딩된 주소를 원래대로 바꿈 (ex. https://~~)
|
||||||
const redirectUri = decodeURIComponent(redirectUriMatch[1]);
|
const redirectUri = decodeURIComponent(redirectUriMatch[1]);
|
||||||
|
|
||||||
// 우회 키워드
|
|
||||||
const bypassPatterns = [
|
const bypassPatterns = [
|
||||||
"%ff@", "/", "%2f@", "%0a@", "%0d@", "\\", ".evil.com", "@", "%2f..%2f"
|
"%ff@", "/", "%2f@", "%0a@", "%0d@", "\\", ".evil.com", "@", "%2f..%2f",
|
||||||
];
|
];
|
||||||
|
|
||||||
return bypassPatterns.some(pattern => redirectUri.includes(pattern));
|
// 위 패턴에 일치하는 게 있으면 true랑 redirectUri 반환 (false일 땐 undefined)
|
||||||
|
const detected = bypassPatterns.some(pattern => redirectUri.includes(pattern));
|
||||||
|
return { detected, redirectUri: detected ? redirectUri : undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 응답에 인가 코드가 포함되어 있는지 확인하는 함수
|
||||||
isCodeIssued(res: Response): boolean {
|
isCodeIssued(res: Response): boolean {
|
||||||
const location = res.getHeader("Location") || "";
|
const location = res.getHeader("Location") || "";
|
||||||
return location.includes("code=");
|
return location.includes("code=");
|
||||||
}
|
}
|
||||||
|
|
||||||
test(req: Request, res: Response): string | false {
|
// 위의 두 함수 모두 만족하면 true, 문제의 주소를 반환하는 함수
|
||||||
if (this.isRedirectUri(req) && this.isCodeIssued(res)) {
|
test(req: Request, res: Response): { detected: boolean; redirectUri?: string } {
|
||||||
return "redirect_uri bypass detected";
|
const redirectCheck = this.isRedirectUri(req);
|
||||||
|
const codeIssued = this.isCodeIssued(res);
|
||||||
|
|
||||||
|
if (redirectCheck.detected && codeIssued) {
|
||||||
|
return { detected: true, redirectUri: redirectCheck.redirectUri };
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return { detected: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
async testAsync(sdk: SDK, req: Request, res: Response) {
|
// 탐지된 결과 저장하는 함수
|
||||||
|
async testAsync(sdk: SDK, req: Request, res: Response): Promise<void> {
|
||||||
const result = this.test(req, res);
|
const result = this.test(req, res);
|
||||||
if (result) {
|
if (result.detected) {
|
||||||
await sdk.findings.create({
|
await sdk.findings.create({
|
||||||
title: "Redirect URI Bypass Detected",
|
title: "Redirect URI Bypass Detected",
|
||||||
description: result,
|
description: `redirect_uri 우회 발견\nRedirect URI: ${result.redirectUri}`,
|
||||||
request: req,
|
request: req,
|
||||||
reporter: "gyu",
|
reporter: "gyu",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue