在JPEG图片中嵌入HTML

最近看到一个有趣的网页: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相关

首先能够肯定这张图片是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,标记后面跟着0x03720x0372转成十进制是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');

复制代码

这张图片是一个网页,不信你就在新标签页中打开它

Lena

点击这里体验。

实际应用

将一段HTML文本嵌入到一张图片中,实际上,还没什么应用,哈哈哈😂。 若是能将JSShell脚本藏在图片中,并能后期执行,那就有意思了;并且自己是一个图片文件,能够避过一些安全软件的检查。

相关文章
相关标签/搜索