labunix's blog

labunixのラボUnix

debian stretchにWAF(modsecurity)を導入する。

■■debian stretchにWAF(modsecurity)を導入する。
 評価目的の環境構築なので、
 DBはここでは決めず、動的コンテンツに関するテストも行わない。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 9.1 (stretch)
Release:        9.1
Codename:       stretch

■攻撃のトレンドを把握する。
 2013年との比較とかも参考に。

$ w3m -dump "https://www.owasp.org/index.php/Category:OWASP_Top_Ten_2017_Project" | \
    awk '/☆/{gsub(" *☆ ","",$0);print}'
A1-Injection
A2-Broken Authentication and Session Management
A3-Cross-Site Scripting (XSS)
A4-Broken Access Control
A5-Security Misconfiguration
A6-Sensitive Data Exposure
A7-Insufficient Attack Protection
A8-Cross-Site Request Forgery (CSRF)
A9-Using Components with Known Vulnerabilities
A10-Underprotected APIs

■IPAを以下も参考にどの機能を使うかを検討する。

 情報セキュリティ 10大脅威 2017
 https://www.ipa.go.jp/security/vuln/10threats2017.html

 Web Application Firewall 読本
 http://www.ipa.go.jp/security/vuln/waf.html

■modsecurityのコメントにもある、代表的な以下2つの検出機能は使えるようにする。

 SQLインジェクション
 クロスサイトスクリプティング

$ apt-cache search modsecurity
libapache2-mod-security2 - Tighten web applications security for Apache
libapache2-modsecurity - Dummy transitional package
modsecurity-crs - OWASP ModSecurity Core Rule Set

$ apt-cache show libapache2-mod-security2 | \
    awk 'BEGIN{flag=0}{if($1=="Description-md5:"){flag=0}}{if($1=="Description-en:"){flag=1}}{if(flag==1){print}}'
Description-en: Tighten web applications security for Apache
 Modsecurity is an Apache module whose purpose is to tighten the Web
 application security. Effectively, it is an intrusion detection and prevention
 system for the web server.
 .
 At the moment its main features are:
   * Audit log; store full request details in a separate file, including POST
     payloads.
   * Request filtering; incoming requests can be analysed and offensive requests
     can be rejected (or simply logged, if that is what you want). This feature
     can be used to prevent many types of attacks (e.g. XSS attacks, SQL
     injection, ...) and even allow you to run insecure applications on your
     servers (if you have no other choice, of course).
OS=Linux(debian)DB=Unknown、Webサーバ=Apache2の構成とする。
 CRS (Core Rule Set) というシグネチャを導入する必要がある。

$ sudo apt-get install -y apache2 libapache2-mod-security2 modsecurity-crs

■apache2の待受ポートを、IPv4のlocalhostでのみアクセスを受け付けるよう変更する。

$ netstat -an | grep :80
tcp6       0      0 :::80                   :::*                    LISTEN

$ sudo sed -i -e 's/\(Listen \)80/\1127.0.0.1:80/' /etc/apache2/ports.conf

$ sudo systemctl restart apache2
$ netstat -an | grep :80
tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN

■apache2のログを有効にする。

$ awk 'BEGIN{cnt=0}{if($2=="a"){cnt=16;print}else if(cnt>0){cnt-=1;print $0}}' /etc/apache2/apache2.conf
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

CustomLog ${APACHE_LOG_DIR}/access.log combined

$ sudo apache2ctl configtest && sudo systemctl enable apache2 && sudo systemctl restart apache2
Syntax OK
Synchronizing state of apache2.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable apache2

■apache2のアクセス確認。
 curlのプロキシ除外方法がホスト名を指定する必要がある点に注意。

$ sudo apt-get install -y curl w3m

$ w3m -dump_head -no-proxy 'http://127.0.0.1'; \
    curl -v --noproxy 127.0.0.1 -s 'http://127.0.0.1/' | w3m -T text/html | head -3; \
    sudo tail -f /var/log/apache2/access.log
HTTP/1.1 200 OK
Date: Sun, 13 Aug 2017 03:36:18 GMT
Server: Apache/2.4.25 (Debian)
Last-Modified: Sat, 12 Aug 2017 16:44:37 GMT
ETag: "29cd-556912526f428-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 3041
Connection: close
Content-Type: text/html

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.52.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sun, 13 Aug 2017 03:36:18 GMT
< Server: Apache/2.4.25 (Debian)
< Last-Modified: Sat, 12 Aug 2017 16:44:37 GMT
< ETag: "29cd-556912526f428"
< Accept-Ranges: bytes
< Content-Length: 10701
< Vary: Accept-Encoding
< Content-Type: text/html
< 
{ [10701 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact
Debian Logo Apache2 Debian Default Page
It works!

127.0.0.1 - - [13/Aug/2017:12:36:18 +0900] "HEAD / HTTP/1.0" 200 302 "-" "w3m/0.5.3+git20170102"
127.0.0.1 - - [13/Aug/2017:12:36:18 +0900] "GET / HTTP/1.1" 200 10956 "-" "curl/7.52.1"

■以下のサイトを参考にapache2の「AH00558」エラーに対処

 ubuntuにおけるapache2のAH00558エラーを解決する。
 http://mk-55.hatenablog.com/entry/2014/07/07/004510

$ sudo awk -F] '/apache2/{a[$NF]+=1}END{for (n in a){print a[n],n}}' /var/log/syslog  | sed -e 's/,/\n\t/g'
3 : AH00558: apache2: Could not reliably determine the server's fully qualified domain name
         using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message

$ sudo echo ServerName $HOSTNAME > /etc/apache2/conf-available/fqdn.conf
$ sudo a2enconf fqdn && sudo systemctl reload apache2
Enabling conf fqdn.
To activate the new configuration, you need to run:
  systemctl reload apache2
■SecRuleEngineをDETECTION_ONLYモード(検出、ログ出力のみ)でmodsecurity機能を有効にする。

$ sudo cp /etc/modsecurity/modsecurity.{conf-recommended,conf}
$ grep -B 8  ^SecRuleEngine /etc/modsecurity/modsecurity.conf
# -- Rule engine initialization ----------------------------------------------

# Enable ModSecurity, attaching it to every transaction. Use detection
# only to start with, because that minimises the chances of post-installation
# disruption.
#
SecRuleEngine DetectionOnly

$ sudo apache2ctl -M  | awk '/sec|crs|head/'
$ find /etc/apache2/mods-available/ /etc/apache2/mods-enabled/ | awk '/sec|crs|head/'
/etc/apache2/mods-available/headers.load
/etc/apache2/mods-available/security2.load
/etc/apache2/mods-available/security2.conf

$ sudo a2enmod security2
Considering dependency unique_id for security2:
Enabling module unique_id.
Enabling module security2.
To activate the new configuration, you need to run:
  systemctl restart apache2

$ sudo a2enmod headers
Enabling module headers.
To activate the new configuration, you need to run:
  systemctl restart apache2
 sudo systemctl restart apache2

$ sudo apache2ctl -M  | awk '/sec|crs|head/'
 headers_module (shared)
 security2_module (shared)
$ find /etc/apache2/mods-available/ /etc/apache2/mods-enabled/ | awk '/sec|crs|head/'
/etc/apache2/mods-available/headers.load
/etc/apache2/mods-available/security2.load
/etc/apache2/mods-available/security2.conf
/etc/apache2/mods-enabled/headers.load
/etc/apache2/mods-enabled/security2.load
/etc/apache2/mods-enabled/security2.conf

■CRSシグニチャを確認する。
 これが無いと検出出来ないのでパスが通っているか確認する。

$ grep -v "#\|^\$" /etc/apache2/mods-enabled/security2.conf
<IfModule security2_module>
        SecDataDir /var/cache/modsecurity
        IncludeOptional /etc/modsecurity/*.conf
        IncludeOptional /usr/share/modsecurity-crs/owasp-crs.load
</IfModule>

$ grep -v "#\|^\$" /etc/apache2/mods-enabled/security2.conf  | awk '/ \//{print "ls -l "$NF}' | sh
合計 0
-rw-r--r-- 1 root root   46  813 02:38 /etc/modsecurity/default.conf
-rw-r--r-- 1 root root 8440  813 03:50 /etc/modsecurity/modsecurity.conf
-rw-r--r-- 1 root root 373 1221  2016 /usr/share/modsecurity-crs/owasp-crs.load

$ grep -v "#\|^\$" /usr/share/modsecurity-crs/owasp-crs.load
Include /etc/modsecurity/crs/crs-setup.conf
IncludeOptional /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Include /usr/share/modsecurity-crs/rules/*.conf
IncludeOptional /etc/modsecurity/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

$ grep -v "#\|^\$" /usr/share/modsecurity-crs/owasp-crs.load | awk '/ \//{print "ls "$NF}' | sh
/etc/modsecurity/crs/crs-setup.conf
/etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
/usr/share/modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf
/usr/share/modsecurity-crs/rules/REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf
/usr/share/modsecurity-crs/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf
/usr/share/modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
/usr/share/modsecurity-crs/rules/REQUEST-910-IP-REPUTATION.conf
/usr/share/modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf
/usr/share/modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf
/usr/share/modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf
/usr/share/modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
/usr/share/modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf
/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf
/usr/share/modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf
/usr/share/modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
/usr/share/modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf
/usr/share/modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf
/usr/share/modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf
/usr/share/modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf
/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf
/usr/share/modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf
/usr/share/modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf
/usr/share/modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
/usr/share/modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
/usr/share/modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
/usr/share/modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf
/etc/modsecurity/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

■modsecurityのログ出力場所と条件を確認。

$ grep ^SecAuditLog /etc/modsecurity/modsecurity.conf
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABDEFHIJZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log

$ grep ^SecDefaultAction /etc/modsecurity/crs/crs-setup.conf
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"

■比較的無害なディレクトリトラバーサルでテスト
 この単純なパスワード一覧の取得がそのまま通るようなWebサーバは存在しないし、
 万が一通るならそのWebサーバは使ってはいけない。

$ w3m -dump_head -no-proxy 'http://127.0.0.1/../../etc/passwd'; \
    curl -v --noproxy 127.0.0.1 -s 'http://127.0.0.1/../../etc/passwd' | w3m -T text/html | head -3; \
    sudo tail -f /var/log/apache2/access.log
HTTP/1.1 400 Bad Request
Date: Sun, 13 Aug 2017 03:43:27 GMT
Server: Apache/2.4.25 (Debian)
Connection: close
Content-Type: text/html; charset=iso-8859-1

* Rebuilt URL to: http://127.0.0.1/etc/passwd
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /etc/passwd HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.52.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Sun, 13 Aug 2017 03:43:27 GMT
< Server: Apache/2.4.25 (Debian)
< Content-Length: 283
< Content-Type: text/html; charset=iso-8859-1
< 
{ [283 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact
Not Found

The requested URL /etc/passwd was not found on this server.

127.0.0.1 - - [13/Aug/2017:12:43:27 +0900] "HEAD /../../etc/passwd HTTP/1.0" 400 161 "-" "w3m/0.5.3+git20170102"
127.0.0.1 - - [13/Aug/2017:12:43:27 +0900] "GET /etc/passwd HTTP/1.1" 404 444 "-" "curl/7.52.1"

■apache2のアクセスログの時刻をキーにmodsecurityのログと突き合せ。

$ sudo strings /var/log/apache2/modsec_audit.log | \
    awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:12:43:27"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | sed -e 's/] /&\n\t/g'
[13/Aug/2017:12:43:27 +0900] 
	WY-K338AAQEAACLEEAkAAABD 127.0.0.1 40126 127.0.0.1 80
--e4c15b56-B--
HEAD /../../etc/passwd HTTP/1.0
User-Agent: w3m/0.5.3+git20170102
Accept: text/html, text/*;q=0.5, image/*, application/*
Accept-Encoding: gzip, compress, bzip, bzip2, deflate
Accept-Language: ja;q=1.0, en;q=0.5
Host: 127.0.0.1
--e4c15b56-F--
HTTP/1.1 400 Bad Request
Connection: close
Content-Type: text/html; charset=iso-8859-1
--e4c15b56-E--
--e4c15b56-H--
Apache-Error: [file "core.c"] 
	[line 4509] 
	[level 3] 
	AH00126: Invalid URI in request %s
Stopwatch: 1502595807705929 1579 (- - -)
Stopwatch2: 1502595807705929 1579; combined=1060, p1=690, p2=0, p3=69, p4=225, p5=76, sr=69, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.1 (http://www.modsecurity.org/); OWASP_CRS/3.0.0.
Server: Apache/2.4.25 (Debian)
Engine-Mode: "DETECTION_ONLY"
[13/Aug/2017:12:43:27 +0900] 
	WY-K338AAQEAACLEEAoAAABE 127.0.0.1 40128 127.0.0.1 80
--136e7961-B--
GET /etc/passwd HTTP/1.1
Host: 127.0.0.1
User-Agent: curl/7.52.1
Accept: */*
--136e7961-F--
HTTP/1.1 404 Not Found
Content-Length: 283
Content-Type: text/html; charset=iso-8859-1
--136e7961-E--
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /etc/passwd was not found on this server.</p>
<hr>
<address>Apache/2.4.25 (Debian) Server at 127.0.0.1 Port 80</address>
</body></html>
--136e7961-H--
Message: Warning. Pattern match "^[\\d.:]+$" at REQUEST_HEADERS:Host. [file "/usr/share/modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] 
	[line "793"] 
	[id "920350"] 
	[rev "2"] 
	[msg "Host header is a numeric IP address"] 
	[data "127.0.0.1"] 
	[severity "WARNING"] 
	[ver "OWASP_CRS/3.0.0"] 
	[maturity "9"] 
	[accuracy "9"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-protocol"] 
	[tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] 
	[tag "WASCTC/WASC-21"] 
	[tag "OWASP_TOP_10/A7"] 
	[tag "PCI/6.5.10"]
Apache-Error: [file "apache2_util.c"] 
	[line 273] 
	[level 3] 
	[client %s] 
	ModSecurity: %s%s [uri "%s"]%s
Stopwatch: 1502595807732815 2916 (- - -)
Stopwatch2: 1502595807732815 2916; combined=1852, p1=824, p2=703, p3=42, p4=238, p5=45, sr=69, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.1 (http://www.modsecurity.org/); OWASP_CRS/3.0.0.
Server: Apache/2.4.25 (Debian)
Engine-Mode: "DETECTION_ONLY"

■ヘッダのリクエストでは引っかからないが、
 IPアドレスのアクセスがあったという「id:920350」が報告されている。
 IPアドレス:ポートでも同様のログが出るとのこと。

$ sudo strings /var/log/apache2/modsec_audit.log | \
    awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:12:43:27"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep ^Message | sed -e 's/] /&\n\t/g'
Message: Warning. Pattern match "^[\\d.:]+$" at REQUEST_HEADERS:Host. [file "/usr/share/modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] 
	[line "793"] 
	[id "920350"] 
	[rev "2"] 
	[msg "Host header is a numeric IP address"] 
	[data "127.0.0.1"] 
	[severity "WARNING"] 
	[ver "OWASP_CRS/3.0.0"] 
	[maturity "9"] 
	[accuracy "9"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-protocol"] 
	[tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] 
	[tag "WASCTC/WASC-21"] 
	[tag "OWASP_TOP_10/A7"] 
	[tag "PCI/6.5.10"]

$ sudo grep -B 22 -A 26 920350 /usr/share/modsecurity-crs/rules/* | awk -F'conf-' '{print $NF}'
# Check that the host header is not an IP address
# This is not an HTTP RFC violation but it is indicative of automated client access.
# Many web-based worms propagate by scanning IP address blocks.
#
# -=[ Rule Logic ]=-
# This rule triggers if the Host header contains all digits (and possible port)
#
# -=[ References ]=-
# http://technet.microsoft.com/en-us/magazine/2005.01.hackerbasher.aspx
#

SecRule REQUEST_HEADERS:Host "^[\d.:]+$" \
  "msg:'Host header is a numeric IP address',\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   t:none,\
   block,\
   logdata:'%{matched_var}',\
   severity:'WARNING',\
/usr/share/modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf:   id:920350,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/POLICY/IP_HOST-%{matched_var_name}=%{matched_var}"


# In most cases, you should expect a certain volume of each a request on your
# website. For example, a request with 400 arguments, can be suspicious.
# This file creates limitations on the request.
#
# TODO Look at the rules in this file, and define the sizes you'd like to enforce.
#      Note that most of the rules are commented out by default.
#      Uncomment the rules you need
#


#
# Maximum number of arguments in request limited
#

■IPアドレスをホスト名に変更して再テスト

$ w3m -dump_head -no-proxy 'http://localhost/../../etc/passwd'; \
    curl -v --noproxy localhost -s 'http://localhost/../../etc/passwd' | w3m -T text/html | head -3; \
    sudo tail -2 /var/log/apache2/access.log
HTTP/1.1 400 Bad Request
Date: Sun, 13 Aug 2017 04:16:05 GMT
Server: Apache/2.4.25 (Debian)
Connection: close
Content-Type: text/html; charset=iso-8859-1

* Rebuilt URL to: http://localhost/etc/passwd
*   Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 80 failed: 接続を拒否されました
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /etc/passwd HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Sun, 13 Aug 2017 04:16:05 GMT
< Server: Apache/2.4.25 (Debian)
< Content-Length: 283
< Content-Type: text/html; charset=iso-8859-1
< 
{ [283 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
Not Found

The requested URL /etc/passwd was not found on this server.
127.0.0.1 - - [13/Aug/2017:13:16:05 +0900] "HEAD /../../etc/passwd HTTP/1.0" 400 161 "-" "w3m/0.5.3+git20170102"
127.0.0.1 - - [13/Aug/2017:13:16:05 +0900] "GET /etc/passwd HTTP/1.1" 404 444 "-" "curl/7.52.1"

$ sudo strings /var/log/apache2/modsec_audit.log | \
    awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:13:16:05"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | sed -e 's/] /&\n\t/g'
[13/Aug/2017:13:16:05 +0900] 
	WY-ShX8AAQEAACLEEA0AAABJ 127.0.0.1 40148 127.0.0.1 80
--97663b14-B--
HEAD /../../etc/passwd HTTP/1.0
User-Agent: w3m/0.5.3+git20170102
Accept: text/html, text/*;q=0.5, image/*, application/*
Accept-Encoding: gzip, compress, bzip, bzip2, deflate
Accept-Language: ja;q=1.0, en;q=0.5
Host: localhost
--97663b14-F--
HTTP/1.1 400 Bad Request
Connection: close
Content-Type: text/html; charset=iso-8859-1
--97663b14-E--
--97663b14-H--
Apache-Error: [file "core.c"] 
	[line 4509] 
	[level 3] 
	AH00126: Invalid URI in request %s
Stopwatch: 1502597765775985 1032 (- - -)
Stopwatch2: 1502597765775985 1032; combined=628, p1=413, p2=0, p3=58, p4=110, p5=47, sr=42, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.1 (http://www.modsecurity.org/); OWASP_CRS/3.0.0.
Server: Apache/2.4.25 (Debian)
Engine-Mode: "DETECTION_ONLY"

■ディレクトリトラバーサルの書式があまりに単純過ぎたので引っかからなかった様子。
 「../../etc/passwd」を「..../etc/passwd」に変更して再実施。

$ w3m -dump_head -no-proxy 'http://localhost/..../etc/passwd'; \
    curl -v --noproxy localhost -s 'http://localhost/..../etc/passwd' | w3m -T text/html | head -3; \
    sudo tail -2 /var/log/apache2/access.log
HTTP/1.1 404 Not Found
Date: Sun, 13 Aug 2017 04:24:10 GMT
Server: Apache/2.4.25 (Debian)
Connection: close
Content-Type: text/html; charset=iso-8859-1

*   Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 80 failed: 接続を拒否されました
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /..../etc/passwd HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Sun, 13 Aug 2017 04:24:10 GMT
< Server: Apache/2.4.25 (Debian)
< Content-Length: 288
< Content-Type: text/html; charset=iso-8859-1
< 
{ [288 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
Not Found

The requested URL /..../etc/passwd was not found on this server.
127.0.0.1 - - [13/Aug/2017:13:24:10 +0900] "HEAD /..../etc/passwd HTTP/1.0" 404 159 "-" "w3m/0.5.3+git20170102"
127.0.0.1 - - [13/Aug/2017:13:24:10 +0900] "GET /..../etc/passwd HTTP/1.1" 404 449 "-" "curl/7.52.1"

$ sudo strings /var/log/apache2/modsec_audit.log | \
    awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:13:24:10"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep ^Message | sed -e 's/] /&\n\t/g'
Message: Warning. Matched phrase "../" at REQUEST_URI. [file "/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] 
	[line "77"] 
	[id "930110"] 
	[rev "1"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[ver "OWASP_CRS/3.0.0"] 
	[maturity "9"] 
	[accuracy "7"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-lfi"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
Message: Warning. Matched phrase "../" at REQUEST_URI. [file "/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] 
	[line "77"] 
	[id "930110"] 
	[rev "1"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[ver "OWASP_CRS/3.0.0"] 
	[maturity "9"] 
	[accuracy "7"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-lfi"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
Message: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] 
	[line "57"] 
	[id "949110"] 
	[msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] 
	[severity "CRITICAL"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-generic"]
Message: Warning. Operator GE matched 5 at TX:inbound_anomaly_score. [file "/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf"] 
	[line "73"] 
	[id "980130"] 
	[msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 10 - SQLI=0,XSS=0,RFI=0,LFI=10,RCE=0,PHPI=0,HTTP=0,SESS=0): Path Traversal Attack (/../)"] 
	[tag "event-correlation"]
Message: Warning. Matched phrase "../" at REQUEST_URI. [file "/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] 
	[line "77"] 
	[id "930110"] 
	[rev "1"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[ver "OWASP_CRS/3.0.0"] 
	[maturity "9"] 
	[accuracy "7"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-lfi"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
Message: Warning. Matched phrase "../" at REQUEST_URI. [file "/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] 
	[line "77"] 
	[id "930110"] 
	[rev "1"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[ver "OWASP_CRS/3.0.0"] 
	[maturity "9"] 
	[accuracy "7"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-lfi"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
Message: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] 
	[line "57"] 
	[id "949110"] 
	[msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] 
	[severity "CRITICAL"] 
	[tag "application-multi"] 
	[tag "language-multi"] 
	[tag "platform-multi"] 
	[tag "attack-generic"]
Message: Warning. Operator GE matched 5 at TX:inbound_anomaly_score. [file "/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf"] 
	[line "73"] 
	[id "980130"] 
	[msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 10 - SQLI=0,XSS=0,RFI=0,LFI=10,RCE=0,PHPI=0,HTTP=0,SESS=0): Path Traversal Attack (/../)"] 
	[tag "event-correlation"]

■「949110」は全体的なトランザクションでの異常の検出を数値化したものなので、
 実質2種類のシグニチャにマッチしたことになる。

$ sudo strings /var/log/apache2/modsec_audit.log |     awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:13:24:10"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep ^Message | sed -e 's/] /&\n\t/g' | \
    awk '/id/{gsub("]","",$NF);a[$NF]+=1}END{for(n in a){print a[n],n}}'
4 "930110"
2 "980130"
2 "949110"

$ sudo strings /var/log/apache2/modsec_audit.log |     awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:13:24:10"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep ^Message | sed -e 's/] /&\n\t/g' | \
    awk '/id/{gsub("]","",$NF);a[$NF]+=1}END{for(n in a){print "grep -B 22 -A 26 "n" /usr/share/modsecurity-crs/rules/*" }}' | \
    sh | grep '\[\|id:[0-9]*,\\'
/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf-# [ Decoded /../ Payloads ]
/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf:        id:930110,\
/usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf-# -=[ OS File Access ]=-
/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf-	id:980120,\
/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf:	id:980130,\
/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf-	id:980140,\
/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf-	id:949100,\
/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf-# -=[ Anomaly Mode: Overall Transaction Anomaly Score ]=-
/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf:    id:949110,\

■IIS向けの場合は以下のようにすれば良いことが分かる。

$ w3m -dump_head -no-proxy 'http://localhost/..../cmd.exe' > /dev/null; \
    curl -v --noproxy localhost -s 'http://localhost/..../cmd.exe' >/dev/null 2>&1 | w3m -T text/html | head -3 ; \
    sudo tail -2 /var/log/apache2/access.log
127.0.0.1 - - [13/Aug/2017:13:41:49 +0900] "HEAD /..../cmd.exe HTTP/1.0" 404 159 "-" "w3m/0.5.3+git20170102"
127.0.0.1 - - [13/Aug/2017:13:41:49 +0900] "GET /..../cmd.exe HTTP/1.1" 404 446 "-" "curl/7.52.1"

$ sudo strings /var/log/apache2/modsec_audit.log | \
    awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:13:41:49"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep ^Message | sed -e 's/] /&\n\t/g' | \
    awk '/id/{gsub("]","",$NF);a[$NF]+=1}END{for(n in a){print a[n],n}}'
4 "930110"
2 "980130"
2 "949110"

■SecRuleEngineをENABLE(ブロック)に変更する。
 HTTPステータスコードが「404 Not Found」から「403 Forbidden」に変わった。

$ sudo sed -i -e 's/^\(SecRuleEngine\) DetectionOnly/\1 On/' /etc/modsecurity/modsecurity.conf
$ sudo systemctl reload apache2.service 

$ w3m -dump_head -no-proxy 'http://localhost/..../etc/passwd'; \
>     curl -v --noproxy localhost -s 'http://localhost/..../etc/passwd' | w3m -T text/html | head -3; \
>     sudo tail -2 /var/log/apache2/access.log
HTTP/1.1 403 Forbidden
Date: Sun, 13 Aug 2017 05:05:15 GMT
Server: Apache/2.4.25 (Debian)
Connection: close
Content-Type: text/html; charset=iso-8859-1

*   Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 80 failed: 接続を拒否されました
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /..../etc/passwd HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> 
< HTTP/1.1 403 Forbidden
< Date: Sun, 13 Aug 2017 05:05:15 GMT
< Server: Apache/2.4.25 (Debian)
< Content-Length: 299
< Content-Type: text/html; charset=iso-8859-1
< 
{ [299 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
Forbidden

You don't have permission to access /..../etc/passwd on this server.
127.0.0.1 - - [13/Aug/2017:14:05:15 +0900] "HEAD /..../etc/passwd HTTP/1.0" 403 159 "-" "w3m/0.5.3+git20170102"
127.0.0.1 - - [13/Aug/2017:14:05:15 +0900] "GET /..../etc/passwd HTTP/1.1" 403 460 "-" "curl/7.52.1"
$ sudo strings /var/log/apache2/modsec_audit.log |     awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:14:05:15"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep ^Message | sed -e 's/] /&\n\t/g' | \
    awk '/id/{gsub("]","",$NF);a[$NF]+=1}END{for(n in a){print a[n],n}}'
4 "930110"
2 "980130"
2 "949110"

$ sudo strings /var/log/apache2/modsec_audit.log | \
    awk 'BEGIN{flag=0} \
              {if($1=="[13/Aug/2017:14:05:15"){flag=1;print} \
          else{if($1=="Engine-Mode:" && flag==1){flag=0;print} \
          else{if(flag==1){print}}}}' | grep "^Message\|^Engine-Mode" | sed -e 's/] /&\n\t/g' | \
    awk '/Engine-Mode|id|msg|data|severity|tag .[A-Z]/'
	[id "930110"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
	[id "930110"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
	[id "949110"] 
	[msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] 
	[severity "CRITICAL"] 
	[id "980130"] 
	[msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 10 - SQLI=0,XSS=0,RFI=0,LFI=10,RCE=0,PHPI=0,HTTP=0,SESS=0): Path Traversal Attack (/../)"] 
Engine-Mode: "ENABLED"
	[id "930110"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
	[id "930110"] 
	[msg "Path Traversal Attack (/../)"] 
	[data "Matched Data: ../ found within REQUEST_URI: /..../etc/passwd"] 
	[severity "CRITICAL"] 
	[tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"]
	[id "949110"] 
	[msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] 
	[severity "CRITICAL"] 
	[id "980130"] 
	[msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 10 - SQLI=0,XSS=0,RFI=0,LFI=10,RCE=0,PHPI=0,HTTP=0,SESS=0): Path Traversal Attack (/../)"] 
Engine-Mode: "ENABLED"

■検出のみに戻しておく。

$ sudo sed -i -e 's/^\(SecRuleEngine\) On/\1 DetectionOnly/' /etc/modsecurity/modsecurity.conf
$ sudo systemctl reload apache2.service