Skip to content

MASTG-TECH-0096: Exploração de Processos

Ao testar um aplicativo, a exploração de processos pode fornecer ao testador insights profundos sobre a memória do processo do app. Isso pode ser alcançado via instrumentação em tempo de execução e permite realizar tarefas como:

  • Recuperar o mapa de memória e bibliotecas carregadas.
  • Buscar ocorrências de determinados dados.
  • Após realizar uma busca, obter a localização de um determinado offset no mapa de memória.
  • Realizar um dump de memória e inspecionar ou realizar engenharia reversa dos dados binários offline.
  • Fazer engenharia reversa de um binário ou Framework enquanto ele está em execução.

Como você pode ver, essas tarefas são mais de suporte e/ou passivas, elas nos ajudarão a coletar dados e informações que darão suporte a outras técnicas. Portanto, normalmente são usadas em combinação com outras técnicas como method hooking.

Nas seções a seguir, você usará r2frida para recuperar informações diretamente do runtime do app. Comece abrindo uma sessão r2frida para o app alvo (por exemplo, iGoat-Swift) que deve estar em execução no seu iPhone (conectado via USB). Use o seguinte comando:

r2 frida://usb//iGoat-Swift

Mapas de Memória e Inspeção

Você pode recuperar os mapas de memória do app executando :dm:

[0x00000000]> :dm
0x0000000100b7c000 - 0x0000000100de0000 r-x /private/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app/iGoat-Swift
0x0000000100de0000 - 0x0000000100e68000 rw- /private/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app/iGoat-Swift
0x0000000100e68000 - 0x0000000100e97000 r-- /private/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app/iGoat-Swift
...
0x0000000100ea8000 - 0x0000000100eb0000 rw-
0x0000000100eb0000 - 0x0000000100eb4000 r--
0x0000000100eb4000 - 0x0000000100eb8000 r-x /usr/lib/TweakInject.dylib
0x0000000100eb8000 - 0x0000000100ebc000 rw- /usr/lib/TweakInject.dylib
0x0000000100ebc000 - 0x0000000100ec0000 r-- /usr/lib/TweakInject.dylib
0x0000000100f60000 - 0x00000001012dc000 r-x /private/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app/Frameworks/Realm.framework/Realm

Enquanto você está pesquisando ou explorando a memória do app, você sempre pode verificar onde seu offset atual está localizado no mapa de memória. Em vez de anotar e procurar o endereço de memória nesta lista, você pode simplesmente executar :dm.. Você encontrará um exemplo na próxima seção "Busca em Memória".

Se você estiver interessado apenas nos módulos (binários e bibliotecas) que o app carregou, você pode usar o comando :il para listar todos:

[0x00000000]> :il
0x0000000100b7c000 iGoat-Swift
0x0000000100eb4000 TweakInject.dylib
0x00000001862c0000 SystemConfiguration
0x00000001847c0000 libc++.1.dylib
0x0000000185ed9000 Foundation
0x000000018483c000 libobjc.A.dylib
0x00000001847be000 libSystem.B.dylib
0x0000000185b77000 CFNetwork
0x0000000187d64000 CoreData
0x00000001854b4000 CoreFoundation
0x00000001861d3000 Security
0x000000018ea1d000 UIKit
0x0000000100f60000 Realm

Como você pode esperar, você pode correlacionar os endereços das bibliotecas com os mapas de memória: por exemplo, o app principal do iGoat-Swift é chamado "iGoat-Swift" e está localizado em 0x0000000100b7c000 e o Realm Framework em 0x0000000100f60000.

Você também pode usar Objection para iOS para exibir a mesma informação.

$ objection --gadget OWASP.iGoat-Swift explore

OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # memory list modules
Save the output by adding `--json modules.json` to this command

Name                              Base         Size                  Path
--------------------------------  -----------  --------------------  ------------------------------------------------------------------------------
iGoat-Swift                       0x100b7c000  2506752 (2.4 MiB)     /var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGo...
TweakInject.dylib                 0x100eb4000  16384 (16.0 KiB)      /usr/lib/TweakInject.dylib
SystemConfiguration               0x1862c0000  446464 (436.0 KiB)    /System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguratio...
libc++.1.dylib                    0x1847c0000  368640 (360.0 KiB)    /usr/lib/libc++.1.dylib

Busca em Memória

A busca em memória é uma técnica muito útil para testar dados sensíveis que possam estar presentes na memória do app.

Consulte a ajuda do r2frida sobre o comando de busca (:/?) para aprender sobre o comando de busca e obter uma lista de opções. A seguir mostra apenas um subconjunto delas:

[0x00000000]> :/?
 /      search
 /j     search json
 /w     search wide
 /wj    search wide json
 /x     search hex
 /xj    search hex json
...

Você pode ajustar sua busca usando as configurações de busca :e~search. Por exemplo, :e search.quiet=true; imprimirá apenas os resultados e ocultará o progresso da busca:

[0x00000000]> :e~search
e search.in=perm:r--
e search.quiet=false

Por enquanto, continuaremos com os padrões e nos concentraremos na busca de strings. Neste primeiro exemplo, você pode começar pesquisando por algo que sabe que deve estar localizado no binário principal do app (por exemplo, o nome do app iGoat-Swift):

[0x00000000]> :/ iGoat
Searching 5 bytes: 69 47 6f 61 74
Searching 5 bytes in [0x0000000100b7c000-0x0000000100de0000]
...
hits: 509
0x100d7d332 hit2_0 iGoat_Swift24StringAnalysisExerciseVCC
0x100d7d3b2 hit2_1 iGoat_Swift28BrokenCryptographyExerciseVCC
0x100d7d442 hit2_2 iGoat_Swift23BackgroundingExerciseVCC
0x100d7d4b2 hit2_3 iGoat_Swift9AboutCellC
0x100d7d522 hit2_4 iGoat_Swift12FadeAnimatorV

Agora pegue o primeiro hit, vá até ele e verifique sua localização atual no mapa de memória:

[0x00000000]> s 0x100d7d332
[0x100d7d332]> :dm.
0x0000000100b7c000 - 0x0000000100de0000 r-x /private/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app/iGoat-Swift

Como esperado, você está localizado na região do binário principal do iGoat-Swift (r-x, leitura e execução). Na seção anterior, você viu que o binário principal está localizado entre 0x0000000100b7c000 e 0x0000000100e97000.

Agora, para este segundo exemplo, você pode pesquisar por algo que não está no binário do app nem em nenhuma biblioteca carregada, tipicamente entrada do usuário. Abra o app iGoat-Swift e navegue no menu para Autenticação -> Autenticação Remota -> Iniciar. Lá você encontrará um campo de senha que pode sobrescrever. Escreva a string "owasp-mstg" mas não clique em Login ainda. Execute as duas etapas a seguir.

[0x00000000]> :/ owasp-mstg
hits: 1
0x1c06619c0 hit3_0 owasp-mstg

De fato, a string pôde ser encontrada no endereço 0x1c06619c0. Vá até lá com s e recupere a região de memória atual com :dm..

[0x100d7d332]> s 0x1c06619c0
[0x1c06619c0]> :dm.
0x00000001c0000000 - 0x00000001c8000000 rw-

Agora você sabe que a string está localizada em uma região rw- (leitura e escrita) do mapa de memória.

Além disso, você pode pesquisar por ocorrências da versão wide da string (/w) e, novamente, verificar suas regiões de memória:

Desta vez executamos o comando :dm. para todos os hits @@ correspondentes ao glob hit5_*.

[0x00000000]> /w owasp-mstg
Searching 20 bytes: 6f 00 77 00 61 00 73 00 70 00 2d 00 6d 00 73 00 74 00 67 00
Searching 20 bytes in [0x0000000100708000-0x000000010096c000]
...
hits: 2
0x1020d1280 hit5_0 6f0077006100730070002d006d00730074006700
0x1030c9c85 hit5_1 6f0077006100730070002d006d00730074006700

[0x00000000]> :dm.@@ hit5_*
0x0000000102000000 - 0x0000000102100000 rw-
0x0000000103084000 - 0x00000001030cc000 rw-

Eles estão em uma região rw- diferente. Note que buscar pelas versões wide de strings às vezes é a única maneira de encontrá-las, como você verá na próxima seção.

A busca em memória pode ser muito útil para saber rapidamente se determinados dados estão localizados no binário principal do app, dentro de uma biblioteca compartilhada ou em outra região. Você também pode usá-la para testar o comportamento do app em relação a como os dados são mantidos na memória. Por exemplo, você poderia continuar o exemplo anterior, desta vez clicando em Login e pesquisando novamente por ocorrências dos dados. Além disso, você pode verificar se ainda consegue encontrar essas strings na memória após o login ser concluído para verificar se esses dados sensíveis são apagados da memória após o uso.

Dump de Memória

Você pode fazer o dump da memória do processo do app com Objection para iOS e Fridump. Para aproveitar essas ferramentas em um dispositivo não-jailbroken, o app Android deve ser reempacotado com frida-gadget.so e reassinado. Uma explicação detalhada desse processo é descrita em Injetando Frida Gadget em um IPA Automaticamente. Para usar essas ferramentas em um phone com jailbreak, simplesmente tenha o frida-server instalado e em execução.

Com o objection é possível fazer o dump de toda a memória do processo em execução no dispositivo usando o comando memory dump all.

$ objection explore

iPhone on (iPhone: 10.3.1) [usb] # memory dump all /Users/foo/memory_iOS/memory
Dumping 768.0 KiB from base: 0x1ad200000  [####################################]  100%
Memory dumped to file: /Users/foo/memory_iOS/memory

Alternativamente você pode usar o Fridump. Primeiro, você precisa do nome do app que deseja fazer dump, que você pode obter com frida-ps.

$ frida-ps -U
 PID  Name
----  ------
1026  Gadget

Posteriormente, especifique o nome do app no Fridump.

$ python3 fridump.py -u Gadget -s

Current Directory: /Users/foo/PentestTools/iOS/fridump
Output directory is set to: /Users/foo/PentestTools/iOS/fridump/dump
Creating directory...
Starting Memory dump...
Progress: [##################################################] 100.0% Complete

Running strings on all files:
Progress: [##################################################] 100.0% Complete

Finished! Press Ctrl+C

Quando você adiciona a flag -s, todas as strings são extraídas dos arquivos de memória raw despejados e adicionadas ao arquivo strings.txt, que é armazenado no diretório de dump do Fridump.

Em ambos os casos, se você abrir o arquivo no radare2 pode usar seu comando de busca (/). Note que primeiro fazemos uma busca padrão de string que não tem sucesso e em seguida buscamos por uma string wide, que encontra com sucesso nossa string "owasp-mstg".

$ r2 memory_ios
[0x00000000]> / owasp-mstg
Searching 10 bytes in [0x0-0x628c000]
hits: 0
[0x00000000]> /w owasp-mstg
Searching 20 bytes in [0x0-0x628c000]
hits: 1
0x0036f800 hit4_0 6f0077006100730070002d006d00730074006700

Em seguida, podemos ir até seu endereço usando s 0x0036f800 ou s hit4_0 e imprimi-lo usando psw (que significa print string wide) ou usar px para imprimir seus valores hexadecimais raw:

[0x0036f800]> psw
owasp-mstg

[0x0036f800]> px 48
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x0036f800  6f00 7700 6100 7300 7000 2d00 6d00 7300  o.w.a.s.p.-.m.s.
0x0036f810  7400 6700 0000 0000 0000 0000 0000 0000  t.g.............
0x0036f820  0000 0000 0000 0000 0000 0000 0000 0000  ................

Note que para encontrar esta string usando o comando strings você terá que especificar uma codificação usando a flag -e e neste caso l para caracteres little-endian de 16 bits.

$ strings -e l memory_ios | grep owasp-mstg
owasp-mstg