浅谈zip格式处理逻辑漏洞
前言:zip
压缩格式应用广泛,各个平台都有使用,Windows
平台使用来压缩文件,Android
平台使用来作为apk
文件的格式。由于zip
文件格式比较复杂,在解析zip
文件格式时,如果处理不当,可能导致一些有意思的逻辑漏洞,本篇文章将挑选有意思的漏洞进行解析。
一、文件扩展名欺骗漏洞
很早之前,国外安全研究人员爆料Winrar 4.x版本存在文件扩展名欺骗漏洞(https://www.exploit-db.com/papers/32480/),黑客可以通过该漏洞诱骗受害者执行恶意程序。该漏洞的主要原理是:Winrar
在文件预览和解压缩显示文件名使用的是不同结构体的字段导致的。
1.1 zip格式文件的结构
在了解漏洞的原理前,先熟悉下zip格式的文件结构。
如果一个压缩包文件里有多个文件,可以认为每个文件都是被单独压缩,然后再拼成一起。
一个 ZIP
文件由三个部分组成:压缩源文件数据区+压缩源文件目录区+压缩源文件目录结束标志,如下图:
1)文件头(压缩源文件目录区)在文件末尾,即图1中的File Header
,记录了索引段的偏移、大小等等。
2)数据段(压缩源文件数据区)在文件开头,即图1中的Local Header
,记录了数据的一些基本信息,可以用来跟File Header
中记录的数据进行比较,保证数据的完整性。
3)Local Header
还包含了文件被压缩之后的存储区,即图1中的Data
区域。
4)图2和图3为Local Header
(图2中的ZIPFILERECORD
)和File Header
(图3中的ZIPDIRENTRY
)的数据对比,两者数据是一致的。
1.2 漏洞产生原因
Winrar
在文件预览的时候使用的是ZIPDIRENTRY
下面的deFileName
字段来显示文件名,解压缩的时候使用的是ZIPFILERECORD
下面的frFileName
字段来显示文件名。如果将deFileName
字段文件扩展名改成jpg
、gif
等图片的文件扩展名,可以欺骗用户运行恶意程序。
Winrar
文件预览示意图:
用户看到的是jpg
图片,打开的确实exe
文件,真坑啊!
Winrar
解压缩文件示意图:
解压缩之后显示的exe
,两处显示的不一样。
二、Android Master Key漏洞
之前,国外安全研究人员爆出第三个Android Master Key漏洞(http://www.saurik.com/id/19),该漏洞的主要原理是:android
在解析Zip
包时,没有校验ZipEntry
和Header
中的FileNameLength
是否一致。
2.1 zip文件格式的结构
在了解漏洞的原理前,还是先熟悉下zip
格式的文件结构。
如果一个压缩包文件里有多个文件,可以认为每个文件都是被单独压缩,然后再拼成一起。
一个 ZIP
文件由三个部分组成:压缩源文件数据区+压缩源文件目录区+压缩源文件目录结束标志,如图1所示:
1)文件头(压缩源文件目录区)在文件末尾,即图1中的File Header
,记录了索引段的偏移、大小等等。
2)数据段(压缩源文件数据区)在文件开头,即图1中的Local Header
,记录了数据的一些基本信息,可以用来跟File Header
中记录的数据进行比较,保证数据的完整性。
3)Local Header
还包含了文件被压缩之后的存储区,即图1中的Data
区域。
4)图2和图3为Local Header
(图2中的ZIPFILERECORD
)和File Header
(图3中的ZIPDIRENTRY
)的数据对比,两者数据是一致的。
2.2 漏洞产生原因
先来看一下是如何定位到Local Header
中的Data
数据:
off64_t dataOffset = localHdrOffset +
kLFHLen +
get2LE(lfhBuf + kLFHNameLen) +
Data
的偏移是通过Header
的起始偏移+Header
的大小(固定值)+Extra data
的大小+文件名的大小,如下图
回头看一下,java
在获取Data
偏移的处理,在读取Extra data
的长度的时候,它已经预存了文件名在FileHeader
中的长度。
// We don't know the entry data's start position.
// All we have is the position of the entry's local
// header. At position 28 we find the length of the
// extra data. In some cases this length differs
// from the one coming in the central header.
RAFStream rafstrm = new RAFStream(raf,
entry.mLocalHeaderRelOffset + 28);
DataInputStream is = new DataInputStream(rafstrm);
int localExtraLenOrWhatever =
漏洞就在这里产生了,如果Local Header
中的FileNameLength
被设成一个大数,并且FileName
的数据包含原来的数据,File Header
中的FileNameLength
长度不变,那么底层C++
运行和上层Java
运行就是不一样的流程。
C++ Header 64k Name Data
+--------> +----------------------> +---------->
length=64k classes.dex dex 35A... dex 35B...
+--------> +---------> +---------->
如上面所示,底层C++
的执行会读取64k的FileName
长度,而Java
层由于是读取File Header
中的数据,FileName
的长度依旧是11,于是Java
层校验签名通过,底层执行会执行恶意代码。
- Free Pascal初次体验(有亮点哦)
- HDU 1312 Red and Black(DFS,板子题,详解,零基础教你代码实现DFS)
- Selenium2+python自动化48-登录方法(参数化)
- 51Nod 1003 阶乘后面0的数量(数学,思维题)
- 如何查看某个用户指定时间段的ABAP开发记录
- Selenium2+python自动化49-判断文本(text_to_be_present_in_element)
- 洛谷 P1876 开灯(思维,枚举,规律题)
- 线性回归:简单线性回归详解
- Codeforces 789A Anastasia and pebbles(数学,思维题)
- hihoCoder #1082 : 然而沼跃鱼早就看穿了一切(字符串处理)
- 51Nod 1182 完美字符串(字符串处理 贪心 Facebook Hacker Cup选拔)
- 51Nod 1080 两个数的平方和(数论,经典题)
- Selenium3+python自动化50-环境搭建(firefox)
- Selenium2+python自动化51-unittest简介
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何将Flink应用的日志发送到kafka
- 锦囊篇|Java中的SPI机制
- webpack实战——生产环境配置【上】
- 深度阅读之《Concurrency in Go》
- 为了不让代码看起来像一坨* 我在工作中反复用了这个
- 在 Go 语言中 Patch 非导出函数
- SpringCloud 配置中心服务端配置解析流程分析
- Qt多线程编程之线程池
- PWN:Tcache Attack原理
- [Go]GO语言实战-GO-FLY在线客服cobra库命令行参数解析
- [Go]GO语言实战-GO-FLY在线客服gorm导入sql文件
- Day7.数据类型-集合
- 详解一条查询select语句和更新update语句的执行流程
- JSP 开发环境搭建与项目运行(二)
- Activity启动时生命周期汇总