mirror of
https://github.com/j93es/oauth-backend.git
synced 2026-06-04 06:01:51 +09:00
테스트 완료
This commit is contained in:
parent
ef61667cfe
commit
57625307a7
1 changed files with 44 additions and 30 deletions
|
|
@ -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}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue