1 pontos por GN⁺ 4 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • O desenvolvedor tratou o favicon, o ícone da aba do navegador, como um armazenamento de bytes por pixel e fez um experimento colocando um pequeno HTML nos canais RGB da imagem
  • A codificação funciona adicionando um cabeçalho de 4 bytes antes dos bytes UTF-8 do HTML e gravando cada byte em sequência nos valores R·G·B dos pixels
  • O payload de demonstração tem 208 bytes e, com o cabeçalho, totaliza 212 bytes, então 71 pixels armazenando 3 bytes cada e um PNG 9×9 foram suficientes
  • A restauração desenha a imagem do favicon em um canvas, depois o JavaScript lê os dados dos pixels e recompõe os valores RGB em um array de bytes para decodificá-los como HTML
  • A estrutura não faz o website rodar de forma independente só com o favicon; é necessário um bootstrap JavaScript separado, então a ideia está mais próxima de um experimento de limites do que de algo prático

Como tratar um favicon como se fosse armazenamento

  • O favicon é um pequeno ícone exibido na aba do navegador, mas na prática é um arquivo de imagem composto por pixels e bytes
  • O ponto de partida do experimento foi a esteganografia, mas na demonstração o foco não está em parecer um ícone, e sim em usá-lo como espaço puro de armazenamento
  • O que é armazenado é um pequeno payload HTML
Website in a Favicon

Everything you're reading right now was decoded from favicon pixels.

  • O procedimento de codificação é simples
    • Converte o HTML em bytes UTF-8 com TextEncoder
    • Adiciona na frente um cabeçalho de 4 bytes com o tamanho do payload
    • Como pode haver pixels sobrando, o cabeçalho de tamanho serve para identificar onde termina o payload real
    • O primeiro byte vai para o canal red do primeiro pixel, o segundo byte para o green, e o terceiro byte para o blue
    • Os pixels seguintes são preenchidos na mesma ordem, então o documento HTML inteiro fica armazenado nos valores de cor
  • A imagem resultante parece visualmente um ruído

Tamanho e processo de restauração

  • O tamanho final da demonstração é muito pequeno
    • Payload: 208 bytes
    • Total com cabeçalho: 212 bytes
    • Pixels necessários: 71 pixels
    • Tamanho da imagem: 9×9 pixels
    • Tamanho do arquivo: 239 bytes
    • Taxa de uso: 87% {p:87}
  • A restauração é feita só com recursos do navegador
    • Carrega o favicon como imagem
    • Desenha a imagem em um canvas
    • Lê todos os pixels com a Canvas API
    • Reconstrói os valores RGB em um array de bytes
    • Lê o tamanho do payload nos 4 primeiros bytes
    • Extrai o payload e o decodifica como texto UTF-8
  • No site de demonstração, ao clicar no botão "Render Website", o favicon é lido, o HTML é restaurado e então o conteúdo da página é substituído

Limitações e alternativas

  • A maior limitação é que o favicon não consegue executar sozinho o website inteiro
    • O favicon contém o conteúdo do website
    • É necessário separadamente um pequeno loader em JavaScript para fazer a decodificação
    • Sem JavaScript, o favicon é apenas um PNG contendo o conteúdo do website
  • A utilidade prática é baixa
    • A quantidade de dados que pode ser armazenada é muito pequena
    • A página precisa ser inicializada com JavaScript
    • Existem maneiras muito melhores de distribuir pequenos documentos HTML
  • Como alternativas, há inserir markup diretamente em um favicon SVG, usar os comment chunks tEXt, zTXt e iTXt do PNG, e usar o formato de arquivo ico, que pode conter ícones em várias resoluções
  • Site de demonstração: https://www.timwehrle.de/labs/favicon-site/
  • Código da implementação: https://github.com/timwehrle/favicon

1 comentários

 
GN⁺ 4 시간 전
Comentários do Hacker News
  • Fiquei pensando se não daria para, em vez de passar por pixels, usar um SVG favicon e armazenar a marcação diretamente dentro dele para depois extrair
    Dá para colocar algo como hello HN! em favicon.svg, usá-lo como SVG favicon e depois extrair e inserir no corpo do documento

    • Acho que faz mais sentido ver isso não como “por que não fazer pela alternativa”, mas como “há também uma variação interessante”. As duas abordagens são formas de brincar com tecnologia por diversão, curiosidade e exploração, e a abordagem de armazenar nos pixels tem uma graça de máquina de Rube Goldberg
    • Sou o autor do post, e claro que esse jeito é mais prático. Só que eu queria que o payload “vivesse” de fato dentro dos dados de pixel, e não como texto escondido dentro de um arquivo XML :)
    • Regex? Ai. Basta codificar corretamente como XML no namespace certo e ler assim
      Ou então servir o arquivo SVG diretamente e incluir HTML embutido nele. Em teoria deveria dar para definir e usar, mas infelizmente nem Firefox nem Chromium parecem tratar isso direito dentro de favicon
    • Já que pessoalmente sou de implicar com esse tipo de coisa, [\s\S] pode ser escrito de forma mais curta e mais exata como [^]
    • SVG pode embutir imagem raster como bytes codificados em base64
      Então dá para empilhar mais uma camada no experimento: o favicon seria SVG, dentro dele haveria um raster codificado, e dentro desses bytes haveria HTML codificado. No mínimo isso daria uma fase de CTF de enlouquecer
  • Claro que não é uma ideia nova. Por exemplo, em 2000 alguém armazenou deCSS num favicon
    https://web.archive.org/web/20010408040524if_/http://decss.z...
    A extração pode ser feita com dd bs=1 skip=2238 < favicon.ico

  • Também não é verdade que “ainda é preciso um pequeno bootstrap loader para decodificar a imagem”. Com um HTML/PNG polyglot dá para fazer tudo em um único arquivo, e hoje em dia formatos mais novos como WebP podem até oferecer melhor compressão
    https://web.archive.org/web/20120801001616/http://daeken.com...

  • Se você redirecionar o usuário por vários domínios, o cache de favicon também pode ser usado como armazenamento. Isso já foi proposto como risco potencial de fingerprinting[0], e se o navegador reutilizar ingenuamente o cache até no modo anônimo, isso pode ser explorado para rastrear usuários entre perfis do navegador
    [0]: https://www.schneier.com/blog/archives/2021/02/browser-track...

    • Isso já não foi corrigido, ou pelo menos corrigido na maior parte dos casos?
    • Assim que li o post original, minha reação instintiva foi pensar “isso deve estar sendo usado para fingerprinting”. Fico curioso se medidas anti-fingerprinting levam em conta a combinação de favicon com a Canvas API
      Infelizmente o link do site de supercookie está morto
  • PNG tem chunks de comentário tEXt, zTXt, iTXt. Dá para enfiar quanto conteúdo quiser num arquivo de imagem aparentemente totalmente normal. Claro, perde um pouco da graça

  • Isso foi coincidência de timing? Acabei de postar, uma hora atrás — na verdade 30 minutos antes deste post — um site que salva uma carteira de ações em URL + favicon
    https://news.ycombinator.com/item?id=48606396

  • Combina muito com essa forma de pensar: monitor também é armazenamento, teclado também é armazenamento, e post de fórum também é armazenamento
    Com o tempo, se você introduzir na edição variações que o Markov aprovaria, dá para ter bastante capacidade de armazenamento. E como comentários às vezes também são socialmente interessantes, vira um armazenamento de uso duplo.
    Ninguém sabe se a receita de frango com creme de alguém é, na verdade, a alça de um GUID cuidadosamente montado e, brincando, aponta para mil posts diferentes em fóruns. Fico curioso se o autor conhece PoC||GTFO, porque isso com certeza parece uma técnica que você encontraria nas profundezas do livro sagrado dos Alchemist Owls

    • Código dentro do código. Roda dentro da roda
  • O estilo, com cortes agressivos e claramente parecendo texto gerado por LLM, foi bem difícil de ler

    • Reclamaram desse estilo há alguns meses no Medium. O autor daquele texto respondeu que é um estilo preferido quando se espera leitura em telas pequenas de smartphone. Até faz algum sentido. Não sei se aquele texto ou este aqui foram gerados por IA ou não
    • Lá pela metade eu estava convencido de que no final haveria a revelação de que “na verdade este próprio texto estava armazenado no favicon do site”, o que explicaria as frases curtas e truncadas. Quando percebi que não era isso, fiquei sinceramente decepcionado. Foi uma oportunidade perdida
    • Eu gostei desse jeito de escrever. Às vezes também escrevo de forma parecida, e nunca usei LLM para gerar meus textos. Já escrevi exatamente assim no trabalho também
      Para mim, parece só que o autor quer ir direto ao ponto. Ele provavelmente sabe que, se houver texto demais, as pessoas começam a passar o olho
    • Faz tempo que não concordo no HN com esse rótulo de estilo gerado por IA. No máximo, ele pode ter usado um LLM para rascunhar, mas o resultado final parece bem humano
      Errou it’s/its, fez But. virar uma frase de uma palavra, não escreveu HTML em maiúsculas e colocou “okayy” entre parênteses. Não estou criticando o autor; pelo contrário, gostei mais justamente por dar para ver essas pequenas imperfeições compondo o post do blog
    • O texto foi envolvente e agradável de ler
  • Lembrou o real pixel coding do Inigo: https://www.youtube.com/watch?v=FvS_DG8yIqQ
    É uma intro de 256 bytes feita posicionando pixels no Photoshop e salvando como exe

  • Fato curioso: qualquer SVG inline pode ser usado como favicon e pode permanecer intacto dentro do documento HTML
    Assim também dá para usar emoji diretamente como favicon. No HN o emoji não aparece

    • Só como observação, se você quiser usar códigos de cor #rrggbb ou links url(#id) ao fazer isso, é preciso escapar # como %23. Caso contrário, ele será interpretado como fragmento de URL e o código SVG será cortado naquele ponto