2 pontos por GN⁺ 2025-01-24 | 1 comentários | Compartilhar no WhatsApp
  • Partindo do experimento de QR code angular de Guy Dupont, Christian Walther implementou um QR code que, mesmo sem lente, é lido como destinos diferentes dependendo das condições de escaneamento
  • A estrutura central é uma máscara em xadrez que sobrepõe 2 QR codes do mesmo tamanho e distribui os pixels de cada um alternadamente
  • Se o leitor de QR amostrar o centro de pixel esperado, um pequeno deslocamento da imagem pode fazer os pontos de amostragem se concentrarem mais em um dos códigos, gerando outro resultado
  • Nos testes, o padrão xadrez funcionou melhor do que listras verticais ou diagonais, e um nível alto de correção de erro ajudou, embora ainda haja diferenças entre decodificadores
  • Isso mostra que uma única imagem de QR pode ser interpretada como vários resultados conforme ângulo, deslocamento, implementação do decodificador e forma de tratar cores e canal alfa

QR code duplo feito sem lente

  • Guy Dupont experimentou QR codes que enviam para origens diferentes conforme o ângulo, com a ideia de “perspectivas diferentes da mesma história”
  • Christian Walther partiu dessa ideia para testar se isso seria possível sem lente, e disse ter criado uma imagem de QR que realmente funciona
  • Dupont reagiu dizendo que, no resultado de Walther, leu dois destinos: GitHub e Mastodon
  • Matt Lacey também disse que, no celular dele, a URL do Mastodon era capturada com mais facilidade, mas a do GitHub também era lida

Estrutura que divide cada pixel ao meio

  • O método básico é criar 2 QR codes do mesmo tamanho e sobrepô-los em uma única imagem
    • Metade de cada pixel vem de um QR code
    • A outra metade vem do outro QR code
  • Na explicação posterior, ele diz que fez um código aparecer nos quadrantes superior esquerdo e inferior direito de cada pixel, e o outro nas áreas restantes
  • Foi mencionado que a imagem pode ter sido feita no Photoshop preenchendo uma máscara de camada com padrão xadrez

Por que o resultado do escaneamento se divide

  • Walther supõe que o leitor de QR amostra a região central das posições de pixel esperadas com base nos blocos de alinhamento
  • Se a mesma máscara for usada em todos os pixels e o centro do pixel cair sobre a borda da máscara, um pequeno deslocamento pode fazer os pontos de amostragem penderem todos para a área de um dos códigos
  • Como resultado, a mesma imagem pode ser lida como QR codes diferentes dependendo do deslocamento
  • O próprio Walther esclarece que essa explicação sobre amostragem é uma hipótese, não o resultado de um estudo real do funcionamento dos decodificadores
  • Um usuário disse que, ao passar o PNG diretamente para o decodificador zbar-tools, ele não detectou o código

Diferenças criadas por máscara e decodificador

  • Nos testes de Walther, a máscara em xadrez deu resultados melhores do que listras verticais ou diagonais
  • Funcionou melhor com o nível mais alto de correção de erro, embora ele diga que ainda são necessários mais experimentos
  • A divisão diagonal é mais bonita visualmente, mas o xadrez ficou à frente em funcionamento real
  • Também foram relatadas diferenças na frequência dos resultados entre apps de escaneamento e o app de câmera padrão
    • Um usuário disse que, em um app scanner de QR code, o link do Mastodon aparecia com mais frequência, enquanto no app de câmera padrão ambos pareciam possíveis
    • Attie Grande disse que também parece haver variabilidade entre decodificadores por software
  • Hadley disse que, com o celular parado, o QR não era lido, mas quando começou a movê-lo em outro ângulo, ele passou a ser escaneado de forma estável durante o movimento

Experimentos derivados e ferramentas públicas

  • Durante a conversa, Walther apresentou dualqrcode.com e o repositório DualQRCode no GitHub como versões interativas
  • xssfox mencionou uma abordagem de encontrar colisões próximas para reduzir o número de bits diferentes, e disse que encontrar por brute force uma diferença de 30 bits parecia bem simples
  • Walther disse que testou escolher padrões de máscara diferentes para os dois QR codes para reduzir a diferença, mas o caso com a mesma máscara nos dois códigos foi o que teve a menor diferença
    • Como a prova de conceito original também usava automaticamente a mask 6 em ambos os códigos, nesse caso não houve ganho adicional
  • Walther disse que escolheu de propósito domínios diferentes porque o app de câmera do iOS mostra apenas o domínio na prévia em tempo real, e o conteúdo completo só aparece ao tocar

Canal de cores, alfa e experimento com 4 códigos

  • Nemo Thorx compartilhou um experimento em que representou 42 de três maneiras, transformou cada uma em QR code e as combinou em canais RGB
    • Vermelho: 6x9
    • Verde: XLII
    • Azul: Forty-two
    • Depois, na conversa, foi confirmado que o canal alfa continha o código
  • Walther disse que entendeu o funcionamento daquela imagem ao ignorar o canal alfa
  • Quando Pixel Dunn tentou colocar vários códigos por mistura de cores, Walther avaliou que esse tipo de blending não funcionaria, porque o decodificador não conseguiria separar 4 códigos individuais
  • Walther disse que já colocou 4 códigos usando blocos de alinhamento móveis e quadrantes de pixel
    • Ao mover ligeiramente o alvo de alinhamento, o foco passaria para outros quadrantes do pixel
  • Uma abordagem em que dois conjuntos de códigos mudam conforme fundo transparente e tema talvez seja possível, mas o iPhone de Walther não reconheceu nem em fundo branco nem em fundo preto, e só funcionou quando ele aplicou processamento manual de limiar

1 comentários

 
GN⁺ 2025-01-24
Comentários do Hacker News
  • Parece possível um ataque em que uma tela em um local público altere sutilmente um código QR com base nas informações do usuário atual, sem que ele pareça muito diferente por fora.
    Por exemplo, criar um código QR misturado meio a meio, definir o alvo por meio de uma entrada externa, como avaliação de características baseada em câmera, e então ajustar minimamente a cor do código para aumentar a probabilidade de ele ser reconhecido como o lado desejado.
    Possíveis usos maliciosos incluiriam mostrar formulários de feedback diferentes para grupos demográficos diferentes e distorcer os resultados, enviesar a probabilidade de ganhar prêmios de acordo com características identificáveis como raça, idade ou aparência, ou enviar apenas certas pessoas para outra rede Wi‑Fi ou página de pagamento.
    Em ambientes estáticos, o efeito seria menor, e não me vem à cabeça de imediato um ataque estático que traga vantagem ao separar apenas alguns usuários. Sob iluminação pública, parece difícil que a maioria das pessoas perceba um código QR mudando dinamicamente.

    • Esse tipo de coisa pode ser tratado de forma muito mais discreta no lado do servidor, então não vejo bem o que a modificação do código QR acrescenta.
      O caso em que a técnica de hacking do texto original parece realmente utilizável é quando o atacante cola seu próprio código por cima de um QR code legítimo. Qual código será lido fica um tanto aleatório, então alguns usuários podem ser enviados ao destino original e a detecção pode ser atrasada, mas não está claro se isso compensaria a perda de tráfego entrando pelo link do atacante.
    • Ataques que alteram códigos QR públicos já existem na prática.
      Nem é preciso algo tão sofisticado quanto esse QR code duplo. Basta ir até uma placa de “pague pelo celular” em um estacionamento, colar seu próprio QR code por cima do QR code de “escaneie para pagar” e esperar os dados de cartão de crédito chegarem.
    • De forma parecida, daria para colar um pôster com um código QR na parede de uma sala com duas lâmpadas LED. Se as duas lâmpadas tiverem temperaturas de cor diferentes, o resultado da decodificação pode mudar dependendo de qual delas estiver acesa.
      Outra abordagem seria um pôster que não fosse completamente plano. Se pixels diferentes fossem levemente salientes em formato de pirâmide e cada face fosse pintada de maneira diferente, o código QR poderia ser escaneado de forma diferente conforme o ângulo de visão.
      Um dos principais bancos de Tbilisi permite compartilhar o número IBAN por código QR. Em teoria, seria possível roubar dinheiro com uma técnica dessas, mas na prática há várias salvaguardas, como o app do banco mostrar o nome do destinatário antes de concluir a transferência.
    • Acho que uma pessoa comum não perceberia mesmo que um código QR médio mudasse bastante. A maioria dos formatos legíveis por máquina parece aos olhos humanos apenas um ruído branco indistinguível.
    • Gostei de também explicarem os casos de abuso. Só pela configuração, eu provavelmente não teria pensado muito nesses usos.
      Na minha cabeça, esse tipo de controle poderia funcionar como forçar a escolha de uma carta específica, então a primeira coisa em que pensei foi em truques de mágica.
  • Criei um site para as pessoas testarem diretamente: https://dualqrcode.com/
    Como não há a metodologia exata usada por Christian, aqui combinei dois códigos QR em uma única imagem usando um padrão de divisão diagonal. Quando os padrões na mesma posição diferem, a célula é dividida na diagonal: um lado representa o primeiro QR code e o outro, o segundo; quando ambos são pretos ou brancos, a célula é preenchida com uma cor sólida.
    Graças à alta capacidade de correção de erros dos códigos QR, especialmente o nível de correção de erros “H”, qualquer uma das URLs pode ser lida dependendo do ângulo de escaneamento. Ainda assim, como observei na UI, ela tende com mais frequência para a segunda URL.

    • No meu ambiente, não funcionou. Criei dois links, BBC e CNN, e tentei com o app “QR & Barcode Scanner” v2.2.47 no Android e com a câmera padrão de um iPhone 13, mas nenhum dos dois conseguiu ler.
  • O mais interessante foi que, no iOS, ao pressionar a imagem por alguns segundos, ele diz que vai para github.com, mas a prévia em si aparece como Mastodon.
    Isso parece significar que o código QR é parseado duas vezes e produz resultados diferentes. Parece algo que poderia ser usado para enganar alguns usuários, embora eu não saiba quantas pessoas olham a URL no menu suspenso ao pressionar e segurar.

    • Às vezes aparece um código QR na própria tela que estou vendo no celular, e isso é meio inconveniente.
      Então já fiz coisas bobas como enviar a captura de tela para o notebook por AirDrop e escanear com a câmera do celular, ou pedir para o celular de um amigo ou familiar escanear o código na tela do meu celular.
      Mas hoje descobri que, se eu pressionar por alguns segundos um código QR em uma captura de tela no rolo da câmera, ele faz o parsing e abre o link diretamente. Acho que já tinha tentado pressionar uma imagem antes, mas talvez a função tenha sido adicionada depois, talvez eu não tenha realmente tentado, ou talvez eu tenha pressionado a parte errada do código QR. De todo modo, é muito bom saber que isso é possível.
    • É totalmente plausível que duas partes do sistema operacional usem parsers de QR diferentes. O SmartText usa um, o sistema de imagens usa outro, algo assim. Parece que cada um implementa correção de erros de um jeito ligeiramente diferente.
      Acho que daria para fazer a mesma coisa até com um código QR padrão contendo erros intencionais. Bastaria descobrir como cada um corrige os erros de forma diferente.
      Parece que encontramos um bug de bug bounty esperando alguém pegar.
    • Códigos QR deveriam mostrar também a URL de destino em texto, para que o usuário saiba para onde está indo. Deveria funcionar como uma espécie de consentimento explícito.
    • No iOS, ao pressionar por alguns segundos, o link padrão “Open” aparece como Mastodon, e o menu de contexto também mostra um link de app “Open in Github”.
    • Parece um caso típico em que a mesma função ou método getter é chamado duas vezes, mas as duas chamadas necessariamente deveriam retornar o mesmo resultado.
      Penso em código como if someCondition(getFoo()) then doSomethingWith(getFoo()), ou em chamar doSomethingWith(getFoo()) e depois doAnotherThingWith(getFoo()). Isso sempre deixa um code smell, ao contrário de obter o valor uma vez com foo := getFoo() e usá-lo.
  • Se você rolar para cima a partir da posição inicial, dá para ver a versão lenticular.

  • Extremamente impactante. Meu iPhone tendia a travar em um dos dois, e girar o celular ajudava a ir para um lado ou para o outro.
    Algumas vezes, os links do Mastodon e do GitHub também ficaram piscando alternadamente.

  • Se quiser testar por conta própria, dá para usar este código feito rapidamente. Instale o pacote Python qrcode e execute o código abaixo.
    Ele realmente gera um código QR duplo contendo foo e bar, mas no HN Unicode não funciona, e, se eu substituir por 8 ou 0, meu celular não reconhece, então fica difícil colar aqui diretamente.

    import qrcode
    
    bar = qrcode.QRCode(border=0)  
    bar.add_data('bar')  
    bar.make()  
    bar_mat = bar.get_matrix()
    
    foo = qrcode.QRCode(border=0)  
    foo.add_data('foo')  
    foo.make()  
    foo_mat = foo.get_matrix()
    
    for l, r in zip(foo_mat, bar_mat):  
        line = ''  
        for lc, rc in zip(l, r):  
            line = line + (lc and '\u2588' or ' ')  
            line = line + (rc and '\u2588' or ' ')  
        print(line)  
        print(line)  
    
  • Acho que seria legal usar isso em uma caça ao tesouro.

    • Também daria para fazer com que fosse necessário ter os resultados de dois, ou de todos os códigos QR, para obter o código, link ou chave final.
  • Códigos QR são perfeitos para abuso, como URLs encurtadas.
    São URLs essencialmente ilegíveis, então você não sabe para onde será enviado nem quantas vezes será redirecionado. Por isso, eu não uso.

  • Um conceito realmente muito legal. Se o foco for o objetivo final, outra abordagem possível é colocar um switch no destino da URL.
    Seria um redirecionamento para páginas diferentes com base em aleatorização, dados do usuário ou outros critérios. Se você quiser experimentar esse tipo de funcionalidade e até fazer testes reais com adesivos, eu trabalho com rótulos variáveis para várias empresas SaaS e posso compartilhar insights, imprimir amostras ou colaborar.