mod_securityのインストールとWordPressの編集を可能にする設定

May 21, 2015 – 11:13 am

最近、このブログに対し、WordPress の plugin の脆弱性を利用した不正アクセスが頻発している。今のところ、ブログへのアクセス解析するうえで多少の不具合はあるものの、こうした不正アクセスによる実害は認められないが、実際に被害を被る前に何らかの対策を講じるに越したことはない。

こうした不正アクセスに対処するためには、クライアント側から送られてくるHTTPリクエスト、それに含まれるデータ等を評価・解析し、それに基づき、そのリクエストを受け入れるか否かを判定する仕組みが必要だ。こうした仕組みとして、WAF(Web Application Firewall)と呼ばれるツールがあり、WAFのうちオープンソースとしてmod_security が利用可能になっている。我がサーバにも、今回、このmod_securityを導入し、サーバのセキュリティを向上させる措置をとることにした。

このエントリーでは、今回実施した一連の作業、即ち、mod_securityのインストール、インストール後のWordPress動作に係る設定上の作業、そして、このツールを用いた上記の不正アクセスに対する対処、についてメモしておいた。


WordPress Pluginの脆弱性を狙った不正アクセス:
ここ数週間、本ブログへのアクセスに不正なアクセスをにおわせるものが認められた。access-logの一部を以下に示す:

blue38.dnsmisitio.net - - [10/May/2015:04:48:34 +0900] "GET /archives/Post-693.html/wp-admin/admin-ajax.php?action=revslider_show_image&img=../wp-config.php HTTP/1.1" 404 43045 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6"
blue38.dnsmisitio.net - - [10/May/2015:04:48:37 +0900] "GET /archives/Post-693.html/wp-admin/admin-ajax.php?action=revslider_show_image&img=../wp-config.php HTTP/1.1" 404 43045 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6"

このログレコードに含まれる revslider_show_image はWordPressのPluginのひとつで、その脆弱性を利用した不正アクセスの存在が報告されている(報告例)。上記ログから、この不正アクセスにより、WordPressの環境設定ファイル wp-config.php が読み取られようとされていることが推察される。wp-config.php には、WordPress の背後で動作するSQLデータベースのユーザー名、パスワードなどが含まれており、これが外部から読み取られるとブログの改ざんなどにつながる。

ブログのaccess-logには、上記したログとリクエストの内容を同一とするが、複数の異なるアクセス元が記録されている。この事実は、多数の計算機が踏み台とされ不正アクセスのアクセス元になっていることを窺わさせる。

不正アクセスに対する実効的な対処方策:
上述したアタックに対処するには、サーバー上で動作するウェブアプリケーション自身をセキュアにすることに加えて、アプリケーションに送られてくるリクエスト、データの内容を評価・解析し、セキュリティ上問題があるものについては、アクセスを許可しないといった仕組みが必要である。こうした仕組みとして、WAF(Web Application Firewall)と呼ばれる仕組み、ツールが知られている。

WAFの役割は「クライアントからWebサーバに向けて送信されるデータおよび入力のチェックを行い、不正な入力がWebサーバーに渡されないようにする」こととされる。そこでWAFはWebアプリケーションが稼働するサーバの前段階に配置され、不正な入力があれば通信を遮断し、内部のWebアプリケーションを防御する。

WAFのオープンソフトプロダクトとして mod_security がある。これはApacheのモジュールとして動作し、不正アクセスやワームなどからApacheを守るソフトウェアであり、GPLライセンスのもと利用可能になっている。

mod_securyityのインストール:
mod_securityを、epelリポジトリを使用しyum インストールした。インストール時のログを以下に掲げる:

[root@  ]# yum --enablerepo=epel install mod_security mod_security_crs
Loaded plugins: refresh-packagekit, security
Setting up Install Process
epel/metalink                                                                                | 5.2 kB     00:00     
epel                                                                                         | 4.4 kB     00:00     
epel/primary_db                                                                              | 6.5 MB     00:04     
Resolving Dependencies
--> Running transaction check
---> Package mod_security.x86_64 0:2.7.3-3.el6 will be installed
---> Package mod_security_crs.noarch 0:2.2.6-3.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

====================================================================================================================
 Package                           Arch                    Version                      Repository             Size
====================================================================================================================
Installing:
 mod_security                      x86_64                  2.7.3-3.el6                  epel                  168 k
 mod_security_crs                  noarch                  2.2.6-3.el6                  epel                   92 k

Transaction Summary
====================================================================================================================
Install       2 Package(s)

Total download size: 260 k
Installed size: 801 k
Is this ok [y/N]: y
Downloading Packages:
(1/2): mod_security-2.7.3-3.el6.x86_64.rpm                                                   | 168 kB     00:00     
(2/2): mod_security_crs-2.2.6-3.el6.noarch.rpm                                               |  92 kB     00:00     
--------------------------------------------------------------------------------------------------------------------
Total                                                                               733 kB/s | 260 kB     00:00     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : mod_security-2.7.3-3.el6.x86_64                                                                  1/2 
  Installing : mod_security_crs-2.2.6-3.el6.noarch                                                              2/2 
  Verifying  : mod_security_crs-2.2.6-3.el6.noarch                                                              1/2 
  Verifying  : mod_security-2.7.3-3.el6.x86_64                                                                  2/2 

Installed:
  mod_security.x86_64 0:2.7.3-3.el6                      mod_security_crs.noarch 0:2.2.6-3.el6                     

Complete!

このログに見られるように、インストールにあたっては mod_security本体に加え、OWASP Modsecurity Core Rule Set (mod_security_crs)をインストールしている。

mod_security インストール時の若干の注意点
apacheのモジュールmod_securityをインストールしたことから、このモジュールを配置したapache の再起動を行なったところ、apacheの起動に失敗し、以下のエラーが発生した。

[Sat May 16 09:35:38 2015] [alert] (EAI 2)Name or service not known: mod_unique_id: unable to find IPv4 address of "yamasserver01"
Configuration Failed

このエラーは、mod_securityがインストールされたことにより apache が server の host名を、直接、参照するようになったことによるものと推察した。このエラーをクリアするには、/etc/hosts 上で、server の host名とIPアドレスを対応付けることが必要になる。/etc/hostsを以下のように変更した。

/etc/hosts:

変更前:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

変更後:

127.0.0.1   yamasserver01 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

  
  
WordPressの管理画面での操作(ポストの新規投稿・編集など)を可能にする
mod_securityインストールの際に導入したルールセットのもとでは、WordPressの管理画面上でのポストの新規登録、編集などを行うことはできない。これは、WordPressにおいてこの種の操作を行おうとすると、mod_securityがこれを不正なアクセスと判定してしまうことによる。運用上、こうした事態をさけるためには、WordPressの通常の操作を「不正」な操作として認識するルールを除去しておけば良い。

除去対象とすべきルールの同定、そしてmod_securityを有効にする手順を以下に示す:

  1. /etc/httpd/conf.d/mod_security.conf を編集し、SecRuleEngine をDetectionOnlyにする
        SecRuleEngine DetectionOnly
    
  2. apacheを再起動する
    [root ]# service httpd restart
    Stopping httpd:                                            [  OK  ]
    Starting httpd:                                            [  OK  ]
    
  3. WordPress上で想定される管理画面へのアクセス、ポストの新規登録、編集などを含む一連の通常操作を行う
       

  4. 前記操作に伴い出力されるログ(/var/log/httpd/modsec_audit.log)上に記録されているルールのidをピックアップし、このidに対応するルールをConfiguration Directive のひとつSecRuleRemoveByIdを用いて除去( mod_security.confの最終行にピックアップしたid対応のルール除去に対応するためのレコードを付加し、SecRuleEngineをOn)。

    modsec_audit.log出力の一部(例示のみ):

    --07e30245-A--
    [20/May/2015:13:55:08 +0900] VVwTrH8AAAEAAAHSNs4AAAAM 153.217.21.197 53968 192.168.11.111 80
    --07e30245-B--
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Accept: */*
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    X-Requested-With: XMLHttpRequest
    Referer: http://wptest.yamasnet.com/wp-admin/post.php?post=30&action=edit
    Accept-Language: ja-JP
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
    Host: wptest.yamasnet.com
    Content-Length: 92
    DNT: 1
    Connection: Keep-Alive
    Cache-Control: no-cache
    Cookie: wordpress_80f1fb8b54362acb8a60a269821955f2=test.password%7C1432270402%7CgNS640khfgyeNUBy56iFQ5lb9KZfpodmZ3f3IEU83gE%7Ccec2931cdab4a3878a409469cfbcc2f59bcda0f8d3c7040994b5d7359f5c0465; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_80f1fb8b54362acb8a60a269821955f2=test.password%7C1432270402%7CgNS640khfgyeNUBy56iFQ5lb9KZfpodmZ3f3IEU83gE%7Cc2eeac349f7b8429bc4115ebad9e8e953912ff42c8c024c175f3957da560c696; wp-settings-1=libraryContent%3Dbrowse%26urlbutton%3Dpost%26mfold%3Df%26cats%3Dpop%26editor%3Dhtml; wp-settings-time-1=1432097703
    
    --07e30245-C--
    action=wordtwit_ajax&wordtwit_action=are-hash-tags-enabled&wordtwit_nonce=2e984b424b&post=30
    --07e30245-F--
    HTTP/1.1 200 OK
    X-Powered-By: PHP/5.3.3
    X-Robots-Tag: noindex
    X-Content-Type-Options: nosniff
    Expires: Wed, 11 Jan 1984 05:00:00 GMT
    Cache-Control: no-cache, must-revalidate, max-age=0
    Pragma: no-cache
    X-Frame-Options: SAMEORIGIN
    Content-Length: 3
    Keep-Alive: timeout=15, max=96
    Connection: Keep-Alive
    Content-Type: text/html; charset=UTF-8
    
    --07e30245-E--
    
    --07e30245-H--
    
    Message: Warning. Pattern match "([\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\+\\=\\{\\}\\[\\]\\|\\:\\;\"\\'\\\xc2\xb4\\\xe2\x80\x99\\\xe2\x80\x98\\`\\<\\>].*?){8,}" at REQUEST_COOKIES:wp-settings-1. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line "168"] [id "981172"] [rev "2"] [msg "Restricted SQL Character Anomaly Detection Alert - Total # of special characters exceeded"]  [data "Matched Data & found within REQUEST_COOKIES:wp-settings-1: libraryContent=browse&urlbutton=post&mfold=f&cats=pop&editor=html"] [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "8"]
    Message: Warning. Operator LT matched 5 at TX:inbound_anomaly_score. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_60_correlation.conf"] [line "33"] [id "981203"] [msg "Inbound Anomaly Score (Total Inbound Score: 3, SQLi=1, XSS=): Restricted SQL Character Anomaly Detection Alert - Total # of special characters exceeded"]  [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "8"]
    Apache-Handler: php5-script
    Stopwatch: 1432097708528204 44880 (- - -)
    Stopwatch2: 1432097708528204 44880; combined=13126, p1=272, p2=12646, p3=3, p4=82, p5=122, sr=55, sw=1, l=0, gc=0
    Response-Body-Transformed: Dechunked
    Producer: ModSecurity for Apache/2.7.3 (http://www.modsecurity.org/); OWASP_CRS/2.2.6.
    Server: Apache
    Engine-Mode: "DETECTION_ONLY"
    

    /etc/httpd/mod_security.conf:

    LoadModule security2_module modules/mod_security2.so
    
    <IfModule !mod_unique_id.c>
        LoadModule unique_id_module modules/mod_unique_id.so
    </IfModule>
    <IfModule mod_security2.c>
        # ModSecurity Core Rules Set configuration
            Include modsecurity.d/*.conf
            Include modsecurity.d/activated_rules/*.conf
        # Default recommended configuration
        SecRuleEngine On
        # SecRuleEngine Off
        # SecRuleEngine DetectionOnly
        SecRequestBodyAccess On
    
        SecRule REQUEST_HEADERS:Content-Type "text/xml" \
            "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
        SecRequestBodyLimit 13107200
        SecRequestBodyNoFilesLimit 131072
        SecRequestBodyInMemoryLimit 131072
        SecRequestBodyLimitAction Reject
    
       SecRule REQBODY_ERROR "!@eq 0" \
        "id:'200001', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}' ,severity:2"
    
    
        SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
        "id:'200002', phase:2,t:none,log,deny,status:44,msg:'Multipart request body \
        failed strict validation: \
        failed strict validation: \
        PE %{REQBODY_PROCESSOR_ERROR}, \
        BQ %{MULTIPART_BOUNDARY_QUOTED}, \
        BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
        DB %{MULTIPART_DATA_BEFORE}, \
        DA %{MULTIPART_DATA_AFTER}, \
        HF %{MULTIPART_HEADER_FOLDING}, \
        LF %{MULTIPART_LF_LINE}, \
        SM %{MULTIPART_MISSING_SEMICOLON}, \
        IQ %{MULTIPART_INVALID_QUOTING}, \
        IP %{MULTIPART_INVALID_PART}, \
        IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
        FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
    
        SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
        "id:'200003',phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'"
    
        SecPcreMatchLimit 1000
        SecPcreMatchLimitRecursion 1000
    
        SecRule TX:/^MSC_/ "!@streq 0" \
                "id:'200004',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
    
        SecResponseBodyAccess Off
        SecDebugLog /var/log/httpd/modsec_debug.log
        SecDebugLogLevel 0
        SecAuditEngine RelevantOnly
        SecAuditLogRelevantStatus "^(?:5|4(?!04))"
        SecAuditLogParts ABIJDEFHZ
        SecAuditLogType Serial
        SecAuditLog /var/log/httpd/modsec_audit.log
        SecArgumentSeparator &
        SecCookieFormat 0
        SecTmpDir /var/lib/mod_security
        SecDataDir /var/lib/mod_security
        SecRuleRemoveById 950001
        SecRuleRemoveById 950005
        SecRuleRemoveById 950010
        SecRuleRemoveById 950109
        SecRuleRemoveById 950901
        SecRuleRemoveById 950908
        SecRuleRemoveById 950910
        SecRuleRemoveById 950911
        SecRuleRemoveById 958007
        SecRuleRemoveById 958039
        SecRuleRemoveById 958051
        SecRuleRemoveById 958052
        SecRuleRemoveById 958413
        SecRuleRemoveById 959073
        SecRuleRemoveById 960009
        SecRuleRemoveById 960015
        SecRuleRemoveById 960024
        SecRuleRemoveById 960912
        SecRuleRemoveById 973300
        SecRuleRemoveById 973302
        SecRuleRemoveById 973303
        SecRuleRemoveById 973304
        SecRuleRemoveById 973305
        SecRuleRemoveById 973306
        SecRuleRemoveById 973316
        SecRuleRemoveById 973330
        SecRuleRemoveById 973331
        SecRuleRemoveById 973332
        SecRuleRemoveById 973333
        SecRuleRemoveById 973335
        SecRuleRemoveById 981172
        SecRuleRemoveById 981173
        SecRuleRemoveById 981204
        SecRuleRemoveById 981231
        SecRuleRemoveById 981240
        SecRuleRemoveById 981242
        SecRuleRemoveById 981243
        SecRuleRemoveById 981244
        SecRuleRemoveById 981245
        SecRuleRemoveById 981246
        SecRuleRemoveById 981248
        SecRuleRemoveById 981249
        SecRuleRemoveById 981251
        SecRuleRemoveById 981257
        SecRuleRemoveById 981260
        SecRuleRemoveById 981317
    </IfModule>
    
  5. apacheを再起動
    [root ]# service httpd restart
    Stopping httpd:                                            [  OK  ]
    Starting httpd:                                            [  OK  ]
    

  
特定の不正アクセスへの対処法
冒頭、このブログに対して Plugin revslider_show_imageの脆弱性を狙ってWordPressの環境設定ファイルwp-config.phpを読み取ろうとする不正アクセスについて述べた。このアタックに対応するHTTPリクエストのなかに、「reveslider_show_image」なる文字列が含まれることに着目し、この文字列を含むアクセスを拒否する「ルール」を付加することにした。

具体的な「ルール」は以下の通り:


    SecRule REQUEST_URI|ARGS|REQUEST_BODY "revslider_show_image" "id:'210001',log,deny,msg:'Access Denied'"

これを前項で示した mod_security.conf の最終行に追記し、apacheを再起動することにより、reveslider_show_image の文字列を含むURIによるアクセスを廃除することができる。

ログファイル mdsec_audit.log において、これに該当する部分を以下に示す:


--41905a1d-A--
[17/May/2015:10:55:41 +0900] VVf1HX8AAAEAADOK@A8AAAAO 94.131.14.12 34408 192.168.11.111 80
--41905a1d-B--
GET /wp-admin/admin-ajax.php?action=revslider_show_image&img=../wp-config.php HTTP/1.1
Host: memorandum.yamasnet.com
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:34.0) Gecko/20100101 Firefox/34.0

--41905a1d-F--
HTTP/1.1 403 Forbidden
Content-Length: 225
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

--41905a1d-E--

--41905a1d-H--
Message: Access denied with code 403 (phase 1). Pattern match "revslider_show_image" at REQUEST_URI. [file "/etc/httpd/conf.d/mod_security.conf"] [line "89"] [id "210001"] [msg "Access Denied"]
Action: Intercepted (phase 1)
Stopwatch: 1431827741049237 700 (- - -)
Stopwatch2: 1431827741049237 700; combined=256, p1=225, p2=0, p3=0, p4=0, p5=30, sr=55, sw=1, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.7.3 (http://www.modsecurity.org/); OWASP_CRS/2.2.6.
Server: Apache
Engine-Mode: "ENABLED"

--41905a1d-Z--

  
まとめ
mod_securityのインストール、そしてその環境下でWordPressを運用するために施した諸設定に係り、その作業記録をメモしておいた。

今回のインストール作業を行う契機となったWordPressのPlugin revslider_show_imageの脆弱性を利用した不正アクセスに対し、mod_securityを活用して対処することができた。

mod_securityのルールセットで導入される防御策は、WordPressへの新規ポストの登録、編集を「不正」なものと判定されることがある。今回の作業のなかで、WordPressの運用上障害となる一定の「ルール」の除外について議論し、ほぼWordPressの一般的な運用にとっては問題のないレベルまで除外ルールを同定することができた。しかし、ルールによる「不正」判定がポストに書き込まれるデータ、特に特殊文字を含むかいなかに強く影響されることがあるので、注意が必要と思われる。
  
参考にしたサイト

   
   


  1. One Response to “mod_securityのインストールとWordPressの編集を可能にする設定”

  2. WordPressに投稿時は、一時的にmod_securityの機能をオフにし、投稿完了時にもとに戻す運用が望ましい。
    mod_securityをオフにするには、
    /etc/httpd/conf.d/mod_security.confに於いて
    SecRuleEngineをOff にし、
    apacheを再起動。
    WordPressへの投稿終了時にもとに戻し、apacheを再起動。

    By Yama on Jul 6, 2015

Post a Comment