从一道题看内存取证与图片隐写


图:没有啥关系,但是当作一个封面的图片

这是第三届红帽杯的Misc题目:Advertising for Marriage,一道做了挺久,但是还是差一个关键步骤的题目。在做题过程中也学到了新的内存取证的知识,因此以此题作为切入,写下本篇WP/学习笔记。

题目:

题目内容

以下为题目:

题目下载

某云备份:q4nw

:warning:注意:

这次题目,给我的一个很大教训就是,题目中的信息!Misc作为CTF中的一种题型,它的特点之一就是“脑洞”和“列文虎克”般的观察能力以及对信息的逻辑整合能力。
题目中的 “Someone want” 其实在题目最后几个步骤中,是一个很重要的提示——确定这个someone是谁,也就是补充完整后面得到的密钥内容(hint,后面会讲到)。

:airplane:启发:

本题作为一道内存取证题,体现的考察内容,其实不单单与解题的工具、技巧有关,很大程度上也是考察一种通用能力:


(来自TK的公开课,链接
其中,我们可以看到,对Misc/取证分析题目的信息进行分析的能力(是否为hint?)判断能力(是否重要?)规划能力(解题的总体步骤和阶段性步骤?)搜集能力(哪些地方得到信息?)学习能力(如何获取信息?)提炼能力(信息间如何进行整合?)都是非常重要的,对做题还是其他的学习和生活。
努力提高自己的通用能力,能想清楚,能写清楚,能讲清楚,逻辑严密,语句通顺,表达清晰。“无论以后你想从事什么工作,在学生时代加强这些能力的培养,对你整个人生都会有很大的帮助。” ——TK

做题笔记

以下是我做题时的一些笔记,有些并不正确或者对解该题没有帮助,放在这里,记录自己的想法:

  1. 查看可能是个Windows磁盘镜像
    可疑文件
    发现可疑文件,但可能只是用户的头像,注意时间

  2. 发现cookies文件
    cookies文件

010打开发现全为空00

  1. 发现桌面PNG文件
  2. Stegsolve打开
    Stegsolve打开
    眼睛上像不像二维码?? > https://xz.aliyun.com/t/2788
  3. IHDR报错,猜测修改宽高,计算CRC
    计算得211,修改IHDR,显示正常
  4. 发现IDAT有问题
  5. 扩展:PNG图像隐写
    https://3gstudent.github.io/3gstudent.github.io/隐写技巧-利用PNG文件格式隐藏Payload/
  6. 尝试LSB
    使用工具https://github.com/livz/cloacked-pixel
  7. 去除了IEND后面(82)的00

解题过程

判断文件/题目类型

首先,拿到题目文件,使用binwalk分析,判断文件类型(输出到txt文件,方便查询信息)
binwalk xxx.raw > fileInfo.txt
可以看到其中有很多Microsoft到信息,且文件形式中很类似于磁盘文件,可以初步判断这是一个Windows磁盘镜像,这很有可能是一道内存取证题。

:warning:注意:此时,判断好类型题目,就应该在心态上调整过来,这是一道取证分析题目,取证分析 = 取证 + 分析,因此,在做题过程中,核心就是做细致的取证工作,获取充分的信息,以及很重要的逻辑分析、串联、整合、归纳。

查看镜像信息

接下来,确定此为磁盘镜像后,使用内存取证工具Volatility查看镜像信息(常常含有出题人的hint):
volatility imageinfo -f xxx.raw
查看镜像信息
图:查看镜像信息

从结果中,可以看到,Suggest Profile为WinXPSP2x86,也就是,Volatility对该镜像文件的架构识别为WinXPSP2x86,此后对该镜像的很多操作,都需要指定预设,例如 --profile WinXPSP2x86。因此,需要将磁盘镜像中的这个关键信息记录下来,以备后面使用。

:bulb:Tips:可以列举该架构可以使用的命令, e.g.
volatility -f xxx.raw --profile=Win7SP1x64 --help

方式一:使用DiskGenius

使用数据恢复综合软件DiskGenius打开虚拟磁盘——恢复文件,可以直接以GUI的形式看到磁盘镜像的内容。然后需要不断翻阅文件目录,寻找可疑的文件/文件夹(重点看一下桌面)。

https://image-host-toky.oss-cn-shanghai.aliyuncs.com/vegetable_origin.png

图·桌面的vegetable.png

发现桌面可疑文件 vegetable.png,PNG图片,恢复可得,根据图片内容猜测为图片隐写。

方式二:使用Volatility

使用Volatility可以更加方便于严谨地分析文件的内容。具体的教程可以查看该博客:链接

  1. 首先,查看进程:
volatility pslist -f xxx.raw

// TODO 图·进程显示
pslist可以用来列出运行的进程。如果Exit所在的一列显示了日期时间,则表明该进程已经结束了。 在图中,我们看到,存在notepad.exe, mspaint.exe,也就是取证对象(出题人)使用过记事本、画图程序。

在查看进程的显示时,注意一下记事本程序notepad.exe, 画画工具mspaint.exe以及DumpIt等使用过的软件,这些就是取证对象的操作,其中很有可能有重要信息。因此在逻辑清晰的一个做题过程中,我们需要对取证对象的操作,分别进行纵向地分析,然后回过头来结合起来进行分析。

Dumpit.exe 一款内存镜像提取工具
TrueCrypt.exe 一款磁盘加密工具
Notepad.exe windows自带的记事本
Mspaint,exe windows自带画图工具

  1. 查看notepad.exe

如果需要查看Notepad程序编辑的内容,需要使用Volatility的Notepad插件:

volatility notepad -f xxx.raw 

Notepad中的Hint
图·Notepad中的Hint
可以看到提示:hint:????needmoneyandgirlfirend

:warning:注意:在做题过程中,我忽略了hint中的问号???,这个其实是个重要的提示,结合前面题目中的提示 Someone want,可以推测出,这是让我们确定someone的名字,而且这个句子在一个内存取证结合图片隐写(后面会发现)的题目中,很有可能是一个密钥key。

  1. 查看mspaint.exe

接下来,我们查看内存操作中对画图程序操作的内容,使用插件mspaint。
详细教程查看:《利用volatility与Gimp实现Windows内存取证》

可以看到mspaint进程pid号,为332,dump下来

volatility -f Advertising_for_Marriage.raw --profile=WinXPSP2x86 memdump -p 332 --dump-dir=./

生成332.dmp修改后缀为332.data,用gimp打开,偏移量(offset)即为分辨率,又因为该系统为Window XP系统,分辨率一般为800x768=614400。设置分辨率,可得:

设置偏移量后的332.data
黄色部分很像菠萝,细看有字母需要图片变换,水平翻转180度,垂直镜像翻转可得:

得到字符 b1cx,结合之前,缺少的四个字符(????),得到密钥:b1cxneedmoneyandgirlfriend。

  1. 扫描文件

使用Volatility中的filescan功能,保存为txt,方便后续查找分析:

volatility filescan -f xxx.raw --profile=WinXPSP2x86 > filescanInfo.txt

通过内存取证操作(见后面列举),查找到PNG图片

volatility filescan -f Advertising\ for\ Marriage.raw --profile=WinXPSP2x86 | grep "jpg\|jpeg\|png\|tif\|gif\|bmp"

Volatility文件扫描
图·Volatility扫描图片

导出图片:
volatility -f xxx.raw dumpfiles -Q 0x000000000249ae78 -D --dump-dir=./

发现图片隐写

Linux 打开vegetable.png发现提示IHDR:CRC 错误,Windows可以正常打开,可以猜测图片尺寸被修改了。

:warning:知识点补充

PNG格式图片的文件头为:89 50 4E 47 0D 0A 1A 0A,该段格式是固定的。windows的图片查看器会忽略错误的CRC校验码,因此会显示图片,但此时的图片已经是修改过的,所以会有显示不全或扭曲等情况,借此可以隐藏信息。
而Linux下的图片查看器不会忽略错误的CRC校验码,因此用Linux打开修改过宽或高的png图片时,会出现打不开的情况

恢复正常尺寸

使用脚本计算正确的CRC校验值,并恢复其正常尺寸:

import os
import binascii
import struct

img = open("vegetable.png", "rb").read()

for w in range(1024):
    for h in range(1024):
        data = img[0xc:0x10] + struct.pack('>i',w) + struct.pack('>i',h) + img[0x18:0x1d]
        crc32 = binascii.crc32(data) & 0xffffffff
        if crc32 == struct.unpack('>i',img[0x1d:0x21])[0] & 0xffffffff:
            print w, h
            print hex(w), hex(h)
            # 直接恢复图片正常尺寸,保存为新的图片
            open("vegetable_new.png", "wb").write(img[:0xc] + data + img[0x1d:])
            exit()

:wrench:工具推荐

使用pngcheck可以对PNG图片进行检测:

pngcheck -v xxx.png

010Editor具有template检测功能,会检测出图片被修改后的很多报错信息,这也是一个好提示:

发现LSB隐写

结合Hint中的文字提示,结合Stegsolve查看图片分析,可以判断其为LSB隐写(详细介绍在后面的PNG图片相关章节),具体的LSB隐写分析如下:
在对vegetable.png使用Stegsolve查看时,切换不同的通道,发现在Red plane1,Blue plane1, Green plane1, 图片上方存在异常,显示为一个横条,由此可猜测为LSB隐写:
Red plane1

Green plane1

使用cloacked-pixel工具,使用密钥进行解密:

python lsb.py extract ./vegetable.png out b1cxneedmoneyandgirlfirend

Base64解密,维吉尼亚解密(密钥相同)即可。

:airplane: CTF图片隐写题到手三连

# 查看图片明文字符串
strings xxx.png
# binwalk分析,
binwalk xxx.png -f picInfo.txt
# foremost 切分图片
foremost xxx.png -o output_xxx

PNG 图片相关

此处探讨PNG图片的文件结构等数字特征,了解这些对解题很有帮助。PNG(Portable Network Graphics,便携式网络图形),从名字上看,这就是一种适用于网络传输的格式。

PNG 文件结构

Refer: 详细的参考

PNG文件结构
从上图可知,一个标准的PNG图片文件结构包含:

  1. PNG文件标志,即文件头:89 50 4e 47 0d 0a 1a 0a。这8位是不会变的。
  2. PNG数据块:
  • 关键数据块:定义了4种标准数据块

  • 辅助数据块:

    • IHDR
      文件头数据块IHDR是PNG文件中的第一个数据块(即在文件头之后, 0A之后),而且一个PNG文件中只能有一个文件头数据块,它包含PNG文件中存储的图像数据的基本信息,e.g. 宽,高,图像深度,图像类型,压缩方法等。

    :bulb:Tips:如何找到和修改16进制编辑器下的图片宽和高?查看图分辨率(10进制),转换为16进制,在16进制编辑器中查找,在IHDR部分的就是宽和高。

    :dart:出题点:比赛中经常通过改变宽和高使得图片显示不完整或者无法显示从而达到隐藏信息的目的。对于这种情况,我们不能轻易修改图片的宽或高的值,应该通过CRC的值推算出宽或高的值,使用脚本计算;或者是修改宽或高的值后,计算修改后的CRC,计算得出新的CRC值替换原本的值,以防图片报错打不开。

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

    • IDAT
      图像数据块 IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。这是一个可以存在多个数据块类型的数据块。它的作用就是存储着图像真正的数据。IDAT采用 LZ77 算法的派生算法进行压缩,可以用 zlib 解压缩(因此有时候foremost切割PNG会出现一些打不开的压缩包)。值得注意的是,IDAT 块只有当上一个块充满时,才会继续一个新的块。因此,做PNG隐写时,一定使用pngcheck查看一下PNG的文件结构信息,注意一下IDAT是否有出现没有填充满就开始新的一个数据块的情况(正常充满的长度应该是65524)。

    :dart:出题点:此处是出题的重灾区,常见的是LSB隐写(详细介绍教程:链接):

    LSB全称least significant bit,最低有效位
    PNG文件中的图像像数一般是由RGB三原色(红绿蓝)组成,每一种颜色占用8位,取值范围为0x00~0xFF,即有256种颜色,一共包含了256的3次方的颜色,即16777216 种颜色
    人类的眼睛可以区分约1000万种不同的颜色
    这意味着人类的眼睛无法区分余下的颜色大约有6777216种
    LSB隐写就是修改RGB颜色分量的最低二进制位(LSB),而人类的眼睛不会注意到这前后的变化
    每个像数可以携带3比特的信息
    :wrench:工具推荐:cloacked-pixel LSB隐写加解密工具,还有analyse功能,可以进行LSB检测

    • IEND
      图像结束数据 IEND(image trailer chunk):它用来标记 PNG 文件或者数据流已经结束,并且必须要放在文件的尾部。IEND 数据块的长度总是 00 00 00 00数据标识总是 IEND 49 45 4E 44,因此,CRC 码也总是 AE 42 60 82
      :dart:出题点:这些PNG图片固定的文件信息,一定要在分析图片时熟记,不用记住具体的值,但要对这些开始、结束等标志熟悉。有时在这些固定的信息附近,会有多余信息要去除。

图像深度

PNG用来存储灰度图像时,灰度图像的深度可达16位,存储彩色图像时,彩色图像的深度可达48位,并且还可存储多达16位的α通道数据。图像深度信息保存在文件头数据块IHDR中。

:bulb:CTF 图片隐写题Tips

  1. Windows、Linux分别打开,看图片内容信息,将图片中的信息与题目、其他的hint写在一个文件里,做逻辑信息提炼、关联、整合
  2. 右键图片,查看图片信息,其中可能会有提示
  3. 英文搜索很重要,很多隐写技术还没有被“翻译”和应用

:keyboard:内存取证其他调查

查看文档
volatility -f xxx.raw --profile=WinXPSP2x86 filescan | grep "doc\|docx\|rtf"

查看图片
volatility -f xxx.raw --profile=WinXPSP2x86 filescan | grep "jpg\|jpeg\|png\|tif\|gif\|bmp"
查看桌面

查看桌面
volatility -f xxx.raw --profile=WinXPSP2x86 filescan | grep "Desktop"

查看命令行输入
volatility -f xxx.raw --profile=WinXPSP2x86 cmdline

查看系统用户名
volatility -f xxx.raw --profile=WinXPSP2x86 printkey -K "SAM\Domains\Account\Users\Names"

查看网络连接
volatility -f mem.data --profile=WinXPSP2x86 netscan

小结一下

  1. 熟悉使用各类取证分析工具,是快速解题的关键
  2. 参透出题人心理,猜测可能的flag位置
  3. 对Hint信息仔细观察并进行逻辑串联,不要忽视Hint中的部分信息

Reference

[1] https://segmentfault.com/a/1190000018813033
[2] https://cloud.tencent.com/developer/article/1527140
[3] https://www.cnblogs.com/WangAoBo/p/7108278.html
[4] https://xz.aliyun.com/t/1836