- Un desarrollador trató el favicon, el ícono de la pestaña del navegador, como un almacén de bytes por píxel e hizo un experimento para meter un pequeño HTML en los canales RGB de una imagen
- La codificación consiste en anteponer un encabezado de 4 bytes a los bytes UTF-8 del HTML y escribir cada byte en orden en los valores R, G y B de los píxeles
- El payload de demostración es de 208 bytes y, con el encabezado, llega a 212 bytes, así que bastaron 71 píxeles guardando 3 bytes por píxel y un PNG de 9×9
- La restauración se hace dibujando la imagen del favicon en un canvas; luego JavaScript lee los datos de píxeles y vuelve a ensamblar los valores RGB como un arreglo de bytes para decodificarlos a HTML
- No es una estructura donde el sitio web se ejecute de forma autónoma solo con el favicon; hace falta un bootstrap JavaScript aparte, así que se parece más a un experimento de exploración de límites que a algo práctico
Cómo tratar un favicon como si fuera almacenamiento
- Un favicon es un pequeño ícono que se muestra en la pestaña del navegador, pero en realidad es un archivo de imagen compuesto por píxeles y bytes
- El punto de partida del experimento fue la esteganografía, pero en la demo el enfoque está más en usarlo como espacio de almacenamiento puro que en hacer que parezca un ícono
- Lo que se guarda es un pequeño payload HTML
Website in a Favicon
Everything you're reading right now was decoded from favicon pixels.
- El proceso de codificación es simple
- Convierte el HTML a bytes UTF-8 con
TextEncoder
- Agrega al principio un encabezado de 4 bytes con la longitud del payload
- Como pueden sobrar píxeles, el encabezado de longitud permite distinguir dónde termina el payload real
- El primer byte se guarda en el canal red del primer píxel, el segundo byte en green y el tercero en blue
- Después se rellenan los demás píxeles en el mismo orden hasta que todo el documento HTML queda representado como valores de color
- La imagen resultante se ve visualmente como ruido
Tamaño y proceso de restauración
- El tamaño final de la demo es muy pequeño
- Payload: 208 bytes
- Total con encabezado: 212 bytes
- Píxeles necesarios: 71 pixels
- Tamaño de imagen: 9×9 pixels
- Tamaño de archivo: 239 bytes
- Uso: 87% {p:87}
- La restauración se resuelve solo con funciones del navegador
- Carga el favicon como imagen
- Dibuja la imagen en un canvas
- Lee todos los píxeles con la Canvas API
- Reconstruye un arreglo de bytes a partir de los valores RGB
- Lee la longitud del payload desde los primeros 4 bytes
- Extrae el payload y lo decodifica como texto UTF-8
- En el sitio de demostración, al pulsar el botón
"Render Website", se lee el favicon, se restaura el HTML y luego se reemplaza el contenido de la página
Límites y alternativas
- La mayor limitación es que el favicon no puede ejecutar por sí solo todo el sitio web
- El favicon contiene el contenido del sitio web
- Se necesita aparte un pequeño cargador en JavaScript para decodificarlo
- Sin JavaScript, el favicon no es más que un PNG con contenido de sitio web
- Su utilidad práctica es baja
- La cantidad de datos que se puede guardar es muy pequeña
- La página tiene que arrancar con bootstrap mediante JavaScript
- Hay muchas mejores formas de distribuir documentos HTML pequeños
- Como alternativas, se mencionan incrustar el markup directamente en un favicon SVG, usar los comment chunks
tEXt, zTXt, iTXt de PNG, o usar el formato de archivo ico, que puede contener íconos de varias resoluciones
- Sitio de demostración: https://www.timwehrle.de/labs/favicon-site/
- Código de implementación: https://github.com/timwehrle/favicon
1 comentarios
Comentarios de Hacker News
Me da la impresión de que, en vez de pasar por los píxeles, se podría usar un SVG favicon y guardar el marcado directamente dentro para luego extraerlo
Podrías poner algo como
hello HN!enfavicon.svg, usarlo como SVG favicon y luego extraerlo y pegarlo en el cuerpo del documentoO también podrías servir el archivo SVG tal cual e incluir HTML embebido dentro. En teoría deberías poder definirlo y luego usarlo, pero por desgracia parece que ni Firefox ni Chromium lo procesan bien dentro de un favicon
[\s\S]se puede escribir de forma más corta y precisa como[^]Así que podrías apilar el experimento una capa más: que el favicon sea un SVG, que dentro tenga un raster codificado y que dentro de esos bytes haya HTML codificado. Como mínimo, eso ya parece una etapa de CTF para perder la cordura
Claro que no es una idea nueva. Por ejemplo, en 2000 alguien guardó deCSS en un favicon
https://web.archive.org/web/20010408040524if_/http://decss.z...
Se puede extraer con
dd bs=1 skip=2238 < favicon.icoTampoco es que “todavía haga falta un pequeño bootstrap loader para decodificar la imagen”. Con un HTML/PNG polyglot se puede hacer todo en un solo archivo, y hoy en día formatos más nuevos como WebP podrían dar incluso mejor compresión
https://web.archive.org/web/20120801001616/http://daeken.com...
Si rediriges al usuario por varios dominios, también puedes usar la caché de favicon como almacenamiento. Se propuso como un posible riesgo de fingerprinting[0], y si el navegador reutiliza la caché de forma ingenua incluso en modo incógnito, se puede abusar para rastrear usuarios entre perfiles del navegador
[0]: https://www.schneier.com/blog/archives/2021/02/browser-track...
Por desgracia, el enlace al sitio del supercookie ya no funciona
PNG tiene chunks de comentarios tEXt, zTXt, iTXt. Puedes meterle todo el contenido que quieras a un archivo de imagen que por fuera parece totalmente normal. Claro, aunque quizá tenga un poco menos de gracia
¿Será casualidad el timing? Justo hace 1 hora, o más exactamente 30 minutos antes de este post, publiqué un sitio para guardar mi portafolio de acciones en la URL + favicon
https://news.ycombinator.com/item?id=48606396
“Pong in S Favicon”
https://news.ycombinator.com/item?id=48608681
Encaja muy bien con esta forma de pensar: el monitor también es almacenamiento, el teclado también es almacenamiento, y los posts de foros también son almacenamiento
Si con el tiempo introduces variaciones en la edición que Markov aprobaría, aparece bastante capacidad de almacenamiento. Además, como los comentarios a veces también son socialmente interesantes, se vuelven almacenamiento de doble uso.
Nadie sabe si la receta de casserole de pollo de alguien es en realidad el handle de un GUID cuidadosamente construido y, en broma, apunta a mil posts distintos en foros. Me pregunto si el autor conoce PoC||GTFO, porque esto definitivamente parece una técnica que encontrarías en lo más profundo del libro sagrado de los Alchemist Owls
El estilo de escritura, con cortes agresivos y muy marcados, me resultó muy difícil de leer porque parecía claramente generado por un LLM
A mí me parece que el autor simplemente quiere ir directo al punto. Da la impresión de que sabe que cuando hay demasiado texto la gente empieza a leer por encima
Se equivocó con
it’s/its, hizo deBut.una oración de una sola palabra, no escribió HTML en mayúsculas y puso “okayy” entre paréntesis. No es por criticar al autor; al contrario, me gustó más ver esas pequeñas imperfecciones que forman parte de un post de blogMe recordó al real pixel coding de Inigo: https://www.youtube.com/watch?v=FvS_DG8yIqQ
Es una intro de 256 bytes hecha colocando píxeles en Photoshop y guardándola como exe
Dato curioso: cualquier SVG inline se puede usar como favicon y dejarlo tal cual dentro de un documento HTML
Así también se pueden usar emojis directamente como favicon. En HN los emojis no se muestran
#rrggbbo enlacesurl(#id), tienes que escapar#como%23. Si no, se interpreta como fragment de URL y el código SVG se corta en ese punto