hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/README.md

36 KiB
Raw Blame History

macOS Apps - Inspeção, depuração e Fuzzing

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Análise Estática

otool

otool -L /bin/ls #List dynamically linked libraries
otool -tv /bin/ps #Decompile application

objdump

O comando objdump é uma ferramenta de linha de comando que permite inspecionar arquivos binários e executáveis no macOS. Ele fornece informações detalhadas sobre o conteúdo do arquivo, como seções, símbolos, instruções de montagem e muito mais.

O objdump pode ser usado para analisar e depurar aplicativos no macOS, identificando vulnerabilidades e possíveis pontos fracos. Ele também pode ser usado para examinar o código de terceiros e entender como um aplicativo funciona internamente.

Para usar o objdump, basta executar o comando seguido do caminho para o arquivo binário ou executável que deseja inspecionar. Por exemplo:

objdump -d /path/to/executable

Isso exibirá o código de montagem do arquivo, permitindo que você analise as instruções e entenda o fluxo de execução do programa.

O objdump é uma ferramenta poderosa para inspecionar e depurar aplicativos no macOS. No entanto, é importante usá-lo com responsabilidade e apenas para fins legais e éticos, como teste de segurança e análise de código.

objdump -m --dylibs-used /bin/ls #List dynamically linked libraries
objdump -m -h /bin/ls # Get headers information
objdump -m --syms /bin/ls # Check if the symbol table exists to get function names
objdump -m --full-contents /bin/ls # Dump every section
objdump -d /bin/ls # Dissasemble the binary

jtool2

A ferramenta pode ser usada como um substituto para codesign, otool e objdump, e oferece algumas funcionalidades adicionais.

# Install
brew install --cask jtool2

jtool2 -l /bin/ls # Get commands (headers)
jtool2 -L /bin/ls # Get libraries
jtool2 -S /bin/ls # Get symbol info
jtool2 -d /bin/ls # Dump binary
jtool2 -D /bin/ls # Decompile binary

# Get signature information
ARCH=x86_64 jtool2 --sig /System/Applications/Automator.app/Contents/MacOS/Automator

Codesign

O comando codesign é uma ferramenta de linha de comando no macOS que permite assinar digitalmente aplicativos e bibliotecas para garantir sua autenticidade e integridade. A assinatura digital é um mecanismo de segurança que verifica se o código não foi alterado ou adulterado desde que foi assinado.

A assinatura digital é especialmente importante para aplicativos distribuídos fora da Mac App Store, pois fornece uma maneira de verificar se o aplicativo não foi modificado por terceiros mal-intencionados. Além disso, a assinatura digital é necessária para recursos como a capacidade de acessar certos recursos protegidos do sistema operacional e para permitir que o aplicativo seja executado em sistemas macOS com Gatekeeper habilitado.

O comando codesign pode ser usado para inspecionar, adicionar ou remover assinaturas digitais de aplicativos e bibliotecas. Ele também pode ser usado para verificar a validade de uma assinatura digital existente.

A assinatura digital é baseada em certificados de identidade, que são emitidos por uma autoridade de certificação confiável. Ao assinar um aplicativo ou biblioteca, um certificado de identidade é usado para criar uma assinatura digital que é anexada ao código. Quando o aplicativo ou biblioteca é executado, o sistema operacional verifica a assinatura digital usando o certificado de identidade correspondente para garantir que o código não tenha sido alterado.

O comando codesign também pode ser usado para especificar requisitos de assinatura, como quais certificados de identidade são aceitos ou quais recursos protegidos do sistema operacional o aplicativo pode acessar. Isso permite que os desenvolvedores controlem quais recursos e permissões são concedidos ao aplicativo.

Em resumo, o comando codesign é uma ferramenta essencial para garantir a segurança e a integridade de aplicativos e bibliotecas no macOS, permitindo a verificação da autenticidade do código e a proteção contra modificações não autorizadas.

# Get signer
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"

# Check if the apps contents have been modified
codesign --verify --verbose /Applications/Safari.app

# Get entitlements from the binary
codesign -d --entitlements :- /System/Applications/Automator.app # Check the TCC perms

# Check if the signature is valid
spctl --assess --verbose /Applications/Safari.app

# Sign a binary
codesign -s <cert-name-keychain> toolsdemo

SuspiciousPackage

SuspiciousPackage é uma ferramenta útil para inspecionar arquivos .pkg (instaladores) e ver o que está dentro antes de instalá-los.
Esses instaladores possuem scripts bash preinstall e postinstall que os autores de malware geralmente abusam para persistir o malware.

hdiutil

Essa ferramenta permite montar imagens de disco Apple (.dmg) para inspecioná-las antes de executar qualquer coisa:

hdiutil attach ~/Downloads/Firefox\ 58.0.2.dmg

Será montado em /Volumes

Objective-C

Metadados

{% hint style="danger" %} Observe que programas escritos em Objective-C mantêm suas declarações de classe quando compilados em binários Mach-O. Tais declarações de classe incluem o nome e o tipo de: {% endhint %}

  • A classe
  • Os métodos da classe
  • As variáveis de instância da classe

Você pode obter essas informações usando class-dump:

class-dump Kindle.app

Chamada de função

Quando uma função é chamada em um binário que usa Objective-C, o código compilado, em vez de chamar essa função, chamará objc_msgSend. Que irá chamar a função final:

Os parâmetros que essa função espera são:

  • O primeiro parâmetro (self) é "um ponteiro que aponta para a instância da classe que receberá a mensagem". Ou de forma mais simples, é o objeto no qual o método está sendo invocado. Se o método for um método de classe, isso será uma instância do objeto da classe (como um todo), enquanto que para um método de instância, self apontará para uma instância instanciada da classe como um objeto.
  • O segundo parâmetro (op) é "o seletor do método que manipula a mensagem". Novamente, de forma mais simples, este é apenas o nome do método.
  • Os parâmetros restantes são quaisquer valores necessários pelo método (op).
Argumento Registrador (para) objc_msgSend
1º argumento rdi self: objeto no qual o método está sendo invocado
2º argumento rsi op: nome do método
3º argumento rdx 1º argumento para o método
4º argumento rcx 2º argumento para o método
5º argumento r8 3º argumento para o método
6º argumento r9 4º argumento para o método
7º+ argumento

rsp+
(na pilha)

5º+ argumento para o método

Swift

Com binários Swift, como há compatibilidade com Objective-C, às vezes é possível extrair declarações usando class-dump, mas nem sempre.

Com os comandos de linha jtool -l ou otool -l, é possível encontrar várias seções que começam com o prefixo __swift5:

jtool2 -l /Applications/Stocks.app/Contents/MacOS/Stocks
LC 00: LC_SEGMENT_64              Mem: 0x000000000-0x100000000    __PAGEZERO
LC 01: LC_SEGMENT_64              Mem: 0x100000000-0x100028000    __TEXT
[...]
Mem: 0x100026630-0x100026d54        __TEXT.__swift5_typeref
Mem: 0x100026d60-0x100027061        __TEXT.__swift5_reflstr
Mem: 0x100027064-0x1000274cc        __TEXT.__swift5_fieldmd
Mem: 0x1000274cc-0x100027608        __TEXT.__swift5_capture
[...]

Você pode encontrar mais informações sobre as seções de informações armazenadas neste post do blog.

Binários compactados

  • Verifique a entropia alta
  • Verifique as strings (se houver quase nenhuma string compreensível, está compactado)
  • O empacotador UPX para MacOS gera uma seção chamada "__XHDR"

Análise Dinâmica

{% hint style="warning" %} Observe que, para depurar binários, o SIP precisa estar desativado (csrutil disable ou csrutil enable --without debug) ou copiar os binários para uma pasta temporária e remover a assinatura com codesign --remove-signature <caminho-do-binário> ou permitir a depuração do binário (você pode usar este script) {% endhint %}

{% hint style="warning" %} Observe que, para instrumentar binários do sistema, (como cloudconfigurationd) no macOS, o SIP deve estar desativado (apenas remover a assinatura não funcionará). {% endhint %}

Logs Unificados

O MacOS gera muitos logs que podem ser muito úteis ao executar um aplicativo para entender o que ele está fazendo.

Além disso, existem alguns logs que conterão a tag <private> para ocultar algumas informações identificáveis do usuário ou do computador. No entanto, é possível instalar um certificado para divulgar essas informações. Siga as explicações aqui.

Hopper

Painel esquerdo

No painel esquerdo do Hopper, é possível ver os símbolos (Labels) do binário, a lista de procedimentos e funções (Proc) e as strings (Str). Essas não são todas as strings, mas aquelas definidas em várias partes do arquivo Mac-O (como cstring ou objc_methname).

Painel central

No painel central, você pode ver o código desmontado. E você pode vê-lo como um desmonte bruto, como gráfico, como descompilado e como binário clicando no ícone respectivo:

Ao clicar com o botão direito em um objeto de código, você pode ver referências para/deste objeto ou até mesmo alterar seu nome (isso não funciona no pseudocódigo descompilado):

Além disso, no meio inferior, você pode escrever comandos python.

Painel direito

No painel direito, você pode ver informações interessantes, como o histórico de navegação (para saber como você chegou à situação atual), o gráfico de chamadas onde você pode ver todas as funções que chamam essa função e todas as funções que essa função chama, e informações sobre variáveis locais.

dtruss

dtruss -c ls #Get syscalls of ls
dtruss -c -p 1000 #get syscalls of PID 1000

ktrace

Você pode usar este mesmo com o SIP ativado.

ktrace trace -s -S -t c -c ls | grep "ls("

dtrace

Ele permite que os usuários acessem aplicativos em um nível extremamente baixo e fornece uma maneira para os usuários rastrearem programas e até mesmo alterarem seu fluxo de execução. O Dtrace usa sondas que são colocadas em todo o kernel e estão em locais como o início e o fim das chamadas do sistema.

O DTrace usa a função dtrace_probe_create para criar uma sonda para cada chamada do sistema. Essas sondas podem ser disparadas no ponto de entrada e saída de cada chamada do sistema. A interação com o DTrace ocorre através do /dev/dtrace, que está disponível apenas para o usuário root.

As sondas disponíveis do dtrace podem ser obtidas com:

dtrace -l | head
ID   PROVIDER            MODULE                          FUNCTION NAME
1     dtrace                                                     BEGIN
2     dtrace                                                     END
3     dtrace                                                     ERROR
43    profile                                                     profile-97
44    profile                                                     profile-199

O nome da sonda consiste em quatro partes: o provedor, módulo, função e nome (fbt:mach_kernel:ptrace:entry). Se você não especificar alguma parte do nome, o Dtrace a considerará como um caractere curinga.

Para configurar o DTrace para ativar sondas e especificar quais ações executar quando elas são acionadas, precisaremos usar a linguagem D.

Uma explicação mais detalhada e mais exemplos podem ser encontrados em https://illumos.org/books/dtrace/chp-intro.html

Exemplos

Execute man -k dtrace para listar os scripts do DTrace disponíveis. Exemplo: sudo dtruss -n binary

  • Na linha
#Count the number of syscalls of each running process
sudo dtrace -n 'syscall:::entry {@[execname] = count()}'

Inspeção, Depuração e Fuzzing de Aplicativos no macOS

Neste guia, exploraremos técnicas para inspecionar, depurar e realizar fuzzing em aplicativos no macOS. Essas técnicas são úteis para identificar vulnerabilidades e realizar escalonamento de privilégios.

Inspeção de Aplicativos

A inspeção de aplicativos envolve examinar o código e a estrutura interna de um aplicativo para identificar possíveis vulnerabilidades. Existem várias ferramentas disponíveis para ajudar nesse processo, como:

  • Hopper: uma ferramenta de desmontagem que permite visualizar o código de um aplicativo.
  • class-dump: uma ferramenta que extrai informações sobre as classes e métodos de um aplicativo.
  • otool: uma ferramenta que exibe informações sobre os binários de um aplicativo.

Depuração de Aplicativos

A depuração de aplicativos é o processo de rastrear e corrigir erros em um aplicativo. No macOS, podemos usar o lldb (Low-Level Debugger) para depurar aplicativos. Algumas das principais funcionalidades do lldb incluem:

  • Definir pontos de interrupção para pausar a execução do aplicativo em um determinado ponto.
  • Examinar e modificar variáveis e registros durante a execução do aplicativo.
  • Rastrear a pilha de chamadas para entender o fluxo de execução do aplicativo.

Fuzzing de Aplicativos

O fuzzing é uma técnica usada para encontrar vulnerabilidades em aplicativos por meio da inserção de dados aleatórios ou inválidos. No macOS, podemos usar a ferramenta AFL (American Fuzzy Lop) para realizar fuzzing em aplicativos. O AFL é capaz de gerar entradas de teste automaticamente e identificar falhas de segurança.

Conclusão

A inspeção, depuração e fuzzing de aplicativos no macOS são técnicas valiosas para identificar vulnerabilidades e realizar escalonamento de privilégios. Ao utilizar as ferramentas e técnicas mencionadas neste guia, você poderá fortalecer a segurança de seus aplicativos e proteger seus sistemas contra possíveis ataques.

syscall:::entry
/pid == $1/
{
}

#Log every syscall of a PID
sudo dtrace -s script.d 1234
syscall::open:entry
{
printf("%s(%s)", probefunc, copyinstr(arg0));
}
syscall::close:entry
{
printf("%s(%d)\n", probefunc, arg0);
}

#Log files opened and closed by a process
sudo dtrace -s b.d -c "cat /etc/hosts"
syscall:::entry
{
;
}
syscall:::return
{
printf("=%d\n", arg1);
}

#Log sys calls with values
sudo dtrace -s syscalls_info.d -c "cat /etc/hosts"

ProcessMonitor

ProcessMonitor é uma ferramenta muito útil para verificar as ações relacionadas a processos que um processo está executando (por exemplo, monitorar quais novos processos um processo está criando).

FileMonitor

FileMonitor permite monitorar eventos de arquivos (como criação, modificações e exclusões), fornecendo informações detalhadas sobre esses eventos.

Apple Instruments

Apple Instruments fazem parte das ferramentas de desenvolvedor do Xcode - usadas para monitorar o desempenho do aplicativo, identificar vazamentos de memória e rastrear a atividade do sistema de arquivos.

fs_usage

Permite acompanhar as ações executadas pelos processos:

fs_usage -w -f filesys ls #This tracks filesystem actions of proccess names containing ls
fs_usage -w -f network curl #This tracks network actions

TaskExplorer

Taskexplorer é útil para ver as bibliotecas usadas por um binário, os arquivos que ele está usando e as conexões de rede.
Ele também verifica os processos binários no virustotal e mostra informações sobre o binário.

PT_DENY_ATTACH

Neste post do blog, você pode encontrar um exemplo de como depurar um daemon em execução que usa PT_DENY_ATTACH para evitar a depuração, mesmo que o SIP esteja desativado.

lldb

lldb é a ferramenta de fato para depuração de binários no macOS.

lldb ./malware.bin
lldb -p 1122
lldb -n malware.bin
lldb -n malware.bin --waitfor

{% hint style="warning" %} Dentro do lldb, faça o dump de um processo com process save-core {% endhint %}

Comando (lldb) Descrição
run (r) Inicia a execução, que continuará até que um ponto de interrupção seja atingido ou o processo seja encerrado.
continue (c) Continua a execução do processo em depuração.
nexti (n / ni) Executa a próxima instrução. Este comando irá pular chamadas de função.
stepi (s / si) Executa a próxima instrução. Ao contrário do comando nexti, este comando irá entrar nas chamadas de função.
finish (f) Executa o restante das instruções na função atual ("frame") e retorna.
control + c Pausa a execução. Se o processo foi iniciado (r) ou continuado (c), isso fará com que o processo pare ... onde quer que esteja executando no momento.
breakpoint (b)

b main

b -[NSDictionary objectForKey:]

b 0x0000000100004bd9

br l #Lista de pontos de interrupção

br e/dis <num> #Habilitar/Desabilitar ponto de interrupção

breakpoint delete <num>
b set -n main --shlib <lib_name>

help

help breakpoint #Obter ajuda sobre o comando breakpoint

help memory write #Obter ajuda para escrever na memória

reg

reg read

reg read $rax

reg write $rip 0x100035cc0

x/s <reg/endereço de memória> Exibe a memória como uma string terminada em nulo.
x/i <reg/endereço de memória> Exibe a memória como instrução de montagem.
x/b <reg/endereço de memória> Exibe a memória como byte.
print object (po)

Isso irá imprimir o objeto referenciado pelo parâmetro

po $raw

{

dnsChanger = {

"affiliate" = "";

"blacklist_dns" = ();

Observe que a maioria das APIs ou métodos Objective-C da Apple retornam objetos e, portanto, devem ser exibidos por meio do comando "print object" (po). Se po não produzir uma saída significativa, use x/b

memory

memory read 0x000....
memory read $x0+0xf2a
memory write 0x100600000 -s 4 0x41414141 #Escreve AAAA nesse endereço
memory write -f s $rip+0x11f+7 "AAAA" #Escreve AAAA no endereço

disassembly

dis #Desmonta a função atual
dis -c 6 #Desmonta 6 linhas
dis -c 0x100003764 -e 0x100003768 # De um endereço até o outro
dis -p -c 4 # Inicia no endereço atual desmontando

parray parray 3 (char **)$x1 #Verifica o array de 3 componentes no registro x1

{% hint style="info" %} Ao chamar a função objc_sendMsg, o registro rsi contém o nome do método como uma string terminada em nulo ("C"). Para imprimir o nome via lldb, faça:

(lldb) x/s $rsi: 0x1000f1576: "startMiningWithPort:password:coreCount:slowMemory:currency:"

(lldb) print (char*)$rsi:
(char *) $1 = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"

(lldb) reg read $rsi: rsi = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:" {% endhint %}

Anti-Análise Dinâmica

Detecção de VM

  • O comando sysctl hw.model retorna "Mac" quando o host é um MacOS, mas algo diferente quando é uma VM.
  • Brincando com os valores de hw.logicalcpu e hw.physicalcpu, alguns malwares tentam detectar se é uma VM.
  • Alguns malwares também podem detectar se a máquina é baseada no VMware pelo endereço MAC (00:50:56).
  • Também é possível descobrir se um processo está sendo depurado com um código simples como:
  • if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //processo sendo depurado }
  • Também pode invocar a chamada de sistema ptrace com a flag PT_DENY_ATTACH. Isso impede um depurador de anexar e rastrear.
  • Você pode verificar se a função sysctl ou ptrace está sendo importada (mas o malware pode importá-la dinamicamente)
  • Como observado neste artigo, “Defeating Anti-Debug Techniques: macOS ptrace variants” :
    A mensagem Processo # saiu com status = 45 (0x0000002d) é geralmente um sinal revelador de que o alvo de depuração está usando PT_DENY_ATTACH

Fuzzing

ReportCrash

ReportCrash analisa processos que estão travando e salva um relatório de travamento no disco. Um relatório de travamento contém informações que podem ajudar um desenvolvedor a diagnosticar a causa de um travamento.
Para aplicativos e outros processos executados no contexto do launchd por usuário, o ReportCrash é executado como um LaunchAgent e salva os relatórios de travamento em ~/Library/Logs/DiagnosticReports/ do usuário.
Para daemons, outros processos executados no contexto do launchd do sistema e outros processos privilegiados, o ReportCrash é executado como um LaunchDaemon e salva os relatórios de travamento em /Library/Logs/DiagnosticReports do sistema.

Se você está preocupado com os relatórios de travamento sendo enviados para a Apple, você pode desativá-los. Caso contrário, os relatórios de travamento podem ser úteis para descobrir como um servidor travou.

#To disable crash reporting:
launchctl unload -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist

#To re-enable crash reporting:
launchctl load -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist

Sleep

Durante a realização de fuzzing em um MacOS, é importante não permitir que o Mac entre em modo de repouso:

  • systemsetup -setsleep Never
  • pmset, Preferências do Sistema
  • KeepingYouAwake

Desconexão SSH

Se você estiver realizando fuzzing por meio de uma conexão SSH, é importante garantir que a sessão não seja encerrada. Portanto, altere o arquivo sshd_config com:

  • TCPKeepAlive Yes
  • ClientAliveInterval 0
  • ClientAliveCountMax 0
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

Manipuladores Internos

Verifique a seguinte página para descobrir como você pode encontrar qual aplicativo é responsável por manipular o esquema ou protocolo especificado:

{% content-ref url="../macos-file-extension-apps.md" %} macos-file-extension-apps.md {% endcontent-ref %}

Enumerando Processos de Rede

Isso é interessante para encontrar processos que estão gerenciando dados de rede:

dtrace -n 'syscall::recv*:entry { printf("-> %s (pid=%d)", execname, pid); }' >> recv.log
#wait some time
sort -u recv.log > procs.txt
cat procs.txt

Ou use netstat ou lsof

Libgmalloc

{% code overflow="wrap" %}

lldb -o "target create `which some-binary`" -o "settings set target.env-vars DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib" -o "run arg1 arg2" -o "bt" -o "reg read" -o "dis -s \$pc-32 -c 24 -m -F intel" -o "quit"

Fuzzers

AFL++

Funciona para ferramentas de linha de comando.

Litefuzz

Ele "simplesmente funciona" com ferramentas de GUI do macOS. Observe que alguns aplicativos do macOS têm requisitos específicos, como nomes de arquivos exclusivos, a extensão correta e a necessidade de ler os arquivos do sandbox (~/Library/Containers/com.apple.Safari/Data)...

Alguns exemplos:

{% code overflow="wrap" %}

# iBooks
litefuzz -l -c "/System/Applications/Books.app/Contents/MacOS/Books FUZZ" -i files/epub -o crashes/ibooks -t /Users/test/Library/Containers/com.apple.iBooksX/Data/tmp -x 10 -n 100000 -ez

# -l : Local
# -c : cmdline with FUZZ word (if not stdin is used)
# -i : input directory or file
# -o : Dir to output crashes
# -t : Dir to output runtime fuzzing artifacts
# -x : Tmeout for the run (default is 1)
# -n : Num of fuzzing iterations (default is 1)
# -e : enable second round fuzzing where any crashes found are reused as inputs
# -z : enable malloc debug helpers

# Font Book
litefuzz -l -c "/System/Applications/Font Book.app/Contents/MacOS/Font Book FUZZ" -i input/fonts -o crashes/font-book -x 2 -n 500000 -ez

# smbutil (using pcap capture)
litefuzz -lk -c "smbutil view smb://localhost:4455" -a tcp://localhost:4455 -i input/mac-smb-resp -p -n 100000 -z

# screensharingd (using pcap capture)
litefuzz -s -a tcp://localhost:5900 -i input/screenshared-session --reportcrash screensharingd -p -n 100000

{% endcode %}

Mais informações sobre Fuzzing no MacOS

Referências

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥