VNCTF2021 MISC wp

冰冰好像藏着秘密

[toc]

image-20210505132345706

这题好像被非预期嘞,出题人本来是想出rar伪加密+傅里叶盲水印的,但变成了foremost+WaterMarkH就能出,呜呜。

直接用winhex打开,能看到png文件头

image-20210505132410192

结尾有png文件尾

image-20210505132423959

这部分数据保存下来即可得到png文件。

解rar伪加密:

image-20210505132434839

第17位置的数据84,改成80即可解开伪加密。rar在伪加密状态下会显示压缩包已损坏或压缩格式未知,所以判断rar伪加密的方法并不难。

image-20210505132445088

解压即可得到图片。

之后根据压缩包的名字FFT,可知是傅里叶。利用傅里叶盲水印即可跑出flag。

脚本如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread('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()

解得:
image-20210505132500355

利用WaterMarkH也能出

image-20210505132515588

得到flag:

VNCTF{Ff5_1S_bEauTiful}

Do_you_like_Rhythm_Doctor

音游题,节奏医生。可惜steam上好贵,我也找不到破解版,没法钞能力做题惹

只能审关卡代码看看哪里比较特殊。(不过其实有这款游戏也只是可以帮助理解)

主要关卡数据如下:

image-20210505132531894

根据经验和英文单词的意思,顺便看看游戏视频,猜测bar为按顺序的1-16,大概是类似进度的数据,beat为节拍,row为轨道。y和row的数据90%都是一样的,但也有部分是有区别的,具体不知道会是什么。

pluseType是脉冲类型,这是关键,只有两种Wave和Square两种情况,很容易想到0或1,而其他的又看不出有什么含义,于是尝试下按顺序读取pulseType信息,脚本如下:

data = open('main.rdlevel', 'r', encoding='UTF-8')
true = 1  #用于对true赋值,保证程序正常运行。因为字符串中存在ture,使用eval时会把ture当做变量。
flag = ''
while 1:
    s = data.readline()
    if not s:
        break
    s = s.strip('\n')
    if not "pulseType" in s:
        continue
    dic1 = eval(s[:-1]) #将每行数据转化为字典,由于每行最后均有逗号,故为s[:-1]
    if dic1['pulseType'] == 'Square':
        flag += '0'
    else:
        flag += '1'
print(flag)
#011001100101011101101101010011100110110000110010111001001101111101100000011100010011101110100011011001010101100010111001111001000000101101110001001111101111001100001111111111111111111100001111

这并不能得到正确答案,但是能正好得到24个字符,且开头为f,方向可能是对的。
根据关卡代码得此关共有0 1 2 3四个轨道,尝试按照轨道顺序读取数据,

最终脚本如下:

from Crypto.Util.number import *
data = open('main.rdlevel', 'r', encoding='UTF-8')
true = 1 #用于对true赋值,保证程序正常运行。因为字符串中存在ture,使用eval时会把ture当做变量。
flag = ''
row = {0:"", 1:"", 2:"", 3:""}
while 1:
    s = data.readline()
    if not s:
        break
    s = s.strip('\n')
    if not "pulseType" in s:
        continue
    dic1 = eval(s[:-1]) #将每行数据转化为字典,由于每行最后均有逗号,故为s[:-1]
    if dic1['pulseType'] == 'Square':
        row[dic1['row']] = row[dic1['row']] + '0'
    else:
        row[dic1['row']] = row[dic1['row']] + '1'
print(row)
flag = int(row[0] + row[1] + row[2] + row[3], 2)
print(long_to_bytes(flag))
#{0: '011001100110110001100001011001110111101101111101', 1: '010101110011001100110001011000110110111101111101', 2: '011011010110010101011111010101100010011001111101', 3: '010011100101111101000011010101000100011001111101'}
#b'flag{}W31co}me_V&}N_CTF}'

由于每个轨道的最后八位都是'01111101',asc转码后为字符'}'。
故将前三个轨道的'}'去掉,得到最终flag:

flag{W31come_V&N_CTF}

interesting_fishing

image-20210505132553245

压缩包内有一个邮件文件,注释.txt即为题目描述

image-20210505132603988

邮件文件内有一串很长的base64编码,解码得到一个rar文件:

image-20210505132614426

在\myproject\giveyourflag\giveyourflag\x64\Debug目录下有一个特殊的db文件

image-20210505132625691

文件内有一串base64编码,解密后得:

image-20210505132637303

根据base64解码后的\u-65432,\u-65420可知是被混淆过了

image-20210505132648262

根据上述解混淆示例,将数据表示为 [65432, 65420, 65420……]的格式,

脚本如下:

list1 = [65432,65420,65420,65424,65421,65478,65489,65489,65418,65426,65437,65420,65434,65491,65486,65487,65485,65491,65487,65486,65483,65481,65488,65482,65487,65487,65486,65485,65490,65437,65425,65421,65490,65439,65424,65491,65426,65439,65426,65430,65431,65426,65433,65490,65427,65415,65423,65437,65428,65425,65419,65436,65490,65437,65425,65427,65489,65456,65415,65425,65426,65433,65415,65439,65426,65433,65499,65486,65488,65421,65420,65425,65422,65435,65421,65499,65486,65488,65428,65425,65417,65499,65486,65488,65425,65426,65499,65486,65488,65434,65425,65422,65435,65431,65433,65426,65499,65486,65488,65433,65425,65425,65436,65421,65499,65486,65488,65439,65427,65431,65436,65499,65486,65488,65458,65425,65422,65420,65432,65499,65486,65488,65461,65425,65422,65435,65439,65426,65499,65486,65488,65469,65457,65450,65463,65468,65491,65487,65479,65499,65486,65488,65424,65439,65422,65439,65426,65425,65431,65439,65490,65422,65439,65422]
flag = ""
for i in list1:
    flag += chr(0xffff - int(i) + 1)
print(flag)

解得:

https://vnctf-213-1257061123.cos.ap-nanjing.myqcloud.com/Pyongyang%20stores%20low%20on%20foreign%20goods%20amid%20North%20Korean%20COVID-19%20paranoia.rar

下载得到一个加密的压缩包,有hint:压缩包是四位数字

image-20210505132658656

利用hashcat爆破

先利用rar2john获取hash值

image-20210505132709236

然后利用hashcat爆破:

.\hashcat.exe -m 13000 -a 3 '$rar5$16$1349cb834c70bf27bb4e48bb3fbe6975$15$ca4a3bc58278b04d9fba4d7d52acb196$8$56245cd11e4a1c2e' ?d?d?d?d --show

得到密码:9705
打开压缩包得到一个word文件,后缀改为zip,有一个hideinfo.xml。虽然里面的数据看起来和word文档显示的数据一样,但有一个零宽字节隐写。

http://330k.github.io/misc_tools/unicode_steganography.html

image-20210505132723064

解得第一部分flag:

vnctf{APT_1S_c0M1nG

重新观察最初的邮件文件,看到一个PG1ldGEgaHR0c开头的有用的base64编码,解码得:

image-20210505132735392

能够看到一张图片的地址,打开并保存image-20210505132747938

根据文件名ThisIsSecret可知是利用OurSecret解密

image-20210505132759401

没有密码,unhide一下即可得到一个2.txt,保存打开即可得到第二部分flag:

_fr0m_l@z@RuS}

将两部分flag连起来得到最终flag:

vnctf{APT_1S_c0M1nG_fr0m_l@z@RuS}

HAPPYNEWYEAR

image-20210505132812798

hint1:https://www.dcode.fr/tools-list#symbols

hint2:stegpy,但是不是那么白给的stegpy

下载附件得到一个加密的压缩包和一副写着密码的图

image-20210505132822946

明显是需要解密了,蓝色的比较简单,很明显是谢赫语言密码

image-20210505132832681

横竖线的密码比较难找,我还假设过这些密码全是数字,尝试掩码爆破,可惜并没有解出答案。根据hint1可以找到解密网站:

https://www.dcode.fr/chinese-code

最终得到密码:

f87840bdddcc01e4

得到一张图片:
image-20210505132846281

尝试过各种png的隐写方式,也尝试过寻找原图去拼合两张图片,但都无济于事。

根据hint2可知是stegpy隐写,但无密码和一些与题目文件名有关的密码都没用,于是尝试爆破。

这个爆破的难点主要在于python和终端的交互,stegpy的输入密码特殊性导致不能像一般的交互那样写脚本。理论上修改stegpy源码让stegpy和终端的交互更倾向于常见的方式也是可行的,但我还没有试过。

下面直接给出爆破脚本,此脚本在misc大师傅们一起写的"automisc"中可以找到,只需要稍加修改即可,我利用的字典也是此项目的字典。

https://github.com/L1near/CTFpics-1/blob/master/webpsteg.py

# -*- coding: utf-8 -*-
import os
from subprocess import Popen,PIPE
import sys
def checkwebp(pic):
    print("IF you don't need a password for the pic please input 1") # 无密钥
    print("IF you know the password of the pic please input 2") # 有密钥且已知
    print("IF not input 3 I will use the password.txt") # 有密钥但未知
    choice = input()
    if choice == '1':
        os.system("stegpy {}".format(pic))
    elif choice == '2':
        print("INPUT THE password:")
        password = input()
        cmd = ["stegpy", "-p",pic]
        subp = Popen([sys.executable, '-c', 'import pty, sys; pty.spawn(sys.argv[1:])', *cmd],stdin=PIPE,stdout=PIPE,stderr=PIPE)
        print(subp.stdout.read(len("Enter password (will not be echoed):")))
        subp.stdin.write(bytes((password+'\n').encode('utf-8')))
        subp.stdin.flush()
        print(subp.stdout.readlines())
        # print(subp.stdout.readlines()[1])
        print('\n')
    elif choice == '3':
        file = open('password.txt', 'r')
        line = file.readline()
        while line:
            print(line)
            cmd = ["stegpy", "-p", pic]
            subp = Popen([sys.executable, '-c', 'import pty, sys; pty.spawn(sys.argv[1:])', *cmd], stdin=PIPE, stdout=PIPE,stderr=PIPE)
            print(subp.stdout.read(len("Enter password (will not be echoed):")))
            subp.stdin.write(bytes((line + '\n').encode('utf-8')))
            subp.stdin.flush()
            print('result:')
            result = subp.stdout.readlines()[1]
            print(result)
            if result != b'Wrong password.\r\n':
                break
            # print(subp.stdout.readlines()[1])
            print('\n')
            line = file.readline()
    else :
        print('Input Wrong!')
if __name__ == "__main__":
    checkwebp('happynewyear.png')

解得:

image-20210505132858250

最终密码即为tyinfo

解得最终flag为:

VNCTF{HappyNewY3a5}
  1.  说道:
    Google Chrome Windows 10
    tql
  2. Demodd说道:
    Google Chrome Windows 10
    师傅太强了
  3. Mas0n说道:
    Google Chrome Windows 10
    Misc师傅!!!!

发表评论