不存在的圖片

不存在的CTF發表於2024-06-03

這是一篇關於misc圖片方面的部落格,可以用作入門misc方向食用。

正文

流程

檢視圖片特徵 --> 檢視圖片表面資訊 --> 利用010檢視二進位制資訊 --> 利用format檢測 --> 利用Stegdetect檢測 --> 解密

圖片16進位制檔案倒置指令碼

整體字元反向輸出

with open("n.png","rb") as f:
    t = f.read()
    for i in t[::-1]:
        a = hex(i)[2:]
        if len(a) == 1:
            a = '0' + a
        print(a,end="")

整體16進位制前後倒置

Stegdetect

jpg圖片隱寫的大殺器,用於檢測jpg圖片的各種隱寫。

下載

以JphideLSB隱寫為例

.\stegdetect.exe -tjopi -s 10.0 檔案路徑

如同可檢測出jphide隱寫。

zsteg

檢測png圖片的隱藏資訊。

查詢圖片詳細資訊

exiftool

檔案結構

在開始圖片學習之前要先了解一些檔案的檔案結構。

檢視檔案16進位制形式需要用到檢視器,如010Editor。

檔案頭

檔案頭是指檔案十六進位制形式下的開頭四個十六進位制碼。

即圖中區域。

還需要了解一些常見的檔案頭。

每個檔案型別都有自己的檔案結構,具體問題具體分析。

附加字串

可以看到在最後新增字串時,圖片並不會受到影響。

在讀取時只需要用到010Editor或其他圖片十六進位制檢視器檢視即可。

檔案載體

隱藏

使用copy指令可以將壓縮包或文字或PDF等等新增到圖片尾部。

可見兩圖片沒有區別,用010Editor開啟。

可以看到flagpk.png的最後存在隱藏的zip壓縮檔案。

提取

這裡用到kali虛擬機器。

1,binwalk分離

binwalk --run-as=root 檔案路徑  -e 

2,foremost分離

foremost 檔案路徑  -T  

寬高修改(檔案結構)

在010中按ALT+4可以喚起模板,找到寬高可以修改。

當我們修改值的時候圖片會發生一點的變化。

舉個例子

假如有一個圖片

看著正常,但是一旦把寬度放大。

就會有隱藏的flag。

圖片修復

對於題目中的一些損壞圖片,可能得自己來修復。

有一個flag-是損壞的檔案,用010開啟。

透過結構的判斷,我們發現這是張png圖片。

但是缺少了檔案頭。

查閱發現png的檔案為89 50 4E 47

新增上檔案頭。

檔案-->新建-->新建十六進位制檔案-->先填入檔案頭,再將其餘部分複製過來。

儲存,並新增png字尾即可。

LSB隱寫(基於PNG圖片)

LSB隱寫(最低有效位隱寫)

看操作

現在有一個LSB隱寫的圖片。

開啟Stegsolve-->File-->Open,開啟LSB隱寫的圖片。
Analyse-->Data Extract

Bit Planes一般會將Red,Green,Blue都選為0。

Order settings裡的選項一般是慢慢的試出來的。

點選Preview即可檢視隱寫內容。

特殊一點的

LSB cloacked-pixel工具隱寫

python2 lsb.py extract 圖片 out.txt 密碼

Jphide

用到Jphswin工具

用工具開啟一個jpg檔案

點選Hide可以隱藏資料,設定密碼為123456,點選Save jpeg即可儲存

點選Seek可以提取隱藏資料,同上輸入密碼即可。

或者在kali中使用

steghide extract -sf '/root/桌面/lianjie/4.jpg' -p 123456

outguess隱寫

用到工具outguess。

在kali中使用。

加密:
outguess -k 密碼 -d 密文 demo.jpg out.jpg
加密之後,demo.jpg會覆蓋out.jpg,hidden.txt的內容是要隱藏的東西。

解密:
outguess -k 密碼 -r 圖片路徑 密文路徑

F5隱寫

加密涉及不到,直接解密

java Extract 檔案路徑
java Extract 檔案路徑   -p 密碼

輸出在output.txt裡。

畫素隱寫

在畫素中可能有隱寫資訊。

提示:把圖片縮小10倍

大機率為畫素隱寫

from PIL import Image

img = Image.open('arcaea.png')
w = img.width
h = img.height
img_obj = Image.new("RGB",(w//10,h//10))

for x in range(w//10):
    for y in range(h//10):
        (r,g,b)=img.getpixel((x*10,y*10))
        img_obj.putpixel((x,y),(r,g,b))

img_obj.save('ok.png')

oursercet

適用於任何檔案的加密,有Key

該隱寫會在檔案為新增資料,導致檔案在放入010時報錯。

特徵

雙圖片隱寫(盲水印雙圖片)

用到BlindWaterMark-master工具

python2 bmp.py decode 1png 2.png 生成.png

kali中使用。

盲水印單圖片

用到WaterMark工具

二維碼分析

二維碼的拼接與修復

不同種類的二維碼用到的解碼器不同,找到對應的二維碼後再找解碼器解碼即可。

條碼/二維碼有多少種(各行業條碼應用情況) - 知乎 (zhihu.com)

二維碼的繪製

0x00000000
0xff71fefe
0x83480082
0xbb4140ba
0xbb6848ba
0xbb4a80ba
0x83213082
0xff5556fe
0xff5556fe
0x00582e00
0x576fb9be
0x707ef09e
0xe74b41d6
0xa82c0f16
0x27a15690
0x8c643628
0xbfcbf976
0x4cd959aa
0x2f43d73a
0x5462300a
0x57290106
0xb02ace5a
0xef53f7fc
0xef53f7fc
0x00402e36
0xff01b6a8
0x83657e3a
0xbb3b27fa
0xbb5eaeac
0xbb1017a0
0x8362672c
0xff02a650
0x00000000

將16進位制轉為2進位制

t = open("D://瀏覽器下載//新建 文字文件.txt","r")
tt = t.readlines()
for num in tt:
    a = bin(eval(num))
    a = a.replace("0b","")
    if len(a) < 32:
        a = "0"*(32 - len(a)) + a
    print(a)
    with open("D://瀏覽器下載//新建2.txt", "a+", encoding="utf-8") as file:
        file.write(a + "\n")
00000000000000000000000000000000
11111111011100011111111011111110
10000011010010000000000010000010
10111011010000010100000010111010
10111011011010000100100010111010
10111011010010101000000010111010
10000011001000010011000010000010
11111111010101010101011011111110
11111111010101010101011011111110
00000000010110000010111000000000
01010111011011111011100110111110
01110000011111101111000010011110
11100111010010110100000111010110
10101000001011000000111100010110
00100111101000010101011010010000
10001100011001000011011000101000
10111111110010111111100101110110
01001100110110010101100110101010
00101111010000111101011100111010
01010100011000100011000000001010
01010111001010010000000100000110
10110000001010101100111001011010
11101111010100111111011111111100
11101111010100111111011111111100
00000000010000000010111000110110
11111111000000011011011010101000
10000011011001010111111000111010
10111011001110110010011111111010
10111011010111101010111010101100
10111011000100000001011110100000
10000011011000100110011100101100
11111111000000101010011001010000
00000000000000000000000000000000

將一設為點,零為空,畫圖。

from PIL import Image
import numpy as np


def hex2bin(hexmat):
    binmattemp = [bin(m)[2:] for m in hexmat]  # 全轉成二進位制
    rowlen = max([len(m) for m in binmattemp])  # 取最寬的值
    binmat = [[0] + [int(b) for b in row.zfill(rowlen)] for row in binmattemp]  # 用0補齊

    print rowlen + 1, 'x', len(binmat)
    for i in xrange(len(binmat)):
        print ''.join([str(b) for b in binmat[i]])

    return binmat, rowlen + 1, len(binmat)


def rm_col(binmat, col):  # 移除指定的列
    return [row[:col] + row[col + 1:] for row in binmat]


def make_bw_img(binmat, w, h, outfilename, blackbit=0):
    bwmat = [[0 if b == blackbit else 255 for b in row] for row in binmat]  # 用255表示白,0表示黑

    imagesize = (w, h)
    img = Image.fromarray(np.uint8(np.array(bwmat)))
    img.save(outfilename)


if __name__ == '__main__':
    hexmat = [0x00000000,
              0xff71fefe,
              0x83480082,
              0xbb4140ba,
              0xbb6848ba,
              0xbb4a80ba,
              0x83213082,
              0xff5556fe,
              0x00582e00,
              0x576fb9be,
              0x707ef09e,
              0xe74b41d6,
              0xa82c0f16,
              0x27a15690,
              0x8c643628,
              0xbfcbf976,
              0x4cd959aa,
              0x2f43d73a,
              0x5462300a,
              0x57290106,
              0xb02ace5a,
              0xef53f7fc,
              0x00402e36,
              0xff01b6a8,
              0x83657e3a,
              0xbb3b27fa,
              0xbb5eaeac,
              0xbb1017a0,
              0x8362672c,
              0xff02a650,
              0x00000000]

    binmat, w, h = hex2bin(hexmat)
    binmat = rm_col(binmat, 22)  # 發現第七行和第22行多餘,故刪除
    binmat = rm_col(binmat, 7)
    make_bw_img(binmat, w, h, 'matrix_rmcol.png', blackbit=1)

可得

QRcode二維碼

QRcode二維碼用一個特性,

如圖黑色都是固定不變的

如圖是損壞的二維碼

在正常的二維碼中,我畫出的這一列和這一行是一黑一白交替的畫素。如下圖

例一 [XYCTF] 我的二維碼為什麼掃不出來

看到一個損壞的二維碼和py指令碼

from PIL import Image
import random


def reverse_color(x):
    return 0 if x == 255 else 255


def reverse_row_colors(pixels, row, width, block_size=10):
    for x_block in range(width // block_size):
        x = x_block * block_size
        y = row * block_size
        for x_small in range(x, x + block_size):
            for y_small in range(y, y + block_size):
                pixel = pixels[x_small, y_small]
                pixels[x_small, y_small] = reverse_color(pixel)


def reverse_col_colors(pixels, col, height, block_size=10):
    for y_block in range(height // block_size):
        x = col * block_size
        y = y_block * block_size
        for x_small in range(x, x + block_size):
            for y_small in range(y, y + block_size):
                pixel = pixels[x_small, y_small]
                pixels[x_small, y_small] = reverse_color(pixel)


original_img = Image.open("flag.png")

new_img = original_img.copy()

width, height = new_img.size
pixels = new_img.load()

count = 0

while count < 7:
    x = random.randint(0, 1)
    if x == 0:
        reverse_col_colors(pixels, random.randint(0, height // 10 - 1), height)
    else:
        reverse_row_colors(pixels, random.randint(0, width // 10 - 1), width)
    count += 1

new_img.save("new.png")

分析指令碼

reverse_row_colors()函式是把一行顏色反轉。

reverse_col_colors()函式是把一列顏色反轉。

while count < 7:
 x = random.randint(0, 1)
 if x == 0:
     reverse_col_colors(pixels, random.randint(0, height // 10 - 1), height)
 else:
     reverse_row_colors(pixels, random.randint(0, width // 10 - 1), width)
 count += 1

這一段就是隨機把一行或者一列顏色反轉。

那麼咱們就只能手工修復了。

reverse_row_colors(pixels, 1, width)  #行
reverse_col_colors(pixels, 0, height)  #列
reverse_col_colors(pixels, 2, height)
reverse_col_colors(pixels, 5, height)

先用以上段調出四個角

這是調了4次,還有3次要調。

由上面的QRcoed的特性來調。

reverse_row_colors(pixels, 12, width)
reverse_col_colors(pixels, 10, height)
reverse_col_colors(pixels, 11, height)

最後得出二維碼

from PIL import Image
import random


def reverse_color(x):
    return 0 if x == 255 else 255


def reverse_row_colors(pixels, row, width, block_size=10):
    for x_block in range(width // block_size):
        x = x_block * block_size
        y = row * block_size
        for x_small in range(x, x + block_size):
            for y_small in range(y, y + block_size):
                pixel = pixels[x_small, y_small]
                pixels[x_small, y_small] = reverse_color(pixel)


def reverse_col_colors(pixels, col, height, block_size=10):
    for y_block in range(height // block_size):
        x = col * block_size
        y = y_block * block_size
        for x_small in range(x, x + block_size):
            for y_small in range(y, y + block_size):
                pixel = pixels[x_small, y_small]
                pixels[x_small, y_small] = reverse_color(pixel)


original_img = Image.open("new.png")

new_img = original_img.copy()

width, height = new_img.size
print(width,height)
pixels = new_img.load()


reverse_row_colors(pixels, 1, width)  #行
reverse_col_colors(pixels, 0, height)  #列
reverse_col_colors(pixels, 2, height)
reverse_col_colors(pixels, 5, height)

reverse_row_colors(pixels, 12, width)
reverse_col_colors(pixels, 10, height)
reverse_col_colors(pixels, 11, height)


new_img.show()

GIF動圖的分析

可以用Stegsolve工具來逐幀分析

開啟jsp.gif檔案
Analyse-->Frame Browser

即可得出。

Logistic混沌變換加密

圖片的混沌加密是先把所有畫素點平坦化了,按照一位陣列處理的,然後再重組為圖片
import cv2
import numpy as np
from PIL import Image

def logistic(Img, x, u,times):
    M = Img.shape[0]
    N = Img.shape[1]
    for i in range(1, times):
        x = u * x * (1 - x)
    array = np.zeros(M * N)
    array[1] = x
    for i in range(1, M * N - 1):
        array[i + 1] = u * array[i] * (1 - array[i])
    array = np.array(array * 255, dtype='uint8')
    code = np.reshape(array, (M, N))
    xor = Img ^ code
    v = xor
    return v

x = 密碼1
u = 密碼2
times = 密碼3

Img = cv2.imread('圖片路徑')
Img = Img[:, :, [2, 1, 0]]
(r, g, b) = cv2.split(Img)
R = logistic(r, x, u, times)
G = logistic(g, x, u, times)
B = logistic(b, x, u, times)
merged = np.ones(Img.shape, dtype=np.uint8)
merged[:, :, 2] = B
merged[:, :, 1] = G
merged[:, :, 0] = R

Img = Image.fromarray(merged)
Img.save('flag.png')

webp圖片隱寫

stegpy隱寫

在kali中使用

stegpy 檔案

轉為其他檔案

stego檔案頭

stego檔案頭的圖片可以在linux中顯示為圖片。

通道低位隱寫

當圖片的位深度大於24位時,就有可能存在通道低位隱寫

如下圖片屬性,這裡注意到是48位的圖片位深度

48位的圖片,平均RBG位16,人眼是看不到低於8bit位的畫素資訊的。

# 提取低位
import cv2
import numpy as np

img = cv2.imread("turing.png", cv2.IMREAD_UNCHANGED) 

img2 = img & 0xFF   
img2 = img2.astype(np.uint8)

cv2.imwrite("turing1.png", img2)

humbnail隱寫(縮圖隱寫)

這裡是縮圖隱寫的方式,叫做thumbnail隱寫

用Magic開啟即可看到

ctfshow{dbf7d3f84b0125e833dfd3c80820a129}

未經作者允許,請勿轉載!!!

相關文章