最近看到一個有趣的網頁:lcamtuf.coredump.cx/squirrel/,或者說一張有趣的圖片——由於用網絡瀏覽器打開它看到的是一個網頁,用圖片瀏覽器打開它看到的又是一張圖片。php
在服務端要對同一個請求地址實現不一樣響應是十分簡單的,好比經過請求頭Accept
來判斷:css
Accept=text/html
則返回超文本;Accept=image/*
則返回圖片;但是lcamtuf.coredump.cx/squirrel/這個網頁(或者說圖片)在脫離服務端的狀況下,依然可以呈現出網頁和圖片兩種文件內容,這是怎樣實現的呢?html
在前端沒有祕密,打開網絡瀏覽器的開發者工具查看一下網址的響應內容:前端
響應內容中有熟悉HTML標籤,也有一大堆亂碼。這堆亂碼應該是圖片文件的字符讀碼,可是爲何在網頁上看不到呢? 原來HTML中使用了body { visibility: hidden; }
樣式和<!--
註釋標籤(瀏覽器自動補全),亂碼部分就這樣被隱藏了。瀏覽器
HTML內容:安全
<html><body><style>body { visibility: hidden; } .n { visibility: visible; position: absolute; padding: 0 1ex 0 1ex; margin: 0; top: 0; left: 0; } h1 { margin-top: 0.4ex; margin-bottom: 0.8ex; }</style><div class=n><h1><i>Hello, squirrel fans!</i></h1>This is an embedded landing page for an image. You can link to this URL and get the HTML document you are viewing right now (soon to include essential squirrel facts); or embed the exact same URL as an image on your own squirrel-themed page:<p><xmp><a href="http://lcamtuf.coredump.cx/squirrel/">Click here!</a></xmp><xmp><img src="http://lcamtuf.coredump.cx/squirrel/"></xmp><p>No server-side hacks involved - the magic happens in your browser. Let's try embedding the current page as an image right now (INCEPTION!):<p><img src="#" style="border: 1px solid crimson"><p>Pretty radical, eh? Send money to: lcamtuf@coredump.cx<!-- 複製代碼
然而在查看圖片的時候,也沒看到HTML的內容,又是爲何呢?網絡
首先能夠肯定這張圖片是JPEG格式,由於內容開頭有明顯的JFIF
標記(JFIF,是JPEG最多見的文件存儲格式,也是標準的JPEG文件轉換格式)。 JPEG格式定義了一系列標記碼,都是以0xFF開頭,常見的有:app
0xFFD8
,SOI(Start Of Image),圖片開始標記;0xFFD9
,EOI(End Of Image),圖片結束標記;0xFFDA
,SOS(Start Of Scan),掃描開始標記;0xFFDB
,DQT(Define Quantization Table),定義量化表;0xFFC4
,DHT(Define Huffman Table),定義哈夫曼表;0xFFEn
,APPn(Application Specific),應用程序信息;0xFFFE
,COM(Comment),註釋;圖片的註釋內容不會展現,很顯然咱們能夠把HTML隱藏在圖片註釋中。 用十六進制讀取這張圖片,能夠看到:ide
這張圖片中使用了註釋標記0xFFFE
,標記後面跟着0x0372
。0x0372
轉成十進制是882
,而HTML內容的長度恰好是880個字節(0x0372
自己佔2個字節),因此能夠知道,HTML內容就是寫在這張圖片註釋中。函數
下面用PHP代碼簡單實現一個將HTML內容嵌入JPEG中的函數:
<?php
function embedHtmlInJpeg($jpeg_file, $html_str, $html_file) {
$length = strlen($html_str) + 2;
if ($length > 256 * 256 - 1) {
return false;
}
$content = '';
$reader = fopen($jpeg_file, 'rb');
$writer = fopen($html_file, 'wb');
$content = fread($reader, 2); // read 0xFFD8
fwrite($writer, $content); // write 0xFFD8
$header = 'FFFE' . sprintf('%04X', $length);
$header = pack('H*', $header);
$content = $header . $html_str;
fwrite($writer, $content); // write 0xFFFE
while (!feof($reader)) {
$content = fread($reader, 8192);
fwrite($writer, $content); // write else
}
fclose($reader);
fclose($writer);
return true;
}
// call it
embedHtmlInJpeg('lena.jpg',
'<html><body><style>body { visibility: hidden; } .n { visibility: visible; position: absolute; padding: 0 1ex 0 1ex; margin: 0; top: 0; left: 0; } h1 { margin-top: 0.4ex; margin-bottom: 0.8ex; }</style><div class=n><h1><i>This image is a page.</i></h1>Just open it in new tab.<p><img src="#" style="border: 1px solid crimson"><!--',
'lena.html');
複製代碼
點擊這裏體驗。
將一段HTML文本嵌入到一張圖片中,實際上,還沒什麼應用,哈哈哈😂。 若是能將JS
或Shell
腳本藏在圖片中,並能後期執行,那就有意思了;並且自己是一個圖片文件,能夠避過一些安全軟件的檢查。