Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2022-20474 — Análise técnica detalhada e prova de conceito para o Android CVE-2022-20474, uma vulnerabilidade de incompatibilidade de Bundle que explora LazyValue com comprimento negativo para alcançar comportamento de Bundle auto-modificável. | Kitploit
Ferramentas/GitHubGitHub/cxxsheng/cve-2022-20474
Segurança AndroidAnálise de VulnerabilidadesExploraçãoPapers e PesquisaAprendizado e EducaçãoExploração de Binários
GitHubcxxsheng/cve-2022-20474

CVE-2022-20474

Análise técnica detalhada e prova de conceito para o Android CVE-2022-20474, uma vulnerabilidade de incompatibilidade de Bundle que explora LazyValue com comprimento negativo para alcançar comportamento de Bundle auto-modificável.

Ver Repositório
2014há 1 anoRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Análise do CVE-2022-20474 - Bundle auto-alterável sob LazyValue

Prefácio

Nota importante: antes de ler este artigo, você deve ter uma compreensão básica das vulnerabilidades relacionadas a Bundle Mismatch. Se ainda não leu os seguintes materiais de referência, é recomendável lê-los primeiro:

  1. Bundle Feng Shui - Explicação detalhada da incompatibilidade entre serialização e desserialização no Android: Tutorial clássico de nível introdutório.
  2. História de ataque e defesa de vulnerabilidades de desserialização no Android: Excelente artigo de resumo.
  3. TheLastBundleMismatch: Primeiro artigo sobre Bundle Mismatch no modo LazyValue.

Contexto

Recentemente, estava estudando detalhadamente o artigo LeakValue de michalbednarski. Ao discutir com Canyie, ele mencionou que neste artigo também é mencionada uma situação de Bundle auto-alterável no cenário LazyValue. Então fui procurar o texto original e, de fato, havia esse trecho, que eu tinha pulado ao ler o artigo de Michal. O original dizia o seguinte:

(Also LazyValue with negative length specified can be used (without using other bugs described in this writeup) to create self-changing Bundle, the thing LazyValue was created to eliminate. But that is another story (and separately reported to Google), in this exploit I'm aiming for more)

Michal provavelmente se refere ao CVE-2022-20474 (boletim, patch). Dei uma olhada no patch, mas a função no link do patch não estava completa. Após completá-la, examinei com mais cuidado:

@@ -4388,6 +4388,9 @@
    public Object readLazyValue(@Nullable ClassLoader loader) {
         int start = dataPosition();
         int type = readInt();
         if (isLengthPrefixed(type)) {
             int objectLength = readInt();
+            if (objectLength < 0) {
+                return null;
+            }
             int end = MathUtils.addOrThrow(dataPosition(), objectLength);
             int valueLength = end - start;
             setDataPosition(end);
             return new LazyValue(this, start, valueLength, type, loader);
         } else {
            return readValue(type, loader, /* clazz */ null);
         }
    }             

O objectLength no código é o length no LazyValue. Na verdade, este é apenas o comprimento do objeto variável contido no LazyValue, enquanto o comprimento total do LazyValue é controlado pelo campo mLength, ou seja, valueLength no código, que é passado para mLength no construtor do LazyValue.

Vamos comparar com o formato de layout do LazyValue:

       /**
         *                      |   4B   |   4B   |
         * mSource = Parcel{... |  type  | length | object | ...}
         *                      a        b        c        d
         * length = d - c
         * mPosition = a
         * mLength = d - a
         */

Com base no conteúdo acima, podemos obter os seguintes fatos:

  1. mLength representa o comprimento total do LazyValue, mLength = objectLength + 8 bytes.
  2. objectLength deve ser maior ou igual a 0.
  3. O objeto LazyValue armazena apenas mLength, não objectLength, porque a cópia de memória do LazyValue é baseada na cópia de todo o objeto.
  4. Após a leitura, o ponteiro é avançado, e pode-se ler o LazyValue novamente.

Então, depois de muita reflexão, concordamos que esses fatos NÃO SERVEM PARA NADA! Porque, com base nos fatos acima, só é possível modificar uma vez durante a leitura, e sabemos que a ideia central do Bundle auto-alterável é modificar após a leitura para contornar as verificações de segurança.

Quando estávamos prestes a desistir, de repente notamos alguns detalhes na descrição do patch:

Addresses a security vulnerability where a (-8) length object would cause dataPosition to be reset back to the statt of the value, and be re-read again.

objectLength anormal

Ele menciona que quando objectLength é -8, existem alguns problemas, o que nos deu algumas dicas extras. Neste ponto, o LazyValue ainda consegue aplicar normalmente?

        @Override
        public Object apply(@Nullable Class<?> clazz, @Nullable Class<?>[] itemTypes) {
            Parcel source = mSource;
            if (source != null) {
                synchronized (source) {
                    // Check mSource != null guarantees callers won't ever see different objects.
                    if (mSource != null) {
                        int restore = source.dataPosition();
                        try {
                            source.setDataPosition(mPosition);
                            mObject = source.readValue(mLoader, clazz, itemTypes);
                        } finally {
                            source.setDataPosition(restore);
                        }
                        mSource = null;
                    }
                }
            }
            return mObject;
        }

  	/**
     * @see #readValue(int, ClassLoader, Class, Class[])
     */
    @Nullable
    private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz,
            @Nullable Class<?>... itemTypes) {
        int type = readInt();
        final T object;
        if (isLengthPrefixed(type)) {
            int length = readInt();
            int start = dataPosition();
            object = readValue(type, loader, clazz, itemTypes);
            int actual = dataPosition() - start;
            if (actual != length) {
                Slog.wtfStack(TAG,
                        "Unparcelling of " + object + " of type " + Parcel.valueTypeToString(type)
                                + "  consumed " + actual + " bytes, but " + length + " expected.");
            }
        } else {
            object = readValue(type, loader, clazz, itemTypes);
        }
        return object;
    }

Pode-se ver que o readValue real começa a ler a partir de mPosition, depois lê LazyType e objectLength em sequência, e então entra no fluxo normal de leitura de Value. Por exemplo, Parcelable precisa ler ClassName e depois executar createFromParcel. Após a leitura, não há diferença de um Key-Value comum, e não afeta a serialização subsequente. Relembrando: a ideia central do Bundle auto-alterável é modificar após a leitura; isso aqui é apenas uma leitura fora dos limites comum. Parece que esse caminho não funciona.

E se o LazyValue não for apply durante esse processo? Ou seja, se ele continuar participando do IPC como LazyValue, então sua função writeToParcel será chamada:

     public void writeToParcel(Parcel out) {
            Parcel source = mSource;
            if (source != null) {
                synchronized (source) {
                    if (mSource != null) {
                        out.appendFrom(source, mPosition, mLength);
                        return;
                    }
                }
            }
            out.writeValue(mObject);
        }

Todo o LazyValue é copiado diretamente, a menos que mLength = 0. Espera! Mencionamos acima que mLength = objectLength + 8 bytes, e pelas informações do patch sabemos que para desencadear a vulnerabilidade, objectLength deve ser -8, então mLength = 0 é válido. Em outras palavras, neste cenário, todo o LazyValue simplesmente desaparece, apenas a String Key é copiada, resultando em uma escrita ausente, e a condição de Bundle auto-alterável é diretamente satisfeita.

Sabendo a causa, podemos começar a reproduzir, mas antes disso, precisamos de mais alguns detalhes.

Detalhe 1: Dois tipos de Bundle

Baixar ferramenta