Google's Project Zero откри как да заобиколи Knox Hypervisor на Samsung (поправено в януарския пакет)

В последната публикация в блога на Project Zero екипът е открил начин за заобикаляне на защитата на ядрото в реално време на Samsung, наречен Knox Hypervisor.

Екипът на Project Zero на Google провери редица експлойти, които позволяват да бъдат атакувани телефоните на Samsung, работещи с уж защитения пакет за сигурност Samsung Knox. Блогът отбелязва, че всички уязвимости са предадени на Samsung, който всъщност е пуснал корекции за тях в софтуерна актуализация през януари.


Заден план

Като част от софтуерния пакет за сигурност Samsung Knox, представен от Samsung, има част от софтуера, който се намира между приложенията на Android и ядрото, наречен Хипервизор. Това може да се използва като допълнителен слой за допълнителна защита на устройства с Android. Хипервайзорът Samsung Knox се нарича "Защита на ядрото в реално време" или накратко RKP, както ще го споменавам в останалата част от тази статия.

Ядрото се намира под RKP в софтуерния стек на Android, а приложенията, които се изпълняват на устройството, се намират отгоре. Идеята зад RKP е да осигури допълнителен слой сигурност за устройството, тъй като всички заявки (памет и други ресурси), направени от приложенията към ядрото трябва първо да преминат през Knox, който се опитва да открие дали дадено приложение прави нещо не трябва. RKP също така осигурява сигурност чрез неизвестност с допълнителен слой за скриване на чувствителна информация, която приложението може да използва, за да компрометира устройството.

Публикацията в блога навлиза доста дълбоко в това как работят паметта на Android, RKP и операционните системи като цяло, така че я съкратих и опростих, за да дам бърз преглед на това, което беше открито. Препоръчвам ви да прочетете цялата статия, ако имате време, тъй като е много поучителна.


Експлойт #1:

КАСЛР или Randomization на оформлението на адресното пространство на ядрото е процес на промяна на местоположението на кода на ядрото в паметта с произволна сума при зареждане. Всеки път, когато устройството се стартира, ядрото се зарежда в различно адресно пространство (област в паметта). Идеята е да се направи по-трудно намирането къде се намира кодът на ядрото, за да се атакува, защото след всяко зареждане кодът на ядрото се "измества" с произволно количество в паметта. Това звучи като страхотна стъпка за предотвратяване на бъдещи нападатели, но скорошни изследвания показа, че всъщност можете да победите това, без да изисквате софтуерна грешка или уязвимост, тъй като KASLR всъщност е много трудно да се приложи по стабилен начин срещу местни нападатели.

В случая със софтуера RKP възможността за заобикаляне на KASLR всъщност е по-проста от изследването, посочено по-горе. Паметта на всички устройства с android се използва от указатели и за да се защитят устройствата от атака, когато устройствата с android отпечатват или извеждат (независимо дали за екран или за архивиране за регистрационни файлове или отстраняване на грешки), препратките към указателите са анонимизирани, което прави невъзможно да се открие къде всъщност сочи указателят при четене на изход.

Мислете за указателите на паметта като уличен знак, който сочи към местоположение, и мислете за анонимизиране като замъгляване на това. Подобно на телевизията, анонимизирането се извършва след заснемането, Android също прилага това анонимизиране по време на изхода и само ако анонимизирането е конфигурирано правилно и авторът заявява че всяко устройство, с което [той] се е сблъсквал, е имало правилно конфигурирано анонимизиране на показалеца. Това може да звучи така, сякаш е много трудно да се разбие, но всичко, което трябва да направите, е да намерите един указател (помислете за уличен знак), който не е анонимизиран (замъглен) от разработчика на ядрото (внимавайте, това не е средният ви разработчик на приложения за Android), когато указателят е записан в регистрационните файлове или на друго място, напр. екран или a файл.

Така че, ако можете да намерите указател, който не е анонимизиран, тогава можете да изчислите случайното изместване на адреса на ядрото като разликата между двете. Интересното е, че авторът не можа да намери използваем указател в ядрото, но го намери в RPK където разработчиците са забравили да анонимизират указател в изхода за отстраняване на грешки (регистриране), което се е случило по пътя на печатна грешка. За да анонимизирате указателите в Android, трябва да използвате специален код и се оказва, че разработчиците на RPK погрешка са използвали малка буква "к" вместо an главна буква "К". Следователно беше сравнително лесно да се изчисли произволното изместване на кода на ядрото и да се атакува.


Експлойт #2:

Следващият експлойт е малко по-сложен: Samsung Knox защитава вашето устройство, като прилага набор от правила към паметта на устройството, за да спре зловреден код. Правилата са както следва:

  1. Всички страници (код в паметта), с изключение на кода на ядрото, са маркирани като „Привилегировано изпълнение никога“ (което означава, че кодът тук никога не може да се изпълнява)
  2. Страниците с данни на ядрото (данните, използвани от програмата в паметта) никога не се маркират като изпълними (така че кодът тук никога не може да се изпълнява)
  3. Кодовите страници на ядрото (кодът в паметта) никога не се маркират за запис (така че никакъв злонамерен код не може да го промени)
  4. Всички страници на ядрото са маркирани като само за четене в таблицата за превод на етап 2 (таблицата, която се намира между приложението и ядрото, за да попречи на приложенията да знаят за реални местоположения в паметта)
  5. Всички записи за превод на паметта са маркирани като само за четене за приложения.

Ще се съсредоточим върху правило 3, тъй като тук авторът откри проблем с прилагането на правилата по-горе. RPK всъщност маркира паметта за ядрото като само за четене, но като пропуск в KASL беше открита дупка, която доведе до писане на код в предполагаемата секция „само за четене“.. За да се скрие местоположението на ядрото по време на зареждане, паметта се разпределя за ядрото, но това количество памет е много по-голямо от текстовия сегмент на ядрото. Чрез разпределянето на по-голямо количество памет това прави много по-трудно намирането на действителния код на ядрото, който може да е навсякъде, и както видяхме по-горе, той се премества на случаен принцип при всяко зареждане на устройството.

_text и _etext маркират защитения диапазон

Авторът успя да потвърди, че паметта, използвана от ядрото, наистина е маркирана като „само за четене“, но останалата част от това голямо количество памет, използвано за скриване на ядрото, е не означен като "само за четене". Това е така, защото RKP защитава само областта, съдържаща текста на ядрото, след прилагане на слайда KASLR.


Експлойт #3

В третия експлойт авторът успя да получи достъп до друга област от паметта, която също трябва да бъде ограничена само за четене. RKP защитава паметта и използва a Регистър на конфигурацията на хипервайзор (HCR) за управление на ключови операции на ядрото. Целта на HCR е да позволи валидни и реални операции на ядрото за достъп до регистрите и блокиране на злонамерени атаки. Той прави това, като проверява повикванията, направени към регистрите, които управляват функциите за виртуализация. HCR е конфигуриран да блокира конкретни операции, които биха се обработвали нормално, позволявайки на RKP да избере дали да разреши или забрани заявка.

В този експлойт контролът на HCR беше без да покрива два регистъра това се оказа много важно. Авторът се задълбочи в справочното ръководство на ARM и откри, че първият регистър му позволява да изключи RKP за приложения. "Системен контролен регистър за EL1 (SCTLR_EL1) осигурява контрол от най-високо ниво върху системата, включително системата с памет." В един перфектен свят приложението ще използва памет, която е картографирана чрез RKP, така че RKP да може да контролира това, до което приложението има достъп. Изключването на този регистър обаче позволи на RKP да бъде деактивиран чрез ефективно връщане на устройството към начина, по който е работило преди инсталирането на RKP - което означава, че устройството е картографирано към физическа памет без допълнителната сигурност, осигурена от RKP. Това от своя страна означава, че авторът може да чете и записва в паметта, която първоначално и правилно е била блокирана от RKP софтуера.

Вторият регистър, който беше пропуснат, имаше по-фин ефект, но в крайна сметка също толкова опустошителен за сигурността. The Регистър за контрол на превода за EL1 (TCR_EL1) регистърът е пряко свързан с количеството памет, с което работи дадено приложение, наречено страница. RKP е твърдо кодиран за размер на страницата от 4kb, тъй като AARCH64 Linux ядрата (като Android) използват размер на превода от 4KB. Въпросният регистър (TCR_EL1) настройва ARM чипсетите на размера на паметта, която трябва да бъде върната. Оказва се, че този регистър не е защитен от HCR и следователно нападателят може да го промени, тъй като авторът го промени на размер на страницата от 64kb.

Това означава, че когато заявката бъде изпълнена от RKP, действителният размер на достъпната памет вече е 64 kb вместо 4 kb. Причината е, че чипсетът ARM все още контролира размера на страницата и той беше зададен на 64 kb от експлойта. Тъй като RKP защитава паметта от записване, като част от правилата, изброени в експлойт #2, паметта все още е действително защитена. Но тук е уловката - тъй като RKP е твърдо кодиран на 4kb, той не се променя на размер на страницата от 64kb, когато регистърът е актуализиран, така че само първите 4kb памет са защитени което позволява на нападателя да направи каквото иска с останалите 60kb.


Експлойт #4

Последният експлойт, който авторът показва, е препращане към паметта, където е RKP софтуерът, така че атакуващият може да атакува самия RKP софтуер. Един трик за спиране на този тип атака, която Linux ядрата също използват, е да декартирате вашата програма от адресното пространство на виртуалната памет, така че никакви приложения да не могат да я атакуват, защото не могат да я препратят.

Не забравяйте, че паметта се състои изцяло от указатели и таблици, които картографират физическата памет към виртуалната памет. Според нормалната защита при този тип атака, RKP декартира себе си, така че да не може да бъде атакуван. Въпреки това, когато ядрото не предоставя такива възможности, RKP позволява част от паметта да бъде картографирана и маркирана като четене/запис. Единствената проверка е, че това не е самото основно ядро, тъй като RKP не прави проверки, за да види дали адресите, които са поискани да бъдат картографирани, са областта, в която самият RKP се намира в паметта. По принцип RKP позволява да бъде картографиран отново обратно в адресното пространство, до което приложенията имат достъп и като страничен ефект върху паметта автоматично се маркира като четене/запис така че нападателят вече може да използва паметта, както пожелае.


Заключение

Един от най-големите проблеми с четирите експлойта, изброени по-горе, е, че авторът споменава колко трудно биха били изпълними поради липсата на функции в базовото ядро ​​на Android. По ирония на съдбата защитеният RKP Hypervisor предостави всички инструменти, необходими за извършване на атаките. Това показва, че понякога добронамереният софтуер причинява повече проблеми, отколкото решава, и имаме късмет, че имаме хора като Гал Бениамини, желаещи да си изцапат ръцете и да тестват дали документацията съответства на действителния софтуер прави.

Въпреки че тези подвизи изглеждат страшни и карат Knox да звучи много уязвим, бих искал да уверя всички, че всички тези проблеми са били коригирано в януарската актуализация от Samsung. Освен това тези експлойти изискват много задълбочено разбиране на ARM процесорите и програмирането, така че бариерата за навлизане в използването на тези експлойти е астрономически висока.


Източник: Project Zero