hacktricks/mobile-pentesting/ios-pentesting/ios-custom-uri-handlers-deeplinks-custom-schemes.md
2023-06-06 18:56:34 +00:00

15 KiB

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

Os esquemas de URL personalizados permitem que os aplicativos se comuniquem por meio de um protocolo personalizado. Um aplicativo deve declarar suporte para os esquemas e lidar com URLs de entrada que usam esses esquemas.

Os esquemas de URL oferecem um vetor de ataque potencial para o seu aplicativo, portanto, certifique-se de validar todos os parâmetros de URL e descartar URLs malformados. Além disso, limite as ações disponíveis para aquelas que não colocam em risco os dados do usuário.

Por exemplo, a URI: myapp://hostname?data=123876123 irá invocar o aplicativo mydata (aquele que registrou o esquema mydata) para a ação relacionada ao hostname hostname enviando o parâmetro data com valor 123876123.

Um exemplo vulnerável é o seguinte bug no aplicativo móvel do Skype, descoberto em 2010: O aplicativo Skype registrou o manipulador de protocolo skype://, o que permitiu que outros aplicativos acionassem chamadas para outros usuários do Skype e números de telefone. Infelizmente, o Skype não pediu permissão aos usuários antes de fazer as chamadas, então qualquer aplicativo poderia ligar para números arbitrários sem o conhecimento do usuário. Os atacantes exploraram essa vulnerabilidade colocando um <iframe src="skype://xxx?call"></iframe> invisível (onde xxx foi substituído por um número premium), então qualquer usuário do Skype que inadvertidamente visitasse um site malicioso chamava o número premium.

Você pode encontrar os esquemas registrados por um aplicativo no arquivo Info.plist do aplicativo procurando por CFBundleURLTypes (exemplo do iGoat-Swift):

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>com.iGoat.myCompany</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>iGoat</string>
        </array>
    </dict>
</array>

No entanto, observe que aplicativos maliciosos podem registrar novamente URIs já registrados por outros aplicativos. Portanto, se você estiver enviando informações confidenciais por meio de URIs (myapp://hostname?password=123456), um aplicativo malicioso pode interceptar a URI com as informações confidenciais.

Além disso, a entrada dessas URIs deve ser verificada e sanitizada, pois pode estar vindo de origens maliciosas tentando explorar SQLInjections, XSS, CSRF, Traversals de Caminho ou outras possíveis vulnerabilidades.

Registro de Esquemas de Consulta do Aplicativo

Os aplicativos podem chamar canOpenURL: para verificar se o aplicativo de destino está disponível. No entanto, como esse método estava sendo usado por aplicativos maliciosos como uma forma de enumerar aplicativos instalados, a partir do iOS 9.0, os esquemas de URL passados para ele também devem ser declarados adicionando a chave LSApplicationQueriesSchemes ao arquivo Info.plist do aplicativo e um array de até 50 esquemas de URL.

<key>LSApplicationQueriesSchemes</key>
    <array>
        <string>url_scheme1</string>
        <string>url_scheme2</string>
    </array>

canOpenURL sempre retornará NO para esquemas não declarados, independentemente de um aplicativo apropriado estar instalado ou não. No entanto, essa restrição se aplica apenas ao canOpenURL.

Testando o Manuseio e Validação de URLs

Para determinar como um caminho de URL é construído e validado, se você tiver o código-fonte original, pode procurar pelos seguintes métodos:

  • Método application:didFinishLaunchingWithOptions: ou application:will-FinishLaunchingWithOptions:: verifique como a decisão é tomada e como as informações sobre a URL são recuperadas.
  • application:openURL:options:: verifique como o recurso está sendo aberto, ou seja, como os dados estão sendo analisados, verifique as opções, especialmente se o acesso pelo aplicativo chamador (sourceApplication) deve ser permitido ou negado. O aplicativo também pode precisar da permissão do usuário ao usar o esquema de URL personalizado.

No Telegram, você encontrará quatro métodos diferentes sendo usados:

func application(_ application: UIApplication, open url: URL, sourceApplication: String?) -> Bool {
    self.openUrl(url: url)
    return true
}

func application(_ application: UIApplication, open url: URL, sourceApplication: String?,
annotation: Any) -> Bool {
    self.openUrl(url: url)
    return true
}

func application(_ app: UIApplication, open url: URL,
options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    self.openUrl(url: url)
    return true
}

func application(_ application: UIApplication, handleOpen url: URL) -> Bool {
    self.openUrl(url: url)
    return true
}

Testando solicitações de URL para outros aplicativos

O método openURL:options:completionHandler: e o método obsoleto openURL: da UIApplication são responsáveis por abrir URLs (ou seja, enviar solicitações / fazer consultas para outros aplicativos) que podem ser locais para o aplicativo atual ou podem ser fornecidos por um aplicativo diferente. Se você tiver o código-fonte original, poderá procurar diretamente por usos desses métodos.

Além disso, se você estiver interessado em saber se o aplicativo está consultando serviços ou aplicativos específicos e se o aplicativo é bem conhecido, também pode pesquisar por esquemas de URL comuns online e incluí-los em seus greps (lista de esquemas de aplicativos iOS).

egrep -nr "open.*options.*completionHandler" ./Telegram-iOS/
egrep -nr "openURL\(" ./Telegram-iOS/
egrep -nr "mt-encrypted-file://" ./Telegram-iOS/
egrep -nr "://" ./Telegram-iOS/

Testando Métodos Obsoletos

Procure por métodos obsoletos como:

Por exemplo, aqui encontramos esses três:

$ rabin2 -zzq Telegram\ X.app/Telegram\ X | grep -i "openurl"

0x1000d9e90 31 30 UIApplicationOpenURLOptionsKey
0x1000dee3f 50 49 application:openURL:sourceApplication:annotation:
0x1000dee71 29 28 application:openURL:options:
0x1000dee8e 27 26 application:handleOpenURL:
0x1000df2c9 9 8 openURL:
0x1000df766 12 11 canOpenURL:
0x1000df772 35 34 openURL:options:completionHandler:
...

Chamando URLs arbitrárias

  • Safari: Para testar rapidamente um esquema de URL, você pode abrir as URLs no Safari e observar como o aplicativo se comporta. Por exemplo, se você escrever tel://123456789, o Safari tentará iniciar a chamada para o número.

  • Notes App: Pressione longamente os links que você escreveu para testar esquemas de URL personalizados. Lembre-se de sair do modo de edição para poder abri-los. Observe que você pode clicar ou pressionar links, incluindo esquemas de URL personalizados, somente se o aplicativo estiver instalado, caso contrário, eles não serão destacados como links clicáveis.

  • IDB:

    • Inicie o IDB, conecte-se ao seu dispositivo e selecione o aplicativo de destino. Você pode encontrar detalhes na documentação do IDB.
    • Vá para a seção URL Handlers. Em URL schemes, clique em Refresh, e à esquerda você encontrará uma lista de todos os esquemas personalizados definidos no aplicativo em teste. Você pode carregar esses esquemas clicando em Open, no lado direito. Ao simplesmente abrir um esquema de URI em branco (por exemplo, abrindo myURLscheme://), você pode descobrir funcionalidades ocultas (por exemplo, uma janela de depuração) e contornar a autenticação local.
  • Frida:

    Se você simplesmente deseja abrir o esquema de URL, pode fazê-lo usando o Frida:

    $ frida -U iGoat-Swift
    
    [iPhone::iGoat-Swift]-> function openURL(url) {
                                var UIApplication = ObjC.classes.UIApplication.sharedApplication();
                                var toOpen = ObjC.classes.NSURL.URLWithString_(url);
                                return UIApplication.openURL_(toOpen);
                            }
    [iPhone::iGoat-Swift]-> openURL("tel://234234234")
    true
    

    Neste exemplo do Frida CodeShare, o autor usa a API não pública LSApplicationWorkspace.openSensitiveURL:withOptions: para abrir as URLs (do aplicativo SpringBoard):

    function openURL(url) {
        var w = ObjC.classes.LSApplicationWorkspace.defaultWorkspace();
        var toOpen = ObjC.classes.NSURL.URLWithString_(url);
        return w.openSensitiveURL_withOptions_(toOpen, null);
    }
    

    Observe que o uso de APIs não públicas não é permitido na App Store, é por isso que nem mesmo testamos essas APIs, mas podemos usá-las para nossa análise dinâmica.

Fuzzing de Esquemas de URL

Se o aplicativo analisa partes da URL, você também pode realizar fuzzing de entrada para detectar bugs de corrupção de memória.

O que aprendemos acima pode ser usado agora para construir seu próprio fuzzer na linguagem de sua escolha, por exemplo, em Python e chamar o openURL usando o RPC do Frida. Esse fuzzer deve fazer o seguinte:

  • Gerar payloads.
  • Para cada um deles, chame openURL.
  • Verifique se o aplicativo gera um relatório de falha (.ips) em /private/var/mobile/Library/Logs/CrashReporter.

O projeto FuzzDB oferece dicionários de fuzzing que você pode usar como payloads.

Fuzzing Usando Frida

Fazer isso com o Frida é bastante fácil, você pode se referir a este post de blog para ver um exemplo que faz fuzzing do aplicativo iGoat-Swift (funcionando no iOS 11.1.2).

Antes de executar o fuzzer, precisamos dos esquemas de URL como entradas. A partir da análise estática, sabemos que o aplicativo iGoat-Swift suporta o seguinte esquema de URL e parâmetros: iGoat://?contactNumber={0}&message={0}.

$ frida -U SpringBoard -l ios-url-scheme-fuzzing.js
[iPhone::SpringBoard]-> fuzz("iGoat", "iGoat://?contactNumber={0}&message={0}")
Watching for crashes from iGoat...
No logs were moved.
Opened URL: iGoat://?contactNumber=0&message=0

Referências

{% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-object-persistence-mstg-platform-8" %}

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