Хакер - Рут в два клика. Разбираем опасную уязвимость в macOS High Sierra
nopaywall
Эксплоит
Этот эксплоит настолько банален и прост, что для начала нам не понадобится даже тестовый стенд.
Чтобы стать суперпользователем, достаточно ввести логин root и любой пароль. После нажатия кнопки «Войти» окошко авторизации, конечно, заерзает и сообщит, что пароль неверен. Но теперь достаточно проделать ту же процедуру еще раз, и ты — рут. Да! Вот так все просто. High Sierra. High Security.
Смешно сказать, но на форуме для разработчиков такой алгоритм однажды предлагали в качестве способа сброса забытого пароля и решения возникших проблем.
Простой способ решения проблемТеперь, когда ты все знаешь, пора разбираться, почему так вышло.
Стенд
А вот сейчас и время для поднятия стенда. Так как я нищеброд и «мака» у меня отродясь не было, то буду использовать вариант для бедных — виртуалку VMware с macOS. Чтобы «просто побаловаться», достаточно будет и бесплатного VMware Player, который можно загрузить с официального сайта компании.
Далее нужно скачать образ готовой системы, например с сайтов, которые нельзя называть, — я думаю, ты знаешь, о чем идет речь. Перед тем как запускать виртуальную машину, примени патч VMware Unlocker. Он открывает возможность для запуска macOS.
Рекомендую установить отладчик lldb для путешествий по недрам системы. Просто набери в консоли lldb
, и система сама предложит тебе варианты установки приложения.
Чтобы отладка прошла без проблем, нам еще понадобится отключить SIP (System Integrity Protection). Для этого перед загрузкой системы держи сочетание клавиш Command + R (если у тебя виндовая клавиатура, то Win + R сработает аналогично) до тех пор, пока не увидишь логотип Apple. После этого система загрузится в Recovery Mode. Теперь запускай терминал и пиши в консоли
csrutil disable
Результатом должно быть сообщение, что SIP отключен. Перезагружай машину в нормальном режиме.
Отключение System Integrity Protection необходимо, чтобы иметь возможность отладки системных приложенийНелишне будет и иметь под рукой IDA для потрошения внутренностей исполняемых файлов, отвечающих за авторизацию.
В общем, выдели виртуалке побольше оперативной памяти и запускай.
Уязвимая версия macOS High Sierra 10.13.1, работающая под VMwareДетали уязвимости
Когда атакующий попытается залогиниться от пользователя, который на данный момент не включен (как root, например), то система услужливо создаст аккаунт с тем паролем, что ты укажешь в поле «Пароль» (например, пустой, почему нет). То есть окошко логина по совместительству служит окном установки пароля — очень удобно. Так как аккаунт был изначально не активирован, результат «логина» будет неудачным и потребуется вторая попытка авторизации, которая уже и станет успешной.
Теперь о том, как все это выглядит на более низком уровне. Давай найдем любое место, где можно указать логин и пароль пользователя. Самый простой вариант — это открыть настройки пользователей и нажать на символ замка для внесения изменений. Тут же выскочит окошко с требованием ввести кредсы. Вбиваем в качестве имени пользователя root, а в качестве пароля что угодно.
Пользователь root присутствует во всех UNIX-подобных системах, и macOS не исключение. Только по умолчанию этот пользователь отключен. Но в наших силах его оживить!
Root-пользователь имеется и в macOSНажимаем на «Снять защиту» и приступаем к увлекательному отладочному пути, который начинается с демона opendirectoryd
(/usr/libexec/opendirectoryd
).
Это он перехватывает попытку авторизации пользователя в системе.
Брейк-пойнт перед вызовом функции проверки пароляДемон вызывает метод odm_RecordVerifyPassword
, который реализован в бандле PlistFile. В macOS есть такое понятие, как bundle (бандл). Бандл представляет собой псевдофайл особой структуры. По сути это папка, которая в графическом интерфейсе отображается как один файл. В частности, приложения — это бандлы. Бандл PlistFile находится в /System/Library/OpenDirectory/Modules/PlistFile.bundle
и подгружается в opendirectoryd
.
Теперь можно загрузить бинарник /System/Library/OpenDirectory/Modules/PlistFile.bundle/Contents/MacOS/PlistFile
в IDA и немного подизассемблировать.
Выполнение метода odm_RecordVerifyPassword
начинается с вызова функции без названия (в моем случае это sub_804C
) для чтения данных о том юзере, за которого мы пытаемся авторизоваться.
Если аккаунт активен, то функция успешно получает метаданные о нем. Их можно посмотреть, используя консольную команду dscl.
dscl . -read /Users/<имя_юзера>
Просмотр метаданных активированного пользователя через утилиту dsclИли посмотреть напрямую: они хранятся в двоичных plist-файлах в директории /private/var/db/dslocal/nodes/Default/users/
в формате <имя_юзера>.plist
. Поэтому демон и подгружает бандл PlistFile
для чтения и парсинга информации из файлов такого типа.
В первую очередь нас интересует параметр AuthenticationAuthority
, который указывает тип аутентификации для выбранного пользователя. Для деактивированных аккаунтов (таких как 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
, чтобы сверить переданный пароль пользователя и тот, что хранится в системе. Ее параметры — это *
и набранный нами пароль.
Функция возвращает 1 в регистре al. Следующая инструкция как раз его проверяет (строка 6309), и выполнение программы продолжается.
Результат работы od_verify_crypt_password в регистре al Дизассемблированный участок кода с вызовом функции 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