From 57625307a795a6420c9c7e86b1dc53986119d703 Mon Sep 17 00:00:00 2001 From: gyuu04 Date: Wed, 11 Jun 2025 15:11:50 +0900 Subject: [PATCH] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/redirect_uri_check.py | 74 ++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/addon/redirect_uri_check.py b/addon/redirect_uri_check.py index 358904e..176e537 100644 --- a/addon/redirect_uri_check.py +++ b/addon/redirect_uri_check.py @@ -17,16 +17,16 @@ class RedirectBypassChecker: """ 우회 페이로드 목록 """ self.bypass_payloads = [ BypassPayload( - name="\@", + name=r"@", mutate_func=self._mutate_pattern1, - description="브라우저는 \@를 사용자정보(@user)로 해석하지만, 일부 서버는 도메인 전체로 해석 → evil.com으로 우회" + description=r"@ 기호를 이용한 호스트 우회 공격: evil.com@target.com" ), - """ 테스트 후 우회 패턴 추가 예정 """ + ] self.session = None """ 우회 URL 생성 목록 """ - # 1. \@ + # 1. @ def _mutate_pattern1(self, original: str) -> str: parsed = urlparse(original) mutated = f"https://evil.com@{parsed.netloc}{parsed.path}" @@ -74,10 +74,24 @@ class RedirectBypassChecker: if not redirect_host or not base_host: return False + + if "@" in redirect_uri: + if redirect_host != base_host: + print(f"[ALERT] 우회 공격 탐지: {redirect_host} != {base_host}") + return False - # 동일 도메인 또는 하위 도메인인지 확인 - return (redirect_host == base_host or redirect_host.endswith(f".{base_host}")) - + at_parts = redirect_uri.split('@') + if len(at_parts) > 1: + before_at = at_parts[0] + if '//' in before_at: + potential_domain = before_at.split('//')[-1] + if '.' in potential_domain and potential_domain != base_host: + print(f"[CRITICAL] @ 우회 공격: {potential_domain}@{base_host}") + return False + + is_valid = (redirect_host == base_host or redirect_host.endswith(f".{base_host}")) + return is_valid + except Exception as e: print(f"[ERROR] 도메인 검증 실패: {e}") return False @@ -118,58 +132,56 @@ class RedirectBypassChecker: """ 개별 우회 패턴 테스트 """ async def _test_bypass_pattern(self, original_url, query, parsed_url, original_redirect_uri, payload, headers): + print(f"[SCAN] 우회 패턴 테스트: {payload.name}") + # 우회 URL 생성 bypassed_uri = payload.mutate(original_redirect_uri) - print(f"[DEBUG] 테스트 중인 우회 패턴 ({payload.name}): {bypassed_uri}") - + # 새로운 쿼리 파라미터 구성 modified_query = query.copy() modified_query["redirect_uri"] = [bypassed_uri] new_query_string = urlencode(modified_query, doseq=True) test_url = urlunparse(parsed_url._replace(query=new_query_string)) - - print(f"[DEBUG] 테스트 URL: {test_url}") # 요청 전송 response = await self._send_request(test_url, headers) - + # 응답 분석 - await self._analyze_response( - original_url, test_url, bypassed_uri, response, payload - ) + await self._analyze_response(original_url, test_url, bypassed_uri, response, payload) """ 응답 분석 및 취약점 판단 """ async def _analyze_response(self, original_url, test_url, bypassed_uri, response, payload): status = response['status'] location = response['location'] - print(f"[DEBUG] 응답 상태: {status}, Location: {location}") - # 리다이렉트 응답이 아니면 스킵 if status not in [301, 302, 303, 307, 308]: - print(f"[DEBUG] 리다이렉트가 아닌 응답: {status}") return # Location 헤더에서 code 추출 auth_code = self._extract_code_from_location(location) if auth_code and not self._is_baseline_valid(bypassed_uri, original_url): - # 취약점 발견! - await self._report_vulnerability( - original_url, test_url, bypassed_uri, location, auth_code, payload - ) - elif auth_code: - print(f"[DEBUG] 인가 코드 발급되었지만 유효한 도메인: {bypassed_uri}") - else: - print(f"[DEBUG] 인가 코드 발급되지 않음") + # 취약점 발견 시에만 로그 + print(f"[🎯 VULNERABILITY] {payload.name} 우회 성공!") + await self._report_vulnerability(original_url, test_url, bypassed_uri, location, auth_code, payload) + """ 취약점 보고서 생성 """ async def _report_vulnerability(self, original_url, test_url, bypassed_uri, location, auth_code, payload): + # payload가 문자열인지 객체인지 확인 + if hasattr(payload, 'name'): + pattern_name = payload.name + pattern_description = payload.description + else: + pattern_name = str(payload) + pattern_description = "Unknown bypass pattern" + description = ( f"Redirect URI 우회 취약점 발견!\n\n" f"-- 상세 정보 --:\n" - f"• 우회 패턴: {payload.name}\n" - f"• 설명: {payload.description}\n" + f"• 우회 패턴: {pattern_name}\n" + f"• 설명: {pattern_description}\n" f"• 원본 URL: {original_url}\n" f"• 우회된 redirect_uri: {bypassed_uri}\n" f"• 테스트 URL: {test_url}\n" @@ -179,10 +191,12 @@ class RedirectBypassChecker: report_data = [{ "target": target.load(), + "status": "CRITICAL", "title": "Redirect URI Bypass Vulnerability", - "description": description + "description": description, + "uri": test_url # uri 필드 추가 }] save_report(report_data) print(f"[🎯 CRITICAL] Redirect URI 우회 취약점 발견 및 보고 완료!") - print(f"[INFO] 패턴: {payload.name}, 우회 URI: {bypassed_uri}") + print(f"[INFO] 패턴: {pattern_name}, 우회 URI: {bypassed_uri}") \ No newline at end of file