Or, “I’m Sorry, You Said You’re from Where Again?”
Fortunately, the application used in that particular demonstration was not checking the Referer header. Our malicious payload worked even though the Referer was wildly incorrect.
It turns out that I lied to you dear readers—not intentionally of course.
But let’s backup a second. What is this Referer header, and why do I keep misspelling it?
The Referer header is set by your browser and sent to the server when you request a page. The value of this header is the URL of the previous page that linked to the newly requested page. It is where you came from, essentially.
And Referer is misspelled because it is misspelled in the actual RFC itself back in 1996—that is totally not my fault. Let’s see what this looks like in practice.
When the user clicks to visit the Archives section for December 2019, the actual request sent by their browser sets the Referer to the location from which they came. In this case, the Referer is set to http://192.168.78.157.
Now that we are on the Archive page, if we follow a link on that page, our Referer will be set to the Archive page.
And once we have clicked on the Who Wore it Best? Post, we see the request has the Archive page set as the Referer.
So why would we, as attackers, have any interest in controlling the Referer value? Let’s look at an example from the weaponized XSS webinar.
Before we run that exploit, let’s look at what a normal request to add a new administrator looks like. Below is the form the administrator fills out to add a new user.
When this form is filled out with the new user information and submitted, the request made has the Referer set to http://192.168.78.157/wp-admin/user-new.php, which is the location of the form.
This incorrect Referer value is highly suspicious, because there is no reason that a new user add action should be coming from the blog post preview page.
Fortunately, in our demonstration application, WordPress is not checking the Referer values. But a recent discussion with a friend on this very topic revolved around an application that was using checks against the Referer value as a security control. And the code example below helped him bypass that security control.
But the browser will not let us do this:
We could attempt to directly set window.document.referrer, but this does not work either.
Fortunately, this incredibly simple trick does it:
The result of changing the history entry before sending the request results in a modified Referer value:
Before we change the user’s URL, let’s grab a copy of the current location and save it. That way, we can restore the URL when we are done with our shenanigans. Let’s print out some values to the console to see what we need to store in order to fix the URL when we are done.
Looking at the values printed out at the console reveals that we want the pathname and the search values to be saved if we are going to properly restore the URL when our attack is complete. Alternatively, you could regex the href property as well.
The code below grabs the current URL, changes it to what we need it to be for our desired Referer value, and then changes it back after we have added our new administrator. The user will never notice the URL change.
The fruits of our efforts give us the Referer we desire:
And the URL switches back instantaneously before the user can notice:
If you are still with me, thank you for allowing me to clear up errors in some of my previous blog posts regarding the ability to control the Referer value. If you wish to know more about the malicious payloads used in this post’s demonstration, please see my previous blog post and webinar on weaponizing XSS payloads:
Code Samples on GitHub: https://github.com/hoodoer/WP-XSS-Admin-Funcs
Code Example: https://gist.github.com/hoodoer/c4eb12b99d5902119fb30e8343b5b228