当前位置: 首页 > news >正文

在JPEG图片中嵌入HTML

最近看到一个有趣的网页:lcamtuf.coredump.cx/squirrel/,或者说一张有趣的图片——因为用网络浏览器打开它看到的是一个网页,用图片浏览器打开它看到的又是一张图片。

在服务端要对同一个请求地址实现不同响应是十分简单的,比如通过请求头Accept来判断:

  • Accept=text/html则返回超文本;
  • Accept=image/*则返回图片;
  • ……

可是lcamtuf.coredump.cx/squirrel/这个网页(或者说图片)在脱离服务端的情况下,依然能够呈现出网页和图片两种文件内容,这是怎样实现的呢?

在前端没有秘密,打开网络浏览器的开发者工具查看一下网址的响应内容:

响应内容中有熟悉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开头,常见的有:

  • 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隐藏在图片注释中。 用十六进制读取这张图片,可以看到:

这张图片中使用了注释标记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');

复制代码

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

点击这里体验。

实际应用

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

相关文章:

  • Spring Bean生命周期详解
  • linux设置预留端口号,防止监听端口被占用 ip_local_reserved_ports
  • 4.5/4.6 磁盘格式化 4.7/4.8 磁盘挂载 4.9 手动增加swap空间
  • Android开发者用RxJs和Python撸了一个网站
  • Vue.js 2.x:组件的定义和注册(详细的图文教程)
  • Nginx负载均衡,ssl原理,生成ssl密钥对,Nginx配置ssl
  • easyui-tree 修改图标
  • egret--一次性给多个对象添加点击事件
  • 《Python从小白到大牛》第3章 第一个Python程序
  • webpack4.X初学之配置VUE开发环境
  • val和var和Java
  • 银河证券互联网转型调研报告:数字化加速器助推银河战舰腾飞
  • 第十七节:易混淆的概念(静态和非静态、拆箱和装箱)
  • 从10亿到百亿规模大促,用云效玩转项目管理
  • for in遍历对象属性注意事项
  • JavaScript 如何正确处理 Unicode 编码问题!
  • ➹使用webpack配置多页面应用(MPA)
  • crontab执行失败的多种原因
  • golang 发送GET和POST示例
  • JS+CSS实现数字滚动
  • LeetCode29.两数相除 JavaScript
  • Python爬虫--- 1.3 BS4库的解析器
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • TypeScript实现数据结构(一)栈,队列,链表
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • Vue组件定义
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 安装python包到指定虚拟环境
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 工程优化暨babel升级小记
  • 关于List、List?、ListObject的区别
  • 机器学习 vs. 深度学习
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 系统认识JavaScript正则表达式
  • 赢得Docker挑战最佳实践
  • 翻译 | The Principles of OOD 面向对象设计原则
  • # Panda3d 碰撞检测系统介绍
  • ###C语言程序设计-----C语言学习(6)#
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (附源码)计算机毕业设计大学生兼职系统
  • (四)linux文件内容查看
  • (转)编辑寄语:因为爱心,所以美丽
  • (转)创业家杂志:UCWEB天使第一步
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .NET/C# 的字符串暂存池
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • /dev下添加设备节点的方法步骤(通过device_create)
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @NestedConfigurationProperty 注解用法
  • @selector(..)警告提示
  • [Android] Implementation vs API dependency