CVE-2017-2641 による攻撃を防ぐための対策を考える

# 現状
Moodleのバージョンによっては[CVE-2017-2641を用いた攻撃で](https://qiita.com/papillon/items/fc67c5eefa1305d1c4e4)管理者権限を奪われる可能性があってヤバい。

# 対策方法
## Moodleをアップグレードする
この脆弱性はMoodle 3.2.2以降などでは解消しているため、対応しているバージョンにアップグレードする。しかし、場合によってはアップグレード出来ない場合もある。例えば大幅にカスタマイズしている場合や、バージョンアップで仕様変更があった場合に利用してる標準外のモジュールが利用できなくなる場合などは簡単にアップグレードすることができない。
しかしながら（略）。

## WAFで対策する
Web Application Firewall(WAF)と呼ばれる仕組みによって防ぐことが可能な攻撃もある。今回はhttpdにmod_securityを追加することで実現する。

### 手順
#### mod_securityのインストール
yumを使ってmod_secuirtyをインストールする。インストール後はhttpdを再起動する。

```
# yum install -y mod_security
# yum list | grep mod_security
mod_security.x86_64                     2.7.3-5.el7                    @base
mod_security_crs.noarch                 2.2.9-1.el7                    base

# systemctl restart httpd
```

今回はmod_security_crsと呼ばれるルールセットはインストールしていない。これをインストールすると追加されたルールによりMoodleの通常の動作にも影響が出るため問題がないか広範な検証を行う必要が出てくる。

#### ルールの追加
今回の攻撃はSQLインジェクションに分類されているが、実際にはオブジェクトインジェクションなのでそのためのルールを追加する。
[このルール](https://github.com/SpiderLabs/owasp-modsecurity-crs/blob/e4e0497be4d598cce0e0a8fef20d1f1e5578c8d0/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf#L338)をほぼコピペする。

```
SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|REQUEST_HEADERS|ARGS_NAMES|ARGS|XML:/* \
                "@rx [oOcC]:\d+:\".+?\":\d+:{.*}" \
        "phase:2, \
        rev:'1', \
        msg:'PHP Injection Attack: Serialized Object Injection',\
        maturity:'1',\
        accuracy:'9',\
        t:none,block, \
        logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\
        id:933170,\
        severity:'CRITICAL',\
        tag:'application-multi',\
        tag:'language-php',\
        tag:'platform-multi',\
        tag:'attack-injection-php',\
        tag:'OWASP_CRS/WEB_ATTACK/PHP_INJECTION',\
        tag:'OWASP_TOP_10/A1',\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.php_injection_score=+%{tx.critical_anomaly_score},\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{tx.0}"
```

#### 動作チェック
脆弱性確認用のPoCを実行してもログには何の反応もない…
どうやらyumでインストールできるバージョンのmod_securityはJSONに対応できないようなのでソースからインストールする。

#### mod_securityのソースからのインストール
先にyumでmod_securityをアンインストールする。残ったファイルが/etc/httpd/配下に無いか確認して削除しておく。
[このあたり](https://gist.github.com/rpfilomeno/1140359f4bd360137a98)を参考にインストール作業を行う。libyajl (Yet Another JSON Library)を有効にしておく。

```
# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

# yum install -y gcc httpd-devel pcre-devel libxml2-devel yajl-devel libcurl-devel

# cd /usr/local/src
# wget https://www.modsecurity.org/tarball/2.9.2/modsecurity-2.9.2.tar.gz
# tar xvzf modsecurity-2.9.2.tar.gz
# cd modsecurity-2.9.2
# ./configure --with-yajl
# make
# make check
# make install

# cp modsecurity.conf-recommended /etc/httpd/conf.d/modsecurity.conf
# cp unicode.mapping /etc/httpd/conf.d/unicode.mapping

# chmod 755 /etc/httpd/modules/mod_security2.so

# vi /etc/httpd/conf.modules.d/20-mod_security2.conf
```
```:/etc/httpd/conf.modules.d/20-mod_security2.conf
LoadModule security2_module modules/mod_security2.so
```

先ほどのオブジェクトインジェクション用SecRuleをmodsecurity.confに追記。別ファイルにして読み込ませるのが妥当なやり方だがとりあえず手抜き。ルールの追記/変更後は`systemctl reload httpd`で設定を反映させる。

#### 動作チェック2

```
--0b199a1a-A--
[24/Nov/2017:02:24:09 +0900] WhcEOWjFtIDO9rEk3XBXdQAAAAE 192.168.11.105 37626 192.168.11.105 80
--0b199a1a-B--
POST //lib/ajax/service.php?sesskey=DXmhRGRiO0 HTTP/1.1
Host: 192.168.11.105
Accept: */*
Cookie: MoodleSession=m6stlikjas7cs2es45cet9g2d6
Content-Type: application/json
Content-Length: 598

--0b199a1a-C--
[{"index":0,"methodname":"core_user_update_user_preferences","args":{"preferences":[{"type":"course_overview_course_order","value":"a:2:{i:0;a:1:{i:0;O:29:\"gradereport_overview_external\":0:{}}i:1;O:40:\"gradereport_singleview\\local\\ui\\feedback\":1:{s:5:\"grade\";O:11:\"grade_grade\":1:{s:10:\"grade_item\";O:10:\"grade_item\":6:{s:11:\"calculation\";s:12:\"[[somestring\";s:22:\"calculation_normalized\";b:0;s:5:\"table\";s:6:\"config\";s:2:\"id\";i:375;s:5:\"value\";s:40:\"1b85107599b6b79def7aa454766b2d1823a5f447\";s:15:\"required_fields\";a:2:{i:0;s:5:\"value\";i:1;s:2:\"id\";}}}}}"}]}}]
--0b199a1a-F--
HTTP/1.1 200 OK
X-Powered-By: PHP/7.1.12
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 29
Content-Type: application/json; charset=utf-8

--0b199a1a-E--

--0b199a1a-H--
Message: Warning. Pattern match "[oOcC]:\\d+:\".+?\":\\d+:{.*}" at ARGS:args.preferences.value. [file "/etc/httpd/conf.d/modsecurity.conf"] [line "250"] [id "933170"] [rev "1"] [msg "PHP Injection Attack: Serialized Object Injection"] [data "Matched Data:  found within ARGS:args.preferences.value: a:2:{i:0;a:1:{i:0;O:29:\x22gradereport_overview_external\x22:0:{}}i:1;O:40:\x22gradereport_singleview\x5clocal\x5cui\x5cfeedback\x22:1:{s:5:\x22grade\x22;O:11:\x22grade_grade\x22:1:{s:10:\x22grade_item\x22;O:10:\x22grade_item\x22:6:{s:11:\x22calculation\x22;s:12:\x22[[somestring\x22;s:22:\x22calculation_normalized\x22;b:0;s:5:\x22table\x22;s:6:\x22config\x22;s:2:\x22id\x22;i:375;s:5:\x22value\x22;s:40:\x221b85107599b6b79def7aa454766b2d1823a5f447\x2..."] [severity "CRITICAL"] [maturity "1"] [accuracy "9"] [tag "application-multi"] [tag "language-php"] [tag "platform-multi"] [tag "attack-injection-php"] [tag "OWASP_CRS/WEB_ATTACK/PHP_INJECTION"] [tag "OWASP_TOP_10/A1"]
Apache-Error: [file "apache2_util.c"] [line 271] [level 3] [client 192.168.11.105] ModSecurity: Warn
40:\"gradereport_singleview\\local\\ui\\feedback\":1:{s:5:\"grade\";O:11:\"grade_grade\":1:{s:10:\"g
rade_item\";O:10:\"grade_item\":6:{s:11:\"calculation\";s:12:\"[[somestring\";s:22:\"calculation_nor
malized\";b:0;s:5:\"table\";s:6:\"config\";s:2:\"id\";i:375;s:5:\"value\";s:40:\"1b85107599b6b79def7
aa454766b2d1823a5f447\";s:15:\"required_fields\";a:2:{i:0;s:5:\"value\";i:1;s:2:\"id\";}}}}}"}]}}]
--0b199a1a-F--
HTTP/1.1 200 OK
X-Powered-By: PHP/7.1.12
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cookie: MoodleSession=m6stlikjas7cs2es45cet9g2d6
Content-Type: application/json
Content-Length: 598
Content-Type: application/json; charset=utf-8

--dcc78b37-E--

--dcc78b37-H--
Message: Warning. Pattern match "[oOcC]:\\d+:\".+?\":\\d+:{.*}" at ARGS:args.preferences.value. [fil
e "/etc/httpd/conf.d/modsecurity.conf"] [line "250"] [id "933170"] [rev "1"] [msg "PHP Injection Att
ack: Serialized Object Injection"] [data "Matched Data:  found within ARGS:args.preferences.value: a
:2:{i:0;a:1:{i:0;O:29:\x22gradereport_overview_external\x22:0:{}}i:1;O:40:\x22gradereport_singleview
\x5clocal\x5cui\x5cfeedback\x22:1:{s:5:\x22grade\x22;O:11:\x22grade_grade\x22:1:{s:10:\x22grade_item
\x22;O:10:\x22grade_item\x22:6:{s:11:\x22calculation\x22;s:12:\x22[[somestring\x22;s:22:\x22calculat
ion_normalized\x22;b:0;s:5:\x22table\x22;s:6:\x22config\x22;s:2:\x22id\x22;i:25;s:5:\x22value\x22;i:
3;s:15:\x22required_fields\x22;a:2:{i:0;s:5:\x22val..."] [severity "CRITICAL"] [maturity "1"] [accur
acy "9"] [tag "application-multi"] [tag "language-php"] [tag "platform-multi"] [tag "attack-injectio
n-php"] [tag "OWASP_CRS/WEB_ATTACK/PHP_INJECTION"] [tag "OWASP_TOP_10/A1"]
Apache-Error: [file "apache2_util.c"] [line 271] [level 3] [client 192.168.11.105] ModSecurity: Warn
ing. Pattern match "[oOcC]:\\\\\\\\d+:\\\\".+?\\\\":\\\\\\\\d+:{.*}" at ARGS:args.preferences.value.
 [file "/etc/httpd/conf.d/modsecurity.conf"] [line "250"] [id "933170"] [rev "1"] [msg "PHP Injectio
n Attack: Serialized Object Injection"] [data "Matched Data:  found within ARGS:args.preferences.val
ue: a:2:{i:0;a:1:{i:0;O:29:\\\\x22gradereport_overview_external\\\\x22:0:{}}i:1;O:40:\\\\x22graderep
ort_singleview\\\\x5clocal\\\\x5cui\\\\x5cfeedback\\\\x22:1:{s:5:\\\\x22grade\\\\x22;O:11:\\\\x22gra
de_grade\\\\x22:1:{s:10:\\\\x22grade_item\\\\x22;O:10:\\\\x22grade_item\\\\x22:6:{s:11:\\\\x22calcul
ation\\\\x22;s:12:\\\\x22[[somestring\\\\x22;s:22:\\\\x22calculation_normalized\\\\x22;b:0;s:5:\\\\x
22table\\\\x22;s:6:\\\\x22config\\\\x22;s:2:\\\\x22id\\\\x22;i:25;s:5:\\\\x22value\\\\x22;i:3;s:15:\\\\x22required_fields\\\\x22;a:2:{i:0;s:5:\\\\x22val..."] [severity "CRITICAL"] [maturity "1"] [accuracy "9"] [tag "application-multi"] [tag "language-php"] [tag "platform-multi"] [tag "attack-injection-php"] [tag "OWASP_CRS/WEB_ATTACK/PHP_INJECTION"] [tag "OWASP_TOP_10/A1"] [hostname "192.168.11.105"] [uri "/lib/ajax/service.php"] [unique_id "WhcEOfhuzp7UoUVIcO6ckAAAAAM"]
Apache-Handler: application/x-httpd-php
Stopwatch: 1511457849077861 149520 (- - -)
Stopwatch2: 1511457849077861 149520; combined=456, p1=77, p2=369, p3=3, p4=2, p5=5, sr=0, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.2 (http://www.modsecurity.org/).
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.1.12
Engine-Mode: "DETECTION_ONLY"

--dcc78b37-Z--
```

無事にmod_securityで検出することができた。設定ファイル中のSecRuleEngineの値が*DetectionOnly*のままなのでブロックしていない。この値を*On*に変更することでアクセスをブロックするようになる。