WordPressの脆弱性スキャンツールwpscanを使ってみる

相変わらずKali Linuxをいじっているので、その中のツールをまた紹介しようと思う。今回は、WordPress脆弱性診断をおこなってくれるツールWPScanを使ってみる。

WPScanとは何か

WordPressは世界中で人気があり広く使われていることから、これを狙ったアタックが多いのも事実である。特に、既知の脆弱性がある古いバージョンのものを使っていると危ない。ということで、WordPressをHTTPスキャンすることで脆弱性診断が行えるのがこのWPScanである。

モノとしてはRubyで書かれたツールであり、特にKali Linuxでなくとも動かすことができる(最初のbundlerで色々入れないといけないのが面倒だが……)。ダウンロードして中身を覗いてみると分かるけど、data/plugin_vulns.xml などに過去の脆弱性を丁寧にリストアップしてくれており、なかなか便利そうなツールだ。

使い方

Kali Linuxにはデフォルトで入っているので、コマンドラインからwpscanと叩けば良い。引数無しで実行すると使い方のヘルプが表示される。ここでは代表的な使い方を順に見てみる。以下の例では、最新版のWordPressを使ってしまうとつまらないので、少し古い WordPress 3.3 を利用しています。

オンラインスキャン

まずはおもむろにノーマルな(?)オンラインスキャンをおこなってみる。このモードは単純に外から見える部分をアクセスして、プラグインなどに脆弱性が無いかを診断してくれる。--url オプションに、宛先URLを指定すれば良い。

root@kali:~# wpscan --url "http://10.211.55.18/wordpress/"
____________________________________________________
 __          _______   _____
 \ \        / /  __ \ / ____|
  \ \  /\  / /| |__) | (___   ___  __ _ _ __
   \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
    \  /\  /  | |     ____) | (__| (_| | | | |
     \/  \/   |_|    |_____/ \___|\__,_|_| |_| v2.1rNA

    WordPress Security Scanner by the WPScan Team
 Sponsored by the RandomStorm Open Source Initiative
_____________________________________________________

| URL: http://10.211.55.18/wordpress/
| Started on Mon Aug 19 22:50:43 2013

[!] The WordPress 'http://10.211.55.18/wordpress/readme.html' file exists
[!] Full Path Disclosure (FPD) in 'http://10.211.55.18/wordpress/wp-includes/rss-functions.php'
[+] XML-RPC Interface available under http://10.211.55.18/wordpress/xmlrpc.php
[+] WordPress version 3.3 identified from meta generator

[!] We have identified 4 vulnerabilities from the version number :
 |
 | * Title: Reflected Cross-Site Scripting in WordPress 3.3
 | * Reference: http://oldmanlab.blogspot.com/2012/01/wordpress-33-xss-vulnerability.html
 |
 | * Title: XSS vulnerability in swfupload in WordPress
 | * Reference: http://seclists.org/fulldisclosure/2012/Nov/51
 |
 | * Title: XMLRPC Pingback API Internal/External Port Scanning
 | * Reference: https://github.com/FireFart/WordpressPingbackPortScanner
 |
 | * Title: WordPress XMLRPC pingback additional issues
 | * Reference: http://lab.onsec.ru/2013/01/wordpress-xmlrpc-pingback-additional.html

[+] The WordPress theme in use is twentyeleven v1.3

 | Name: twentyeleven v1.3
 | Location: http://10.211.55.18/wordpress/wp-content/themes/twentyeleven/
 | Readme: http://10.211.55.18/wordpress/wp-content/themes/twentyeleven/readme.txt

[+] Enumerating plugins from passive detection ...
No plugins found :(

[+] Finished at Mon Aug 19 22:50:48 2013
[+] Elapsed time: 00:00:04

見ての通り、脆弱性を検知しご丁寧にその解説URL(モノによってはそのExploitコードも^^;)まで紹介してくれる。こりゃー便利だ。また、wp-includes/rss-functions.php というファイルを脆弱性として診断している。このスクリプトはデフォルトそのままだとエラーになるので、以下のようにPHPのエラーが出てDocumentRootの物理パスが漏洩してしまうようだ。

また、このスキャンの際のアクセスログを見ていると、以下のようにDB設定を行うwp-config.phpについてありがちなバックアップファイルを探してくれている。

10.211.55.20 - - [19/Aug/2013:22:50:43 +0900] "GET /wordpress/wp-config.php.save HTTP/1.1" 404 226
10.211.55.20 - - [19/Aug/2013:22:50:43 +0900] "GET /wordpress/wp-config.php.swp HTTP/1.1" 404 225
10.211.55.20 - - [19/Aug/2013:22:50:43 +0900] "GET /wordpress/wp-config.php~ HTTP/1.1" 404 222
10.211.55.20 - - [19/Aug/2013:22:50:44 +0900] "GET /wordpress/wp-config.php.swo HTTP/1.1" 404 225
10.211.55.20 - - [19/Aug/2013:22:50:44 +0900] "GET /wordpress/wp-config.php_bak HTTP/1.1" 404 225
10.211.55.20 - - [19/Aug/2013:22:50:44 +0900] "GET /wordpress/wp-config.bak HTTP/1.1" 404 221
10.211.55.20 - - [19/Aug/2013:22:50:44 +0900] "GET /wordpress/wp-config.php.bak HTTP/1.1" 404 225
10.211.55.20 - - [19/Aug/2013:22:50:44 +0900] "GET /wordpress/wp-config.save HTTP/1.1" 404 222
10.211.55.20 - - [19/Aug/2013:22:50:45 +0900] "GET /wordpress/wp-config.old HTTP/1.1" 404 221
10.211.55.20 - - [19/Aug/2013:22:50:45 +0900] "GET /wordpress/wp-config.php.old HTTP/1.1" 404 225
10.211.55.20 - - [19/Aug/2013:22:50:45 +0900] "GET /wordpress/wp-config.php.orig HTTP/1.1" 404 226
10.211.55.20 - - [19/Aug/2013:22:50:46 +0900] "GET /wordpress/wp-config.orig HTTP/1.1" 404 222
10.211.55.20 - - [19/Aug/2013:22:50:46 +0900] "GET /wordpress/wp-config.php.original HTTP/1.1" 404 230
10.211.55.20 - - [19/Aug/2013:22:50:46 +0900] "GET /wordpress/wp-config.original HTTP/1.1" 404 226
10.211.55.20 - - [19/Aug/2013:22:50:46 +0900] "GET /wordpress/wp-config.txt HTTP/1.1" 404 221

便利だなー。

ユーザ一覧表示モード

続いて、Enumerate usersモードというのを使ってみる。これはWordPressに設定しているユーザ一覧を表示してくれる。

root@kali:~# wpscan --url "http://10.211.55.18/wordpress/" --enumerate u
(前半出力は同じなので省略)
[+] Enumerating usernames ...
[+] We found the following 3 user/s :
    +----+----------+----------+
    | Id | Login    | Name     |
    +----+----------+----------+
    | 1  | admin    | admin    |
    | 2  | guest    | guest    |
    | 3  | viewtest | viewtest |
    +----+----------+----------+

[+] Finished at Mon Aug 19 22:55:50 2013
[+] Elapsed time: 00:00:08

うへー、なぜログインIDが分かっちゃうんだろ!? このカギは、アクセスログを見てみると分かる。このEnumerate usersモードでアクセスした際のApacheアクセスログは以下のようになっている。

10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=10 HTTP/1.1" 404 5810
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=8 HTTP/1.1" 404 5811
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=4 HTTP/1.1" 404 5808
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=5 HTTP/1.1" 404 5808
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=9 HTTP/1.1" 404 5811
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=3 HTTP/1.1" 200 7203
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=7 HTTP/1.1" 404 5808
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=6 HTTP/1.1" 404 5812
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=2 HTTP/1.1" 200 10428
10.211.55.20 - - [19/Aug/2013:22:55:45 +0900] "GET /wordpress/?author=1 HTTP/1.1" 200 8494

WordPressでは、ユーザのログインIDには数値のインデックスが付いている。そして "?author=1" の形でアクセスすると、そのインデックス番号のユーザが作成した記事が見られるようになっている。

このユーザごとのまとめページの「作成者」は、デフォルトではログインIDが表示されてしまう。いったんログインIDを取得すれば、あとはそこからブルートフォースアタックがやってくるという寸法である。

これを防ぐためには、ログインIDと表示される名前を別にすれば良い。表示される名前(Display Name,あるいはニックネーム)は管理画面のユーザ設定から変更可能である。

ここで設定できる「ニックネーム」を変えると、外から見える作成者の名前も変更される。ログインIDを推察されないためにも、必ず変えておいた方がいいだろう。この例では、guestというログインIDについて、ニックネームとしてguest-nicknameという値を設定している。

なお本来ならば、そもそもユーザを新規追加するときにニックネームを入れさせて欲しいのだが、何故かWordPressではそれはできない。新規ユーザ作成画面に、ニックネームを入力する項目が無いのだ。そのためまずユーザ新規作成を完了してから、改めて設定画面を開き直してニックネームを設定……としないといけない。ちょっと不親切、というか意味不明である。

と、ここまで書いておいてちゃぶ台をひっくり返すが、実はニックネームを付けていてもスキャンをすると元のIDは取れてしまう。

[+] Enumerating usernames ...
[+] We found the following 3 user/s :
    +----+----------+----------------+
    | Id | Login    | Name           |
    +----+----------+----------------+
    | 1  | admin    | admin          |
    | 2  | guest    | guest-nickname |
    | 3  | viewtest | viewtest       |
    +----+----------+----------------+

むむむ、なぜ分かっちゃうんだろう? guestのニックネームはguest-nicknameにしたから、もう元のログインIDは出ていないはずだけど……。このカラクリは、結局よく分からなかった。

ちなみに、記事をひとつも投稿していないユーザの記事一覧ページは 200 OK で記事が無いと言われ、存在しないユーザの場合は 404 Not Found で記事が無いと言われるため、たとえ投稿がゼロでもユーザが存在するかどうかの判別は可能である。


と、なんだか中途半端ですがこれでおしまい。

追記

どこからログインIDを取得しているか分かったので追記しました。
http://d.hatena.ne.jp/ozuma/20130830/1377868474