第二屆BMZCTF公開賽-easymisc

2022-01-03 11:00:01


題目附件請自取:
連結:https://pan.baidu.com/s/1u8jiXfpD7HvoQTCe4fW80w 
提取碼:4whw

題目設計

  • 考察知識點:資料處理wav檔案頭高低振幅轉換LSB隱寫
  • 題目思路:逆序位元組流資料->wav檔案->高低振幅轉換->LSB隱寫->互斥或測試

以下是設計題目時所用到的指令碼

檔案轉換二進位制01資料

from binascii import *

with open('1.png', 'rb') as f:#需要轉換的檔案
	with open('bin.txt', 'w') as f1:
		hex_data = hexlify(f.read()).decode()
		for i in range(0, len(hex_data), 2):
			data = '{:08b}'.format(int(hex_data[i:i+2], 16))
			f1.write(data)

二進位制資料轉換wav高低振幅

import wave,struct,random

sampleRate = 44100.0
obj = wave.open('sound.wav','w')
obj.setnchannels(1)
obj.setsampwidth(2)
obj.setframerate(sampleRate)

with open('bin.txt', 'r') as f:
    bin_data = f.read()
    for i in bin_data:
        if i == '1':
            if random.randint(0,1) == 1:
                obj.writeframesraw(struct.pack('<h', random.randint(30000, 32000)))
            else:
                obj.writeframesraw(struct.pack('<h', random.randint(-32000, -30000)))
        elif i == '0':
            if random.randint(0,1) == 1:
                obj.writeframesraw(struct.pack('<h', random.randint(18000, 20000)))
            else:
                obj.writeframesraw(struct.pack('<h', random.randint(-20000, -18000)))
        else:
            break
obj.close()

逆序檔案位元組流

from binascii import *

with open('sound.wav', 'rb') as f:
	hex_data = hexlify(f.read()).decode()[::-1]
	with open('sound', 'wb') as f1:
		for i in range(0, len(hex_data), 2):
			data = hex_data[i:i+2][::-1]
			f1.write(unhexlify(data))

對檔案整體進行互斥或

from binascii import *

with open('qrcode.png', 'rb') as f:
	all_data = f.read()
	with open('data', 'wb') as f1:
		for i in range(len(all_data)):
			f.seek(i)
			data = int(hexlify(f.read(1)), 16)
			xor_data = '{:02x}'.format(data ^ 0x7f)
			f1.write(unhexlify(xor_data))

解題步驟(Writeup)

what檔案開頭並不是什麼型別的檔案頭
在這裡插入圖片描述
檔案尾發現端倪,RIFF、 WAVE、fmt等字樣,很明顯這是wav檔案的檔案頭
在這裡插入圖片描述
使用Python簡單處理、反轉位元組流資料等到正確的wav檔案

from binascii import *

with open('what', 'rb') as f:
	hex_data = hexlify(f.read()).decode()[::-1]
	with open('data.wav', 'wb') as f1:
		for i in range(0, len(hex_data), 2):
			data = hex_data[i:i+2][::-1]
			f1.write(unhexlify(data))

得到的wav檔案使用Audacity分析
在這裡插入圖片描述
在這裡插入圖片描述
通過分析不難發現,每一幀高低頻區別明顯,高頻在一定的範圍內,低頻也在一定的範圍內

首先來簡單分析下振幅的規律

import wave

obj = wave.open('data.wav', 'r')
frames = obj.getnframes()
print("All Frames: {}".format(frames))
frames_data = obj.readframes(20).hex()#提取出前20幀的資料
for i in range(0, len(frames_data), 4):
	data = frames_data[i:i+4]
	real_data = int(data[2:] + data[:2], 16)
	data1 = data[2:] + data[:2]
	print("第{:<2}幀: {} => {}  真實資料值: {}".format(int((i+4)/4), data,data1 , real_data))

提取出來的每一幀的資料大小為兩位元組,且儲存方式為小端儲存,所以需要高位元組位和低位元組位換一下,然後轉換成數值
在這裡插入圖片描述
先分析正振幅的資料值,通過多次嘗試分析,基本就可以確認高振幅範圍為:30000-32000,低振幅範圍為:18000-20000

PS:分析高低振幅取值範圍可以提升提取出來的幀數來進行更精確的判斷

而負振幅資料無論高振幅還是低振幅,為什麼都看起來都不在這個範圍之內呢,明明從Audacity中觀察到的波形的高低範圍和正振幅範圍都應該是一樣的,而得到的數值確大相徑庭呢?

我們知道如果是帶符號的2位元組整型的取值範圍是:[-2^(15)] ~ [2^(15)-1]也就是-32768至32767之間

那麼就能解釋負振幅資料的問題了,很明顯發生了溢位;需要對數值進行一個轉換處理即可得到在範圍內的正常的資料

>>> import math
>>> math.pow(2,15)-(45650-math.pow(2,15))
19886.0#第二幀
>>> math.pow(2,15)-(47417-math.pow(2,15))
18119.0#第三幀
>>> math.pow(2,15)-(33915-math.pow(2,15))
31621.0#第五幀
>>> math.pow(2,15)-(35258-math.pow(2,15))
30278.0#第十二幀

OK,這樣就解決了負振幅資料轉換的問題
接下來就直接使用Python簡單處理,將高低振幅轉換成二進位制資料即可;然後將得到的二進位制資料寫成位元組流轉成檔案

import wave, math, struct
from binascii import *

obj = wave.open('data.wav', 'r')
frames = obj.getnframes()
frames_data = obj.readframes(frames).hex()

bin_data = ''
for idx in range(0, len(frames_data), 4):
	data = frames_data[idx:idx+4]
	data = data[2:] + data[:2]
	if int(data, 16) <= 20000:
		bin_data += '0'
	elif int(data, 16) > 20000 and int(data, 16) <= 32000:
		bin_data += '1'
	elif int(data, 16) > math.pow(2, 15):
		overflow_data = math.pow(2, 15) - (int(data, 16) - math.pow(2, 15))
		if overflow_data > 20000 and overflow_data <= 32000:
			bin_data += '1'
		elif overflow_data <= 20000:
			bin_data += '0'

hex_data = ''
for idx in range(0, len(bin_data), 8):
	hex_data += '{:02x}'.format(int(bin_data[idx:idx+8], 2))

with open('data', 'wb') as f1:
	f1.write(unhexlify(hex_data))

在這裡插入圖片描述
得到一張PNG圖片,從binwalk分析來看,檔案尾附加了內容
在這裡插入圖片描述
在這裡插入圖片描述
附加內容直接看不出來什麼,嘗試對圖片分析,發現存在無密碼的LSB隱寫
在這裡插入圖片描述

hint: xor [00-ff] which one?

提示互斥或一個範圍內的一個值,即可猜測附加的資料是經過互斥或的;可以嘗試提取開頭的幾個位元組進行互斥或看看結果是否為常見檔案型別的檔案頭;Python簡單處理即可

head_bytes = 'F6 2F 31 38'
for n in range(0xff):
	hex_data = head_bytes.split(" ")
	xor_data = ''
	for data in hex_data:
		data = int(data, 16) ^ n
		xor_data += ' {:02x}'.format(data)
	print("XOR {:02x}: {}".format(n, xor_data))

從結果中可以發現出現了PNG檔案頭
在這裡插入圖片描述
將附加資料提取出來,使用010 Editor開啟工具->十六進位制運算->二進位制互斥或
在這裡插入圖片描述
在這裡插入圖片描述
得到一張二維條碼,掃描即可得到flag
在這裡插入圖片描述

BMZCTF{755f3d5c-4817-4610-a377-68743f09e60a}