- Một lập trình viên đã xem favicon, biểu tượng trên tab trình duyệt, như một kho lưu trữ byte theo pixel và thực hiện thí nghiệm nhét một HTML nhỏ vào các kênh RGB của ảnh
- Cách mã hóa là gắn thêm phần đầu 4 byte chứa độ dài trước các byte UTF-8 của HTML, rồi ghi lần lượt từng byte vào các giá trị R·G·B của pixel
- Payload demo dài 208 byte và là 212 byte tính cả phần đầu, nên chỉ cần 71 pixel lưu trữ theo từng nhóm 3 byte và một ảnh PNG 9×9 là đủ
- Việc khôi phục được thực hiện bằng cách vẽ ảnh favicon lên canvas, sau đó JavaScript đọc dữ liệu pixel và lắp lại các giá trị RGB thành mảng byte để giải mã về HTML
- Cấu trúc này không phải là một website có thể tự chạy chỉ với favicon; nó vẫn cần bootstrap JavaScript riêng, nên gần với một thử nghiệm khám phá ranh giới hơn là thứ thực dụng
Cách xử lý favicon như một kho lưu trữ
- favicon là biểu tượng nhỏ hiển thị trên tab trình duyệt, nhưng về bản chất nó là một tệp ảnh được tạo nên từ pixel và byte
- Điểm xuất phát của thử nghiệm là steganography, nhưng trong bản demo trọng tâm không phải làm cho nó trông như một biểu tượng mà là dùng nó như không gian lưu trữ thuần túy
- Đối tượng được lưu là một payload HTML nhỏ
Website in a Favicon
Everything you're reading right now was decoded from favicon pixels.
- Quy trình mã hóa khá đơn giản
- Dùng
TextEncoder để chuyển HTML thành các byte UTF-8
- Gắn phần đầu 4 byte chứa độ dài payload ở phía trước
- Vì có thể còn pixel thừa, phần đầu độ dài được dùng để xác định điểm kết thúc thực sự của payload
- Byte đầu tiên được lưu vào kênh red của pixel đầu tiên, byte thứ hai vào green, byte thứ ba vào blue
- Các pixel sau đó cũng được lấp theo cùng thứ tự để toàn bộ tài liệu HTML đi vào các giá trị màu
- Ảnh kết quả nhìn trực quan giống như nhiễu
Kích thước và quy trình khôi phục
- Kích thước cuối cùng của bản demo rất nhỏ
- Payload: 208 bytes
- Tổng dung lượng gồm cả header: 212 bytes
- Pixel cần thiết: 71 pixels
- Kích thước ảnh: 9×9 pixels
- Dung lượng: 239 bytes
- Tỷ lệ sử dụng: 87% {p:87}
- Việc khôi phục chỉ dùng các tính năng của trình duyệt
- Tải favicon như một ảnh
- Vẽ ảnh lên canvas
- Đọc toàn bộ pixel bằng Canvas API
- Tái tạo các giá trị RGB thành mảng byte
- Đọc độ dài payload từ 4 byte đầu tiên
- Trích xuất payload và giải mã thành văn bản UTF-8
- Trên trang demo, khi nhấn nút
"Render Website", favicon sẽ được đọc, HTML được khôi phục rồi nội dung trang được thay thế
Giới hạn và các phương án thay thế
- Ràng buộc lớn nhất là favicon không thể một mình chạy toàn bộ website
- favicon chứa nội dung của website
- vẫn cần một trình nạp JavaScript nhỏ riêng để giải mã
- nếu không có JavaScript, favicon chỉ là một PNG chứa nội dung website mà thôi
- Tính thực dụng thấp
- lượng dữ liệu có thể lưu rất nhỏ
- trang phải được bootstrap bằng JavaScript
- có nhiều cách tốt hơn để phân phối các tài liệu HTML nhỏ
- Các phương án thay thế gồm chèn trực tiếp markup vào SVG favicon, dùng các comment chunk
tEXt, zTXt, iTXt của PNG, hoặc dùng định dạng tệp ico có thể chứa biểu tượng ở nhiều độ phân giải
- Trang demo: https://www.timwehrle.de/labs/favicon-site/
- Mã triển khai: https://github.com/timwehrle/favicon
1 bình luận
Ý kiến trên Hacker News
Có vẻ như chẳng cần đi qua pixel, chỉ cần dùng SVG favicon rồi lưu trực tiếp markup vào trong đó và trích xuất ra là được
Có thể đặt nội dung như
hello HN!vàofavicon.svg, dùng nó làm SVG favicon, rồi trích xuất và chèn vào phần thân tài liệuHoặc cứ phân phối nguyên tệp SVG và nhúng HTML vào trong đó cũng được. Về mặt lý thuyết thì phải có thể định nghĩa rồi dùng được, nhưng tiếc là cả Firefox lẫn Chromium dường như không xử lý tử tế bên trong favicon
[\s\S]có thể viết ngắn hơn và chính xác hơn thành[^]Vì vậy có thể xếp thêm một lớp thí nghiệm nữa: favicon là SVG, bên trong có raster đã mã hóa, và trong các byte đó lại mã hóa HTML. Ít nhất cũng đủ để thành một màn CTF gây choáng váng
Dĩ nhiên đây không phải ý tưởng mới. Ví dụ, hồi năm 2000 đã có người lưu deCSS vào favicon
https://web.archive.org/web/20010408040524if_/http://decss.z...
Có thể trích xuất bằng
dd bs=1 skip=2238 < favicon.icoKhông hẳn là “vẫn cần một bootstrap loader nhỏ để giải mã ảnh”. Nếu dùng HTML/PNG polyglot thì có thể xử lý mọi thứ bằng một tệp duy nhất, và ngày nay với các định dạng mới như WebP thì tỷ lệ nén còn có thể tốt hơn
https://web.archive.org/web/20120801001616/http://daeken.com...
Nếu chuyển hướng người dùng qua nhiều domain thì cache favicon cũng có thể dùng làm nơi lưu trữ. Từng có đề xuất về điều này như một rủi ro fingerprinting tiềm tàng[0], và nếu trình duyệt ngây thơ tái sử dụng cache ngay cả trong chế độ ẩn danh thì nó có thể bị lạm dụng để theo dõi người dùng giữa các profile trình duyệt
[0]: https://www.schneier.com/blog/archives/2021/02/browser-track...
Tiếc là link tới trang supercookie giờ đã chết
PNG có các chunk chú thích tEXt, zTXt, iTXt. Có thể nhét vào đó bao nhiêu nội dung tùy thích trong một tệp ảnh trông hoàn toàn bình thường. Tất nhiên sẽ bớt vui hơn một chút
Cái thời điểm này là ngẫu nhiên à? Mới đúng 1 giờ trước, chính xác là 30 phút trước bài này, tôi vừa đăng một trang lưu danh mục cổ phiếu vào URL + favicon mà tôi làm
https://news.ycombinator.com/item?id=48606396
“Pong in S Favicon”
https://news.ycombinator.com/item?id=48608681
Cách tư duy này thật sự rất hợp: màn hình cũng là lưu trữ, bàn phím cũng là lưu trữ, và bài đăng trên diễn đàn cũng là lưu trữ
Nếu theo thời gian bạn chèn vào các chỉnh sửa là những biến thể mà Markov sẽ chấp nhận thì sẽ có khá nhiều dung lượng lưu trữ. Thêm nữa, bình luận đôi khi còn thú vị về mặt xã hội nên thành ra là một dạng lưu trữ hai mục đích.
Không ai biết liệu công thức gà casserole của ai đó thực ra có phải là tay cầm của một GUID được sắp đặt tinh vi hay không, hay đùa thôi nhưng biết đâu nó lại trỏ tới một nghìn bài đăng diễn đàn khác nhau. Không rõ tác giả có biết PoC||GTFO không, nhưng đây chắc chắn là kiểu kỹ thuật có thể tìm thấy sâu trong cuốn thánh thư của Alchemist Owls
Văn phong ngắt mạnh, gắt gỏng, trông rõ kiểu do LLM tạo ra, khiến tôi đọc rất mệt
Với tôi thì tác giả chỉ đơn giản là muốn đi thẳng vào ý chính. Có vẻ họ biết rằng nếu bài dài quá thì mọi người sẽ bắt đầu đọc lướt
it’s/itsbị dùng sai,But.thành câu chỉ có một từ, HTML không được viết hoa, và có chữ “okayy” trong ngoặc. Tôi không chê tác giả đâu, ngược lại chính những chút không hoàn hảo này làm nên bài blog và khiến tôi thích hơnLàm tôi nhớ tới real pixel coding của Inigo: https://www.youtube.com/watch?v=FvS_DG8yIqQ
Đó là một intro 256 byte được tạo bằng cách đặt pixel trong Photoshop rồi lưu thành exe
Một sự thật thú vị: bất kỳ SVG inline nào cũng có thể dùng làm favicon và giữ nguyên trong tài liệu HTML
Làm vậy thì cũng có thể dùng emoji trực tiếp làm favicon. Trên HN thì emoji không hiển thị
#rrggbbhoặc liên kếturl(#id)thì phải escape#thành%23. Nếu không nó sẽ bị parse như URL fragment và mã SVG sẽ bị cắt ở điểm đó