CTF misc图片类总结(入门级)

misc文件头尾
文件隐写和图片隐写步骤
misc思路
MISC文件隐写总结(图片,音频,视频,压缩包等文件)
misc图片类总结(新赛题)

使用图片隐写的Python远控恶意样本分析

一、改高宽

打开图片发现下面好像少了什么。
在这里插入图片描述
WinHex打开可以看到PNG的文件头
在这里插入图片描述
解析:
(固定)八个字节89 50 4E 47 0D 0A 1A 0A为png的文件头
(固定)四个字节00 00 00 0D(即为十进制的13)代表数据块的长度为13
(固定)四个字节49 48 44 52(即为ASCII码的IHDR)是文件头数据块的标示(IDCH)
(可变)13位数据块(IHDR)
前四个字节代表该图片的宽
后四个字节代表该图片的高
后五个字节依次为:
Bit depth、ColorType、Compression method、Filter method、Interlace method
(可变)剩余四字节为该png的CRC检验码,由从IDCH到IHDR的十七位字节进行crc计算得到。
文件尾:AE 42 60 82

图片尺寸为787x500(高x宽)
00 00 00 0D 说明IHDR头块长为13
49 48 44 52 IHDR标识
00 00 03 13 图像的宽,787像素
00 00 01 F4 图像的高,500像素
发现高宽错误
这里需要注意的是,文件宽度不能任意修改,需要根据 IHDR 块的 CRC 值爆破得到宽度,否则图片显示错误不能得到 flag

import os
import binascii
import struct

crcbp = open("D:\\桌面文件\\bingbing.png", "rb").read()    #打开图片
for i in range(2000):
    for j in range(2000):
        data = crcbp[12:16] + \
            struct.pack('>i', i)+struct.pack('>i', j)+crcbp[24:29]
        crc32 = binascii.crc32(data) & 0xffffffff
        if(crc32 == 0xda5a4a50):    #图片当前CRC
            print(i, j)
            print('hex:', hex(i), hex(j))

在这里插入图片描述
把高宽都改成787保存得flag
在这里插入图片描述

二、lsb(最低有效位)隐写+base64编码图片

lsb隐写简介

攻防世界Misc高手进阶区 3-11

下载png文件,binwalk,发现zlib文件。
binwalk详解
在这里插入图片描述
在这里插入图片描述
LSB隐写,save bin,改后缀解压,弹出已损坏,用winrar自带的修复
在这里插入图片描述
在这里插入图片描述
结尾的=号判断是base64编码,开头iVBORw0K说明是base64编码的图片。
用captfencoder加上头,转为图片:FLAG{LSB_i5_SO_EASY}
在这里插入图片描述

CRC32碰撞脚本

Misc中的有一类题目是要求我们知道加密后的rar文件中的内容。但是rar文件密码我们不知道,直接爆破密码也不是很现实。
但是当文件的大小比较小,或者字符数量较少时,就可以根据crc校验码来爆破出rar内部文件的内容。

在这里插入图片描述
可以看到最后一列是对应文件的CRC校验码。并且每个文件只有4字节,所以可以看作每个CRC校验码都对应了唯一的文件。Python2爆破如下:

import binascii
import string
 
dic=string.printable #打印出字符表
crc1=0x7DE0AB32
crc2=0xB1441D53
crc3=0x49BD11F5
crc4=0xB42F1DFA
crc5=0x8163F43E
crc6=0x1FC8FEE5
 
for i in dic:
    for j in dic:
        for n in dic:
            for m in dic:
                s=i+j+n+m
                if(crc1==(binascii.crc32(s) & 0xffffffff)):
                    text1=s
                if (crc2 == (binascii.crc32(s) & 0xffffffff)):
                    text2=s
                if (crc3 == (binascii.crc32(s) & 0xffffffff)):
                    text3=s
                if (crc4 == (binascii.crc32(s) & 0xffffffff)):
                    text4=s
                if (crc5 == (binascii.crc32(s) & 0xffffffff)):
                    text5=s
                if (crc6 == (binascii.crc32(s) & 0xffffffff)):
                    text6=s
print text1+text2+text3+text4+text5+text6

CRC爆破的另一个脚本

三、盲水印+明文攻击

攻防世界Misc的warmup,2017ciscn(全国大学生信息安全竞赛)
下载打开,两个一样的open_forun.png, 明文攻击,将open_forum.png压缩成zip,然后使用ARCHPR的明文攻击
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注:两个open_forum.png的crc32的值一样,以及两个文件被压缩之后的大小,满足明文攻击要求。
在这里插入图片描述
在这里插入图片描述
解压出来是这样:
在这里插入图片描述
两个图,试试盲水印:

python bwmforpy3.py decode fuli.png fuli2.png flag.png --oldseed

注:如果要让python3兼容python2的random算法请加 --oldseed参数。结果就是flag.png。

在这里插入图片描述

在这里插入图片描述
盲水印详解

傅里叶盲水印

VNCTF021 冰冰好像藏着秘密
傅里叶盲水印原理:
图片经过傅里叶变换后,水印图片直接按像素覆盖到频率域,因为频谱是中心对称的,所以加水印也要对称的加,具体就是图片分上下两部分,左上加了什么,右下也要加同样的内容。之后傅里叶反变换回去。解水印的时候变换到傅里叶变换提取就可以了。

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread('D:\\CTF\\FFT.png', 0) #直接读为灰度图像,不过此题已经是灰度图片了
f = np.fft.fft2(img)            #做频率变换
fshift = np.fft.fftshift(f)     #转移像素做幅度谱
s1 = np.log(np.abs(fshift))#取绝对值:将复数变化成实数取对数的目的为了将数据变化到0-255
plt.subplot(121)
plt.imshow(img, 'gray')
plt.title('original')
plt.subplot(122)
plt.imshow(s1,'gray')
plt.title('center')
plt.show()

CTF盲水印详解

四、IDAT块隐写

提数据+zlib解压+625二维码

图像数据块 IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。IDAT 块只有当上一个块充满时,才会继续一个新的块。

pngcheck.exe -v sctf.png

在这里插入图片描述

前面的块都是65524,到了0x150008变为45027,再到0x15aff7的138。
很明显最后一个 IDAT 块是有问题的,因为他本来应该并入到倒数第二个未满的块里。
0x150008中的45027位数据是正常的图片信息。0x15aff7的138位数据是人为录入的,且所在的数据块也是人为创建的。
IDAT中的数据采用 LZ77 算法的派生算法进行压缩,所以可以用 zlib 解压缩。
可以用010 editor直接提取出数据,然后扔进zlib解压脚本里解压获得原始数据。

查看异常数据块的情况,使用010editor/winhex打开,导出异常数据块:
在这里插入图片描述
查找78 9C文件头标志,zlib。
在这里插入图片描述
将异常的IDAT数据块斩头去尾之后使用脚本解压,在python2代码如下:

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

得到压缩后的文件:
在这里插入图片描述
发现是625,是一个二维码的矩阵,使用python2代码做成二维码:

from PIL import Image
MAX = 25
pic = Image.new("RGB",(MAX,MAX))
str ="1111111000100001101111111100000101110010110100000110111010100000000010111011011101001000000001011101101110101110110100101110110000010101011011010000011111111010101010101111111000000001011101110000000011010011000001010011101101111010101001000011100000000000101000000001001001101000100111001111011100111100001110111110001100101000110011100001010100011010001111010110000010100010110000011011101100100001110011100100001011111110100000000110101001000111101111111011100001101011011100000100001100110001111010111010001101001111100001011101011000111010011100101110100100111011011000110000010110001101000110001111111011010110111011011"
i=0
for y in range(0,MAX):
    for x in range(0,MAX):
        if(str[i] == '1'):
            pic.putpixel([x,y],(0,0,0))
        else:pic.putpixel([x,y],(255,255,255))
        i = i+1
pic.show()
pic.save("flag.png")

运行得到二维码

png末尾藏zip

PNG (png),文件头:89504E47 文件尾:49454E44AE426082
在这里插入图片描述
从0304后全部保存,在前面和后面加上504B,后保存为zip
在这里插入图片描述
用stegpy得到zip密码:
在这里插入图片描述

五、分离与拼接

convert分离gif+montage拼接

攻防世界MISC进阶:glance-50,mma-ctf-2nd-2016

下载拿到一个gif图片,很窄(宽2px)。
(1)用kali的convert命令先把gif分解开:

convert glance.gif flag.png

补充:
水平镜像反转图片

convert -flop reverse.jpg reversed.jpg

垂直镜像反转图片

convert -flip reverse.jpg reversed.jpg

convert命令使用

总共分离出来200个图片。用工具:montage合成,命令:

montage flag*.png -tile x1 -geometry +0+0 flag.png

-tile是拼接时每行和每列的图片数,这里用x1,就是只一行
-geometry是首选每个图和边框尺寸,我们边框为0,图照原始尺寸即可
flag:TWCTF{Bliss by Charles O’Rear}

(2)也可以直接用网站。GIF动态图片是由多张静态图片组合而成,按照一定的顺序和时间进行播放。该网站将GIF图片反向分解成一张张静态图。GIF图片有多少帧,就有多少张静态图片。
GIF分解网站

(3)也可以写脚本

import os 
from PIL import Image

im = Image.new('RGB', (2*201,600))#new(mode,size) size is long and width
PATH = 'E:/ctf/glance.gif'

FILE_NAME = [i for i in os.listdir(PATH)]

width = 0
for i in FILE_NAME:
    im.paste(Image.open(PATH+i),(width,0,width+2,600))#box is 左,上,右,下
    width += 2
im.show()    

六、像素点合成

1、PPM格式+多种文件转换网站

攻防世界 Misc Miscellaneous-200 defkthon-ctf
miscellaneous
adj. 混杂的; 各种各样的;

(1)提供的flag.txt文件每行包含由三个逗号分隔的值组成的元组。这看起来像一个给定RGB值的图像。
在这里插入图片描述
总共有61366行:
在这里插入图片描述
注:Linux wc命令用于计算字数。
-l或–lines 显示行数。
-w或–words 只显示字数。
-c或–bytes或–chars 只显示Bytes数。
flag.txt文件的行数为61366、单词数61366、字节数730988

图像的尺寸是这个数字(61366)的等分,所以可能是:1,2,61,122,503,1006,30683,61366。
最可能的图像大小是 122×503px 或 503×112px 。

注:px是分辨率的单位,是英语单词pixel的缩写,意为像素(组成屏幕图像的最小独立元素)。

将文本文件转换为图像的最可以将其转换为PPM格式,其标题如下:

P3
122 503
255

注:PPM(Portable PixMap,便携式像素映射)。这些图片格式都相对比较容易处理,跟平台无关,所以称之为portable,简单理解,就是比较直接的图片格式,比如PPM,其实就是把每一个点的RGB分别保存起来。所以,PPM格式的文件是没有压缩的,相对比较大,但是由于图片格式简单,一般作为图片处理的中间文件(不会丢失文件信息),或者作为简单的图片格式保存。
PPM文件
PPM文件格式详解

然后是flag.txt的内容,逗号用空格替换。(快捷键ctrl+h 实现替换的功能)
在这里插入图片描述
TXT到PPM转换器
这个网站可以转换许多东西!
结果是flag.ppm。用极速看图软件打开(kali中可以直接打开):
在这里插入图片描述

转换为PNG,并翻转+旋转它,使它更容易阅读,结果如下图所示:

convert -flip -rotate 90 flag.ppm flag.png

在这里插入图片描述

(2)分析文本发现是道画图题,直接编写 python 程序

from ast import literal_eval as make_tuple
from PIL import Image
f = open('flag.txt', 'r')
corl = [make_tuple(line) for line in f.readlines()]
f.close()
img0 = Image.new('RGB', (270, 270), '#ffffff')
k=0
for i in range(246):
   for j in range(246):
      img0.putpixel ([i , j], corl[k])
      k=k+1
img0.save("result.png")

flag{ youc@n’tseeme }

七、流量类

1、wireshark提取数据流//tcpxtract

攻防世界misc进阶Cephalopod
用wireshark搜索flag字符串,可以看到
在这里插入图片描述
PNG头的16进制为89504E47,然后搜索该16进制,找到一条TCP报文,然后追踪TCP流。
可以看到这是一个图片数据流。尾为:文件尾:AE 42 60 82。保留原始数据。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后复制进去winhex只保留png头尾数据,然后修改文件后缀名为png,就可以得到flag图片
在这里插入图片描述

tcpxtract

也可以直接

tcpxtract -f 1.pcap

得到一张png图片 得到flag :HITB{95700d8aefdc1648b90a92f3a8460a2c}
Tcpxtract是用来从网卡抓包并将其还原成文件的一个开源软件,它的基本原理是在抓取的数据包中匹配文件的特征头和特征尾。

strings

strings webshell.pcapng | grep {

strings命令在对象文件或二进制文件中查找可打印的字符串。字符串是4个或更多可打印字符的任意序列,以换行符或空字符结束。 strings命令对识别随机对象文件很有用。 grep 命令用于查找文件里符合条件的字符串

strings xxx.png
有时可以出flag

2、协议分级+导出HTTP对象

攻防世界-互相伤害!!!
wireshark打开,协议分级,基本都是TCP流量,又以超文本传输协议为主,导出HTTP对象。

八、二维码类

1、bmp转二维码

攻防世界 Misc高手low
下来一个bmp文件,用stegsolve分析无果,但是通过观察发现是RGB的通道有问题,利用的是图片中最低位的奇偶性。
实验吧原题直接用画图另存为png格式,用StegSolve打开后,调到RGB红色位置。这里有所变化
转QR Code,即二维码(Quick Response Code)

# lsb隐写
import PIL.Image as Image
img = Image.open('low.bmp')
img_tmp = img.copy()
pix = img_tmp.load()
width,height = img_tmp.size
for w in range(width):
   for h in range(height):
      if pix[w,h]&1 == 0:
         pix[w,h] = 0
      else:
         pix[w,h] = 255
img_tmp.show()

在这里插入图片描述
用QR research解码得:
在这里插入图片描述

2、16进制转pyc

攻防世界 MISC 适合作为桌面(世安杯)

使用stegsolve发现在绿色的低位通道中有二维码
在这里插入图片描述
使用二维码扫描器扫描,并将16进制数字结果在winhex中打开
在这里插入图片描述
在这里插入图片描述
注:如果错选中间这个(ANSI-ASCII),则再ASCII码转二进制(快捷键Ctrl+R)
在这里插入图片描述
03F3开头,pyc文件。保存为.pyc然后反编译,在脚本后加上flag(),运行之后即可得到flag。

pyc在线转换

或者,使用“uncompyle6 文件路径\文件名.pyc > 文件路径\文件名.py”命令

D:\Python385\Lib\site-packages\uncompyle6\bin

pyc隐写Stegosaurus

在这里插入图片描述
Stegosaurus 是一款隐写工具,它允许我们在 Python 字节码文件( pyc 或 pyo )中嵌入任意 Payload 。由于编码密度较低,因此我们嵌入 Payload 的过程既不会改变源代码的运行行为,也不会改变源文件的文件大小。 Payload 代码会被分散嵌入到字节码之中,所以类似 strings 这样的代码工具无法查找到实际的 Payload 。 Python 的 dis 模块会返回源文件的字节码,然后我们就可以使用 Stegosaurus 来嵌入 Payload 了。
pyc文件存在无效空间,修改后大小不变,不影响运行,可以隐藏信息。
stegosaurus.py可以隐藏和解密pyc文件中隐藏的信息。
只能利用pyc文件中的无效空间(Python3.6后参数会占1字节,如果没有参数用0x00填充,运行时被忽
略,修改不影响),编码密度较低,嵌入 Payload 后不会改变源代码的正常运行和大小,不容易被发现。
同时 Payload 会被分散嵌入到字节码之中,类似 strings 这样的代码工具无法查找到实际的 Payload 。
通过github下载后(https://github.com/AngelKitty/stegosaurus)运行 python stegosaurus.py -h
在这里插入图片描述

可以发现有很多参数,-p 要隐藏的文本,-r 显示最大隐藏字节,-x可以解密。
stegosaurus解密
使用 python stegosaurus.py py_py_py.pyc -x 得到如下结果 Extracted payload: Flag{HiD3_Pal0ad_1n_Python} 。

Stegosaurus详解

3、二进制作二维码

攻防世界 Misc很普通的数独
下载发现是一堆数独图片,把有数字的记为1,没有数字的记为0,结果保存在txt文本中。也可以调节文件位置后用画图拼接,并将有数字的格涂黑。

# -*- coding:utf-8 -*-
from PIL import Image
x = 45
y = 45

im = Image.new("RGB", (x, y))  # 创建图片
file = open('1.txt', 'r')  # 打开rbg值文件
for i in range(0, x):
    line = file.readline()  # 获取一行
    for j in range(0, y):
        if line[j] == '0':
            im.putpixel((i, j), (255, 255, 255))  # rgb转化为像素
        else:
            im.putpixel((i, j), (0, 0, 0))  # rgb转化为像素
im.show()

扫描得到一串字符串,base64多次解码得到flag:flag{y0ud1any1s1}

4、4个值转二维码

2019西湖论剑网络安全技能大赛(大学生组)–奇怪的TTL字段
发现ttl.txt中的ttl只有4个值63,127,191,255,写出他们的二进制表示后发现只有最高两位不同(高两位比特的数在数据传输中不容易受影响),拿下来,每4个TTL值凑出一个字节的二进制数来
63=00111111
127=01111111
191=10111111
255=11111111
于是考虑做如下转换,发现写出来的16进制数开头是ffd8,应该是jpg,于是写入文件中:

fp = open('ttl.txt','r')
a = fp.readlines()
p = []
for i in a:
    p.append(int(i[4:]))
s = ''
for i in p:
    if i == 63:
        a = '00'
    elif i == 127:
        a = '01'
    elif i == 191:
        a = '10'
    elif i == 255:
        a = '11'
    s += a
# print(s)

import binascii
flag = ''
for i in range(0,len(s),8):
    flag += chr(int(s[i:i+8],2))
flag = binascii.unhexlify(flag)
wp = open('res.jpg','wb')
wp.write(flag)
wp.close()

写完之后发现只有二维码的一部分,应该是不止一张图,用foremost直接分开就好了,之后用PPT拼在一块,扫描之后得到如下信息:
key:AutomaticKey cipher:fftu{2028mb39927wn1f96o6e12z03j58002p}
是AutoKey加密,用在线网站解密得flag
autokey解密
自动密钥密码(Autokey Cipher)也是多表替换密码,与维吉尼亚密码密码类似,但使用不同的方法生成密钥。

  • 37
    点赞
  • 214
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值