MISC

编码分析

取证隐写

大部分的CTF比赛中,取证及隐写两者密不可分,两者所需要的知识也相辅相成,所以这里也将对两者一起介绍。

任何要求检查一个静态数据文件从而获取隐藏信息的都可以被认为是隐写取证题(除非单纯地是密码学的知识),一些低分的隐写取证又常常与古典密码学结合在一起,而高分的题目则通常用与一些较为复杂的现代密码学知识结合在一起,很好地体现了Misc题的特点。

前置技能

  • 了解常见的编码

能够对文件中出现的一些编码进行解码,并且对一些特殊的编码(Base64,十六进制,二进制等)有一定的敏感度,对其进行转换并得到最终的flag。

  • 能够利用脚本语言(python)去操作二进制数据
  • 熟知常见文件的文件格式,尤其是 文件头,协议,结构等
  • 灵活运用常见的工具

python操作二进制数据

Struct模块

有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成。

struct模块中最重要的三个函数是pack(), unpack(), calcsize()

  • pack(fmt, v1, v2, ...)按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)
  • unpack(fmt, string)按照给定的格式(fmt)解析字节流string,返回解析出来的tuple
  • calcsize(fmt)计算给定的格式(fmt)占用多少字节的内存

这里打包格式 fmt 确定了将变量按照什么方式打包成字节流,其包含了一系列的格式字符串。这里就不再给出不同格式字符串的含义了,详细细节可以参照 Python Doc

>>> import struct
>>> struct.pack('>I',16)
'\x00\x00\x00\x10'

pack的第一个参数是处理指令,’>I’的意思是:
>表示字节顺序是big-endian,也就是网络序,I表示4字节无符号整数。
后面的参数个数要和处理指令一致。

读入一个BMP文件的前30字节,文件头的结构按顺序如下

  • 两个字节:’BM’表示Windows位图,’BA’表示OS/2位图
  • 一个4字节整数:表示位图大小
  • 一个4字节整数:保留位,始终为0
  • 一个4字节整数:实际图像的偏移量
  • 一个4字节整数:Header的字节数
  • 一个4字节整数:图像宽度
  • 一个4字节整数:图像高度
  • 一个2字节整数:始终为1
  • 一个2字节整数:颜色数
1
2
3
4
>>>> import struct
>>> bmp = '\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00'
>>> struct.unpack('<ccIIIIIIHH',bmp)
('B', 'M', 691256, 0, 54, 40, 640, 360, 1, 24)

bytearray字节数组

将文件以二进制数组形式读取

data = bytearray(open('challenge.png', 'rb').read())

字节数组就是可变版本的字节

data[0] = '\x89'

常用工具

010Editor

SweetScape 010 Editor是一个全新的十六进位文件编辑器,它有别於传统的十六进位编辑器在於它可用’范本’来解析二进位文件, 从而让你读懂和编辑它. 它还可用来比较一切可视的二进位文件.

利用它的模板功能可以非常轻松的观察文件内部的具体结构并且依此快速更改内容。

010

file

file命令根据文件头(魔法字节)去识别一个文件的文件类型

root in ~/Desktop/tmp λ file flag
flag: PNG image data, 450 x 450, 8-bit grayscale, non-interlaced

strings

打印文件中可打印的字符,经常用来发现文件中的一些提示信息或是一些特殊的编码信息,常常用来发现题目的突破口。

  • 可以配合grep命令探测指定信息

strings test|grep -i XXCTF

  • 也可以配合-o参数获取所有ASCII字符偏移
1
2
3
4
5
6
7
8
9
10
11
>root in ~/Desktop/tmp λ strings -o flag|head
14 IHDR
45 gAMA
64 cHRM
141 bKGD
157 tIME
202 IDATx
223 NFdVK3
361 |;*-
410 Ge%<W
431 5duX@%

binwalk

binwalk本是一个固件的分析工具,比赛中常用来发现多个文件粘合再在一起的情况。根据文件头去识别一个文件中夹杂的其他文件,有时也会存在误报率(尤其是对Pcap流量包等文件时)。

1
2
3
4
5
6
7
8
9
>root in ~/Desktop/tmp λ binwalk flag

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 450 x 450, 8-bit grayscale, non-interlaced
134 0x86 Zlib compressed data, best compression
25683 0x6453 Zip archive data, at least v2.0 to extract, compressed size: 675, uncompressed size: 1159, name: readme.txt
26398 0x671E Zip archive data, at least v2.0 to extract, compressed size: 430849, uncompressed size: 1027984, name: trid
457387 0x6FAAB End of Zip archive

配合-e参数可以进行自动化提取

也可以结合dd命令进行手动切割

1
2
3
4
>root in ~/Desktop/tmp λ dd if=flag of=1.zip bs=1 skip=25683
431726+0 records in
431726+0 records out
431726 bytes (432 kB, 422 KiB) copied, 0.900973 s, 479 kB/s

图片分析

Image Analysis

PNG

文件格式

对于一个PNG文件来说,其文件头总是由位固定的字节来描述的,剩余的部分由3个以上的PNG的数据块(Chunk)按照特定的顺序组成

文件头89 50 4E 47 0D 0A 1A 0A + 数据块 + 数据块 + 数据块….

数据块CHUNk

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,PNG读写软件也都必须要支持这些数据块。

数据块符号 数据块名称 多数据块 可选否 位置限制
IHDR 文件头数据块 第一块
cHRM 基色和白色点数据块 在PLTE和IDAT之前
gAMA 图像γ数据块 在PLTE和IDAT之前
sBIT 样本有效位数据块 在PLTE和IDAT之前
PLTE 调色板数据块 在IDAT之前
bKGD 背景颜色数据块 在PLTE之后IDAT之前
hIST 图像直方图数据块 在PLTE之后IDAT之前
tRNS 图像透明数据块 在PLTE之后IDAT之前
oFFs (专用公共数据块) 在IDAT之前
pHYs 物理像素尺寸数据块 在IDAT之前
sCAL (专用公共数据块) 在IDAT之前
IDAT 图像数据块 与其他IDAT连续
tIME 图像最后修改时间数据块 无限制
tEXt 文本信息数据块 无限制
zTXt 压缩文本数据块 无限制
fRAc (专用公共数据块) 无限制
gIFg (专用公共数据块) 无限制
gIFt (专用公共数据块) 无限制
gIFx (专用公共数据块) 无限制
IEND 图像结束数据 最后一个数据块

对于每个数据块都有着统一的数据结构,每个数据块由4个部分组成

名称 字节数 说明
Length (长度) 4字节 指定数据块中数据域的长度,其长度不超过(231-1)字节
Chunk Type Code (数据块类型码) 4字节 数据块类型码由ASCII字母(A-Z和a-z)组成
Chunk Data (数据块数据) 可变长度 存储按照Chunk Type Code指定的数据
CRC (循环冗余检测) 4字节 存储用来检测是否有错误的循环冗余码

CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。

IHDR

文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,由13字节组成,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块

其中我们关注的是前8字节的内容

域的名称 字节数 说明
Width 4 bytes 图像宽度,以像素为单位
Height 4 bytes 图像高度,以像素为单位

我们经常会去更改一张图片的高度或者宽度使得一张图片显示不完整从而达到隐藏信息的目的。

ihdr

这里可以发现在Kali中是打不开这张图片的,提示IHDR CRC error(Windows 10自带的图片查看器能够打开),就提醒了我们IHDR块被人为的篡改过了,从而尝试修改图片的高度或者宽度发现隐藏的字符串

例题
  • WDCTF-finals-2017

观察文件可以发现,文件头及宽度异常

00000000  80 59 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.YNG........IHDR|
00000010  00 00 00 00 00 00 02 f8  08 06 00 00 00 93 2f 8a  |............../.|
00000020  6b 00 00 00 04 67 41 4d  41 00 00 9c 40 20 0d e4  |k....gAMA...@ ..|
00000030  cb 00 00 00 20 63 48 52  4d 00 00 87 0f 00 00 8c  |.... cHRM.......|
00000040  0f 00 00 fd 52 00 00 81  40 00 00 7d 79 00 00 e9  |....R...@..}y...|
...

这里需要注意的是,文件宽度不能任意修改,需要根据IHDR块的CRC值爆破得到宽度,否则图片显示错误不能得到flag

import os
import binascii
import struct

misc = open("misc4.png","rb").read()

for i in range(1024):
    data = misc[12:16] + struct.pack('>i',i)+ misc[20:29]
    crc32 = binascii.crc32(data) & 0xffffffff
    if crc32 == 0x932f8a6b:
        print i

得到宽度值为709后,恢复图片得到flag

misc4

PLTE

调色板数据块PLTE(palette chunk):它包含有与索引彩色图像((indexed-color image))相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data chunk)之前。真彩色的PNG数据流也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。

IDAT

图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

  • 储存图像像数数据
  • 在数据流中可包含多个连续顺序的图像数据块
  • 采用LZ77算法的派生算法进行压缩
  • 可以用zlib解压缩

值得注意的是,IDAT块只有当上一个块充满时,才会继续一个新的块。

pngcheck去查看此png文件

λ .\pngcheck.exe -v sctf.png
File: sctf.png (1421461 bytes)
  chunk IHDR at offset 0x0000c, length 13
    1000 x 562 image, 32-bit RGB+alpha, non-interlaced
  chunk sRGB at offset 0x00025, length 1
    rendering intent = perceptual
  chunk gAMA at offset 0x00032, length 4: 0.45455
  chunk pHYs at offset 0x00042, length 9: 3780x3780 pixels/meter (96 dpi)
  chunk IDAT at offset 0x00057, length 65445
    zlib: deflated, 32K window, fast compression
  chunk IDAT at offset 0x10008, length 65524
...
  chunk IDAT at offset 0x150008, length 45027
  chunk IDAT at offset 0x15aff7, length 138
  chunk IEND at offset 0x15b08d, length 0
No errors detected in sctf.png (28 chunks, 36.8% compression).

可以看到,正常的块的length是在65524的时候就满了,而倒数第二个IDAT块长度是45027,最后一个长度是138,很明显最后一个IDAT块是有问题的,因为他本来应该并入到倒数第二个未满的块里.

利用python zlib解压多余IDAT块的内容,此时注意剔除长度,数据块类型及末尾的CRC校验值

import zlib
import binascii
IDAT = "789...667".decode('hex')
result = binascii.hexlify(zlib.decompress(IDAT))
print result

IEND

图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

00 00 00 00 49 45 4E 44 AE 42 60 82

IEND数据块的长度总是00 00 00 00,数据标识总是IEND49 45 4E 44,因此,CRC码也总是AE 42 60 82

其余辅助数据块

  • 背景颜色数据块bKGD(background color)。
  • 基色和白色度数据块cHRM(primary chromaticities and white point)。所谓白色度是指当R=G=B=最大值时在显示器上产生的白色度。
  • 图像γ数据块gAMA(image gamma)。
  • 图像直方图数据块hIST(image histogram)。
  • 物理像素尺寸数据块pHYs(physical pixel dimensions)。
  • 样本有效位数据块sBIT(significant bits)。
  • 文本信息数据块tEXt(textual data)。
  • 图像最后修改时间数据块tIME (image last-modification time)。
  • 图像透明数据块tRNS (transparency)。
  • 压缩文本数据块zTXt (compressed textual data)。

LSB

LSB全称leastsignificant bit,最低有效位PNG文件中的图像像数一般是由RGB三原色(红绿蓝)组成,每一种颜色占用8位,取值范围为0x00~0xFF,即有256种颜色,一共包含了256的3次方的颜色,即16777216种颜色人类的眼睛可以区分约1000万种不同的颜色

这意味着人类的眼睛无法区分余下的颜色大约有6777216种

LSB隐写就是修改RGB颜色分量的最低二进制位(LSB),每个颜色会有8bit,LSB隐写就是修改了像数中的最低的1bit,而人类的眼睛不会注意到这前后的变化,每个像数可以携带3比特的信息

lsb

如果是要寻找这种LSB隐藏痕迹的话,有一个工具Stegsolve是个神器,可以来辅助我们进行分析。

通过下方的按钮可以观察每个通道的信息,例如查看R通道的最低位第8位平面的信息

lsb1

LSB的信息借助于Stegsolve查看各个通道时一定要细心捕捉异常点,抓住LSB隐写的蛛丝马迹

例题

HCTF-2016-Misc

这题的信息隐藏在RGB三个通道的最低位中,借助Stegsolve-->Analyse-->Data Extract可以指定通道进行提取。

hctfsolve

可以发现zip头,用save bin保存为压缩包后,打开运行其中的ELF文件就可以得到最后的flag

更多关于LSB的研究可以看这里

隐写软件

Stepic

JPG

文件结构

  • jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化。在保存时有个质量参数可在[0,100]之间选择,参数越大图片就越保真,但图片的体积也就越大。一般情况下选择70或80就足够了。
  • jpeg没有透明度信息。

JPG基本数据结构为两大类型:“段”和经过压缩编码的图像数据。

名 称 字节数 数据 说明
段 标识 1 FF 每个新段的开始标识
段类型 1 类型编码(称作“标记码”)
段长 度 2 包括段内容和段长度本身,不包括段标识和段类型
段内容 2 ≤65533字节
  • 有些段没有长度描述也没有内容,只有段标识和段类型。文件头和文件尾均属于这种段。
  • 段与段之间无论有多少FF都是合法的,这些FF称为“填充字节”,必须被忽略掉。

一些常见的段类型

jpgformat

0xffd8 && 0xffd9为JPG文件的开始结束的标志

隐写软件

Stegdetect

通过统计分析技术评估JPEG文件的DCT频率系数的隐写工具, 可以检测到通过JSteg、JPHide、OutGuess、Invisible Secrets、F5、appendX和Camouflage等这些隐写工具隐藏的信息,并且还具有基于字典暴力破解密码方法提取通过Jphide、outguess和jsteg-shell方式嵌入的隐藏信息

-q 仅显示可能包含隐藏内容的图像。
-n 启用检查JPEG文件头功能,以降低误报率。如果启用,所有带有批注区域的文件将被视为没有被嵌入信息。如果JPEG文件的JFIF标识符中的版本号不是1.1,则禁用OutGuess检测。
-s 修改检测算法的敏感度,该值的默认值为1。检测结果的匹配度与检测算法的敏感度成正比,算法敏感度的值越大,检测出的可疑文件包含敏感信息的可能性越大。
-d 打印带行号的调试信息。
-t 设置要检测哪些隐写工具(默认检测jopi),可设置的选项如下:
j 检测图像中的信息是否是用jsteg嵌入的。
o 检测图像中的信息是否是用outguess嵌入的。
p 检测图像中的信息是否是用jphide嵌入的。
i 检测图像中的信息是否是用invisible secrets嵌入的。
JPHS

JPEG图像的信息隐藏软件JPHS,它是由Allan Latham开发设计实现在Windows和Linux系统平台针对有损压缩JPEG文件进行信息加密隐藏和探测提取的工具。软件里面主要包含了两个程序JPHIDE和JPSEEK, JPHIDE程序主要是实现将信息文件加密隐藏到JPEG图像功能,而JPSEEK程序主要实现从用JPHIDE程序加密隐藏得到的JPEG图像探测提取信息文件,Windows版本的JPHS里的JPHSWIN程序具有图形化操作界面且具备JPHIDE和JPSEEK的功能。

slienteye

SilentEye is a cross-platform application design for an easy use of steganography, in this case hiding messages into pictures or sounds. It provides a pretty nice interface and an easy integration of new steganography algorithm and cryptography process by using a plug-ins system

GIF

文件结构

一个GIF文件的结构可分为

  • 文件头(File Header)
    • GIF文件署名(Signature)
    • 版本号(Version)
  • GIF数据流(GIF Data Stream)
    • 控制标识符
    • 图象块(Image Block)
    • 其他的一些扩展块
  • 文件终结器(Trailer)

下表显示了一个GIF文件的组成结构:

gif

中间的那个大块可以被重复任意次

文件头

GIF署名(Signature)和版本号(Version)

GIF署名用来确认一个文件是否是GIF格式的文件,这一部分由三个字符组成:”GIF”;文件版本号也是由三个字节组成,可以为”87a”或”89a”

逻辑屏幕标识符(Logical Screen Descriptor)

Logical Screen Descriptor(逻辑屏幕描述符)紧跟在header后面。这个块告诉decoder(解码器)图片需要占用的空间。它的大小固定为7个字节,以canvas width(画布宽度)和canvas height(画布高度)开始

全局颜色列表(Global Color Table)

GIF格式可以拥有global color table,或用于针对每个子图片集,提供local color table。每个color table由一个RGB(就像通常我们见到的(255,0,0)红色 那种)列表组成。

图像标识符(Image Descriptor)

一个GIF文件一般包含多个图片。之前的图片渲染模式一般是将多个图片绘制到一个大的(virtual canvas)虚拟画布上,而现在一般将这些图片集用于实现动画。

每个image都以一个image descriptor block(图像描述块)作为开头,这个块固定为10字节。

imagesdescription

图像数据(Image Data)

终于到了图片数据实际存储的地方。Image Data是由一系列的输出编码(output codes)构成,它们告诉decoder(解码器)需要绘制在画布上的每个颜色信息。这些编码以字节码的形式组织在这个块中。

文件终结器(Trailer)

该块为一个单字段块,用来指示该数据流的结束。取固定值0x3b.

更多参见 gif 格式图片详细解析

空间轴

由于GIF的动态特性,由一帧帧的图片构成,所以每一帧的图片,多帧图片间的结合,都成了隐藏信息的一种载体。

对于需要分离的GIF文件,可以使用convert命令将其每一帧分割开来

root in ~/Desktop/tmp λ convert cake.gif cake.png
root in ~/Desktop/tmp λ ls
cake-0.png  cake-1.png  cake-2.png  cake-3.png  cake.gif
例题

WDCTF-2017:3-2

打开gif后,思路很清晰,分离每一帧图片后,将起合并得到完整的二维码即可

from  PIL import Image

flag = Image.new("RGB",(450,450))

for i in range(2):
    for j in range(2):
        pot = "cake-{}.png".format(j+i*2)
        potImage = Image.open(pot)
        flag.paste(potImage,(j*225,i*225))
flag.save('./flag.png')

扫码后得到一串16进制字符串

03f30d0ab8c1aa5....74080006030908

开头03f3pyc文件的头,恢复为python脚本后直接运行得到flag

时间轴

GIF文件每一帧间的时间间隔也可以作为信息隐藏的载体。

例如在当时在XMan选拔赛出的一题

XMAN-2017:100.gif

通过identify命令清晰的打印出每一帧的时间间隔

$ identify -format "%s %T \n" 100.gif
0 66
1 66
2 20
3 10
4 20
5 10
6 10
7 20
8 20
9 20
10 20
11 10
12 20
13 20
14 10
15 10

推断20 & 10 分别代表0 & 1,提取每一帧间隔并进行转化

1
2
$ cat flag|cut -d ' ' -f 2|tr -d '66'|tr -d '\n'|tr -d '0'|tr '2' '0'
0101100001001101010000010100111001111011001110010011011000110101001101110011010101100010011001010110010101100100001101000110010001100101011000010011000100111000011001000110010101100100001101000011011100110011001101010011011000110100001100110110000101100101011000110110011001100001001100110011010101111101#

最后转ASCII码得到flag

隐写软件

压缩包分析

Zip格式

文件结构

Zip文件主要由三部分构成,分别为

压缩源文件数据区 核心目录 目录结束
local file header + file data + data descriptor central directory end of central directory record
  • 压缩源文件数据区中每一个压缩的源文件/目录都是一条记录,其中

    • local file header:文件头用于标识该文件的开始,记录了该压缩文件的信息,这里的文件头标识由固定值 50 4B 03 04 开头,也是 Zip 的文件头的重要标志
    • file data:文件数据记录了相应压缩文件的数据
    • data descriptor:数据描述符用于标识该文件压缩结束,该结构只有在相应的 local file header 中通用标记字段的第3 bit设为 1 时才会出现,紧接在压缩文件源数据后
  • Central directory 核心目录

    • 记录了压缩文件的目录信息,在这个数据区中每一条纪录对应在压缩源文件数据区中的一条数据。

      Offset Bytes Description
      0 4 Central directory file header signature = 0x02014b50 核心目录文件header标识=(0x02014b50)
      4 2 Version made by 压缩所用的pkware版本
      6 2 Version needed to extract (minimum) 解压所需pkware的最低版本
      8 2 General purpose bit flag 通用位标记伪加密
      10 2 Compression method 压缩方法
      12 2 File last modification time 文件最后修改时间
      14 2 File last modification date 文件最后修改日期
      16 4 CRC-32 CRC-32校验码
      20 4 Compressed size 压缩后的大小
      24 4 Uncompressed size 未压缩的大小
      28 2 File name length (n) 文件名长度
      30 2 Extra field length (m) 扩展域长度
      32 2 File comment length (k) 文件注释长度
      34 2 Disk number where file starts 文件开始位置的磁盘编号
      36 2 Internal file attributes 内部文件属性
      38 4 External file attributes 外部文件属性
      42 4 relative offset of local header 本地文件头的相对位移
      46 n File name 目录文件名
      46+n m Extra field 扩展域
      46+n+m k File comment 文件注释内容
  • End of central directory record(EOCD) 目录结束标识

    • 目录结束标识存在于整个归档包的结尾,用于标记压缩的目录数据的结束。每个压缩文件必须有且只有一个EOCD记录。

更加详细参见 官方文档

主要攻击

爆破

这里主要介绍两款爆破使用的工具

  • Windows下的神器ARCHPR

    1

    暴力枚举,跑字典,明文攻击,应有尽有

  • Linux下的命令行工具 fcrackzip

    # -b 指定模式为暴破,-c1指定密码类型为纯数字,其它类型可以rtfm,-u这个参数非常重要不然不显示破解出来的密码,-l 5-6可以指定长度
    root@kali:fcrackzip -b -c1 -u test.zip
    

CRC32

原理

CRC 本身是「冗余校验码」的意思,CRC32 则表示会产生一个 32bit(8 位十六进制数)的校验值。由于 CRC32 产生校验值时源数据块的每一个 bit(位)都参与了计算,所以数据块中即使只有一位发生了变化,也会得到不同的 CRC32 值。

CRC32 校验码出现在很多文件中比如 png 文件,同样 zip 中也有 CRC32 校验码.值得注意的是 zip 中的 CRC32 是未加密文件的校验值.

这也就导致了基于 CRC32 的攻击手法。

  • 文件内内容很少(一般比赛中大多为 4 字节左右)
  • 加密的密码很长

我们不去爆破压缩包的密码,而是直接去直接爆破源文件的内容(一般都是可见的字符串),从而获取想要的信息。

比如我们新建一个 flag.txt,其中内容为 123,使用密码 !QAZXSW@#EDCVFR$ 去加密。

2

而我们去计算文件的 CRC32 值发现和上图中的 CRC32 值吻合

文件: flag.txt
大小: 3
时间: Tue, 29 Aug 2017 10:38:10 +0800
MD5: 202cb962ac59075b964b07152d234b70
SHA1: 40bd001563085fc35165329ea1ff5c5ecbdbbeef
CRC32: 884863D2

注意

在爆破时我们所枚举的所有可能字符串的CRC32值是要与压缩源文件数据区中的CRC32值所对应

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
# -*- coding: utf-8 -*-

import binascii
import base64
import string
import itertools
import struct

alph = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/='

crcdict = {}
print "computing all possible CRCs..."
for x in itertools.product(list(alph), repeat=4):
st = ''.join(x)
testcrc = binascii.crc32(st)
crcdict[struct.pack('<i', testcrc)] = st
print "Done!"

f = open('flag.zip')
data = f.read()
f.close()
crc = ''.join(data[14:18])
if crc in crcdict:
print crcdict[crc]
else:
print "FAILED!"
例题

Abctf-2016:Zippy

根据每个压缩包内的文件大小可以推断使用 CRC32 攻击手法,获得每个压缩包内的内容后连在一起 base64 解码后时一个加密的压缩包,爆破获得 flag。

明文攻击

原理
  • 一个加密的压缩文件
  • 解压缩文件的 ZIP 版本(比如加密平台、zip 版本号等,可以通过文件属性了解。如果是 Linux 平台,用 zipinfo -v 可以查看一个 zip 包的详细信息,包括加密算法等)
  • 知道压缩包里某个文件的部分连续内容(至少 12 字节)

如果你已经知道加密文件的部分内容,比如在某个网站上发现了它的 readme.txt 文件,你就可以开始尝试破解了。

首先,将这个明文文件打包成 zip 包,比如将 readme.txt 打包成 readme.zip。

打包完成后,需要确认二者采用的压缩算法相同。一个简单的判断方法是用 WinRAR 打开文件,同一个文件压缩后的体积是否相同。如果相同,基本可以说明你用的压缩算法是正确的。如果不同,就尝试另一种压缩算法。

工具

注解

建议使用 Windows 的 ARCHPR,一是速度较快,二是较稳定(之前出题时遇到过用 PKCrack 爆不出来的情况)。

伪加密

原理

在上文 Zip 格式中的 核心目录区 中,我们强调了一个叫做通用位标记(General purpose bit flag)的 2 字节,不同比特位有着不同的含义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Bit 0: If set, indicates that the file is encrypted.

(For Method 6 - Imploding)
Bit 1: If the compression method used was type 6,
Imploding, then this bit, if set, indicates
an 8K sliding dictionary was used. If clear,
then a 4K sliding dictionary was used.
...
Bit 6: Strong encryption. If this bit is set, you should
set the version needed to extract value to at least
50 and you must also set bit 0. If AES encryption
is used, the version needed to extract value must
be at least 51.
...

在 010Editor 中我们尝试着将这 1 位修改 0-->1

4

再打开文件发现已要求输入密码。

5

修改伪加密的方法:

  • 16 进制下修改通用位标记
  • binwalk -e 无视伪加密
  • 在 Mac OS 及部分 Linux(如 Kali)系统中,可以直接打开伪加密的 zip 压缩包
  • 检测伪加密的小工具 ZipCenOp.jar
  • 有时候用 WinRar 的修复功能(此方法有时有奇效,不仅针对伪加密)
例题

SSCTF-2017:我们的秘密是绿色的

WP: http://bobao.360.cn/ctf/detail/197.html

我们在得到两个 readme.txt,且一个加密,一个已知,很容易想到明文攻击的手法。

注意在用明文攻击时的操作。

3

得到密码 Y29mZmVl 后,解压缩文件,得到另一个压缩包。

观察通用位标记位,猜测伪加密,修改后解压得到 flag

这一题,基本涵盖了比赛中 zip 的常见考察手法,爆破,伪加密,明文攻击等,都在本题中出现。

Next Previous

RAR格式

文件格式

Rar 文件主要由标记块,压缩文件头块,文件头块,结尾快组成。

其每一块大致分为以下几个字段:

名称 大小 描述
HEAD_CRC 2 全部块或块部分的CRC
HEAD_TYPE 1 块类型
HEAD_FLAGS 2 阻止标志
HEAD_SIZE 2 块大小
ADD_SIZE 4 可选字段 - 添加块大小

Rar压缩包的文件头为 0x 52 61 72 21 1A 07 00

紧跟着文件头(0x526172211A0700)的是标记块(MARK_HEAD),其后还有文件头(File Header)。

名称 大小 描述
HEAD_CRC 2 CRC of fields from HEAD_TYPE to FILEATTR and file name
HEAD_TYPE 1 Header Type: 0x74
HEAD_FLAGS 2 Bit Flags (Please see ‘Bit Flags for File in Archive’ table for all possibilities)(伪加密)
HEAD_SIZE 2 File header full size including file name and comments
PACK_SIZE 4 Compressed file size
UNP_SIZE 4 Uncompressed file size
HOST_OS 1 Operating system used for archiving (See the ‘Operating System Indicators’ table for the flags used)
FILE_CRC 4 File CRC
FTIME 4 Date and time in standard MS DOS format
UNP_VER 1 RAR version needed to extract file (Version number is encoded as 10 * Major version + minor version.)
METHOD 1 Packing method (Please see ‘Packing Method’ table for all possibilities
NAME_SIZE 2 File name size
ATTR 4 File attributes
HIGH_PACK_SIZ 4 High 4 bytes of 64-bit value of compressed file size. Optional value, presents only if bit 0x100 in HEAD_FLAGS is set.
HIGH_UNP_SIZE 4 High 4 bytes of 64-bit value of uncompressed file size. Optional value, presents only if bit 0x100 in HEAD_FLAGS is set.
FILE_NAME NAME_SIZE bytes File name - string of NAME_SIZE bytes size
SALT 8 present if (HEAD_FLAGS & 0x400) != 0
EXT_TIME variable size present if (HEAD_FLAGS & 0x1000) != 0

每个 rar 文件的结尾快(Terminator)都是固定的

Field Name Size (bytes) Possibilities
HEAD_CRC 2 Always 0x3DC4
HEAD_TYPE 1 Header type: 0x7b
HEAD_FLAGS 2 Always 0x4000
HEAD_SIZE 2 Block size = 0x0007

更多详见 http://www.forensicswiki.org/wiki/RAR

主要攻击

爆破
伪加密

Rar 文件的伪加密在文件头中的位标记字段上,用 010Editor 可以很清楚的看见这一位,修改这一位可以造成伪加密

6

其余明文攻击等手法依旧同 zip 中介绍的一样。

音频分析

与音频相关的 CTF 题目主要使用了隐写的策略,主要分为 MP3 隐写,LSB 隐写,波形隐写,频谱隐写等等。

常见手段

通过 binwalk 以及 strings 可以发现的信息不再详述。

MP3 隐写

原理

MP3隐写主要是使用 Mp3Stego 工具进行隐写,其基本介绍及使用方法如下

MP3Stego will hide information in MP3 files during the compression process. The data is first compressed, encrypted and then hidden in the MP3 bit stream.

encode -E hidden_text.txt -P pass svega.wav svega_stego.mp3
decode -X -P pass svega_stego.mp3

例题

ISCC-2016: Music Never Sleep

初步观察后,由 strings 无发现,听音频无异常猜测使用隐写软件隐藏数据。

1

得到密码后使用 Mp3Stego 解密、。

decode.exe -X ISCC2016.mp3 -P bfsiscc2016

得到文件 iscc2016.mp3.txt: Flag is SkYzWEk0M1JOWlNHWTJTRktKUkdJTVpXRzVSV0U2REdHTVpHT1pZPQ== ???

base64 && base32 后得到flag。

波形

原理

通常来说,波形方向的题,在观察到异常后,使用相关软件(Audacity, Adobe Audition)观察波形规律,将波形进一步转化为 01 字符串等,从而提取转化出最终的 flag。

例题

ISCC-2017: Misc-04

其实这题隐藏的信息在最开始的一段音频内,不细心听可能会误认为是隐写软件。

3

以高为 1 低为 0,转换得到 01 字符串。

110011011011001100001110011111110111010111011000010101110101010110011011101011101110110111011110011111101

转为 ASCII,莫斯密码解密,得到 flag。

注解

一些较复杂的可能会先对音频进行一系列的处理,如滤波等。例如 JarvisOJ: 上帝之音,writeup

频谱

原理

音频中的频谱隐写是将字符串隐藏在频谱中,此类音频通常会有一个较明显的特征,听起来是一段杂音或者比较刺耳。

例题

Su-ctf-quals-2014:hear_with_your_eyes

4

LSB音频隐写

原理

类似于图片隐写中的 LSB 隐写,音频中也有对应的 LSB 隐写。主要可以使用 Silenteye 工具,其介绍如下:

SilentEye is a cross-platform application design for an easy use of steganography, in this case hiding messages into pictures or sounds. It provides a pretty nice interface and an easy integration of new steganography algorithm and cryptography process by using a plug-ins system.

例题

广东省强网杯-2015: Little Apple

直接使用 slienteye 即可。

2

延伸

磁盘 / 内存分析

常用工具

磁盘

常见的磁盘分区格式有以下几种

  • Windows: FAT12 -> FAT16 -> FAT32 -> NTFS
  • Linux: EXT2 -> EXT3 -> EXT4
  • FAT 主磁盘结构

FAT 主磁盘结构

  • 删除文件:目录表中文件名第一字节 e5

VMDK

VMDK 文件本质上是物理硬盘的虚拟版,也会存在跟物理硬盘的分区和扇区中类似的填充区域,我们可以利用这些填充区域来把我们需要隐藏的数据隐藏到里面去,这样可以避免隐藏的文件增加了 VMDK 文件的大小(如直接附加到文件后端),也可以避免由于 VMDK 文件大小的改变所带来的可能导致的虚拟机错误。而且 VMDK 文件一般比较大,适合用于隐藏大文件。

内存

  • 解析 Windows / Linux / Mac OS X 内存结构
  • 分析进程,内存数据
  • 根据题目提示寻找线索和思路,提取分析指定进程的特定内存数据

题目

  • Jarvis OJ - MISC - 取证 2

参考

流量分析

分析流量需要对一些常用的协议有简单的了解。

  • IP / TCP
  • UDP / TCP
  • DNS
  • HTTP / HTTPS

基本工具

技巧

  • 统计流量,以便于知道该流量包主要利用了哪些协议
  • ip contains "xxx",过滤内容
  • 流重组:Follow TCP Stream
  • 提取流中的文件数据

常见题型

  • 直接包含 flag

    直接使用 Wireshark 的过滤条件, ip contains "flag"。之所以会选择 IP,是因为信息一般要么走 UDP 要么走 TCP,都会封装到 IP 段。

  • WiFi 包

    使用 aircrack 破解,可用的字典。或使用 Elcomsoft Wireless Security Auditor 破解。

题目

  • CFF 2016 简单网管协议
  • Jarvis OJ - MISC - 简单网管协议
  • CFF 2016 远程登录协议
  • Jarvis OJ - MISC - 远程登录协议
  • CFF 2016 Structs 漏洞
  • Jarvis OJ - MISC - Structs 漏洞
  • Jarvis OJ - Basic - 握手包

来源CTF-Wiki


⬆︎TOP