--- name: exploiting-xss-vulnerabilities description: >- SQIsoft 웹 애플리케이션에서 XSS 취약점의 실제 악용 가능성을 동적으로 확정한다. 정적 detecting-xss-vulnerabilities 스킬이 도출한 후보 URL/파라미터/입력필드에 고유 마커 페이로드를 실제로 주입하고, HTTP 응답 반사(attack_xss.py)와 브라우저 실행(Playwright MCP)으로 취약점을 확정한다. 반사형·저장형·DOM XSS를 모두 다루며, 컨텍스트별 이스케이프 우회 기법을 포함한다. domain: cybersecurity subdomain: web-application-security tags: [xss, exploiting, pentest, playwright, cwe-79, owasp-a03, sqisoft] cwe: [CWE-79] owasp: [A03:2021-Injection] version: "0.3.0" author: sqisoft-security license: Proprietary --- # XSS 취약점 공격 검증 (Exploiting Cross-Site Scripting) > ⚠️ **운영 환경 절대 금지** > > 이 스킬은 **권한 있는 사내 펜테스트** 전용이다. > SQIsoft 사업부가 소유하고 테스트가 승인된 **로컬/스테이징** 환경에서만 실행한다. > `tools/scope_guard.py`가 코드 수준에서 운영 의심 대상을 강제 차단한다. > 자사 미소유 시스템에 대한 무단 사용은 정보통신망법 위반이다. --- ## When to Use 다음 조건이 **모두** 충족될 때 이 스킬을 실행한다. - `detecting-xss-vulnerabilities` 스킬이 XSS 후보를 도출했고, 실제 악용 가능성을 **동적으로 확정**해야 할 때 - 대상이 **로컬 또는 스테이징** 환경에서 기동 중일 때 - 테스트 대상에 대한 **명시적 승인**이 있을 때 (사내 자산 또는 --authorized + 환경변수) **이 스킬을 쓰지 않을 때:** 대상 서버가 미가동 상태(→ 정적 스킬만 사용), 운영 환경, CSRF/SQLi 등 다른 취약점 클래스. ## Prerequisites - `detecting-xss-vulnerabilities` 스킬 실행 결과(후보 URL·파라미터·입력필드 목록) - Python 3.11+, `tools/scope_guard.py` (플러그인 루트에 존재) - Playwright MCP 서버 연결 (브라우저 실행 확인 단계에서 필요) - 대상 애플리케이션이 로컬/스테이징에서 기동 중 --- ## Workflow ### 0단계 — 안전 범위 확인 (scope_guard) 페이로드를 발사하기 전에 **반드시** scope_guard를 통과해야 한다. `attack_xss.py`는 내부에서 이를 자동으로 강제한다. 수동으로 확인하려면: ```bash python tools/scope_guard.py "http://localhost:8080/search" # → ALLOW: 사설/로컬 IP: 127.0.0.1 (통과) python tools/scope_guard.py "https://www.example.com" --param q # → [차단] 운영 의심 호스트 차단 패턴 매치: www.example.com (종료) ``` | 대상 유형 | 결과 | |---|---| | 127.x(정수 표기 포함), localhost, `.local`/`.test` 등 RFC 예약 TLD | 자동 허용 | | 10.x, 172.16.x, 192.168.x (사설) | 기본 차단 → `SECURITY_PLUGIN_ALLOW_PRIVATE=1` 시 허용 | | 사내 스테이징 도메인 | `SECURITY_PLUGIN_ALLOW_HOSTS` 등록 시만 (staging/dev/qa 부분일치 자동 허용 아님) | | www.\*, prod\*, production\*, 169.254.x, IP 위장 | **항상 차단** | | 그 외 공인 도메인·IP | `--authorized` + `SECURITY_PLUGIN_AUTHORIZED=1` 동시 필요 | ### 1단계 — 대상·후보 입력 확인 `detecting-xss-vulnerabilities` 결과에서 아래 정보를 확인한다. - **저장형 우선**: 게시판 글·댓글·공지사항 등 저장 후 다른 사용자에게 출력되는 경로를 먼저 검증 (피해 범위 넓음) - 반사형: URL 파라미터(검색어, 오류 메시지 등) → `--method get --param <파라미터명>` - DOM: 서버 응답이 아닌 클라이언트 JS가 처리하는 경로 → HTTP 반사 검사로는 불충분, 2단계-b 필수 후보 정보 정리 예시: ``` URL: http://localhost:8080/search 파라미터: q 유형: 반사형 (GET) 근거: detecting-xss 결과 scan_xss.py line 42 — JSP EL ${param.q} 미이스케이프 URL: http://localhost:8080/board/write 파라미터: content (POST) 유형: 저장형 조회URL: http://localhost:8080/board/view?id=<작성된글ID> ``` ### 2단계 — 실제 공격 발사 두 경로를 순서대로 실행한다. #### (a) 빠른 반사 확인 — attack_xss.py HTTP 응답에서 마커가 이스케이프 없이 반사되는지 검사한다 (반사형 XSS 판별에 적합). ```bash # 기본 실행 (GET, 반사형) python skills/exploiting-xss-vulnerabilities/scripts/attack_xss.py \ "http://localhost:8080/search" --param q # POST (저장형 주입 단계) python skills/exploiting-xss-vulnerabilities/scripts/attack_xss.py \ "http://localhost:8080/board/write" \ --param content --method post \ --data "title=테스트제목&category=1" # JSON 출력 (자동화·리포트 통합용) python skills/exploiting-xss-vulnerabilities/scripts/attack_xss.py \ "http://localhost:8080/search" --param q --json ``` 스크립트 동작 요약: 1. scope_guard 범위 확인 → 실패 시 즉시 종료 2. `sqixss<랜덤8자>` 고유 마커 생성 3. 7가지 컨텍스트 페이로드 순차 주입 (`references/payloads.md` 참고) 4. 응답 HTML에서 마커가 **이스케이프 안 된 채** 반사되는지 확인 5. 반사 컨텍스트 분류(`reflected_context`, 응답에서 실제 반사된 위치): `js_block` / `html_event_attr` / `html_url_attr` / `html_body` / `unknown` (미반사·이스케이프 시 `null`) - **주의**: 이 값은 페이로드 카테고리(`expected_context`: `html_body`/`html_attr`/`js_inline`)와 **다르다** — `expected_context`는 주입한 페이로드 종류, `reflected_context`는 응답에서 실제 반사가 관찰된 컨텍스트다. 6. 판정 및 결과 출력 **대상 미가동 시**: 스크립트가 "대상 미가동" 안내를 출력하고 Playwright 수동 절차를 안내한다. > **트레이드오프(PRG 미탐)**: HTTP 반사 검사는 주입 요청의 **원(최초) 응답**만 본다. 따라서 PRG(POST-redirect-GET) 패턴처럼 주입 후 **리다이렉트된 다음 페이지에서만** 마커가 반사되는 흐름은 `attack_xss.py`가 미탐할 수 있다. 이 경우 2단계-b Playwright MCP로 조회 페이지를 직접 열어 확인한다. #### (b) 실제 실행 확인 — Playwright MCP HTTP 응답 반사 검사만으로는 확정할 수 없는 경우(DOM XSS, 저장형 조회 시 실행)에 **필수**로 실행한다. 반사형도 브라우저에서 실제 실행 여부를 확인해야 최종 확정이다. **단계별 Playwright MCP 도구 사용:** ``` # 1. 대상 페이지 탐색 browser_navigate(url="http://localhost:8080/search") # (준비) 스냅샷으로 입력창·버튼의 ref 확보 — browser_type/browser_click은 ref 기반 browser_snapshot() # 2. 페이로드 입력 (반사형: 검색창 등 입력 필드) browser_type(element="검색 입력창", ref="<스냅샷에서 얻은 ref>", text="") # 3. 폼 제출 또는 버튼 클릭 (스냅샷 ref 기반) browser_click(element="검색 버튼", ref="<스냅샷에서 얻은 ref>") # 또는 URL 직접 이동 (GET 파라미터 방식) browser_navigate(url="http://localhost:8080/search?q=") # 4. 브라우저에서 마커 실행 여부 확인 browser_evaluate(script="JSON.stringify({fired: window.__xss_fired})") # 결과 예: {"fired":"sqixss테스트01"} → 취약 확정 # 결과 예: {"fired":null} → 차단됨 # 5. 증거 수집 browser_console_messages() # 콘솔 로그 (오류, XSS 실행 흔적) browser_take_screenshot(path="evidence/reflected_xss_search_q.png") ``` **저장형 XSS — 주입 후 조회 페이지 실행 확인:** ``` # 1. 주입 단계: 게시판 글 작성 페이지 이동 browser_navigate(url="http://localhost:8080/board/write") # (준비) 스냅샷으로 입력 필드·버튼의 ref 확보 — browser_fill_form/browser_click은 ref 기반 browser_snapshot() # 2. 제목·내용 입력 (여러 필드 일괄 입력: browser_fill_form) browser_fill_form(fields=[ {"name": "제목 입력창", "type": "textbox", "ref": "<스냅샷에서 얻은 ref>", "value": "테스트 제목"}, {"name": "내용 입력창", "type": "textbox", "ref": "<스냅샷에서 얻은 ref>", "value": ""}, ]) # 3. 저장 제출 (스냅샷 ref 기반) browser_click(element="저장 버튼", ref="<스냅샷에서 얻은 ref>") # 4. 조회 페이지로 이동 (저장된 글 확인) browser_navigate(url="http://localhost:8080/board/view?id=<저장된글ID>") # 5. 스크립트 실행 여부 확인 browser_evaluate(script="JSON.stringify({fired: window.__xss_fired})") # 6. 스크린샷·콘솔 로그 증거 수집 browser_take_screenshot(path="evidence/stored_xss_board_content.png") browser_console_messages() ``` **DOM XSS — 클라이언트 JS가 URL을 DOM에 삽입하는 경우:** ``` # URL 해시/쿼리에 페이로드 포함하여 직접 이동 browser_navigate(url="http://localhost:8080/page#") # 페이지 로드 후 실행 여부 확인 browser_evaluate(script="window.__xss_fired || 'not fired'") # 스크린샷 수집 browser_take_screenshot(path="evidence/dom_xss_hash.png") ``` ### 3단계 — 악용 확정 | XSS 유형 | 확정 기준 | |---|---| | 반사형 | `attack_xss.py`에서 마커 미이스케이프 반사 **AND** Playwright `window.__xss_fired` 설정 확인 | | 저장형 | 주입 후 조회 페이지에서 Playwright `window.__xss_fired` 설정 확인 | | DOM XSS | Playwright에서 URL 파라미터/해시로 이동 후 `window.__xss_fired` 설정 확인 | HTTP 응답 반사만으로는 취약 **후보**이며, 브라우저 실행 확인이 있어야 **확정**이다. ### 4단계 — 검증된 리포트 작성 확정된 항목만 아래 양식으로 출력한다. --- ## Output Format ```markdown # XSS 취약점 공격 검증 리포트 - 대상: | 파라미터: | 유형: <반사형|저장형|DOM> - 도구: attack_xss.py + Playwright MCP | 점검일: ## 요약 - 확정 취약: N건 (High n / Medium n) - 차단 확인: M건 (이스케이프·필터 정상 동작) ## 확정 취약점 ### [High] 반사형 XSS — 검색 파라미터 q — /search?q= - 유형 / 위치: 반사형 / GET /search?q= - **① 취약한 점(What)**: 검색 파라미터 `q` 값이 JSP EL `${param.q}`로 이스케이프 없이 HTML에 출력됨. - **② 취약한 이유(Why)**: JSP EL 표현식은 HTML 자동 이스케이프를 수행하지 않는다. 사용자가 입력한 ` ``` - **④ 해결방법(Fix)**: ```jsp <%-- Before (취약) --%>

${param.q}

<%-- After (안전) --%>

<%-- 또는:

${fn:escapeXml(param.q)}

--%> ``` - **Evidence**: - 주입 페이로드: `` - 반사 위치: 응답 HTML body, 이스케이프 없이 원문 반사 (attack_xss.py 반사 컨텍스트: html_body) - 브라우저 실행: `browser_evaluate` 결과 `{"fired":"sqixss4f2a1b3c"}` 확인 - 스크린샷: `evidence/reflected_xss_search_q.png` - 콘솔 로그: (별도 첨부) - 참조: CWE-79, OWASP A03:2021 ### [High] 저장형 XSS — 게시판 본문 — /board/view?id=123 - 유형 / 위치: 저장형 / POST /board/write → GET /board/view?id=123 - **① 취약한 점(What)**: 게시글 본문 `content` 필드가 DB에 원문 저장되고, 조회 시 `${board.content}`로 이스케이프 없이 출력됨. - **② 취약한 이유(Why)**: 저장 단계에서 입력 필터링 없음 + 출력 단계에서 HTML 이스케이프 없음. 조회하는 **모든 사용자**의 브라우저에서 저장된 스크립트가 실행됨(피해 범위 넓음). - **③ 뚫리는 방법(How)**: 공격자가 게시글 본문에 아래를 저장: ```html ``` 다른 사용자가 글을 조회하면 세션 쿠키가 공격자 서버로 전송됨. 관리자 조회 시 관리자 권한으로 악성 동작 수행 가능(권한 상승). - **④ 해결방법(Fix)**: 출력 이스케이프 적용. HTML 에디터 허용 시 AntiSamy/jsoup 허용 목록 필터. ```jsp <%-- Before (취약) --%>
${board.content}
<%-- After (안전, 일반 텍스트) --%>
<%-- After (리치 텍스트 허용 시) — AntiSamy 서버 측 정화 후 출력 --%>
${board.sanitizedContent}
``` - **Evidence**: - 주입 페이로드: `` - 주입 위치: POST /board/write, 파라미터 content - 실행 확인: /board/view?id=123 조회 후 `browser_evaluate` 결과 `{"fired":"sqixssSTORED01"}` 확인 - 스크린샷: `evidence/stored_xss_board_content.png` - 참조: CWE-79, OWASP A03:2021 ## 차단 확인 (이스케이프 정상 동작) - GET /notice?keyword= — `fn:escapeXml()` 래핑으로 마커 이스케이프됨 (안전) ``` --- ## Verification (검증 체크리스트) - [ ] scope_guard가 대상을 차단하지 않고 통과했는가 (로컬/스테이징 확인) - [ ] attack_xss.py가 각 파라미터에 7가지 페이로드를 모두 주입했는가 - [ ] 반사형: HTTP 응답 반사 확인 **AND** Playwright `window.__xss_fired` 확인을 모두 수행했는가 - [ ] 저장형: 주입 후 **조회 페이지**를 Playwright로 열어 실행 여부를 확인했는가 - [ ] DOM XSS 후보는 Playwright MCP로 브라우저에서 직접 URL 이동 후 확인했는가 - [ ] 각 확정 취약점에 Evidence 4항목(페이로드·반사위치·실행 결과·스크린샷)이 붙어 있는가 - [ ] 스크린샷 파일이 `evidence/` 디렉토리에 저장됐는가 - [ ] 해결방법이 해당 스택(JSP/Spring/React)에 맞게 구체적으로 기술됐는가 --- ## Key Concepts | 용어 | 설명 | |---|---| | 반사형 XSS | URL 파라미터 등 요청 값이 즉시 응답에 출력되어 브라우저에서 실행 | | 저장형 XSS | 악성 스크립트가 DB에 저장되어 다른 사용자 조회 시 실행 — 피해 범위 넓음 | | DOM XSS | 서버 응답이 아닌 클라이언트 JS가 DOM을 조작할 때 발생 — HTTP 반사 검사로 불검출 | | 고유 마커 | `sqixss<랜덤8자>` — 중복 방지용 식별자. 응답에서 미이스케이프 반사 여부 확인에 사용 | | `window.__xss_fired` | Playwright가 브라우저 실행 확인에 사용하는 전역 변수 마커 | | scope_guard | 운영 대상 발사를 코드 수준에서 차단하는 안전 게이트 | | 비파괴 페이로드 | 마커 변수 설정만 수행, 데이터 변조·삭제·외부 전송 없음 | ## Tools & Systems - `scripts/attack_xss.py` — HTTP 반사 검사 (scope_guard 내장) - `tools/scope_guard.py` — 안전 게이트 (운영 차단) - Playwright MCP — 브라우저 실행 확인, 증거 스크린샷 수집 - `references/payloads.md` — 컨텍스트별 페이로드 레퍼런스 - 연계 스킬: `detecting-xss-vulnerabilities` (정적 후보 도출)