浙江省CTF决赛MISC writeup

排名

初赛决赛均第一

image-20220924233312659

解题情况

image-20220924141658973

checkin_gift

winhex打开,搜索FFD9可以发现一共有两张JPG图片,两张JPG图片之间存在base编码

image-20220924225048441

base64换表N-ZA-Mn-za-m0-9+/=+base32解密一下即可得到flag,可以直接利用cyberchef的Magic直接爆破得到flag。

image-20220924131455035

Unkn0wnData

下载附件得到一个flag.png,文件尾存在base64编码

V2hlcmUxc0tleT8KCu2gve25g+2gve2yte2gvO28v+2gvO2+pO2gve26qu2gvO28j+2gve2wju2gvu21i+2gve26q+2gve24huKche2gvO29je2gvO2+pO2gve2wmO2gvO28j+KEueKMqO2gve24je2gvO2+iOKcie2gvu20o+2gve27qe2gvO29jO2gve26qu2gvO29tOKEueKYuu2gve26ueKdk+2gvO29tO2gve20rO2gvO28qu2gvO29te2gve2xo+2gve20hOKYg+2gve2xjO2gve24ju2gve2xjO2gve20hO2gve2xjO2gve20qu2gvO29jO2gve2xge2gvO29je2gvO29jO2gvO28j+2gvO2+g+2gve26sO2gvO29te2gve2wje2gvO2+heKche2gvO29je2gvu22k+2gve24ju2gve24iu2gvu20o+2gvO2/ue2gvO29je2gve2yp+2gve20hO2gve20hO2gvu20o+2gve2xge2gvu21i+2gve26q+KYuu2gvO29tO2gve24ge2gve26q+2gve24h+2gve26sOKPqe2gve24je2gvO28v+2gve2yte2gvu22k+2gve24h+2gve27qeKclu2gve21ue2gve2wju2gve2zgu2gve2zgu2gve2yp+2gve23ku2gve23kg==

image-20220924225315613

base64解码一下得到乱码数据

image-20220924225419391

之后将该编码做一个utf-8转码,即可得到aes-emoji字符

image-20220924131728636

当然也可以通过爆破获取编码:

image-20220924225526130

??????????✅????ℹ⌨??✉?????ℹ☺?❓??????☃????????????????✅??????????????☺?????⏩??????✖???????

利用stegsolve对flag.png进行lsb隐写解密,发现504B0304字段

image-20220924131822984

hex解码一下即可保存为zip压缩包

image-20220924131915560

压缩包内是一个txt文件

data:
0000100000000000
00000c0000000000
00000e0000000000
00002a0000000000
0000100000000000
0000040000000000
0000080000000000
00002a0000000000
0000160000000000
00000b0000000000
00000c0000000000
00001c0000000000
00002a0000000000
00002c0000000000
0200340000000000
00002a0000000000
0200090000000000
00000c0000000000
0000110000000000
0000070000000000
0200170000000000
00002a0000000000
0200170000000000
00000b0000000000
0000080000000000
0000120000000000
00002a0000000000
0200150000000000
0000080000000000
0000040000000000
00000f0000000000
00000a0000000000
00002a0000000000
02000e0000000000
0000080000000000
00001c0000000000
00000a0000000000
00002a0000000000
0000040000000000
0000110000000000
0000070000000000
00000f0000000000
00002a0000000000
0200100000000000
0000040000000000
00000e0000000000
0000080000000000
0000080000000000
00002a0000000000
02000c0000000000
0000170000000000
02001e0000000000
0000070000000000
00002a0000000000

写一个python脚本解密键盘流量:

normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}

shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}

keys = open('key.txt')
output = ""
for line in keys:
    k = line[1]
    n = line[4:6]
    if k == '0':
        print(normalKeys[n], end='')
    elif k == '2':
        print(shiftKeys[n], end='')

得到结果:

mik<DEL>mae<DEL>shiy<DEL><SPACE>:<DEL>FindT<DEL>Theo<DEL>Realg<DEL>Keyg<DEL>andl<DEL>Makee<DEL>It!d<DEL>

将DEL的值删除后得到:

mimashi FindTheRealKeyandMakeIt!

解密后,该key的意思是让我们寻找真实的key,说明这是一个假key,仔细观察被DEL的字符,可以发现开头几位是key:,可知被DEL的字符才是关键。

只读取被DEL的字符的脚本:

normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}

shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}

keys = open('key.txt')
output = ""
for line in keys:
    k = line[1]
    n = line[4:6]
    if n == '2a':
        print(output[-1], end='')
    if k == '0':
        output += normalKeys[n]
    elif k == '2':
        output += shiftKeys[n]

跑一下即可得到aes-emoji的key

key:Toggled

emoji-aes正常需要在线网站,结果如下:

项目地址:https://aghorler.github.io/emoji-aes/#

image-20220924132207214

但是省赛环境是不能联网的,只能直接写个脚本替换,根据aes-emoji的原理,实际上就只是一个带盐的aes加密,把结果base64一下,然后把表换成了65个emoji,所以只需要进行一个替换即可。

脚本如下:

import base64
from Crypto.Cipher import AES
import string
emojisInit="????????ℹ??✉????????☂??✖☀?????????☃???????⌨???????❓⏩????☺?????✅??"
alpha = string.ascii_lowercase+string.ascii_uppercase+string.digits+"+/="
a = "??????????✅????ℹ⌨??✉?????ℹ☺?❓??????☃????????????????✅??????????????☺?????⏩??????✖???????"
base64data = ""
for i in a:
    base64data += alpha[emojisInit.index(i)]
print(base64data)

换表后得到:

U2FsdGVkX1+psEGiQ9Bl3PbdKi4mYKSHJfRIoCoRo/bepbG8tJvD+pzC53ApwRR3ekX4K0X6tZ9F2z6PxNVOOw==

最后进行aes解密即可得到flag

image-20220924231114845

m4a

下载附件得到一个m4a文件,发现打不开,观察一下正常的m4a文件,可以发现第五位到第十一位是固定头文件667479704D3441,但是题目中的头文件被损坏了,全是00,修复文件头即可正常打开

image-20220924132514623

m4a是一个音频文件,可以听出是摩斯电码,放不进audacity,用格式工厂转成mp3再放,得到摩斯电码

-... .- ....- ...-- -... -.-. . ..-. -.-. ..--- ----- ....-

image-20220924231652258

解MORSE密码得到:

BA43BCEFC204

image-20220924231749614

文件尾存在一个倒叙的zip压缩包

image-20220924132550499

倒叙一下即可保存为zip压缩包

image-20220924132639475

打开发现需要密码

image-20220924132705946

利用该key解压压缩包,得到atbash.txt

(+w)v&LdG_FhgKhdFfhgahJfKcgcKdc_eeIJ_gFN

根据提示atbash.txt,可知需要解埃特巴什码

image-20220924231859444

可以直接利用cyberchef进行解密,先进行ROT47解密,然后进行atbash解密即可

image-20220924132927618

hard_Digital_plate

下载附件得到一个流量包文件,发现报了长度错误

image-20220924232042888

报了长度错误可知文件尾存在隐藏数据,用winhex打开发现隐藏数据如下:

image-20220924133218460

提取出来发现是一个压缩包,压缩包内存在oursecret.jpg,之后删除隐藏的压缩包数据,流量包就不会报错了

image-20220924133051670

分析流量包发现是一个数位板流量,先利用tshark分离数据

tshark -r hard_Digital_plate.pcapng -T fields -e usbhid.data | sed '/^\s*$/d' > out.txt

得到(数据量过大,随意截取一段展示):

08803708951e000000000000
08803708951e000000000000
08803708951e000000000000
08803708951e000000000000
08803708951e000000000000
08813708951e650000000000
08813808951ec10000000000
08813908951e2e0100000000
08813a08951e940100000000
08813b08951ee20100000000
08813c08951e1c0200000000
08813c08951e440200000000
08813c08951e610200000000

第二个字节代表了是否启用0x81位有效坐标,同时后四位还有数位板的压感值。

当第二字节为0x81时,说明数位板正在作画,且第8字节和第9字节存在压感值,当第二字节为0x80时,说明数位板没有落笔,即没有作画,此时第8字节和第9字节不存在压感,为0x0000。

坐标分析直接说结论,第5-8位是x轴坐标,第9-12位是y轴坐标,并且是小端序储存方法。

例如:

08803708951e000000000000

这个数据,0x3708是x坐标信息,0x951e是y坐标信息,但是由于数据为小端序储存,实际x坐标为0x0837,y坐标为0x1e95。

根据如下规律,写个python脚本提取存在压感的数位板坐标:

nums = []
keys = open('out.txt', 'r')
result = open('result.txt', 'w')
for line in keys:
    if int(line[12:16], 16) == 0:
        continue
    x = int(line[4:6], 16) + int(line[6:8], 16) * 0xff
    y = int(line[8:10], 16) + int(line[10:12], 16) * 0xff
    result.write(str(x)+' '+str(-y)+'\n')
keys.close()
result.close()

得到最表后,利用kali自带的gnuplot画图得到:

the key is:kfae5y4wi2shwj81y2kda6ax7x

image-20220924134013697

根据jpg文件名提示,可知是oursecret隐写,利用kfae5y4wi2shwj81y2kda6ax7x解一下oursecret:

image-20220924134138121

解得flag.txt

U2FsdGVkX18jQgWzhln3pPiVK8gaBxIzhY1JWcFlKiRdBkV/jDmEBxJV9PZmwBJ7MU3IdNf4hWryZLYRLuxA4w==

在jpg注释中发现备注,提示需要提取数位板压感低的数据

image-20220924134234425

写个脚本专门提取低压感数据,这里将0xf000作为压感临界值:

nums = []
keys = open('out.txt', 'r')
result = open('result.txt', 'w')
for line in keys:
    if int(line[12:16], 16) == 0:
        continue
    x = int(line[4:6], 16) + int(line[6:8], 16) * 0xff
    y = int(line[8:10], 16) + int(line[10:12], 16) * 0xff
    if int(line[12:16], 16) < 0xf000:
        result.write(str(x)+' '+str(-y)+'\n')
keys.close()
result.close()

画图:

image-20220924134351171

得到:

key is w12kax

最后解一个aes密码即可得到flag

image-20220924232851894

发表评论