题目描述 你能突破九大关卡修成神仙吗?
hint1:压缩包密码为比赛名称+8位什么来着?忘了。哈哈哈!
hint2:flag格式:XYCTF{md5(flag)}
hint3:第三层非夏多,看看交点
hint4:第六层键盘画图,狼蛛键盘最新版你值得拥有!
开头 由提示猜测压缩包密码XYCTF20240401
炼气 第一层是天书加密,用随波逐流就可以解出压缩包密码。
第二层是一张图片,修改高就可以看到flag的第一部分:
XYCTF{T3e_c0mb1nation_
筑基 第一层是BubbleBabble 编码,在线解码 就能解出压缩包密码。
第二层是一张图片,010看不出什么东西,用StegSolve通过LSB可以找到一串Base64编码,解码可得flag第二部分:
0f_crypt0_and_
结丹(全复现) 给出一张图片
hint说看交点,可能跟Begin CTF 2023的下一站上岸差不多,四个交点为”-”,三个交点为空格,一个交点为”.”,可以转化为:
- .... . ..--.- - .... .. .-. -..
摩斯密码解码就可以得到压缩包的密码
打开压缩包发现还有一层压缩包和一个txt,文本文件里面没有有用信息,但是压缩包带密码,用010打开看看,看到末尾有一段附加信息:
分析特征,显然是Base64,解码之后可以得到压缩包密码,解压发现里面有一个文本文件,由特征可知是Base32,解码就可以得到flag的第三部分。
misc_1s_re6lly_fun!!
元婴 hint4.txt打开一看发现是base64,解密一看salted,用这个网站解密:在线Triple DES加密 | Triple DES解密- 在线工具 (sojson.com) (一个个试出来的),密码是2024.
拿密码打开压缩包,有个hint.txt和一个db文件,hint内容如下:
wqk:1m813onn17o040358p772q37rm137qpnqppqpn38nr704m56n2m9q22po7r05r77
进行一个凯撒解密就可以得到一个key,
下面是在52上面找到的一个解密微信聊天数据库的脚本:
from Crypto.Cipher import AESimport hashlib, hmac, ctypesSQLITE_FILE_HEADER = bytes ("SQLite format 3" ,encoding='ASCII' ) + bytes (1 ) IV_SIZE = 16 HMAC_SHA1_SIZE = 20 KEY_SIZE = 32 DEFAULT_PAGESIZE = 4096 DEFAULT_ITER = 64000 password = bytes .fromhex("..." .replace(' ' ,'' )) with open (r'...\\MSG0.db' , 'rb' ) as f: blist = f.read() print (len (blist))salt = blist[:16 ] key = hashlib.pbkdf2_hmac('sha1' , password, salt, DEFAULT_ITER, KEY_SIZE) first = blist[16 :DEFAULT_PAGESIZE] mac_salt = bytes ([x^0x3a for x in salt]) mac_key = hashlib.pbkdf2_hmac('sha1' , key, mac_salt, 2 , KEY_SIZE) hash_mac = hmac.new(mac_key ,digestmod = 'sha1' ) hash_mac.update(first[:-32 ]) hash_mac.update(bytes (ctypes.c_int(1 ))) if (hash_mac.digest() == first[-32 :-12 ]): print ('Correct Password' ) else : raise RuntimeError('Wrong Password' ) blist = [blist[i:i+DEFAULT_PAGESIZE] for i in range (DEFAULT_PAGESIZE,len (blist),DEFAULT_PAGESIZE)] with open (r'...\\ChatMsg.db' , 'wb' ) as f: f.write(SQLITE_FILE_HEADER) t = AES.new(key ,AES.MODE_CBC ,first[-48 :-32 ]) f.write(t.decrypt(first[:-48 ])) f.write(first[-48 :]) for i in blist: t = AES.new(key ,AES.MODE_CBC ,i[-48 :-32 ]) f.write(t.decrypt(i[:-48 ])) f.write(i[-48 :])
用打开数据库的软件打开解密之后的数据库(我用的Dbeaver),在MSG表里面就可以看到flag的第四部分:
L1u_and_K1cky_Mu
化神(第二部分复现): hint5给出了一串字符和md5后的结果,进行爆破,爆破出压缩包密码,解压第五层.zip
看到flag.txt里面没有有用的东西.
serpent.txt文件里有东西,考虑serpent加密,用这个网站Serpent Encryption – Easily encrypt or decrypt strings or files (online-domain-tools.com)
通过文件输入,从头到尾没有密钥,猜测密钥是前面爆破得到的key,解密之后下载下来塞进Cyberchef可以看到
导出为txt并转换编码为UTF-8后可以得到:
字数比可以看到的多很多,考虑零宽字符隐写:
将文本转化为unicode编码后:
筛选发现,里面包含零宽unicode字符\u200A,\u200B,\u200C,\u202C,\uFEFF
用Unicode Steganography with Zero-Width Characters (mzy0.com) 解码即可得出flag的第五部分:
_3re_so_sm4rt!
炼虚(第二部分复现): 第一层是键盘画图,是一个句子,不确定的字母可以掩码爆破。
用上面得到的密码打开压缩包,可以看到一个压缩包,一个word文档,一个Excel文档,一个PPT,一个文本文件还有一张图片。除了图片之外,都没有看到有什么有用的,直接用steghide提取一下,发现要密码,发现上面几个文件名称都是数字,倒着来输一遍(98641)就是密码(纯猜谜),提取出来就可以得到flag的第六部分:
In_just_a_few_m1nutes_
合体 第一层UTF-7加维吉尼亚,密钥是字母表。
解开压缩包可以看到一个图片:
就一个八进制,按颜色填数字就行,八进制转换之后就可以得到flag的第七部分:
they_were_thr0ugh!
大乘 这一层的第一部分是一个RSA,显然是p^q泄露,加密代码如下:
from Crypto.Util.number import bytes_to_long, getPrimeflag=b"password{xxxxx}" p,q= getPrime(1024 ),getPrime(1024 ) n = p * q e = 65537 m = bytes_to_long(flag) c = pow (m,e,n) print ("n=" ,n)print ("c=" ,c)print ("p^q=" ,p^q)''' n= 22424440693845876425615937206198156323192795003070970628372481545586519202571910046980039629473774728476050491743579624370862986329470409383215065075468386728605063051384392059021805296376762048386684738577913496611584935475550170449080780985441748228151762285167935803792462411864086270975057853459586240221348062704390114311522517740143545536818552136953678289681001385078524272694492488102171313792451138757064749512439313085491407348218882642272660890999334401392575446781843989380319126813905093532399127420355004498205266928383926087604741654126388033455359539622294050073378816939934733818043482668348065680837 c= 1400352566791488780854702404852039753325619504473339742914805493533574607301173055448281490457563376553281260278100479121782031070315232001332230779334468566201536035181472803067591454149095220119515161298278124497692743905005479573688449824603383089039072209462765482969641079166139699160100136497464058040846052349544891194379290091798130028083276644655547583102199460785652743545251337786190066747533476942276409135056971294148569617631848420232571946187374514662386697268226357583074917784091311138900598559834589862248068547368710833454912188762107418000225680256109921244000920682515199518256094121217521229357 p^q= 14488395911544314494659792279988617621083872597458677678553917360723653686158125387612368501147137292689124338045780574752580504090309537035378931155582239359121394194060934595413606438219407712650089234943575201545638736710994468670843068909623985863559465903999731253771522724352015712347585155359405585892 '''
解密代码如下:
from Crypto.Util.number import *import syssys.setrecursionlimit(100000 ) def pq_high_xor (p="" , q="" ): lp, lq = len (p), len (q) tp0 = int (p + (1024 -lp) * "0" , 2 ) tq0 = int (q + (1024 -lq) * "0" , 2 ) tp1 = int (p + (1024 -lp) * "1" , 2 ) tq1 = int (q + (1024 -lq) * "1" , 2 ) if tp0 * tq0 > n or tp1 * tq1 < n: return if lp == leak_bits: pq.append(tp0) return if xor[lp] == "1" : pq_high_xor(p + "0" , q + "1" ) pq_high_xor(p + "1" , q + "0" ) else : pq_high_xor(p + "0" , q + "0" ) pq_high_xor(p + "1" , q + "1" ) def pq_low_xor (p="" , q="" ): lp, lq = len (p), len (q) tp = int (p, 2 ) if p else 0 tq = int (q, 2 ) if q else 0 if tp * tq % 2 **lp != n % 2 **lp: return if lp == leak_bits: pq.append(tp) return if xor[-lp-1 ] == "1" : pq_low_xor("0" + p, "1" + q) pq_low_xor("1" + p, "0" + q) else : pq_low_xor("0" + p, "0" + q) pq_low_xor("1" + p, "1" + q) n = ... c = ... mask = (1 <<1024 )-1 leak_bits = 1024 leak = ... xor = bin (leak)[2 :].zfill(1024 ) pq = [] pq_low_xor() for p in pq: if n % p == 0 : q = n // p phi = (p-1 )*(q-1 ) d = inverse(65537 ,phi) m = pow (c,d,n) print (long_to_bytes(m))
得到密码解开压缩包,可以见到一个txt,打开看到一堆no和yes,将no替换为0,yes替换为1,通过下述脚本转换为图片:
from PIL import Imagewith open ("temp.txt" ,'r' ) as f: s = f.read() pic = Image.new("L" ,(548 ,72 )) for h in range (72 ): for w in range (548 ): if s[h * 548 + w] == '0' : pic.putpixel((w,h),0 ) else : pic.putpixel((w,h),255 ) pic.save("out.png" )
是须弥沙漠文,对字母表换就行,下附字母表
换完就可以得到flag的第八部分:
sm3rty0ucando
渡劫(第二部分复现) 这一层的第一部分是一个RSA,很简单,加密代码如下:
from Crypto.Util.number import *from random import randintp = getPrime(512 ) q = getPrime(512 ) n = p * q e = 65537 list = []for _ in range (2 ): a, b = randint(0 , 2 **8 ), randint(0 , 2 **256 ) list .append(a * p + b * q) password = b"xxxxx" c = pow (bytes_to_long(password), e, n) print (f'{n = } ' )print (f'{c = } ' )print (f'{list = } ' )
解密代码如下:
from Crypto.Util.number import *import gmpy2n = ... c = ... list = [..., ...]e = 65537 for a1 in range (2 **8 ): for a2 in range (2 **8 ): if (gmpy2.gcd(list [0 ]*a1-list [1 ]*a2,n)!=1 and gmpy2.gcd(list [0 ]*a1-list [1 ]*a2,n)!=n): print (gmpy2.gcd(list [0 ]*a1-list [1 ]*a2,n)) q = ... p = n // q assert p*q == nphi = (p-1 )*(q-1 ) d = gmpy2.invert(e,phi) m = pow (c,d,n) print (long_to_bytes(m))
解开压缩包就是一个带图片的压缩包和一个txt,txt内容如下:
图片里面确实没有东西,由压缩包名字“我们的小秘密嘿嘿”猜测是oursecret隐写,猜测密码是上面解出来的,尝试发现是正确的,就可以得到flag的第九部分:
_nine_turns?}
汇总 组合之后:
XYCTF{T3e_c0mb1nation_0f_crypt0_and_misc_1s_re6lly_fun!!L1u_and_K1cky_Mu_3re_so_sm4rt!In_just_a_few_m1nutes_they_were_thr0ugh!Sm3rt_y0u_can_do_nine_turns?}
注意,第八段开头大写,然后要按词加下划线得到flag之后要整体用md5加密之后再包上XYCTF{}才是flag。