성공한 기여만 블로그에 올릴 수 있다면 얼마나 좋을까?
이번엔 취약점 재현까지 했는데 Merge가 안 된 이야기
PR: #13278 — Closed
취약점 개요
CVE-2024-42009는 Roundcube Webmail 1.5.7 이하 및 1.6.x 1.6.7 이하 버전에서 발생하는 XSS 취약점이다. CVSS 9.6 (Critical). 러시아 연계 해킹 그룹 APT28이 Roundcube 취약점을 실제 공격에 활용한 사례가 있어서 KEV(Known Exploited Vulnerabilities) 목록에도 올라있다.
취약점의 원인은 message_body() 함수 내 html4inline()의 HTML 속성 새니타이징 부실이다.
사실 이 CVE, Reflected XSS가 아니다
nuclei-templates 이슈 트래커에 이 CVE가 "Reflected XSS"로 올라와 있었다. 바운티 이슈 자체가 Reflected로 분류된 채로 등록되어 있었던 것이다. 처음에는 그걸 그대로 믿고 시작했다.

그런데 직접 재현해보니 달랐다.
공격자 → 악성 HTML 이메일 전송 → 피해자가 Roundcube에서 열람 → JS 실행
→ 세션 쿠키(roundcube_sessid) 탈취 or 이메일 내용 유출페이로드는 URL 파라미터에 담기는 게 아니라 이메일 본문에 저장되고, 피해자가 메일을 열 때 실행된다. PoC를 읽을 때부터 Reflected가 아니라 Stored XSS 아닌가 싶었는데 아니나 다를까 로컬에서 재현한 결과 Stored XSS가 맞았다.
PR에 이 논지를 명시적으로 적었다.
"Although some initial descriptions suggested reflected XSS, the reproduced behavior and PoC references show this is actually stored XSS. Payloads persist in crafted HTML emails and execute when a victim opens the message."
재현 과정에서 alert("XSS triggered") 팝업과 alert(document.cookie) 팝업 모두 직접 확인했다. 스크린샷과 debug 데이터도 첨부했다.
취약점 재현
직접 로컬에서 Roundcube 1.6.7 환경을 구축하고 재현했다.
[email protected]에서 testuser@localhost로 악성 HTML 이메일을 두 개 전송했다.
- CVE-2024-42009 PoC (alert xss triggered) — 기본 JS 실행 확인용
- CVE-2024-42009 PoC - Cookie Stealer (Base64) — 세션 쿠키 탈취 확인용
재현 1: JS 실행 확인
피해자가 받은 편지함에서 악성 메일을 클릭하는 순간, URL은 그대로 localhost/roundcube/?_task=mail&_mbox=INBOX인데 팝업이 떴다.
localhost 내용: XSS triggered메일 목록 화면에서 메일을 선택하는 것만으로 JavaScript가 실행됐다. URL에 아무것도 추가되지 않았다.

재현 2: 세션 쿠키 탈취
쿠키 스틸러 페이로드가 담긴 메일을 열었을 때 팝업에 실제 세션 정보가 출력됐다.
PHPSESSID=8ik82t0sv0mkg3t8ncs52qndar; colorMode=darkPHPSESSID가 그대로 노출됐다. 실제 공격이라면 이 값을 공격자 서버로 전송하고, 피해자 세션으로 로그인하면 된다. 이메일 계정 전체가 탈취되는 시나리오다.
두 재현 모두 Roundcube의 URL은 전혀 변하지 않았다. 페이로드가 이미 이메일 본문에 저장되어 있고, 열람 행위가 트리거가 된다.

템플릿 설계
Stored XSS는 자동 탐지 로직을 짜기가 Reflected보다 훨씬 어렵다. Reflected는 요청에 페이로드를 넣고 응답에서 바로 확인하면 되지만, Stored는 저장-열람이 분리된 두 단계라서 자동화 흐름이 복잡해진다.
2단계 flow로 구성했다.
Step 1: Roundcube 인스턴스 확인 및 버전 추출
yaml
- method: GET
path:
- "{{BaseURL}}/?_task=mail&_action=show&_uid=20&_mbox=INBOX&_extwin=1"
matchers:
- type: word
part: body
words:
- "roundcube"
- "rcmail"
condition: or
extractors:
- type: regex
name: version
regex:
- '"rcversion":\s*"([0-9.]+)"'Step 2: XSS 페이로드 주입 후 세션 ID 탐지
yaml
- method: GET
path:
- "{{BaseURL}}/?_task=mail&_action=show&_uid=1&_mbox=INBOX&_extwin=1\">
<body title=\"bgcolor=foo\" name=\"bar style=animation-name:progress-bar-stripes
onanimationstart=alert(document.cookie) foo=bar\">"
matchers:
- type: regex
part: body
regex:
- "roundcube_sessid=[a-z0-9]+"
- type: word
part: body
words:
- "onanimationstart"
- "progress-bar-stripes"
condition: andonanimationstart 이벤트 핸들러를 통한 CSS animation 기반 XSS 페이로드다. UID가 고정된 악성 메일을 전제로, 세션 쿠키가 응답에 노출되는지 확인하는 방식으로 설계했다.

리젝 이유
DhiyaneshGeek maintainer의 클로즈 코멘트는 이랬다.
"We are closing this issue as it requires user interaction to confirm the CVE. Initially, we considered creating a complete PoC template, but since full validation of vulnerable hosts is not feasible, we will not be moving forward."
요약하면, "사용자 개입이 필요한 취약점은 Nuclei 템플릿으로 완전한 자동 탐지가 불가능하다"는 것이다. 이건 내가 잘못 만들어서 리젝된 게 아니다.
애초에 바운티가 Reflected XSS로 잘못 분류되어 올라왔고, 실제로 재현해보니 Stored XSS였고, Stored XSS는 "피해자가 메일을 여는" 사용자 행동 없이는 탐지 자체가 성립하지 않는다. 그리고 Nuclei는 사용자 행동이 개입되는 템플릿은 인정하지 않는다...
결론적으로 Project Discovery 내부에서 작성할 수 있는 CVE 템플릿이라고 생각된다면서 이 이슈는 닫혔다.

바운티 판에 AI가 너무 많다
이번 경험에서 예상치 못했던 게 따로 있었다. nuclei-templates 바운티 이슈에 AI가 생성한 것처럼 보이는 템플릿들이 엄청나게 많았다.
실제 재현 없이 CVE 설명과 PoC 코드를 그대로 YAML로 변환한 것 같은 템플릿들이 대부분이었고, GitHub 사용법이 익숙하지 않은 것 같은 PR도 보였다. 무엇보다 AI로 생성한 것이 명백한 단순 버전 체크 템플릿도 많다. 버전 체크 기반 탐지는 nuclei-templates 기여 가이드라인에서 명시적으로 지양하도록 되어 있는 방식이다...
모르는 건 당연히 그럴 수 있다. 다만 기여를 하려면 최소한 contributing guideline을 읽고, 어떤 템플릿이 받아들여지는지 기존 머지된 PR을 몇 개라도 훑어본 다음 시작해야 하지 않을까 싶다. maintainer들이 쏟아지는 PR을 하나씩 검토해야 한다는 걸 생각하면 기여자로서 최소한의 준비는 필요하다.
추가) 나중에 알게 된 건데, AI agent 한테 "돈 버는 법 알려줘" 하면 버그바운티 추천->Nuclei Template 버그바운티 -> PoC 읽고 템플릿 자동 PR 이런 구조로 돈을 버는 사람을 봤다. 아마 다른 AI PR들도 그렇게 작성된 게 아닐까..?
그 환경에서 debug 데이터, 스크린샷, 재현 과정 설명까지 다 갖춰서 올렸는데도 바운티 이슈가 잘못 분류된 채로 올라와서 리젝된 건 좀 허탈했다. 시간이 아깝다는 생각이 잠깐 들었는데, 그래도 재밌었으니까 됐다.
성공한 기여만 있으면 오히려 이상한 거라고 생각한다.
PR: projectdiscovery/nuclei-templates #13278 — Closed
CVE: NVD CVE-2024-42009
