- 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
42de 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
㊷
- Vermelho:
- 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
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.
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.
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.
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.
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.
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.
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.
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.
Penso em código como
if someCondition(getFoo()) then doSomethingWith(getFoo()), ou em chamardoSomethingWith(getFoo())e depoisdoAnotherThingWith(getFoo()). Isso sempre deixa um code smell, ao contrário de obter o valor uma vez comfoo := 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
qrcodee execute o código abaixo.Ele realmente gera um código QR duplo contendo
fooebar, mas no HN Unicode não funciona, e, se eu substituir por8ou0, meu celular não reconhece, então fica difícil colar aqui diretamente.Acho que seria legal usar isso em uma caça ao tesouro.
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.