2 سال پیش grain

بررسی باگ [Content Injection] در وردپرس 4.7.0 / 4.7.1

باسلام، همانطور که اطلاع دارید هفته گذشته وردپرس بدون اطلاع رسانی در آپدیت جدید خود یک آسیب پذیری DREAD Score 9 را برطرف کرد، این باگ مربوط به قسمت REST API Endpoint در نسخه 4.7.0/1 هست که قادر خواهید بود محتوا پست ها و پیج ها را ادیت یا محتوا تزریق کنید، باهم بررسی میکنیم این اتفاق چگونه رخ میده.

مشکل از جایی شروع میشود که در فایل زیر مسیر دهی ای برای request ها تعریف شده است که مقدار پارامتر پست آیدی را از کاربر دریافت کند :

./wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
مقدار پست آیدی به 2 صورت زیر قایل دریافت است :
/wp-json/wp/v2/posts/1452?id=1452
/wp-json/wp/v2/posts/1452
در حالت اول هکر به صورت زیر پارامتر پست آیدی را مقدار دهی میکند :
wp-json/wp/v2/posts/1452?id=14521َََََAA
سپس برای بررسی که کاربر اجازه دارد پست را آپدیت یا ادیت و .. بکند تابع update_item_permissions_check از کلاس WP_REST_Posts_Controller فراخوانی و اجرا خواهد شد :
public function update_item_permissions_check( $request ) {
    
        $post = $this->get_post( $request['id'] );
        $post_type = get_post_type_object( $this->post_type );

        if ( $post && ! $this->check_update_permission( $post ) ) {
            return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this post.' ), array( 'status' => rest_authorization_required_code() ) );
        }

        if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) {
            return new WP_Error( 'rest_cannot_edit_others', __( 'Sorry, you are not allowed to update posts as this user.' ), array( 'status' => rest_authorization_required_code() ) );
        }

        if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) ) {
            return new WP_Error( 'rest_cannot_assign_sticky', __( 'Sorry, you are not allowed to make posts sticky.' ), array( 'status' => rest_authorization_required_code() ) );
        }

        if ( ! $this->check_assign_terms_permission( $request ) ) {
            return new WP_Error( 'rest_cannot_assign_term', __( 'Sorry, you are not allowed to assign the provided terms.' ), array( 'status' => rest_authorization_required_code() ) );
        }

        return true;
    }  

کافیست ما شرط اول را bypass کنیم، در شرط اول مقدار پست آیدی فرستاده شده بررسی میشود تا همچین پستی وجود داشته باشد سپس در مرجله دوم دسترسی کاربر بررسی میشود، کافیست پست آیدی ما وجود نداشته باشد تا به مرحله دوم شرط نرسیم :
if ( $post && ! $this->check_update_permission( $post ) )  

زمانی که هکر مقدار پست آیدی : 1452AA را ارسال میکند (get_post مقدار false را برگشت میدهد) این شرط در مرحله اول false برگشت میخورد و به مرحله تایید هویت کاربر (check_update_permission در کلاس) نخواهیم رسید، سپس تابع update_item_permissions_check که برای بررسی دسترسی کاربر اجرا شده بود با مقدار true برگشت خواهد خورد، به همین سادگی تایید دسترسی byepass خواهد شد!

شاید حالا براتون سوال بشه پست آیدی 1452AA که وجود ندارد چه پستی را قرار هست آپدیت یا ادیت کنیم ؟! مقدار (1452) یک پست آیدی معتبر که در دیتابیس وجود دارد است سپس چند کارکتر به آن اضافه کردیم برای byepass کردن مرحله تایید دسترسی. حالا که دسترسی داریم تابع update_item اجرا خواهد شد در 2 خط اول این تابع مشاهده خواهید کرد :

public function update_item( $request ) {
        $id = (int) $request['id'];
        $post = get_post( $id );  
		....
}
در خط اول مقدار پست آیدی ما که (14521َََََAA) بود به (14521) تبدیل خواهد شد، چرا ؟ به دلیل اینکه تایپ int برای پست آیدی مشخص شده است و تمامی کارکتر ها به جز numberic ها از رشته حذف خواهد شد و به این صورت پست ما با آیدی 14521 آپدیت خواهد شد.

« برگشت

Powered by WHMCompleteSolution