--- name: exploiting-ssrf-and-open-redirect description: >- SQIsoft 웹 애플리케이션에서 SSRF(CWE-918)와 오픈 리다이렉트(CWE-601)의 실제 악용 가능성을 동적으로 확정한다. SSRF는 루프백에 임시 OOB(out-of-band) canary 리스너를 띄우고 표적에 canary URL을 주입해 콜백 수신 여부로 블라인드 SSRF까지 확정한다. 오픈 리다이렉트는 리다이렉트 파라미터에 외부 도메인을 주입하고 Location 응답 헤더가 외부로 향하는지 인밴드로 검증한다. 발사 전 scope_guard를 fail-closed로 강제 통과하며 비파괴(GET 주입)가 기본이다. domain: cybersecurity subdomain: web-application-security tags: - ssrf - open-redirect - server-side-request-forgery - oob - dast - cwe-918 - cwe-601 - owasp-a10 - owasp-a01 - sqisoft cwe: - CWE-918 - CWE-601 owasp: - A10:2021-Server-Side-Request-Forgery - A01:2021-Broken-Access-Control stacks: - spring-modern - jsp-legacy version: "0.3.0" author: sqisoft-security license: Proprietary --- # 동적 SSRF · 오픈 리다이렉트 침투 (OOB canary · Location 헤더) > ⚠️ **권한 있는 사내 보안 테스트(펜테스트) 전용.** 자사 소유 + 격리된 스테이징/로컬만 대상. > `tools/scope_guard.py`가 운영·공인·IP 위장을 코드로 차단한다. ## When to Use - `detecting-ssrf-and-open-redirect` 정적 진단에서 SSRF·오픈 리다이렉트 후보가 나왔고, 실제 악용 가능 여부를 확정하고 싶을 때 - 서버가 사용자 입력 URL로 실제 내부 요청을 보내는지(SSRF) OOB 콜백으로 실증할 때 - 리다이렉트 파라미터(`returnUrl`/`next`/`redirectUrl`)가 외부 도메인으로 실제 리다이렉트되는지 확인할 때 ## Prerequisites - 실행 중인 스테이징/로컬 대상 - SSRF 검사: canary 콜백을 받을 **루프백 리스너**(스크립트가 자동 기동). 앱이 Docker면 `--canary-host host.docker.internal`로 광고 호스트 지정 - (선택) 테스트 계정/토큰 — 보호 엔드포인트가 인증 뒤일 때(`--token-a` 또는 `--user-a-id/pw`). 로그인 폼 `returnUrl`은 보통 비인증이라 토큰 없이 발사 가능 - (선택) 정적 결과 `--scan ` — 표적 후보(파일·라인·파라미터) 분류 가이드용 ## Workflow ### 0단계 — 안전 범위 확인 (강제) ```bash python tools/scope_guard.py ``` ### 1단계 — 실제 발사 ```bash python skills/exploiting-ssrf-and-open-redirect/scripts/attack_ssrf.py \ http://localhost:7171 \ --redirect-target "/login?returnUrl=" \ --ssrf-target "/api/v1/proxy?url=" \ --json # 인증 뒤 엔드포인트면: --user-a-id --user-a-pw (또는 --token-a ) # Docker 앱이면 canary 광고 호스트: --canary-host host.docker.internal # 주입점에 명시 위치가 필요하면 {INJ} 사용: --ssrf-target "/api/fetch?url={INJ}&x=1" # 후보만 보려면 정적 결과 연계: --scan reports/scan_ssrf.json (표적 미지정 시 후보 목록 출력) ``` 흐름: scope 확인 → (선택)로그인 → canary 리스너 기동 → 표적에 페이로드/canary 주입·발사 → Location 헤더·콜백 판정 → JSON ### 2단계 — 판정 | 검사 | 취약 | 방어 | |---|---|---| | 오픈 리다이렉트(6변형) | `Location`이 **외부 호스트**(base_host 아님) | 동일 origin·상대경로·페이로드 무시 | | SSRF(OOB canary) | canary **콜백 수신**(또는 응답 본문 nonce 반영) | 타임아웃(미수신) | > SSRF 미수신은 "안전 확정"이 아니라 **동적 미확정**일 수 있다(앱이 비동기/지연 요청, canary 호스트 도달 불가). `callback=false`이고 본문 반영도 없으면 정적 의심은 유지하고 리포트엔 "동적 미확정"으로 남긴다. 신뢰도는 콜백 수신 시 `dynamic`(확정), 미수신 시 `static-only`(의심 유지). ### 3단계 — AI 검증 + 리포트 취약 후보만 실제 코드(URL 화이트리스트 검증·리다이렉트 목적지 처리)로 재확인 후, 확정 항목을 4요소로 `reports/pentest-ssrf-<대상>.md`에 저장한다. ## 비파괴 정책 - 모든 발사는 GET 주입. 데이터 변조/삭제 페이로드 없음. - canary 리스너는 **127.0.0.1 바인딩 고정**(외부 노출 없음). `--canary-host`는 앱에게 알려줄 광고 주소일 뿐 바인딩 주소가 아니다. - 오픈 리다이렉트 페이로드 목적지는 `evil.test`(RFC 예약 — 실제 라우팅 안 됨). ## Output Format ```markdown # 동적 SSRF · 오픈 리다이렉트 침투 리포트 - 대상: | 점검일: | 신뢰도: 동적 확정(dynamic) ## 확정 취약점 ### [High] SSRF — 사용자 입력 URL로 서버측 요청 — GET /api/v1/proxy?url= - **① 취약한 점**: canary URL 주입 → 서버가 루프백 리스너로 콜백(블라인드 SSRF 확정) - **② 이유**: 공격자가 내부망·클라우드 메타데이터(169.254.169.254)로 요청 유도 → IAM 자격 탈취 - **③ Evidence**: canary `http://127.0.0.1:/c/` 콜백 수신 - **④ 해결방법**: URL 호스트 화이트리스트 검증, 내부 IP·메타데이터 대역 차단, 리다이렉트 비활성 ### [Medium] 오픈 리다이렉트 — 미검증 returnUrl — GET /login?returnUrl= - **① 취약한 점**: `returnUrl=https://evil.test` 주입 → 302 Location이 외부 도메인 - **② 이유**: 정상 로그인 후 피싱 사이트로 유도(자격·신뢰 탈취) - **③ Evidence**: `Location: https://evil.test` (변형 absolute_https/userinfo 등) - **④ 해결방법**: 상대경로만 허용 또는 도메인 화이트리스트 검증 ``` ## 안전 (ATTACK_SAFETY.md 계승) - 모든 발사 전 `scope_guard.assert_in_scope()` 강제(fail-closed). 차단 시 exit 1, 로그인 실패 시 exit 2. - 토큰·자격은 출력 시 마스킹(`dyn_session.mask_token`). - **자격 노출 주의**: 토큰·비밀번호를 CLI 인자(`--token-a`·`--user-a-pw`)로 넘기면 프로세스 목록 (작업관리자/`ps`)에 노출될 수 있다. 공유·멀티유저 호스트를 피하고 단일 운영자 환경에서 테스트 계정으로만 실행한다. ## Tools & Systems - 공용 엔진: `tools/dyn_session.py` (로그인·인증 HTTP·응답 헤더·scope 위임) - OOB 리스너: `scripts/oob_canary.py` (루프백 canary) - 안전 게이트: `tools/scope_guard.py` - 정적 연계: `detecting-ssrf-and-open-redirect` - 시나리오: `references/payloads.md`