MRCTF My secret

  • 2021 年 4 月 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}