Android Kiosk Mode: Como Comprar um Salgado Quando a Lanchonete Está Fechada
Há alguns meses, um colega de trabalho embarcou em um voo longo, com cerca de 8 horas de duração. Entediado rapidamente, ele notou a tela do sistema multimídia no encosto do assento à sua frente. Ao iniciar o mapa do voo, ele descobriu que se tratava de um dispositivo Android com o Modo Kiosk ativado. Este modo deveria impedir (ou, no mínimo, dificultar significativamente) a exploração do dispositivo, mas na prática, o oposto aconteceu. Meu colega conseguiu contornar o Modo Kiosk no tablet sem dificuldades e ler o arquivo /etc/shadow. Foi assim que surgiu a ideia de investigar o Modo Kiosk mais a fundo e descobrir: ele é realmente tão seguro?
Neste artigo, tentarei explicar como o Modo Kiosk funciona internamente no Android, detalharei os principais componentes necessários para transformar um dispositivo em um "kiosk-device" e apresentarei alguns exemplos de exploração real de dispositivos e aplicativos Kiosk. Este material foi apresentado pela primeira vez como uma palestra no "zeronight".
O Que é o Modo Kiosk?
Comecemos pelo básico: o que é o Modo Kiosk? O Modo Kiosk é um recurso em diversas plataformas (Windows, Linux, Android) projetado para limitar as capacidades do usuário em um dispositivo a um ou mais aplicativos específicos. Em termos simples, ao usar o Modo Kiosk, tentamos "prender" o usuário em aplicativos pré-selecionados. É crucial que o usuário permaneça nesses aplicativos. A saída do Modo Kiosk, no melhor dos casos, "quebra" a funcionalidade do dispositivo; no pior, pode levar a perdas financeiras ou à compromissão de toda a rede local onde o dispositivo Kiosk está conectado.
O Modo Kiosk é bastante difundido, embora não seja frequentemente discutido na comunidade de segurança da informação. Ele é utilizado em terminais POS (recentemente, um artigo detalhou esse uso do Modo Kiosk), lockers de entrega, caixas de autoatendimento, transporte público, menus eletrônicos em restaurantes, terminais industriais e dispositivos corporativos. No entanto, apesar da importância da segurança do Modo Kiosk, ela é frequentemente negligenciada. Este artigo se concentrará exclusivamente na implementação do Modo Kiosk no Android, sem abordar as implementações em Linux ou Windows.
Dispositivos com Modo Kiosk podem ser divididos em duas categorias: Single App e Multi App. Como o nome sugere, o Single App é usado quando as capacidades do usuário são restritas a um único aplicativo específico. O Single App é geralmente aplicado em sinalização digital, sistemas POS móveis, terminais de aeroportos, terminais na indústria hoteleira e terminais de reserva de passagens. Embora o modo Single App seja mais simples de instalar e gerenciar em um dispositivo, ele é usado com menos frequência.
No modo Multi App, o acesso do usuário ao dispositivo é limitado a vários aplicativos; ao mesmo tempo, ele pode alternar livremente entre eles, o que expande significativamente a funcionalidade do dispositivo com Modo Kiosk. O Multi App Kiosk é comumente usado em serviços, fins educacionais e em empresas de entrega e produção.
Aplicativo Kiosk no Android
Neste artigo, não descreverei detalhadamente o processo de desenvolvimento de um aplicativo para o Modo Kiosk. As informações para esta seção foram retiradas de um artigo no Github por mrugacz95. Aqui, abordarei apenas os mecanismos essenciais para garantir o "isolamento" do usuário, utilizados em aplicativos Kiosk no Android. Em um aplicativo que restringe completamente as capacidades do usuário, três componentes principais podem ser identificados:
- Home Launcher: Este é o ecrã principal do Android, onde estão localizados os ícones de aplicativos, widgets e outros elementos que o usuário pode adicionar. Se o nosso aplicativo não for o launcher padrão, após a reinicialização, o Modo Kiosk deixará de funcionar e o dispositivo retornará às suas funções padrão.
- Screen Pinning: O "Screen Pinning" (Fixação de Tela) é um recurso que permite exibir um único aplicativo até que ele seja desfixado. Ele foi introduzido no Android 5.0 e originalmente destinado a permitir que telefones fossem entregues a outras pessoas sem o risco de vazamento de informações. Após ativar esta função no dispositivo, as seguintes alterações ocorrem: a barra de status é completamente oculta, os botões "Home" e "Aplicativos Recentes" são desativados, e o lançamento de novas ações por outros aplicativos é proibido.
- Device Admin: O aplicativo se torna um administrador do dispositivo. Se este passo for omitido, não poderemos restringir completamente o acesso do usuário a notificações e à barra de status, nem alterar as configurações do sistema a partir do aplicativo, o que é crucial para dispositivos Kiosk.
Home Launcher
Para tornar um aplicativo um launcher, é necessário atribuir-lhe intents, escrever o intentFilter correspondente e conceder as permissões necessárias usando addPersistentPreferredActivity. Em seguida, é preciso desativar o Keyguard (tela de bloqueio). Isso permitirá que nosso aplicativo seja iniciado imediatamente, contornando a tela de bloqueio. Além disso, é necessário impedir o desligamento da tela. Para isso, deve-se definir o flag FLAG_KEEP_SCREEN_ON para a janela atual (a window pertence à classe Activity e aponta para a janela atual).
Screen Pinning
Para o funcionamento do Screen Pinning no Android, existe um mecanismo especial chamado Lock Task Mode (Modo de Fixação de Tarefa). Ele permite fixar uma Activity sobre a tela. Para fixar um aplicativo, são usadas duas funções: setLockTaskPackages() no DevicePolicyManager e startLockTask() na Activity. setLockTaskPackages permite que o aplicativo seja fixado, e startLockTask garante a fixação. O passo final para fixar o aplicativo é adicionar o código que garante a ativação do modo de tela cheia para o nosso aplicativo.
Estes são os mecanismos essenciais necessários para ativar o Modo Kiosk do lado do desenvolvedor do aplicativo. Agora, vamos nos aprofundar no Modo Kiosk e ver internamente como funciona o isolamento de aplicativos.
Modo Kiosk por Dentro
setLockTaskPackages
Conforme mencionado na seção anterior, a função setLockTaskPackages é necessária para que o sistema permita que um aplicativo seja fixado. Para isso, é utilizado um mecanismo de políticas, mais especificamente o DevicePolicyEngine (DPE) – um mecanismo interno do Android que regula o gerenciamento de políticas. A essência do funcionamento do DPE é bastante simples:
- Cada administrador configura o sistema à sua maneira (por exemplo, permitindo ou proibindo o uso da câmera).
- O DPE, com base em regras predefinidas, determina qual política será adotada e, em seguida, formula a política final a ser aplicada pelo sistema.
Por exemplo, no caso da câmera, o Android tem uma prioridade maior para a proibição. Portanto, se dois administradores de dispositivo, com direitos iguais, solicitarem simultaneamente a permissão e a proibição de acesso à câmera, o DPE aplicará a política de proibição. A função setLockTaskPackages define justamente essa política. A própria função é implementada no DevicePolicyManagerService e é usada para criar a política "este aplicativo (ou estes aplicativos) podem ser fixados". Abaixo está o código-fonte da função.
Ao analisar esta função, podemos notar duas chamadas principais: getLocalPolicySetByAdmin e setLocalPolicy. getLocalPolicySetByAdmin é usado para ler a política definida pelo administrador para o usuário atual. O uso desta função permite atualizar políticas sem substituir a "contribuição" de outros administradores: alteramos apenas nosso valor local, e então o DPE combina todas as fontes e recalcula a política final a ser usada posteriormente. Além disso, esse valor é útil para entender se houve uma alteração real: se não houve alteração, ações e notificações desnecessárias podem ser evitadas.
setLocalPolicy é o ponto central de gravação da política local de um administrador específico. O método adiciona a "contribuição" do administrador à política, recalcula o valor final considerando a "contribuição" de outros administradores e, se necessário, aplica as alterações ao sistema, notifica o administrador e distribui a política para perfis herdados.
Iniciando o Lock Task Mode
O início do Lock Task Mode ocorre na função startLockTask da classe Activity, que, por sua vez, chama startLockTaskModeByToken. Isso leva à chamada da função startLockTaskMode na classe LockTaskController. É esta função que vale a pena analisar mais detalhadamente. Primeiro, deve-se prestar atenção à verificação do parâmetro isSystemCaller. Ele determina quem está tentando fixar o aplicativo. Ao chamar de startLockTask, este parâmetro é sempre false. A funcionalidade dentro do bloco if (!isSystemCaller) é responsável pela janela pop-up na qual o usuário do dispositivo deve confirmar a fixação (função showScreenPinningRequest).
Após a confirmação da fixação pelo usuário, a função startLockTaskMode é chamada novamente, mas o parâmetro isSystemCaller será passado como true, e a função principal de fixação do aplicativo será chamada – setLockTaskMode na classe LockTaskController. Ao analisar setLockTaskMode, a atenção principal deve ser dada a três funções: findTaskToMoveToFront, resumeFocusedTasksTopActivities e executeAppTransition.
Um Pouco Sobre Janelas no Android
Para um entendimento mais aprofundado do processo, é necessário fazer um pequeno desvio e explicar por que o Android precisa da classe Task e como ela se relaciona com os aplicativos que o usuário vê. Uma Task é um contêiner de um stack de Activity. Esta classe armazena um conjunto ordenado de ActivityRecord. Quando o usuário alterna entre aplicativos ou entre telas dentro de um mesmo aplicativo, o sistema seleciona o ActivityRecord superior (mais recente) nesta lista. Este ActivityRecord superior é considerado o atual: sua Activity deve aparecer na tela no estado RESUMED, e os registros abaixo nesta mesma lista são transferidos para os estados PAUSED ou STOPPED.
Ao chamar startActivity() normalmente, uma nova entrada é adicionada no topo da lista ActivityRecord da Task atual, alterando assim o topo do stack. Ao pressionar "Voltar", a entrada superior é removida da lista, e a entrada anterior assume seu lugar. Se regras especiais estiverem ativadas (por exemplo, singleTop), um novo elemento pode não ser adicionado: em vez disso, o sistema usa o ActivityRecord superior existente e atualiza seu Intent. Se CLEAR_TOP ou singleTask for usado, o sistema encontra o ActivityRecord desejado dentro da lista desta Task, remove todas as entradas acima dele e torna a entrada encontrada a superior. Se o usuário abrir outro aplicativo, o stack não é reconstruído: simplesmente o Task superior se torna ativo.
Além disso, uma Task é um nó na árvore do WindowManager. Isso significa que a Task existe como um contêiner de janela (WindowContainer), que participa da composição, renderização e ordem Z – a ordem de sobreposição dos elementos no eixo de profundidade da tela (o que é exibido em primeiro plano e o que permanece em segundo plano). Se duas janelas ou contêineres se sobrepõem, o elemento com a ordem Z mais alta estará em primeiro plano e geralmente receberá o foco de entrada.
Na hierarquia do WMS (WindowManagerService), a Task está localizada abaixo da RootTask. A hierarquia geral dentro do WMS é a seguinte: DisplayContent → TaskDisplayArea → RootTask → Task → ActivityRecord → janelas/Surface. Uma RootTask é um contêiner de tarefas de nível superior no WindowManager. Ela agrupa Tasks comuns por modo e política de exibição (por exemplo, fullscreen, split-screen, PiP, freeform). É a RootTask que define o modo de janela geral e os limites para suas tarefas filhas, além de gerenciar sua ordem de exibição no display.
Como um nó na árvore WM, a Task define os limites para todo o conteúdo, herda ou substitui o modo de janela (fullscreen, split-screen, freeform) e é uma unidade que pode ser movida inteiramente na ordem Z (por exemplo, move-to-front – trazer a tarefa para cima de seus vizinhos na mesma RootTask). Além disso, no nível da Task, é conveniente aplicar operações em grupo para renderização: exibir uma superfície temporária (starting window ou snapshot), executar animações e transformações, além de fazer reparenting – mover a tarefa para outra RootTask ou até mesmo para outro DisplayContent (mover para outro display).
Retornando ao Modo Kiosk
Agora que entendemos como funciona a exibição de Activity no Android, podemos retornar ao Modo Kiosk, mais especificamente à função findTaskToMoveToFront. findTaskToMoveToFront implementa a fase move-to-front para a Task: ela move a Task selecionada para o primeiro plano e garante que sua ActivityRecord superior seja exibida no display correto, no modo de janela correto (geralmente fullscreen), e também se torne a primeira em foco e entrada. As etapas executadas em findTaskToMoveToFront podem ser descritas da seguinte forma:
- Reparenting: Se a
Taskestiver em um modo de janela inadequado (split-screen,PiP) ou em outro display, ela é movida para a root de tela cheia de destino para obter uma única janela de foco. - Preparação para transição no WM: Antes de mover para o primeiro plano, as
ActivityRecords necessárias são marcadas para animação correta e transações de Surface adequadas. - Move-to-front e foco: A
Taské movida para o topo na hierarquia de tarefas, e o foco de entrada é transferido para suaActivitysuperior. - Starting window (se necessário): Se a
Activitysuperior ainda não estiver pronta para renderização, uma janela inicial é aberta para evitar uma "tela preta". - Transferência de controle para a fase RESUME: Após a
Taskse tornar a primeira na fila e receber o foco de entrada, o controle é transferido para a lógica que move aActivitysuperior para o estadoRESUMED.
resumeFocusedTasksTopActivities percorre todas as zonas do display (se houver várias) e, para cada área, verifica qual RootTask é considerada principal e deve receber o foco. Em seguida, o método não tenta diretamente mover uma Activity específica para o estado RESUMED, mas simplesmente delega o trabalho para o nível inferior: um comando é enviado à RootTask selecionada para "mover para o estado RESUMED a ActivityRecord superior", e então, dentro dessa RootTask, a Task correta é selecionada, e dentro dela – a ActivityRecord superior.
Dentro da root, resumeTopActivityUncheckedLocked executa várias verificações (estado do display, estado do contêiner), após o que a ActivityRecord superior específica é selecionada e sua transição para o estágio RESUME é iniciada. O trabalho principal é realizado em TaskFragment.resumeTopActivity. Se a Activity já estiver no estado RESUMED e vinculada ao processo, o método simplesmente atualiza sua visibilidade e conclui a execução. Caso contrário, ele move a Activity anterior para o estado PAUSED e inicia a chamada onResume para a Activity superior atual. Para isso, um PauseActivityItem é passado para o processo da Activity anterior, e um ResumeActivityItem para o processo da nova Activity.
Após a Activity do aplicativo ser preparada e transitar para o estado RESUMED, o WindowManager passa para a fase de aplicação visual das alterações. Para isso, é chamada executeAppTransition. Primeiro, o método informa ao TransitionController que o DisplayContent atual está pronto para iniciar transições, em seguida, verifica se alguma transição está definida em mAppTransition. Se uma transição estiver definida, ela é marcada como pronta para execução, após o que mWindowPlacerLocked.requestTraversal é chamado.
A chamada requestTraversal inicia a próxima etapa de posicionamento de janelas e superfícies (layout e posicionamento de superfície): nesta etapa, as alterações são exibidas na tela e a animação é reproduzida (se houver).
Erros Comuns na Criação de Dispositivos Kiosk
Agora que entendemos em linhas gerais como funciona o Modo Kiosk, é hora de falar sobre como tornar nossos aplicativos Kiosk mais seguros (e no que prestar atenção em soluções de terceiros). Esta seção abordará erros frequentes na configuração de aplicativos e dispositivos que operam no Modo Kiosk. A lista de aplicativos permitidos inclui aplicativos extras. Como demonstrado acima, ao configurar dispositivos Kiosk, é necessário especificar explicitamente a lista de aplicativos permitidos para execução. Frequentemente, aplicativos extras são adicionados a esta lista (por exemplo, o navegador Chrome), o que, para um dispositivo Android baseado em Linux, pode ser crítico. O acesso ao navegador abre muitas possibilidades: desde sair do modo Kiosk até executar código no dispositivo. Foi esse problema que foi descoberto na implementação do Modo Kiosk do aplicativo mencionado no início do artigo: por meio de manipulações simples com o WebView, o navegador foi iniciado e o acesso ao sistema de arquivos foi obtido. Além disso, aplicativos de terceiros não verificados podem conter suas próprias vulnerabilidades e, assim, permitir contornar as restrições do modo ou alterar as configurações do sistema.
Isolamento insuficiente e componentes exportados. Em configurações de Modo Kiosk com vários aplicativos (Multi App), a necessidade de interação entre eles surge com frequência. Por exemplo, pode ser necessário um serviço para alterar as configurações do sistema. Tal serviço geralmente possui privilégios maiores do que os aplicativos Kiosk comuns. Se o acesso a ele de fora não for restrito (por exemplo, se o componente for deixado exportado), um atacante pode instalar seu próprio aplicativo ou enviar intents personalizados e usar componentes privilegiados: desativar o Modo Kiosk ou obter acesso a informações confidenciais.
Parâmetros de desenvolvedor e ADB ativados. Infelizmente, às vezes, ao trabalhar com dispositivos Kiosk, os desenvolvedores esquecem de desativar os parâmetros de desenvolvedor ou o ADB. Como o usuário quase sempre tem acesso físico ao dispositivo Kiosk, a depuração permitida pode se tornar um problema sério. Ela permite instalar e executar APKs de terceiros, além de interferir no funcionamento do sistema. Por exemplo, no caso de CVE-2023-41255 e CVE-2023-43488 em terminais industriais Bosch ctrlX WR21, o arquivo su foi deixado no sistema, o que permitiu obter acesso root com quase nenhum esforço.
Uso de HTTP e falta de criptografia. Alguns aplicativos em quiosques multimídia usam protocolos abertos para obter configuração. Por exemplo, em CVE-2023-45220 e CVE-2023-45321, o aplicativo cliente no Android transmitia o endereço IP e as credenciais para conexão com o broker MQTT via HTTP. Um invasor na mesma sub-rede poderia interceptar esses dados e obter controle sobre o sistema. Outro exemplo é a falta de verificação do servidor ao conectar-se ao MQTT (CVE-2023-45851): o cliente se conectava ao broker sem autenticação, o que permitia que ele fosse forçado a se conectar a um servidor malicioso e receber comandos falsos.
Portas USB abertas e ataques de teclado. Na presença de portas USB abertas, um atacante pode usar técnicas do tipo BadUSB: conectar um dispositivo que emula um teclado, digitar comandos automaticamente, iniciar aplicativos ou abrir telas do sistema. Como resultado, é possível tirar o dispositivo do modo Kiosk, obter acesso às configurações do sistema ou executar código malicioso.
Claro, estes não são todos os erros. Na prática, existem muito mais, e listá-los todos é quase impossível. Eu apenas queria mostrar os problemas mais populares e frequentes. E agora, apresentarei alguns exemplos de vulnerabilidades em dispositivos Kiosk.
Vulnerabilidades em Dispositivos Kiosk
- CVE-2023-21189 / CVE-2025-26428: No método
startLockTaskMode, para uma tarefa que já estava fixada, o código continuava a executar a lógica de fixação sem verificar a listamLockTaskModeTasksquanto à presença dessa tarefa. Como resultado, estando no modo Kiosk, era possível chamarstopLockTaskModee exibir novamente o diálogo "Fixar Aplicativo", e então contornar as restrições do Modo Kiosk e desbloquear o dispositivo. A vulnerabilidade foi corrigida apenas em um dos últimos commits do Android 15 com uma verificação adicional. - CVE-2025-5344: A empresa Bluebird lança muitos dispositivos diferentes: telefones, terminais de pagamento, computadores móveis, tablets corporativos, quiosques de autoatendimento interativos, dispositivos RFID, leitores de código de barras Bluetooth, dispositivos automotivos e telemáticos (gateway veicular), além de impressoras móveis. Entre eles, existem vários dispositivos que operam no Modo Kiosk e utilizam um Home Launcher especial. Neste launcher, foi implementado um serviço AIDL para gerenciar as configurações do sistema, que foi exportado sem proteção adequada. Como resultado, qualquer aplicativo ou processo local no dispositivo poderia se conectar a este serviço e alterar as configurações do sistema. Essa vulnerabilidade permitia desativar políticas de segurança ou alterar parâmetros críticos do sistema, como o modo de desenvolvedor ou o acesso ao shell.
- CVE-2023-45844: A Bosch Rexroth fabrica painéis industriais HMI ctrlX-HMI-WR21, que rodam em Android e são frequentemente usados como terminais de operador no Modo Kiosk: ao usuário é exibida apenas a interface web através do Google Chrome/Chromium. Nas firmwares vulneráveis de tais dispositivos, as restrições são implementadas de forma que o caminho padrão do sistema para instalação de aplicativos esteja disponível no navegador: o usuário com acesso físico pode levar o Chrome a iniciar o instalador de pacotes do Android (Package Installer) e, assim, instalar um APK arbitrário, embora essa possibilidade deva ser bloqueada no Modo Kiosk. Após instalar seu próprio aplicativo, o atacante efetivamente "quebra" o modelo Kiosk: pode executar código fora do cenário permitido e acessar as configurações críticas do dispositivo.
Conclusão
Dispositivos operando no Modo Kiosk não devem ser tratados levianamente. Um erro de configuração, um aplicativo extra na lista de permissões, um componente exportado, ADB ativado ou uma proteção de rede fraca podem anular todo o modelo de isolamento. É por isso que a segurança dos dispositivos Kiosk deve ser vista como uma tarefa completa de proteção de toda a plataforma, e não como uma simples configuração de interface ou restrição de acesso do usuário. A compromissão de tal dispositivo frequentemente vai muito além de um único aplicativo ou tela: em alguns casos, pode levar à compromissão de toda a rede local da organização, e a saída do Modo Kiosk pode abrir amplas oportunidades para ações futuras do atacante.
Espero que este artigo tenha sido útil, ou pelo menos interessante, e que eu tenha conseguido mergulhá-lo um pouco no mundo dos dispositivos Android operando no Modo Kiosk.







