macOS XPC
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
XPC, que significa Comunicação Inter-Processo XNU (o kernel usado pelo macOS), é uma estrutura para comunicação entre processos no macOS e iOS. O XPC fornece um mecanismo para fazer chamadas de método assíncronas e seguras entre diferentes processos no sistema. É parte do paradigma de segurança da Apple, permitindo a criação de aplicativos com separação de privilégios onde cada componente é executado com apenas as permissões necessárias para realizar sua função, limitando assim o potencial de dano de um processo comprometido.
O XPC usa uma forma de Comunicação Inter-Processo (IPC), que é um conjunto de métodos para diferentes programas em execução no mesmo sistema trocarem dados.
Os principais benefícios do XPC incluem:
Segurança: Ao separar o trabalho em diferentes processos, cada processo pode receber apenas as permissões necessárias. Isso significa que, mesmo que um processo seja comprometido, ele tem capacidade limitada de causar danos.
Estabilidade: O XPC ajuda a isolar falhas no componente onde ocorrem. Se um processo falhar, ele pode ser reiniciado sem afetar o restante do sistema.
Desempenho: O XPC permite fácil concorrência, pois diferentes tarefas podem ser executadas simultaneamente em diferentes processos.
A única desvantagem é que separar um aplicativo em vários processos que se comunicam via XPC é menos eficiente. Mas nos sistemas de hoje, isso não é quase perceptível e os benefícios são melhores.
Os componentes XPC de um aplicativo estão dentro do próprio aplicativo. Por exemplo, no Safari, você pode encontrá-los em /Applications/Safari.app/Contents/XPCServices
. Eles têm a extensão .xpc
(como com.apple.Safari.SandboxBroker.xpc
) e também são pacotes com o binário principal dentro dele: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker
e um Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist
Como você pode estar pensando, um componente XPC terá diferentes direitos e privilégios do que os outros componentes XPC ou o binário principal do aplicativo. EXCETO se um serviço XPC estiver configurado com JoinExistingSession definido como “True” em seu Info.plist. Nesse caso, o serviço XPC será executado na mesma sessão de segurança que o aplicativo que o chamou.
Os serviços XPC são iniciados pelo launchd quando necessário e encerrados uma vez que todas as tarefas estão concluídas para liberar recursos do sistema. Componentes XPC específicos de aplicativos só podem ser utilizados pelo aplicativo, reduzindo assim o risco associado a potenciais vulnerabilidades.
Os serviços XPC de sistema são acessíveis a todos os usuários. Esses serviços, seja launchd ou do tipo Mach, precisam ser definidos em arquivos plist localizados em diretórios especificados, como /System/Library/LaunchDaemons
, /Library/LaunchDaemons
, /System/Library/LaunchAgents
, ou /Library/LaunchAgents
.
Esses arquivos plist terão uma chave chamada MachServices
com o nome do serviço, e uma chave chamada Program
com o caminho para o binário:
Os que estão em LaunchDameons
são executados pelo root. Portanto, se um processo não privilegiado puder se comunicar com um desses, poderá ser capaz de escalar privilégios.
xpc_object_t
Cada mensagem XPC é um objeto dicionário que simplifica a serialização e deserialização. Além disso, libxpc.dylib
declara a maioria dos tipos de dados, então é possível garantir que os dados recebidos sejam do tipo esperado. Na API C, cada objeto é um xpc_object_t
(e seu tipo pode ser verificado usando xpc_get_type(object)
).
Além disso, a função xpc_copy_description(object)
pode ser usada para obter uma representação em string do objeto que pode ser útil para fins de depuração.
Esses objetos também têm alguns métodos para chamar, como xpc_<object>_copy
, xpc_<object>_equal
, xpc_<object>_hash
, xpc_<object>_serialize
, xpc_<object>_deserialize
...
Os xpc_object_t
são criados chamando a função xpc_<objetType>_create
, que internamente chama _xpc_base_create(Class, Size)
, onde é indicado o tipo da classe do objeto (um dos XPC_TYPE_*
) e o tamanho dele (alguns 40B extras serão adicionados ao tamanho para metadados). O que significa que os dados do objeto começarão no deslocamento de 40B.
Portanto, o xpc_<objectType>_t
é uma espécie de subclasse do xpc_object_t
, que seria uma subclasse de os_object_t*
.
Observe que deve ser o desenvolvedor quem usa xpc_dictionary_[get/set]_<objectType>
para obter ou definir o tipo e o valor real de uma chave.
xpc_pipe
Um xpc_pipe
é um pipe FIFO que os processos podem usar para se comunicar (a comunicação usa mensagens Mach).
É possível criar um servidor XPC chamando xpc_pipe_create()
ou xpc_pipe_create_from_port()
para criá-lo usando uma porta Mach específica. Em seguida, para receber mensagens, é possível chamar xpc_pipe_receive
e xpc_pipe_try_receive
.
Observe que o objeto xpc_pipe
é um xpc_object_t
com informações em sua struct sobre as duas portas Mach usadas e o nome (se houver). O nome, por exemplo, o daemon secinitd
em seu plist /System/Library/LaunchDaemons/com.apple.secinitd.plist
configura o pipe chamado com.apple.secinitd
.
Um exemplo de um xpc_pipe
é o bootstrap pipe criado pelo launchd
, tornando possível compartilhar portas Mach.
NSXPC*
Estes são objetos de alto nível em Objective-C que permitem a abstração de conexões XPC. Além disso, é mais fácil depurar esses objetos com DTrace do que os anteriores.
GCD Queues
XPC usa GCD para passar mensagens, além disso, gera certas filas de despacho como xpc.transactionq
, xpc.io
, xpc-events.add-listenerq
, xpc.service-instance
...
Estes são pacotes com extensão .xpc
localizados dentro da pasta XPCServices
de outros projetos e no Info.plist
eles têm o CFBundlePackageType
definido como XPC!
.
Este arquivo possui outras chaves de configuração, como ServiceType
, que pode ser Application, User, System ou _SandboxProfile
, que pode definir um sandbox, ou _AllowedClients
, que pode indicar direitos ou ID necessários para contatar o serviço. Essas e outras opções de configuração serão úteis para configurar o serviço ao ser iniciado.
O aplicativo tenta conectar a um serviço XPC usando xpc_connection_create_mach_service
, então o launchd localiza o daemon e inicia xpcproxy
. xpcproxy
impõe as restrições configuradas e gera o serviço com os FDs e portas Mach fornecidos.
Para melhorar a velocidade da busca pelo serviço XPC, um cache é utilizado.
É possível rastrear as ações de xpcproxy
usando:
A biblioteca XPC usa kdebug
para registrar ações chamando xpc_ktrace_pid0
e xpc_ktrace_pid1
. Os códigos que utiliza não são documentados, então é necessário adicioná-los em /usr/share/misc/trace.codes
. Eles têm o prefixo 0x29
e, por exemplo, um é 0x29000004
: XPC_serializer_pack
.
A utilidade xpcproxy
usa o prefixo 0x22
, por exemplo: 0x2200001c: xpcproxy:will_do_preexec
.
Aplicativos podem se inscrever em diferentes mensagens de evento, permitindo que sejam iniciadas sob demanda quando tais eventos ocorrem. A configuração para esses serviços é feita em arquivos plist do launchd, localizados nas mesmas diretórios que os anteriores e contendo uma chave extra LaunchEvent
.
Quando um processo tenta chamar um método via uma conexão XPC, o serviço XPC deve verificar se esse processo tem permissão para se conectar. Aqui estão as maneiras comuns de verificar isso e as armadilhas comuns:
macOS XPC Connecting Process CheckA Apple também permite que aplicativos configurem alguns direitos e como obtê-los, então, se o processo chamador os tiver, ele será permitido a chamar um método do serviço XPC:
macOS XPC AuthorizationPara capturar as mensagens XPC, você pode usar xpcspy, que utiliza Frida.
Outra ferramenta possível de usar é XPoCe2.
Essa funcionalidade fornecida pelo RemoteXPC.framework
(do libxpc
) permite comunicar via XPC através de diferentes hosts.
Os serviços que suportam XPC remoto terão em seu plist a chave UsesRemoteXPC, como é o caso de /System/Library/LaunchDaemons/com.apple.SubmitDiagInfo.plist
. No entanto, embora o serviço esteja registrado com launchd
, é o UserEventAgent
com os plugins com.apple.remoted.plugin
e com.apple.remoteservicediscovery.events.plugin
que fornece a funcionalidade.
Além disso, o RemoteServiceDiscovery.framework
permite obter informações do com.apple.remoted.plugin
, expondo funções como get_device
, get_unique_device
, connect
...
Uma vez que connect
é usado e o socket fd
do serviço é coletado, é possível usar a classe remote_xpc_connection_*
.
É possível obter informações sobre serviços remotos usando a ferramenta cli /usr/libexec/remotectl
com parâmetros como:
A comunicação entre o BridgeOS e o host ocorre através de uma interface IPv6 dedicada. O MultiverseSupport.framework
permite estabelecer sockets cujos fd
serão usados para comunicação.
É possível encontrar essas comunicações usando netstat
, nettop
ou a opção de código aberto, netbottom
.
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)