WordPressのREST APIにおける脆弱性をDockerを使って検証してみる
2017年2月7日にIPAからWordPressにおける脆弱性が発表された。
割と簡単にポストを書き換えることができるっぽい。Wordpressってセキュリティホール多そうなイメージあるけど、ここまででかいやつは初めて?
検証している方がいたので、こちらのサイトを参考に自分もやってみる。
そこらへんに転がってる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.1やlocalhostではなく、VMのIPなので
docker-machine ip
で得られたIPに8000ポートでアクセス。自分の環境だと192.168.99.100だったので
にアクセス。長ったらしいIPは好きじゃなので
sudo vi /etc/hosts
#Docker 192.168.99.100 wp.docker
を追記して http://wp.docker:8000 でアクセスできるようにした。
アクセスするとWordpressインストール画面になるので、ログインID/PASSなど設定して完了。
サンプルに記事もダミーで作る。
かっこいいウェッブサイトができました。一番上の記事を書き換えます。
Postmanのインストール
今回の脆弱性はWordPressのREST APIによるものなので、悪意のあるパラメータをくっつけて改ざんするというものらしいです。
POSTするならcurlでもいいのですが、僕はカールおじさんじゃないのでGUIでぽちぽちやりたいです。ということでChromeアプリのPostmanを使います。
アイコンがイカしてるね。デイリーポータルZくんみたい。
起動し、無料会員登録すると、メイン画面が出てくる。
上のURL入力するフォームに該当APIのエンドポイントを入力すると
実行
参考サイトにならって、叩くエンドポイントとフィールドを伏せておきます。
これをPOSTメソッドにプルダウンから切り替えて、BodyタブのForm-dataにパラメータを突っ込んでく。
パラメータはidと、改ざんしたいフィールドを入力。
idは記事番号に適当な文字をくっつけたもの(ex. id:4の記事を書き換える→4A)
Sendボタンをクリックして帰ってきたJSONを見て、ステータスコードが401とかではないことを確認。
サイトをリフレッシュすると
本文が書き換えられて危険なWebサイトになってしまいました。
脆弱性の原因
参考にしたサイトでわかりやすく解説されていました。こちらを確認されたし。
WordPress 4.7.1 の権限昇格脆弱性について検証した | 徳丸浩の日記
get_post関数のラッパーを作って、invalidなパラメータが入ったらエラーを吐くようにしたようです。
所感
updateの認証はupdate_item_permissions_check関数が負ってるっぽいけど、最初にセッションから確認しないのが違和感あるなー。
get_current_user_id関数がちらほら見えるので他はやってるんだろうけど、このcheck関数はget_postがemptyでもcheckがtrueになるのでキモさある。こんなもんなのかなあ。あと、ブラックリスト的にエラーを投げてる(原則true)のは怖いってことがよくわかった。
どの関数が今回の責任なのかと考えると、認証周りが甘いからcheck関数かなと思ったけども、int型以外許してとりあえずemptyにしてたget_postが悪いことになるんだな。なるほど。
intキャストで末尾のStringが消えるのもトリックだった。知んかった。ほえー。