JustPaste.it

Хакер - Рут в два клика. Разбираем опасную уязвимость в macOS High Sierra

nopaywall

https://t.me/nopaywall

Буквально на днях главной новостью инфосека была опасная брешь в macOS 10.13.1, благодаря которой любой пользователь мог завладеть правами рута всего в несколько кликов. Мы разберем, почему так произошло и как работает уязвимость.
 

Эксплоит

Этот эксплоит настолько банален и прост, что для начала нам не понадобится даже тестовый стенд.

Чтобы стать суперпользователем, достаточно ввести логин root и любой пароль. После нажатия кнопки «Войти» окошко авторизации, конечно, заерзает и сообщит, что пароль неверен. Но теперь достаточно проделать ту же процедуру еще раз, и ты — рут. Да! Вот так все просто. High Sierra. High Security.

 

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

Простой способ решения проблем Простой способ решения проблем

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

 

Стенд

А вот сейчас и время для поднятия стенда. Так как я нищеброд и «мака» у меня отродясь не было, то буду использовать вариант для бедных — виртуалку VMware с macOS. Чтобы «просто побаловаться», достаточно будет и бесплатного VMware Player, который можно загрузить с официального сайта компании.

Далее нужно скачать образ готовой системы, например с сайтов, которые нельзя называть, — я думаю, ты знаешь, о чем идет речь. Перед тем как запускать виртуальную машину, примени патч VMware Unlocker. Он открывает возможность для запуска macOS.

Рекомендую установить отладчик lldb для путешествий по недрам системы. Просто набери в консоли lldb, и система сама предложит тебе варианты установки приложения.

Вооружаемся отладчиком lldb Вооружаемся отладчиком lldb

Чтобы отладка прошла без проблем, нам еще понадобится отключить SIP (System Integrity Protection). Для этого перед загрузкой системы держи сочетание клавиш Command + R (если у тебя виндовая клавиатура, то Win + R сработает аналогично) до тех пор, пока не увидишь логотип Apple. После этого система загрузится в Recovery Mode. Теперь запускай терминал и пиши в консоли

csrutil disable

Результатом должно быть сообщение, что SIP отключен. Перезагружай машину в нормальном режиме.

Отключение System Integrity Protection необходимо, чтобы иметь возможность отладки системных приложений Отключение System Integrity Protection необходимо, чтобы иметь возможность отладки системных приложений

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

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

Уязвимая версия macOS High Sierra 10.13.1, работающая под VMware Уязвимая версия macOS High Sierra 10.13.1, работающая под VMware
 

Детали уязвимости

Когда атакующий попытается залогиниться от пользователя, который на данный момент не включен (как root, например), то система услужливо создаст аккаунт с тем паролем, что ты укажешь в поле «Пароль» (например, пустой, почему нет). То есть окошко логина по совместительству служит окном установки пароля — очень удобно. Так как аккаунт был изначально не активирован, результат «логина» будет неудачным и потребуется вторая попытка авторизации, которая уже и станет успешной.

Теперь о том, как все это выглядит на более низком уровне. Давай найдем любое место, где можно указать логин и пароль пользователя. Самый простой вариант — это открыть настройки пользователей и нажать на символ замка для внесения изменений. Тут же выскочит окошко с требованием ввести кредсы. Вбиваем в качестве имени пользователя root, а в качестве пароля что угодно.

Пользователь root присутствует во всех UNIX-подобных системах, и macOS не исключение. Только по умолчанию этот пользователь отключен. Но в наших силах его оживить!

Root-пользователь имеется и в macOS Root-пользователь имеется и в macOS

Нажимаем на «Снять защиту» и приступаем к увлекательному отладочному пути, который начинается с демона opendirectoryd (/usr/libexec/opendirectoryd).

Присоединяемся к процессу, который отвечает за авторизацию, при помощи отладчика lldb Присоединяемся к процессу, который отвечает за авторизацию, при помощи отладчика lldb

Это он перехватывает попытку авторизации пользователя в системе.

Брейк-пойнт перед вызовом функции проверки пароля Брейк-пойнт перед вызовом функции проверки пароля

Демон вызывает метод odm_RecordVerifyPassword, который реализован в бандле PlistFile. В macOS есть такое понятие, как bundle (бандл). Бандл представляет собой псевдофайл особой структуры. По сути это папка, которая в графическом интерфейсе отображается как один файл. В частности, приложения — это бандлы. Бандл PlistFile находится в /System/Library/OpenDirectory/Modules/PlistFile.bundle и подгружается в opendirectoryd.

Бандл PlistFile — это директория со специальной структурой Бандл PlistFile — это директория со специальной структурой

Теперь можно загрузить бинарник /System/Library/OpenDirectory/Modules/PlistFile.bundle/Contents/MacOS/PlistFileв IDA и немного подизассемблировать.

Выполнение метода odm_RecordVerifyPassword начинается с вызова функции без названия (в моем случае это sub_804C) для чтения данных о том юзере, за которого мы пытаемся авторизоваться.

Если аккаунт активен, то функция успешно получает метаданные о нем. Их можно посмотреть, используя консольную команду dscl.

dscl . -read /Users/<имя_юзера> Просмотр метаданных активированного пользователя через утилиту dscl Просмотр метаданных активированного пользователя через утилиту dscl

Или посмотреть напрямую: они хранятся в двоичных plist-файлах в директории /private/var/db/dslocal/nodes/Default/users/ в формате <имя_юзера>.plist. Поэтому демон и подгружает бандл PlistFile для чтения и парсинга информации из файлов такого типа.

Метаданные всех пользователей macOS High Sierra в формате plist-файлов Метаданные всех пользователей macOS High Sierra в формате plist-файлов

В первую очередь нас интересует параметр AuthenticationAuthority, который указывает тип аутентификации для выбранного пользователя. Для деактивированных аккаунтов (таких как root) этот параметр отсутствует. Поэтому результат работы метода будет некорректным.

Просмотр метаданных деактивированного пользователя root Просмотр метаданных деактивированного пользователя root

При проверке odm_RecordVerifyPassword вернет некорректный результат. Посмотрим на псевдокод условия, в котором выполняется сверка этих данных.

PlistFile.c
6303: if ( !v15 ) 6304: { 6305: v19 = odproplist_get_array(a8, kODAttributeTypePassword); 6306: if ( v19 || (v14 = CFSTR("passwd"), (v19 = odproplist_get_array(a8, CFSTR("passwd"))) != 0) ) 6307: { 6308: v14 = (const __CFString *)v19; 6309: if ( (unsigned __int8)od_verify_crypt_password(v54, v19, v56, &v57, &v59) ) [test al, al] 6310: { 6311: if ( qword_29AA0 != -1 ) 6312: dispatch_once(&qword_29AA0, &off_27928); 6313: v20 = qword_29A98; 6314: if ( (unsigned __int8)os_log_type_enabled(qword_29A98, 1LL) ) 6315: { 6316: LOWORD(v32) = 0; 6317: _os_log_impl(&dword_0, v20, 1LL, aFoundCryptPass, &v32, 2LL); 6318: v10 = v53; 6319: } 6320: goto LABEL_29; 6321: } 6322: } 6323: LABEL_30:

Здесь условие перейдет на ветку else. Далее выполнение плавно перетекает в вызов функции od_verify_crypt_password, чтобы сверить переданный пароль пользователя и тот, что хранится в системе. Ее параметры — это * и набранный нами пароль.

Параметры, которые передаются в функцию od_verify_crypt_password Параметры, которые передаются в функцию od_verify_crypt_password

Функция возвращает 1 в регистре al. Следующая инструкция как раз его проверяет (строка 6309), и выполнение программы продолжается.

Результат работы od_verify_crypt_password в регистре al Результат работы od_verify_crypt_password в регистре alДизассемблированный участок кода с вызовом функции od_verify_crypt_password Дизассемблированный участок кода с вызовом функции od_verify_crypt_password

Получается, после всех этих проверок система считает, что у пользователя имеется пароль и для его хранения используется устаревшая техника, а так как система заботится о нашей безопасности, то она любезно изменяет тип его хранения в системе. То есть обновляет на securetoken или shadowhash. Да, в логах так и запишется: «found crypt password in user-record — upgrading to shadowhash or securetoken».

Добавление в лог информации об обновлении пароля Добавление в лог информации об обновлении пароляИнформация в журнале о некорректном обращении к атрибутам пользователя и обновлении пароля Информация в журнале о некорректном обращении к атрибутам пользователя и обновлении пароля

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

Вызов функции обновления пароля пользователя Вызов функции обновления пароля пользователя

Теперь мы можем спокойно авторизоваться и гулять с правами суперпользователя. Изи мани.

 

Демонстрация уязвимости (видео)

 

 

 

Выводы

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

Такие экстренные обновления — редкость, и выпускают их только по случаю обнаружения особо опасных багов. В прошлый раз апдейт такого типа приходил в 2014 году — в связи с уязвимостью в ntpd.

Рассмотренный нами баг получил номер CVE-2017-13872 и описание «a logic error… in the validation of credentials».

В дополнение представители Apple извинились и пообещали навести порядок и избежать таких проколов в будущем. Но всего через пару дней вскрылась новая неприятность: оказалось, что пользователи, которые не успели обновить систему до версии 10.13.1 и обновили ее уже после выхода экстренного патча, снова получили уязвимость.

В общем, все это длится уже неприлично долго и наносит заметный ущерб репутации компании, особенно если учитывать, что это уже не первый баг в этом году. В сентябре обнаружилась другая нелепая ошибка, из-за которой при работе с томами APFS пароль выводился открытым текстом. Похоже, теперь в команде безопасности грядут большие кадровые перестановки. Но поможет ли это решить проблему системно?

Читайте ещё больше платных статей бесплатно: https://t.me/nopaywall