저장형 XSS

저장형 XSS는 서버에 남아 있습니다. 한 번 제출하면(댓글, 프로필 필드, 채팅 메시지) 누군가 해당 페이지를 볼 때마다 실행됩니다. Dalfox에는 이 패턴을 위한 전용 모드가 있습니다.

기본 흐름

dalfox scan https://target.app/post-comment \
  --sxss \
  --sxss-url https://target.app/comments

Dalfox는 다음을 수행합니다.

  1. 각 페이로드를 첫 번째 URL(post-comment)에 주입합니다.
  2. 두 번째 URL(comments)을 GET으로 조회합니다(--sxss-method로 바꿀 수 있음).
  3. 페이로드가 조회 응답에 반사되는지, 그리고 실제 DOM 요소를 생성했는지 검증합니다.

조회 페이지에 다시 나타난 페이로드는 R로, 그곳에서 실제 DOM 요소까지 만든 페이로드는 V로 보고됩니다. 저장형 탐지 결과의 inject_type에는 sxss- 접두어가 붙으므로(sxss-inHTML), 리포트에서 반사형 결과와 구분됩니다.

저장형 모드는 철저히 순차적으로 동작합니다. 쓰기 순서와 조회 재시도가 이를 전제로 하므로 파라미터도 하나씩, 요청도 하나씩 보냅니다. --workers를 늘려도 빨라지지 않습니다.

쓰기 엔드포인트가 제출한 값을 돌려줄 필요는 없습니다. 제출 응답이 "saved"만 돌려줘도 괜찮으며, Dalfox는 그 응답으로 싱크가 어떤 문자를 거르는지 판단하지 않습니다.

모든 필드가 같은 페이로드를 받고 저장된 값은 페이지에 계속 남으므로, Dalfox는 각 파라미터의 페이로드를 보내기 전에 두 가지를 합니다.

  • 스냅샷. 조회 페이지를 한 번씩 가져옵니다. 페이로드는 그 파라미터의 주입으로 스냅샷보다 더 많이 나타날 때에만 해당 파라미터에 귀속되므로, 다른 필드가 먼저 저장한 사본이 잘못 귀속되지 않습니다. 파라미터마다 조회 URL당 GET이 한 번 더 듭니다.
  • 저장 프로브. 마커를 주입합니다. 긴 마커를 먼저, 짧은 값만 보관하는 싱크를 위해 짧은 마커를 이어서 시도합니다. 둘 다 조회 페이지(또는 쓰기 응답)의 마커 수를 늘리지 못하면 이 필드는 저장되지 않는 것으로 보고 페이로드를 건너뜁니다.

프로브는 저장이 언제 보이는지도 확인합니다. 바로 보이면 Dalfox는 페이로드마다 조회를 한 번만 합니다. 지연 후에만 보이는 쓰기 지연(write-behind) 저장이라면 페이로드마다 조회 재시도를 모두 유지합니다. 대상이 그보다도 느리게 저장한다면 --sxss-retries(기본값 3, 최대 20)를 높이세요. n번째 재시도는 500 ms × n만큼 기다리며, 한 번의 대기는 최대 5 s입니다. --deep-scan을 주면 저장 프로브를 건너뛰고 모든 필드에 모든 페이로드를 보냅니다.

조회 URL 선택

저장된 값을 읽어 오는 페이지를 선택하세요. 예시:

주입 URL 조회 URL
POST /comments/new GET /post/123/comments
PATCH /profile GET /u/myself
POST /support/ticket GET /admin/tickets (관리자 권한이 있는 경우)

Dalfox는 후보 조회 페이지를 모두 읽으며, 순서는 --sxss-url(지정한 경우), 폼이 발견된 페이지, 폼의 action 엔드포인트(대상과 같은 오리진이거나 같은 호스트를 HTTPS로 올린 경우에만), 주입 대상 자신입니다. 중복된 URL은 한 번만 가져옵니다. --sxss-url이 없으면 뒤의 세 곳이 전부이므로, 저장된 값이 그 밖의 곳에 렌더링된다면 --sxss-url을 직접 지정하세요. --sxss-url은 --sxss 없이는 아무 효과가 없으며, 단독으로 주면 Dalfox가 경고합니다.

조회 메서드

dalfox scan https://target.app/form --sxss \
  --sxss-url https://target.app/list \
  --sxss-method GET

GET이 기본값입니다. 조회 엔드포인트가 필요로 한다면 POST나 다른 메서드를 사용하세요.

인증

저장형 XSS에는 세션이 두 개 필요한 경우가 많습니다. 하나는 쓰는 쪽(사용자), 다른 하나는 읽는 쪽(관리자)입니다. 조회 GET이 작성해 둔 내용을 볼 수 있을 만큼 충분한 접근 권한을 주는 헤더/쿠키를 사용하세요.

dalfox scan https://target.app/profile \
  --sxss --sxss-url https://target.app/admin/users \
  -H "Cookie: admin_session=abc; role=admin"

블라인드 + 저장형

조회 페이지가 로그인 뒤에 있는데 그 로그인 정보가 없다면, 블라인드 XSS로 전환하세요. 페이로드는 관리자의 브라우저에서 실행되고, 콜백 서버가 이를 기록합니다.

dalfox scan https://target.app/support/ticket \
  -b https://callback.interact.sh

여전히 누군가가 페이지를 볼 때까지 기다려야 하며, 콜백이 그 시점을 알려 줍니다. -b 대신 --blind-oob를 쓰면 Dalfox가 interactsh 세션을 직접 폴링해 콜백을 V 탐지 결과로 보고합니다. 다만 --blind-oob-wait이 끝나기 전에 도착한 콜백만 해당하며, 몇 시간 뒤의 조회는 직접 운영하는 리스너에만 닿습니다. Blind XSS를 참고하세요.

팁

  • 범위를 좁게 설정하세요. -p를 사용해 조회 URL에서 렌더링된다고 알고 있는 필드를 지정하세요. 그러면 Dalfox가 모든 쿠키를 테스트하지 않습니다.
  • 새니타이즈 후 렌더링에 주의하세요. 저장형 XSS는 쓰기 시점의 HTML 새니타이저는 통과하지만 읽기 시점의 두 번째 새니타이즈에서 깨지는 경우가 많습니다. Dalfox의 mXSS 페이로드는 이에 맞춰 조정되어 있습니다.
  • 속도를 늦추세요. 일부 앱은 쓰기를 디바운스하거나 배치 처리합니다. 작은 --delay 값을 주면 조회가 페이로드를 보는 데 도움이 됩니다.

다음 단계

ESC