ここ最近巷を賑わせているWordPress4.7で投稿を書き換えられる脆弱性。
そういえばWordPres4.6系+WP REST apiの段階では話題にならなかったなぁと思ってソースを掘ってみた。
そもそもどんな脆弱性?
ニュースをにぎわせてるので小話にたどり着く方はだいたいご存知かとは思いますので詳しくは省略しますが、認証ロジックに不備があり、認証を回避して記事を更新できてしまう脆弱性です。
詳しく知りたい方は徳丸先生の記事をどうぞ。
WordPress 4.7.1 の権限昇格脆弱性について検証した
Pluginの実装を追う
今回Coreに取り込まれたWP REST APIはGitHubでソースが公開されているため、tagを順番に追ってみると、2.0-bate13の時点ではまだwp coreのget_postをコールしていることが分かります。
【GitHub】WP REST API
以下抜粋
public function update_item_permissions_check( $request ) {
$post = get_post( $request['id'] );
$post_type = get_post_type_object( $this->post_type );
環境作ってみた
手元の環境にWordPress4.6+WP REST API(2.0-bate13)の環境を作成し実行してみると・・・
{"id":"1b","title":"change title","content":"hogehoge"}
{
"code": "rest_cannot_edit",
"message": "Sorry, you are not allowed to update this post.",
"data": {
"status": 401
}
}
実はこの段階では脆弱性はなかった事が分かった。
挙動を確認すると、IDに文字列を付与していても、記事を取得できている。
ソースを追う
次に、WordPress本体のソースを追ってみる。
【GitHub】WordPress
WP4.6とWP4.7を比較すると、原因が分かった。
public static function get_instance( $post_id ) {
global $wpdb;
$post_id = (int) $post_id;
if ( ! $post_id )
return false;
$_post = wp_cache_get( $post_id, 'posts' );
public static function get_instance( $post_id ) {
global $wpdb;
if ( ! is_numeric( $post_id ) || $post_id != floor( $post_id ) || ! $post_id ) {
return false;
}
$post_id = (int) $post_id;
$_post = wp_cache_get( $post_id, 'posts' );
ソースを見てわかる通り、4.6系まではCore側で記事を取得する際にpost_idの方チェックが無かった。
そのため、仮に文字列付きのIDが送られてきていても、intにキャストした際に落ちていたので、記事が取得できていた模様。
終わりに
プラグインはそのまま持ってきたけど、Coreの仕様が変わっていたためイレギュラーケースに対応しきれませんでした。という状況でしょうか。
自分が担当であっても見落としてしまいそうなレベルですね。
何となく事情を察しないわけでもないのであれですが、影響範囲がこうなるともう乾いた笑いしか出てきません。
WordPressサイトの改ざん被害は150万件超に 「最悪級の脆弱性」
セキュリティ担当としてはこういった事象は経験として学ばせていただくとともに、社内のセキュリティ投資の為の説得材料として積極的に利用させていただきたいと思います。