Aprofunde sua experiência em Segurança Móvel com a 8kSec Academy. Domine a segurança do iOS e Android através de nossos cursos autônomos e obtenha certificação:
Instalando o Frida
Passos para instalar o Frida em um dispositivo Jailbroken:
Abra o aplicativo Cydia/Sileo.
Navegue até Gerenciar -> Fontes -> Editar -> Adicionar.
Insira "https://build.frida.re" como a URL.
Vá para a nova fonte do Frida adicionada.
Instale o pacote do Frida.
Se você estiver usando Corellium, precisará baixar a versão do Frida em https://github.com/frida/frida/releases (frida-gadget-[sua versão]-ios-universal.dylib.gz) e descompactar e copiar para o local dylib que o Frida solicita, por exemplo: /Users/[seu usuário]/.cache/frida/gadget-ios.dylib
Após a instalação, você pode usar no seu PC o comando frida-ls-devices e verificar se o dispositivo aparece (seu PC precisa ser capaz de acessá-lo).
Execute também frida-ps -Uia para verificar os processos em execução do telefone.
Frida sem dispositivo Jailbroken e sem patching do aplicativo
Com o servidor Frida instalado e o dispositivo em execução e conectado, verifique se o cliente está funcionando:
frida-ls-devices# List devicesfrida-ps-Uia# Get running processes
Frida Trace
# Functions## Trace all functions with the word "log" in their namefrida-trace-U<program>-i"*log*"frida-trace-U<program>-i"*log*"|swiftdemangle# Demangle names# Objective-C## Trace all methods of all classesfrida-trace-U<program>-m"*[* *]"## Trace all methods with the word "authentication" from classes that start with "NE"frida-trace-U<program>-m"*[NE* *authentication*]"# Plug-In## To hook a plugin that is momentarely executed prepare Frida indicating the ID of the Plugin binaryfrida-trace-U-W<if-plugin-bin>-m'*[* *]'
Obter todas as classes e métodos
Auto completar: Basta executar frida -U <program>
Obter todas as classes disponíveis (filtrar por string)
Obter todos os métodos de uma classe (filtrar por string)
/tmp/script.js
// frida -U <program> -l /tmp/script.jsvar specificClass ="YourClassName";var filterMethod ="filtermethod";if (ObjC.available) {if (ObjC.classes.hasOwnProperty(specificClass)) {var methods =ObjC.classes[specificClass].$ownMethods;for (var i =0; i <methods.length; i++) {if (!filterMethod || methods[i].includes(filterClass)) {console.log(specificClass +': '+ methods[i]);}}} else {console.log("Class not found.");}} else {console.log("Objective-C runtime is not available.");}
Chamar uma função
// Find the address of the function to callconstfunc_addr=Module.findExportByName("<Prog Name>","<Func Name>");// Declare the function to callconstfunc=newNativeFunction(func_addr,"void", ["pointer","pointer","pointer"], {});var arg0 =null;// In this case to call this function we need to intercept a call to it to copy arg0Interceptor.attach(wg_log_addr, {onEnter:function(args) {arg0 =newNativePointer(args[0]);}});// Wait untill a call to the func occurswhile (! arg0) {Thread.sleep(1);console.log("waiting for ptr");}var arg1 =Memory.allocUtf8String('arg1');var txt =Memory.allocUtf8String('Some text for arg2');wg_log(arg0, arg1, txt);console.log("loaded");
Frida Fuzzing
Frida Stalker
Da documentação: Stalker é o motor de rastreamento do Frida. Ele permite que threads sejam seguidas, capturando cada função, cada bloco, até mesmo cada instrução que é executada.
Este é outro exemplo para anexar o Frida Stalker toda vez que uma função é chamada:
console.log("loading");constwg_log_addr=Module.findExportByName("<Program>","<function_name>");constwg_log=newNativeFunction(wg_log_addr,"void", ["pointer","pointer","pointer"], {});Interceptor.attach(wg_log_addr, {onEnter:function(args) {console.log(`logging the following message: ${args[2].readCString()}`);Stalker.follow({events: {// only collect coverage for newly encountered blockscompile:true,},onReceive:function (events) {constbbs=Stalker.parse(events, {stringify:false,annotate:false});console.log("Stalker trace of write_msg_to_log: \n"+bbs.flat().map(DebugSymbol.fromAddress).join('\n'));}});},onLeave:function(retval) {Stalker.unfollow();Stalker.flush(); // this is important to get all events}});
Isso é interessante para fins de depuração, mas para fuzzing, estar constantemente .follow() e .unfollow() é muito ineficiente.
fpicker é um conjunto de ferramentas de fuzzing baseado em Frida que oferece uma variedade de modos de fuzzing para fuzzing em processo, como um modo AFL++ ou um modo de rastreamento passivo. Deve funcionar em todas as plataformas suportadas pelo Frida.
# Get fpickergitclonehttps://github.com/ttdennis/fpickercdfpicker# Get Frida core devkit and prepare fpickerwgethttps://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-[yourOS]-[yourarchitecture].tar.xz# e.g. https://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-macos-arm64.tar.xztar-xf./*tar.xzcplibfrida-core.alibfrida-core-[yourOS].a#libfrida-core-macos.a# Install fpickermakefpicker-[yourOS]# fpicker-macos# This generates ./fpicker# Install radamsa (fuzzer generator)brewinstallradamsa
Preparar o FS:
# From inside fpicker clonemkdir-pexamples/wg-log# Where the fuzzing script will bemkdir-pexamples/wg-log/out# For code coverage and crashesmkdir-pexamples/wg-log/in# For starting inputs# Create at least 1 input for the fuzzerechoHelloWorld>examples/wg-log/in/0
Script de Fuzzer (examples/wg-log/myfuzzer.js):
examples/wg-log/myfuzzer.js
// Import the fuzzer base classimport { Fuzzer } from"../../harness/fuzzer.js";classWGLogFuzzerextendsFuzzer {constructor() {console.log("WGLogFuzzer constructor called")// Get and declare the function we are going to fuzzvar wg_log_addr =Module.findExportByName("<Program name>","<func name to fuzz>");var wg_log_func =newNativeFunction(wg_log_addr,"void", ["pointer","pointer","pointer"], {});// Initialize the objectsuper("<Program nane>", wg_log_addr, wg_log_func);this.wg_log_addr = wg_log_addr; // We cannot use "this" before calling "super"console.log("WGLogFuzzer in the middle");// Prepare the second argument to pass to the fuzz functionthis.tag =Memory.allocUtf8String("arg2");// Get the first argument we need to pass from a call to the functino we want to fuzzvar wg_log_global_ptr =null;console.log(this.wg_log_addr);Interceptor.attach(this.wg_log_addr, {onEnter:function(args) {console.log("Entering in the function to get the first argument");wg_log_global_ptr =newNativePointer(args[0]);}});while (! wg_log_global_ptr) {Thread.sleep(1)}this.wg_log_global_ptr = wg_log_global_ptr;console.log("WGLogFuzzer prepare ended")}// This function is called by the fuzzer with the first argument being a pointer into memory// where the payload is stored and the second the length of the input.fuzz(payload, len) {// Get a pointer to payload being a valid C string (with a null byte at the end)var payload_cstring =payload.readCString(len);this.payload =Memory.allocUtf8String(payload_cstring);// Debug and fuzzthis.debug_log(this.payload, len);// Pass the 2 first arguments we know the function needs and finally the payload to fuzzthis.target_function(this.wg_log_global_ptr,this.tag,this.payload);}}constf=newWGLogFuzzer();rpc.exports.fuzzer = f;
Compile o fuzzer:
# From inside fpicker clone## Compile from "myfuzzer.js" to "harness.js"frida-compileexamples/wg-log/myfuzzer.js-oharness.js
Chame o fuzzer fpicker usando radamsa:
# Indicate fpicker to fuzz a program with the harness.js script and which folders to usefpicker-v--fuzzer-modeactive-eattach-p<Programtofuzz>-Dusb-oexamples/wg-log/out/-iexamples/wg-log/in/-fharness.js--standalone-mutatorcmd--mutator-command"radamsa"# You can find code coverage and crashes in examples/wg-log/out/
Neste caso, não estamos reiniciando o aplicativo ou restaurando o estado após cada payload. Portanto, se o Frida encontrar um crash, as próximas entradas após esse payload também podem crashar o aplicativo (porque o aplicativo está em um estado instável), mesmo que a entrada não devesse crashar o aplicativo.
Além disso, o Frida irá interceptar sinais de exceção do iOS, então quando o Frida encontrar um crash, provavelmente relatórios de crash do iOS não serão gerados.
Para evitar isso, por exemplo, poderíamos reiniciar o aplicativo após cada crash do Frida.
Logs & Crashes
Você pode verificar o console do macOS ou o log cli para checar os logs do macOS.
Você também pode verificar os logs do iOS usando idevicesyslog.
Alguns logs omitem informações adicionando <private>. Para mostrar todas as informações, você precisa instalar algum perfil de https://developer.apple.com/bug-reporting/profiles-and-logs/ para habilitar essas informações privadas.
Aprofunde sua experiência em Mobile Security com a 8kSec Academy. Domine a segurança de iOS e Android através de nossos cursos autônomos e obtenha certificação: