First, explain the background. wordpress user permissions are divided into subscribers, contributors, authors, editors and administrators. Permission the lowest is the Subscriber, the Subscriber only Subscribe to the articles of permissions, wordpress open registration the default registration of the user is the Subscriber. Many domestic well-known sites such as Freebuf, the user registration status is“Subscribe”. We first see a mention of the right to exploit, by this mention the right vulnerability, we as a subscriber, you can override the database inserted into an article. Wordpress to check the user permissions is to call the current_user_can function, we see this function: ! Calls the has_cap method, follow-up ! Again follow the map_meta_cap function: ! It can be seen, this function is really to check the permissions. The error code in the check for’edit_post’and’edit_page’part: ! Visible, where when the$post does not exist when, directly break out of the switch logic, all subsequent checks of the code are not executed. $post is to edit the article ID, that is, if I want to edit an article does not exist article, where permissions are not checked directly returned. Under normal circumstances there is no problem, because there is no article nor the Edit statement. We then see the background editing articles part:/wp-admin/post.php ! Here first gets the$_GET[‘post’], not found only to get$_POST[‘post_ID’], that is, it can be said at this time the$post_ID from the GET. But behind us call the current_user_can function when incoming post_ID is from the POST: ! Here is a logical question, when we in the GET parameters passed in the correct postid this in get_post time does not produce an error, while in the POST parameters of the incoming one does not exist postid, then it is possible to bypass the check the edit_post permission step. But this logic is temporarily unable to cause serious harm, as actually editing an article code in edit_post function, and this function takes the post_ID from$_POST it. 0x02 obtain _wpnonce to bypass CSRF Defense wordpress for CSRF vulnerabilities defensive measures is to use the _wpnonce is a token, and its token is very strict, different operations have different token. Such as we have here, if you want to call the edit_post function, need to go through the following logic: ! check_admin_referer is to check _wpnonce function, when$post_type==’postajaxpost’, in this case _wpnonce name is“add-postajaxpost” in. Then how to obtain the name of”add-postajaxpost”_wpnonce? See the above point location: ! There's a post-quickdraft-save operation. This operation is used to temporarily store the draft, as long as the user to access this operation, it will be in the database post table to insert a status for auto-draft of new articles. As on the picture out of step, because we don't know the name of”add-post”_wpnonce so into wp_dashboard_quick_press function, follow up: ! See on the figure, very fortunately, in this function of wordpress actually own put this _wpnonce output in the form. So, as long as we have access to a post-quickdraft-save, you can get add-post. _wpnonce, thereby bypassing the check_admin_referer function. 0x03 competition vulnerability to cause the logic vulnerability This section is actually this mention of the right hole of the true core, in we got _wpnonce into the edit_post function. Our purpose is to update an article, but just 0x01 said, If you want to bypass the permissions check function, need to pass a“does not exist,”the article id. So even if you can perform the update, we cannot modify the already existing article? Here in fact relates to a competition result of logical loopholes. See the edit_post function code: ! The above two figures should be very intuitive. In the 0x01 that to current_user_can be bypassed later, to the final execution of the update statement in the middle, this piece of code The execution time is vacuum. For example, our incoming tax_input=1,2,3,4...1 0 0 0 0, Then in fact that query would execute 1 0 0 0 0 times, which is the need to perform for a long time. In my own virtual machine to test on, Do 1 0 0 0 0 This statement, probably need 5 to 1 0 seconds to about It is assumed that in this period of time, there is a new insertion of the article, then we before that“does not exist”, id, not just may be there can be? only need to put the id set to the latest post id+1 be? But there is a problem is, how do we in this period of time inserted into a new article? Because at 0x02 in order to obtain _wpnonce, has been performed over the post-quickdraft-save. Perform a post-quickdraft-save in the database the insertion of a post status for auto-draft of articles, but each user will only insert an article.