(Editor’s note: This post has been updated since publication.)
Since WordPress is such a popular website platform (a.k.a. Content Management System, or CMS), there’s a multitude of different ways to misconfigure it. Consequently, there’s also someone out on the Internet who will attempt to exploit every possible misconfiguration in your WordPress installation. This time on Server Logs Explained we’ll be looking at one such attempt, albeit a fairly basic one.
WordPress sites get random requests all the time for pages that should normally be off-limits to the outside world, which brings us to today’s log excerpt:
203.0.113.42 - - [19/Jun/2016:07:37:57 -0400] "GET /wp-admin/post-new.php HTTP/1.1" 302 5 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0"
This hardly borders on an attempted exploit, since it’s just a plain HTTP
GET request for the
post-new.php page. However, if you’re still getting familiar with WordPress’s file structure, it can be a good learning experience to examine some of the unexpected requests your server gets.
Call and Response
First, let’s see what happened next, since the server returned a
302 Found (moved temporarily) response code. A
302 response generally provides the client with an alternate URL it should try instead:
203.0.113.42 - - [19/Jun/2016:07:37:57 -0400] "GET /wp-login.php?redirect_to=http%3A%2F%2Fwww.example.com%2Fwp-admin%2Fpost-new.php&reauth=1 HTTP/1.1" 200 1307 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0"
In plain English, the server politely asked the client to try
wp-login.php instead, and the client followed the redirect.
This is exactly what’s supposed to happen, because
post-new.php is the admin page that allows a site author to create a new post. Like the other admin pages in the
/wp-admin/ directory, it should only be accessible to users who are logged in and have the permission to create new posts. If an unauthenticated user tries to access an admin page, WordPress is supposed to redirect them to the login page so that they can authenticate (or not).
Bonus Section: A Little Information About Query Strings
The most interesting part of this exchange is the request to
wp-login.php, so let’s examine that. Stripping away the extra information from the second log excerpt leaves us with the request the client made to
GET /wp-login.php?redirect_to=http%3A%2F%2Fwww.example.com%2Fwp-admin%2Fpost-new.php&reauth=1 HTTP/1.1
The first part,
GET, is the HTTP method used (as opposed to
POST, etc.). Check out Mozilla’s HTTP request methods documentation if you are curious about other methods defined in the HTTP standard. The last part,
HTTP/1.1, is the version of HTTP that was used between the client and the server, so we can skip that as well.
The middle part is the request the client made to
wp-login.php, and it includes an interesting query string. The query string begins with
? and looks like this:
Query strings are one way to allow data to be passed to a webpage. This is useful if your webpage is coded in a dynamic language, like PHP, and can accept input. This particular query string contains two pieces of data, separated by the
redirect_to, a string, and
reauth, a value.
The data contained in the request is highlighted in the following example:
Let’s look at each piece of data individually:
The URL in
redirect_to is where
wp-login.php will send the client to after it has successfully authenticated. If you examine the WordPress source code, you can locate the section in the
wp-login.php that handles the redirection logic.
If we clean up the URL by replacing the escaped characters with their human-readable counterparts, we can see what the full URL looks like:
In other words, after successfully authenticating, the client would have been redirected to
post-new.php, which was where it was trying to go in the first place.
ReAuth is a special WordPress feature that forces the client to re-authenticate no matter what. Normally, when you sign into your WordPress site (and you have cookies enabled in your browser), you’ll stay logged in to WordPress for a certain amount of time. This is because WordPress is able to store cookies locally in your browser that indicate that you’ve already authenticated properly and shouldn’t need to log in again. However, as a safety method, if WordPress fails to detect a proper login cookie, it redirects the client to
wp-login.php and forces it to re-authenticate and acquire new cookies by setting