There's been some talk, lately, about the "friendly" AJAX worm coded by Benjamin Flesch as a proof of concept both leveraging and patching 3 XSS vulnerabilities he found in WordPress 2.2.x.

Allowing a foreign program to run on your system without a chance to scrutinize its source code is not a great idea (I know, many Microsoft customers could not agree).

I'm very new to WordPress (I started playing with it 3 days ago), and I've heard many nightmarish stories about its security, so I'd really love to patch everything I can before I start my own auditing.

On the other hand, I fully subscribe to .mario's concerns -- w/o code review no usage -- and looks like Symantec agrees about this beastie being not harmless, despite its good intentions.

Hence I decided to grab the snail by its tail and forced it to spit its 3 "little secrets".
Here you'll find the patches in a concise and readable form, and you can decide if manually applying them or not.

--- options._unpatched 2007-08-02 08:01:50.000000000 +0200 +++ options.php 2007-08-02 08:05:21.000000000 +0200 @@ -86,8 +86,9 @@ case 'update': $any_changed = 0; check_admin_referer('update-options'); + if (preg_match("/['\"<>]/", $_POST['page_options'])) wp_die(__('Cheatin, uh?')); if ( !$_POST['page_options'] ) { foreach ( (array) $_POST as $key => $value) { if ( !in_array($key, array('_wpnonce', '_wp_http_referer')) )

I'm not 100% sure about the full effectiveness of this one, since it's blacklist based (blocking just quotes and acute brackets), and therefore potentially open to some filtering evasion techniques. But as I said, I'm still far from knowing the intricacies of WordPress code, so maybe it does suffice. Anyway, better than nothing -- you can refine it later.

The remaining two are pretty straight-forward:

--- upload._unpatched 2007-08-02 07:53:45.000000000 +0200 +++ upload.php 2007-08-02 08:15:13.000000000 +0200 @@ -11,8 +11,10 @@ // IDs should be integers $ID = (int) $ID; $post_id = (int) $post_id; +$style = preg_replace('/\W/', '', $style); + // Require an ID for the edit screen if ( $action == 'edit' && !$ID ) wp_die(__("You are not allowed to be here")); --- link-import._unpatched 2007-08-02 08:02:20.000000000 +0200 +++ link-import.php 2007-08-02 08:13:24.000000000 +0200 @@ -72,9 +72,9 @@ <div class="wrap"> <h2><?php _e('Importing...') ?></h2> <?php - $cat_id = $_POST['cat_id']; + $cat_id = preg_replace('/\D/', '',$_POST['cat_id']); if ( $cat_id == '' || $cat_id == 0 ) $cat_id = 1; $opml_url = $_POST['opml_url'];

OK, another lesson I learned today is that publishing patches (and code, in general) with WordPress can be a true pain... Now I understand why bloggers deliver them as worms.
For the curious, here's the source code of the original worm and how to grab it the safe way.

Thanks to Benjamin for all the fis... patches, and happy hacking to everybody.

5 Responses to “Patching WordPress, WormLess”

  1. #1 .mario says:


    Thanks for the code. I planed to check that out this weekend and that just saved lots of time.
    Btw - the source code link seems broken...


  2. #2 Giorgio says:

    .mario, thank you very much for reporting the broken link!
    I'm such a WordPress n00b, and I didn't know that attachments inherit publishing status of their parent post (that's fine), but also that's quite easy to create orphaned attachment by error, like in this case.
    Being logged in as the author the link worked perfectly, while it was missing for everyone else.
    To repair it, I manually set the


    field of the attachment record.
    Maybe there's an UI way to bind an orphaned attachment to a certain already published post, and I'm grateful for any enlightenment in my perilous blogging journey.

  3. #3 .mario says:

    cool, thanks!

  4. #4 Jammer says:

    preg_replace is rather proces costly just do a typecast to INTeger
    $cat_id = (INT) $_POST['cat_id'];
    (same as the post_id is parsed)

  5. #5 Giorgio says:

    I agree with you, but these patches are extracted more or less verbatim from the worm.
    At any rate, they're superseded by the official fixes released with WP 2.2.2 which, incidentally, did prefer your typecast technique :)

Bad Behavior has blocked 725 access attempts in the last 7 days.