Содержание. __ от редакции. Биография сетевого периметра в картинках
Скачать 5.92 Mb.
|
if (cmdParams != null) { handleCommand(cmdParams, false); } } break ; case MSG_ID_PROACTIVE_COMMAND: try { cmdParams = (CommandParams) rilMsg.mData; } catch (ClassCastException e) { // for error handling : cast exception CatLog.d(this, "Fail to parse proactive command" ); // Don't send Terminal Resp if command detail is not available if (mCurrntCmd != null) { sendTerminalResponse(mCurrntCmd.mCmdDet, ResultCode. CMD_DATA_NOT_UNDERSTOOD, false , 0x00 , null); } break ; } if (cmdParams != null) { if (rilMsg.mResCode == ResultCode.OK) { handleCommand(cmdParams, true); } else { // for proactive commands that couldn't be decoded // successfully respond with the code generated by the // message decoder. sendTerminalResponse(cmdParams.mCmdDet, rilMsg.mResCode, false , 0 , null); } } break ; Оба оператора switch приводят к вызову метода handleCommand(), однако второй параметр в каждом случае разный: + MSG_ID_EVENT_NOTIFY — обычное уведомление, которое не требует ответа от пользователя; + MSG_ID_PROACTIVE_COMMAND — а это, как раз наоборот, тре- бует. Переходим к handleCommand: /** * Handles RIL_UNSOL_STK_EVENT_NOTIFY or RIL_UNSOL_STK_PROACTIVE_ COMMAND command * from RIL. * Sends valid proactive command data to the application using intents. * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE will be send back if the command is * from RIL_UNSOL_STK_PROACTIVE_COMMAND. */ private void handleCommand (CommandParams cmdParams, boolean isProactiveCmd) { CatLog.d(this, cmdParams.getCommandType().name()); 61 // Мобильные угрозы 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 101 103 03 05 07 09 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 CharSequence message; CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams); switch (cmdParams.getCommandType()) { case SET_UP_MENU: if (removeMenu(cmdMsg.getMenu())) { mMenuCmd = null; } else { mMenuCmd = cmdMsg; } sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , null); break ; case DISPLAY_TEXT: break ; case REFRESH: // ME side only handles refresh commands which meant to // remove IDLE MODE TEXT. cmdParams.mCmdDet.typeOfCommand = CommandType.SET_UP_IDLE_ MODE_TEXT.value(); break ; case SET_UP_IDLE_MODE_TEXT: sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , null); break ; case SET_UP_EVENT_LIST: if (isSupportedSetupEventCommand(cmdMsg)) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , null); } else { sendTerminalResponse(cmdParams.mCmdDet, ResultCode. BEYOND_TERMINAL_CAPABILITY, false, 0 , null); } break ; case PROVIDE_LOCAL_INFORMATION: ResponseData resp; switch (cmdParams.mCmdDet.commandQualifier) { case CommandParamsFactory.DTTZ_SETTING: resp = new DTTZResponseData(null); sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , resp); break ; case CommandParamsFactory.LANGUAGE_SETTING: resp = new LanguageResponseData(Locale.getDefault(). getLanguage()); sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , resp); break ; default : sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , null); } // No need to start STK app here. return ; case LAUNCH_BROWSER: if ((((LaunchBrowserParams) cmdParams).mConfirmMsg.text != null ) && (((LaunchBrowserParams) cmdParams).mConfirmMsg.text. equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string. launchBrowserDefault); ((LaunchBrowserParams) cmdParams).mConfirmMsg.text = message.toString(); } break ; case SELECT_ITEM: case GET_INPUT: case GET_INKEY: break ; case SEND_DTMF: case SEND_SMS: case SEND_SS: case SEND_USSD: if ((((DisplayTextParams)cmdParams).mTextMsg.text != null) && (((DisplayTextParams)cmdParams).mTextMsg.text. equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string. sending); ((DisplayTextParams)cmdParams).mTextMsg.text = message. toString(); } break ; case PLAY_TONE: break ; case SET_UP_CALL: if ((((CallSetupParams) cmdParams).mConfirmMsg.text != null) && (((CallSetupParams) cmdParams).mConfirmMsg.text. equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string. SetupCallDefault); ((CallSetupParams) cmdParams).mConfirmMsg.text = message. toString(); } break ; case OPEN_CHANNEL: case CLOSE_CHANNEL: case RECEIVE_DATA: case SEND_DATA: BIPClientParams cmd = (BIPClientParams) cmdParams; /* Per 3GPP specification 102.223, * if the alpha identifier is not provided by the UICC, * the terminal MAY give information to the user * noAlphaUsrCnf defines if you need to show user confirmation or not */ boolean noAlphaUsrCnf = false; try { noAlphaUsrCnf = mContext.getResources().getBoolean( com.android.internal.R.bool.config_stkNoAlphaUsrCnf); } catch (NotFoundException e) { noAlphaUsrCnf = false; } if ((cmd.mTextMsg.text == null) && (cmd.mHasAlphaId || noAlphaUsrCnf)) { CatLog.d(this, "cmd " + cmdParams.getCommandType() + " with null alpha id" ); // If alpha length is zero, we just respond with OK. if (isProactiveCmd) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , null); } else if (cmdParams.getCommandType() == CommandType.OPEN_CHANNEL) { mCmdIf.handleCallSetupRequestFromSim(true, null); } return ; } // Respond with permanent failure to avoid retry if // STK app is not present. if (!mStkAppInstalled) { CatLog.d(this, "No STK application found." ); if (isProactiveCmd) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.BEYOND_TERMINAL_CAPABILITY, false , 0 , null); return ; } } /* * CLOSE_CHANNEL, RECEIVE_DATA and SEND_DATA can be * delivered by either PROACTIVE_COMMAND or EVENT_NOTIFY. * If PROACTIVE_COMMAND is used for those commands, * send terminal response here. */ if (isProactiveCmd && ((cmdParams.getCommandType() == CommandType.CLOSE_ CHANNEL) || (cmdParams.getCommandType() == CommandType.RECEIVE_DATA) || (cmdParams.getCommandType() == CommandType.SEND_DATA))) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false , 0 , null); } break ; default : CatLog.d(this, "Unsupported command" ); return ; } mCurrntCmd = cmdMsg; broadcastCatCmdIntent(cmdMsg); } positive research 2016 62 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 02 04 06 08 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 И, наконец, broadcastCatCmdIntent(): private void broadcastCatCmdIntent(CatCmdMessage cmdMsg) { Intent intent = new Intent(AppInterface.CAT_CMD_ACTION); intent.putExtra( "STK CMD" , cmdMsg); intent.putExtra( "SLOT_ID" , mSlotId); CatLog.d(this, "Sending CmdMsg: " + cmdMsg+ " on slotid:" + mSlotId); mContext.sendBroadcast(intent); } А вот эта часть довольно занятная: + AppInterface.CAT_CMD_ACTION равняется android. intent.action.stk.command; + SLOT_ID используется для устройств с несколькими SIM-картами; + STK CMD — команда в качестве объекта Parcelable. Проблема заключается в том, что для отправки команды другому приложению CatService использует неявный интент без ограничения привилегий. Как злоумышленник может этим воспользоваться? Например, ис- пользовать вредоносное приложение, не требующее дополнитель- ных привилегий, для перехвата команд, отправляемых SIM-картой на телефон. Для этого необходимо лишь зарегистрировать receiver с действием android.intent.action.stk.command и получить STK CMD из интента. Пример перехваченной команды: 22:08:37: Receive action: android.intent.action.stk.command 22:08:37: STK CMD 3100000063006F006D002E0061006E00640072006F00690064002E0069006E00740 0650072006E0061006C002E00740065006C006500700068006F006E0079002E0063 00610074002E0043006F006D006D0061006E006400440065007400610069006C007 3000000010000000100000021000000810000002E00000063006F006D002E00610 06E00640072006F00690064002E0069006E007400650072006E0061006C002E0074 0065006C006500700068006F006E0079002E006300610074002E005400650078007 4004D006500730073006100670065000000000000000000000000000F000000330 0350035003700360032003000350032003200370038003900310030000000FFFFFF FF00000000010000000100000001000000FFFFFFFFFFFFFFFFFFFFFFFF00000000 (com.android.internal.telephony.cat.CatCmdMessage) Это объект Parcelable в байтах. Преобразовав Hex в ASCII, вы полу- чите сообщение SIM-карты. эмуляция Однако это лишь половина уязвимости. Рассмотрим приложение, ко- торое получает вот такое широковещательное сообщение: Это приложение называется SIM Toolkit (STK) и является частью стан- дартного Android-фреймворка. "http://schemas.android.com/apk/res/android" xmlns:androidprv = "http://schemas.android.com/apk/prv/res/ android" package = "com.android.stk" android:sharedUserId = "android.uid.phone" > "com.android.stk" /> "android.permission.RECEIVE_BOOT_ COMPLETED" /> "android.permission.GET_TASKS" /> "@drawable/ic_launcher_sim_toolkit" android:label = "@string/app_name" android:clearTaskOnLaunch = "true" android:process = "com.android.phone" android:taskAffinity = "android.task.stk" > "com.android.stk.StkCmdReceiver" > android.intent.action.stk. command " /> android.intent.action.stk. session_end " /> android.intent.action.stk. icc_status_change " /> android.intent.action.stk. alpha_notify " /> android.intent.action. LOCALE_CHANGED " /> Выше приведен фрагмент файла AndroidManifest.xml, относя- щийся к компоненту receiver. Как видно, компонент полностью экспортирован. Это позволяет не только перехватывать команды SIM-карты, но и создавать при помощи вредоносных программ объект Parcelable, а затем отправлять его на com.android.stk. StkCmdReceiver. Receiver не проверяет отправителя, а действие android.intent.action.stk.command не объявлено в системном файле AndroidManifest.xml в качестве защищенного сообщения, что позво- ляет мошенникам эмулировать отправку команд SIM-карты. Например: 1. SIM-карта запрашивает подтверждение некоторой операции, скажем транзакции в интернет-банке, выводя на экран телефо- на сообщение типа «Подтвердить транзакцию № 1234 на сум- му 100 500 рублей» с двумя опциями — «ОК» и «Отмена». Код на StkDialogActivity.java: public void onClick (View v) { String input = null; switch (v.getId()) { case OK_BUTTON: CatLog.d(LOG_TAG, "OK Clicked!, mSlotId: " + mSlotId); cancelTimeOut(); sendResponse(StkAppService.RES_ID_CONFIRM, true); break ; case CANCEL_BUTTON: CatLog.d(LOG_TAG, "Cancel Clicked!, mSlotId: " + mSlotId); cancelTimeOut(); sendResponse(StkAppService.RES_ID_CONFIRM, false); break ; } finish(); } 2. Если пользователь нажмет «ОК», будет вызвана команда sendResponse(StkAppService.RES_ID_CONFIRM, true); в противном случае — sendResponse(StkAppService.RES_ ID_CONFIRM, false);. 3. Что, если при помощи действия android.intent.action. stk.command создать такое же диалоговое окно с другим тек- вид сообщения 63 // Мобильные угрозы 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 101 103 03 05 07 09 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 стом (поддельное) и вывести его на экран за несколько секунд до генерации SIM-картой оригинального сообщения («Под- твердить транзакцию № 1234 на сумму 100 500 рублей»)? В тек- сте сообщения напишем «Нажмите ОК для закрытия», а кнопки оставим те же — «ОК» и «Отмена». 4. Пользователь не увидит оригинальный диалог с подтвержде- нием транзакции, пока не выберет одну из этих опций в под- дельном окне, так как все команды, требующие взаимодействия с пользователем, помещаются в очередь. 5. SIM-карта ожидает ответа от пользователя, Android показывает пользователю первый (поддельный) диалог. Если нажать «ОК», будет вызван метод sendResponse() с флагом «true» и SIM-карта получит команду «ОК», как если бы она была от- правлена из оригинального диалога. Даже если пользователь вы- берет во втором окне опцию «Отмена», это никак не повлияет на предыдущую команду. SIM-карта воспримет это как новый отклик, которого она не ожидает. В исходниках мне удалось найти описание подобной ситуации: private void handleCmdResponse (CatResponseMessage resMsg) { // Make sure the response details match the last valid command. // An invalid response is a one that doesn't have a corresponding // proactive command and sending it can "confuse" the baseband/ril. // One reason for out of order responses can be UI glitches. // For example, if the application launch an activity, and that // activity is stored by the framework inside the history stack. // That activity will be available for relaunch using the latest // application dialog (long press on the home button). // Relaunching that activity can send the same command's result // again to the CatService and can cause it to get out of sync // with the SIM. This can happen in case of non-interactive type // Setup Event List and SETUP_MENU proactive commands. // Stk framework would have already sent Terminal Response // to Setup Event List and SETUP_MENU proactive commands. After // sometime Stk app will send Envelope Command/Event Download. // In which case, the response details doesn't match with last // valid command (which are not related). However, we should // allow Stk framework to send the message to ICC. Здесь сообщается, что «недопустимым является отклик, который не имеет соответствующей проактивной команды и отправка которого может "сбить с толку" baseband/ril». На деле, если RIL или SIM-карта будут получать от вас неожиданные отклики, последствия могут быть непредсказуемыми. В ходе моего исследования несколько SIM-карт вышло из строя, так и не загрузив меню. заключение Команда AOSP устранила эту ошибку в обновлении Android 5.1.1 для Nexus-устройств (сборка LMY48I). Вот некоторые из моих патчей: For /platform/frameworks/opt/telephony/+/master/: --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ - 501 , 7 + 501 , 7 @@ intent.putExtra( "STK CMD" , cmdMsg); intent.putExtra( "SLOT_ID" , mSlotId); CatLog.d(this, "Sending CmdMsg: " + cmdMsg+ " on slotid:" + mSlotId); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent,"android.permission. RECEIVE_STK_COMMANDS"); } /** @@ -514,7 +514,7 @@ mCurrntCmd = mMenuCmd; Intent intent = new Intent(AppInterface.CAT_SESSION_END_ACTION); intent.putExtra("SLOT_ID", mSlotId); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent,"android.permission. RECEIVE_STK_COMMANDS"); } @@ -868,7 +868,7 @@ intent.putExtra(AppInterface.CARD_STATUS, cardPresent); CatLog.d(this, "Sending Card Status: " + cardState + " " + "cardPresent: " + cardPresent); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent,"android.permission. RECEIVE_STK_COMMANDS"); } private void broadcastAlphaMessage(String alphaString) { @@ -877,7 +877,7 @@ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(AppInterface.ALPHA_STRING, alphaString); intent.putExtra("SLOT_ID", mSlotId); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent,"android.permission. RECEIVE_STK_COMMANDS"); } @Override For /platform/frameworks/base/ : --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -303,6 +303,11 @@ SET_RADIO_CAPABILITY_DONE" /> SET_RADIO_CAPABILITY_FAILED" /> + command" /> + session_end" /> + icc_status_change" /> + alpha_notify" /> + @@ -2923,6 +2928,9 @@ android:description="@string/ permdesc_bindCarrierMessagingService" android:protectionLevel="signature|system" /> + RECEIVE_STK_COMMANDS" + android:protectionLevel="signature|system" /> + launch the confirmation UI for full backup/restore --> For /platform/packages/apps/Stk/ : --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -24,6 +24,7 @@ + |