Ticket #4690 (closed defect: fixed)

Opened 10 months ago

Last modified 9 months ago

Wordpress options.php SQL Injection Vulnerability

Reported by: BenjaminFlesch Assigned to: Nazgul
Priority: high Milestone: 2.0.11
Component: Security Version: 2.2.1
Severity: major Keywords: has-patch commit
Cc:

Description

Read here http://mybeni.rootzilla.de/mybeNi/2007/wordpress_zeroday_vulnerability_roundhouse_kick_and_why_i_nearly_wrote_the_first_blog_worm/ beginning from the second point, in short:

in options.php the parameter page_options isnt filtered, patch:

case 'update':

$any_changed = 0;

check_admin_referer('update-options');

* if ( preg_match("/['\"<>]/", $_POSTpage_options?) ) * wp_die(('Cheatin&#8217; uh?'));

add the lines marked with a star in options.php.

Additionally, because of this Persistant XSS and information disclosure by opening options.php directly in the browser may occur. Better stop the database dump.

Attachments

4690.diff (0.5 kB) - added by Nazgul on 07/31/07 21:45:09.
4690.002.diff (1.6 kB) - added by markjaquith on 08/01/07 18:10:07.
Patches to update_option/add_option

Change History

07/31/07 21:34:37 changed by Nazgul

  • keywords set to needs-patch.
  • priority changed from highest omg bbq to high.
  • severity changed from critical to major.
  • milestone set to 2.3 (trunk).

First, there is a nonce protecting that page, so it can't be exploited remotely. Second, you need the "manage_options" capability which by default is only given to Administrators.

Administrators can do all sorts of "bad things" to their own blog by design. It should be fixed asap, but isn't critical in my opinion.

07/31/07 21:45:09 changed by Nazgul

  • attachment 4690.diff added.

07/31/07 21:46:55 changed by Nazgul

  • keywords changed from needs-patch to has-patch needs-testing.
  • owner changed from anonymous to Nazgul.
  • status changed from new to assigned.

Patch adds the missing $wpdb->escapes, which should fix this issue.

It could use some extensive testing for regression bugs though.

07/31/07 22:11:18 changed by BenjaminFlesch

Okay I know, but XSS flaws are existing everywhere and this can be used for persistant XSS. Append ' OR '"><script>alert(1)</script>'='"><script>alert(1)</script> to the page_options value in one of the options files (e.g. options-privacy.php) via WebDeveloper? Toolbar and submit. Then, visit /options.php which dumps the whole database without output validation -> Persistant XSS flaws. Plus the step from XSS (Client/Webpage manipulation) to SQLInjection (Database Manipulation) is taken. This makes attacks like adding users much easier because the take less time the authenticated Admin needs to stay on the attacker's page. --beni

08/01/07 17:25:05 changed by markjaquith

Nazgul, we can't use that fix now (although it is planned for 2.4) because it will break a lot of things. For now, we have to do our escaping outside of those functions.

08/01/07 18:10:07 changed by markjaquith

  • attachment 4690.002.diff added.

Patches to update_option/add_option

08/01/07 18:12:21 changed by markjaquith

Try that patch on for size. The issue here is that while add_option() and update_option() expect the option name to be unescaped, get_option() expects it to be pre-escaped. So we need to create a safe version of the option name to use when add/update_option call get_option().

This is seriously messed up, and will be fixed properly in 2.4 (by making ALL FUNCTIONS expect unescaped data).

08/01/07 18:42:23 changed by Nazgul

New patch looks good to me.

08/01/07 19:13:19 changed by markjaquith

  • keywords changed from has-patch needs-testing to has-patch commit.
  • milestone changed from 2.3 (trunk) to 2.0.11.

Targeting all three branches here.

08/01/07 19:14:10 changed by markjaquith

  • status changed from assigned to closed.
  • resolution set to fixed.

(In [5829]) add_option()/update_option() should pass the option name to get_option() pre-escaped. fixes #4690 for trunk

08/01/07 19:14:28 changed by markjaquith

(In [5830]) add_option()/update_option() should pass the option name to get_option() pre-escaped. fixes #4690 for 2.2.x

08/01/07 19:14:40 changed by markjaquith

(In [5831]) add_option()/update_option() should pass the option name to get_option() pre-escaped. fixes #4690 for 2.0.x