MRCTF My secret

Scr1ptgogogo發表於2021-04-13

My secret

知識點:wireshark基本操作,shadowsocks3.0原始碼利用,拼圖(os指令碼編寫能力),

根據這裡的資訊可以知道,tcp所傳輸的源資料是在target address後面的資料。那麼我們現在去尋找target address(即wireshark中的Destination)

那麼我們已經找到了,即第一張圖中的2f 5e ca a8。我們取走後面的資料儲存為檔案。

通過匯出位元組流檔案可以得到一下兩個檔案

image-20210411143949761

image-20210411143956429

通過010拿走16進位制編碼數然後進行解密。

D1 DF BC 46 8E 33 B2 AE A4 E7 D7 4F 35 B2 0D 0A
CE EC 19 F7 2B FC B7 64 1B E8 55 12 5C 53 F1 08
C7 B9 FD EE B1 16 B5 79 C2 EE 6F F6 3D 74 8D 54
D6 4D DC 6B A2 50 C7 0C 32 5F 8E 38 9D 78 73 AA
88 1E 40 2C BF 32 54 E8 6C 6C 33 E2 B7 8E CA 89
9F 51 BB 36 87 8F AF CF EA 75 3A 10 CE 0D A7 C7
9F F7 84 91 AF 1D 53 81 87 97 33 5E 2D 7C DF

那麼我的思路在這裡就停滯了。經過師傅的提醒和幫助下,我下載了shadowsocks3.0版本的原始碼(python版),然後很容易找到一個顯眼的cryptor.py檔案。(這裡有一個誤區,如果你下載到的原始碼中沒有題目所示的aes-256-gcm加密方法,後續是無法進行解密的。因此需要下載到相應的版本的shadowsocks3.0)

image-20210413110105234

我們仔細看一下這個加密的演算法。

加密演算法如下。當設定了iv_sent時進行iv的設定,false時不設定iv

image-20210412095531516

然後發現這裡是自帶decrypt函式的。那麼資料包解密就簡單多了。

image-20210413111255061

這個函式對資料進行了iv的判斷和提取。我們只需要傳入完整的資料包進行解密就可以了。

image-20210413112056668

with open('tcp.txt','rb') as f:
    encrypted_data = f.read()

c = Cryptor('db6c73af3d8585c', 'aes-256-gcm')

data = (c.decrypt(encrypted_data))
with open('tcp2.txt', 'wb') as f:
    f.write(data)

對資料進行解密,然後就可以在tcp2.txt中看到我們想要看到的資料包了!

那麼資料該提取哪一部分呢?紅色部分或者藍色部分。也就是請求部分和響應部分。

image-20210413113504280

image-20210413112147590

拿到壓縮包後就是一個2500個圖片的拼圖題。hint為gps。

我們在exiftool中可以找到圖片的gps值。編寫指令碼進行提取並修改名字。(我寫的指令碼)

import os
import re

path = r"/root/Desktop/jigsaw on earch"  # 資料夾目錄
files = os.listdir(path)  # 得到資料夾下的所有檔名稱

for file in files:  # 遍歷資料夾
	cmd=r"exiftool {0} | grep GPS\ Position".format(re.escape(file))
	#print(cmd)
	#print(file)
	gpsTemp = os.popen(cmd).read()

	for i in range(len(gpsTemp)):
		if gpsTemp[i]==':':
			num1 = int(gpsTemp[i+2:i+4].strip())
		if gpsTemp[i] == ',':
			num2 = int(gpsTemp[i+2:i+4].strip())
	fileName = num1*50+num2
	cmdNext = "mv {0} {1}\.png".format(re.escape(file),fileName)
	#print(cmdNext)
	os.system(cmdNext)
	#print(num1*50+num2)
	#print(gpsTemp)

後面拼圖指令碼不會寫了。

師傅放了wp出來。看了一下,真複雜。看不懂。先進行rename

import os
import piexif
from PIL import Image

file = os.listdir('jigsaw')

def calc_file(x, y):
    num = str(y * 50 + x).zfill(4)
    return f'jigsaw/{num}.png'

for i in file:
    img = Image.open(f'jigsaw/{i}')
    exif_dict = piexif.load(img.info['exif'])
    img.close()
    latitude = exif_dict['GPS'][piexif.GPSIFD.GPSLatitude]
    longtitude = exif_dict['GPS'][piexif.GPSIFD.GPSLongitude]
    y = latitude[0][0]
    x = longtitude[0][0]
    file = calc_file(x, y)
    os.rename(f'jigsaw/{i}', file)

然後利用拼圖指令碼進行拼圖

from PIL import Image
from tqdm import tqdm

x_sum = 50
y_sum = 50
ori_width = 60
ori_height = 60
jigsaw_width = 20

width = ori_width + jigsaw_width * 2
height = ori_height + jigsaw_width * 2

def calc_file(x, y):
    num = str(y * x_sum + x).zfill(4)
    return f'jigsaw/{num}.png'

def check_info(file):
    img_info = [0, 0, 0, 0]
    img = Image.open(file)
    pix_out1 = img.getpixel((width // 2, 0))[3]
    pix_out2 = img.getpixel((width - 1, height // 2))[3]
    pix_out3 = img.getpixel((width // 2, height - 1))[3]
    pix_out4 = img.getpixel((0, height // 2))[3]
    pix_out = [pix_out1, pix_out2, pix_out3, pix_out4]
    pix_in1 = img.getpixel((width // 2, jigsaw_width))[3]
    pix_in2 = img.getpixel((width - jigsaw_width - 1, height // 2))[3]
    pix_in3 = img.getpixel((width // 2, height - jigsaw_width - 1))[3]
    pix_in4 = img.getpixel((jigsaw_width, height // 2))[3]
    pix_in = [pix_in1, pix_in2, pix_in3, pix_in4]
    for i in range(4):
        if pix_out[i] == 0 and pix_in[i] == 0:
            img_info[i] = -1
        elif pix_out[i] != 0 and pix_in[i] != 0:
            img_info[i] = 1
        elif pix_out[i] == 0 and pix_in[i] != 0:
            img_info[i] = 0
        else:
            raise Exception("Invalid jigsaw!", file)
    return img_info

def init_table():
    info_table = []
    for y in range(y_sum):
        row_info = []
        for x in range(x_sum):
            file = calc_file(x, y)
            img_info = check_info(file)
            row_info.append(img_info)
        info_table.append(row_info)
    return info_table

def cut(direction, file):
    if direction == 0:
        left_top_x = (ori_width - jigsaw_width) // 2 + jigsaw_width
        left_top_y = 0
    elif direction == 1:
        left_top_x = ori_width + jigsaw_width
        left_top_y = (ori_height - jigsaw_width) // 2 + jigsaw_width
    elif direction == 2:
        left_top_x = (ori_width - jigsaw_width) // 2 + jigsaw_width
        left_top_y = ori_height + jigsaw_width
    elif direction == 3:
        left_top_x = 0
        left_top_y = (ori_height - jigsaw_width) // 2 + jigsaw_width

    right_bottom_x = left_top_x + jigsaw_width
    right_bottom_y = left_top_y + jigsaw_width
    img = Image.open(file)
    cut_img = img.crop((left_top_x, left_top_y, right_bottom_x, right_bottom_y))
    blank_img = Image.new('RGBA', (jigsaw_width, jigsaw_width), (0, 0, 0, 0))
    img.paste(blank_img, (left_top_x, left_top_y))
    img.save(file)
    return cut_img

def paste(direction, file, cut_img):
    if direction == 0:
        left_top_x = (ori_width - jigsaw_width) // 2 + jigsaw_width
        left_top_y = jigsaw_width
    elif direction == 1:
        left_top_x = ori_width
        left_top_y = (ori_height - jigsaw_width) // 2 + jigsaw_width
    elif direction == 2:
        left_top_x = (ori_width - jigsaw_width) // 2 + jigsaw_width
        left_top_y = ori_height
    elif direction == 3:
        left_top_x = jigsaw_width
        left_top_y = (ori_height - jigsaw_width) // 2 + jigsaw_width

    img = Image.open(file)
    img.paste(cut_img, (left_top_x, left_top_y))
    img.save(file)

def recover_jigsaw(info_table):
    for y in tqdm(range(y_sum)):
        for x in range(x_sum):
            img_info = info_table[y][x]
            for direction in range(4):
                if img_info[direction] != 'free':
                    file = calc_file(x, y)

                    if direction == 0:
                        x2 = x
                        y2 = y - 1
                        file2 = calc_file(x2, y2)
                        direction2 = 2
                    elif direction == 1:
                        x2 = x + 1
                        y2 = y
                        file2 = calc_file(x2, y2)
                        direction2 = 3
                    elif direction == 2:
                        x2 = x
                        y2 = y + 1
                        file2 = calc_file(x2, y2)
                        direction2 = 0
                    elif direction == 3:
                        x2 = x - 1
                        y2 = y
                        file2 = calc_file(x2, y2)
                        direction2 = 1

                    if img_info[direction] == 1:
                        cut_img = cut(direction, file)
                        paste(direction2, file2, cut_img)
                    elif img_info[direction] == -1:
                        cut_img = cut(direction2, file2)
                        paste(direction, file, cut_img)
                    info_table[y2][x2][direction2] = 'free'
                    img_info[direction] = 'free'

def remove_border(file):
    img = Image.open(file)
    new_img = img.crop((jigsaw_width, jigsaw_width, width - jigsaw_width, height - jigsaw_width))
    new_img.save(file)

if __name__ == '__main__':
    info_table = init_table()
    recover_jigsaw(info_table)
    for i in range(x_sum * y_sum):
        file = 'jigsaw/' + str(i).zfill(4) + '.png'
        remove_border(file)

out

掃描後得到flag

MRCTF{795c666e-6244-4768-981d-3b******2c}