- 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
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!emfavicon.svg, usá-lo como SVG favicon e depois extrair e inserir no corpo do documentoOu 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
[\s\S]pode ser escrito de forma mais curta e mais exata como[^]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.icoTambé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...
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
“Pong in S Favicon”
https://news.ycombinator.com/item?id=48608681
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
O estilo, com cortes agressivos e claramente parecendo texto gerado por LLM, foi bem difícil de ler
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
Errou
it’s/its, fezBut.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 blogLembrou 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
#rrggbbou linksurl(#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