Lo-Fi Memories

酒と音楽と技術

WordPressのREST APIにおける脆弱性をDockerを使って検証してみる

2017年2月7日にIPAからWordPressにおける脆弱性が発表された。

www.ipa.go.jp

割と簡単にポストを書き換えることができるっぽい。Wordpressってセキュリティホール多そうなイメージあるけど、ここまででかいやつは初めて?

検証している方がいたので、こちらのサイトを参考に自分もやってみる。

blog.tokumaru.org

そこらへんに転がってるWordPressによるサイトでやっちまうと不正アクセスとかなんとかでお縄になってしまうので、もちろんローカルホストにて行う。サクッと環境を作るべく今回はDockerで。

環境

macOS 10.12.2

WordPressの環境を立てる

Dockerが入ってなければインストールする。DockerはLinux系でないと動かないので、MacだとDocker for Macとかを入れVM上にて行う。

docker-machineを起動した後、適当な場所でディレクトリを作る。

mkdir wordpress
cd wordpress

Docker公式に空のWordpressを立ち上げるdocker-compose.ymlがあるので、wordpressのバージョンを4.7.0にしてwordpressディレクトリに保存。

Quickstart: Compose and WordPress - Docker

version: '2'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:4.7.0
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:


docker-composeにて立ち上げる

docker-compose up -d

起動できたか確認

docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
8378a4f3b730        wordpress:4.7.0     "docker-entrypoint.sh"   2 hours ago         Up 2 hours          0.0.0.0:8000->80/tcp     wordpress_wordpress_1
2af784067a28        mysql:5.7           "docker-entrypoint.sh"   2 hours ago         Up 2 hours          0.0.0.0:3306->3306/tcp   wordpress_db_1

あーいいっすねー。
ブラウザで確認する。VM上でやってる場合はIPが127.0.0.1localhostではなく、VMのIPなので

docker-machine ip

で得られたIPに8000ポートでアクセス。自分の環境だと192.168.99.100だったので

http://192.168.99.100:8000

にアクセス。長ったらしいIPは好きじゃなので

sudo vi /etc/hosts
#Docker
192.168.99.100 wp.docker

を追記して http://wp.docker:8000 でアクセスできるようにした。

アクセスするとWordpressインストール画面になるので、ログインID/PASSなど設定して完了。
サンプルに記事もダミーで作る。

f:id:shalman:20170210143324p:plain

かっこいいウェッブサイトができました。一番上の記事を書き換えます。

Postmanのインストール

今回の脆弱性WordPressREST APIによるものなので、悪意のあるパラメータをくっつけて改ざんするというものらしいです。
POSTするならcurlでもいいのですが、僕はカールおじさんじゃないのでGUIでぽちぽちやりたいです。ということでChromeアプリのPostmanを使います。

chrome.google.com

アイコンがイカしてるね。デイリーポータルZくんみたい。
起動し、無料会員登録すると、メイン画面が出てくる。

f:id:shalman:20170210144635p:plain


上のURL入力するフォームに該当APIのエンドポイントを入力すると

f:id:shalman:20170210150027p:plain

JSONで帰ってくる。APIだもの。

実行

参考サイトにならって、叩くエンドポイントとフィールドを伏せておきます。

これをPOSTメソッドにプルダウンから切り替えて、BodyタブのForm-dataにパラメータを突っ込んでく。
パラメータはidと、改ざんしたいフィールドを入力。

idは記事番号に適当な文字をくっつけたもの(ex. id:4の記事を書き換える→4A)
Sendボタンをクリックして帰ってきたJSONを見て、ステータスコードが401とかではないことを確認。

サイトをリフレッシュすると

f:id:shalman:20170210150407p:plain

本文が書き換えられて危険なWebサイトになってしまいました。

脆弱性の原因

参考にしたサイトでわかりやすく解説されていました。こちらを確認されたし。
WordPress 4.7.1 の権限昇格脆弱性について検証した | 徳丸浩の日記

get_post関数のラッパーを作って、invalidなパラメータが入ったらエラーを吐くようにしたようです。

所感

そもそもWordPressってAPI提供してたんすね。

updateの認証はupdate_item_permissions_check関数が負ってるっぽいけど、最初にセッションから確認しないのが違和感あるなー。

get_current_user_id関数がちらほら見えるので他はやってるんだろうけど、このcheck関数はget_postがemptyでもcheckがtrueになるのでキモさある。こんなもんなのかなあ。あと、ブラックリスト的にエラーを投げてる(原則true)のは怖いってことがよくわかった。

どの関数が今回の責任なのかと考えると、認証周りが甘いからcheck関数かなと思ったけども、int型以外許してとりあえずemptyにしてたget_postが悪いことになるんだな。なるほど。

intキャストで末尾のStringが消えるのもトリックだった。知んかった。ほえー。