XYCTF 2024 出题记录
MISC
美妙的歌声
题目描述:
这首歌能深深地打动你吗?
我的解答:
频谱图查看密码
分析题目描述:深深地打动?想到 deepsound 隐写
密码就是:XYCTF_1s_w3ll
XYCTF{T0uch_y0ur_he3rt_d55ply!!}
疯狂大杂烩!九转功成
题目描述:
你能突破九大关卡修成神仙吗?
题目提示:
1.压缩包密码为比赛名称+8位什么来着?忘了。哈哈哈!
2.flag格式:XYCTF{md5(flag)}
3.第三层非夏多,看看交点
4.第六层键盘画图,狼蛛键盘最新版你值得拥有!
我的解答:
根据提示:压缩包密码为比赛名称+8位什么来着?忘了。哈哈哈!
掩码爆破或猜测可知密码为 XYCTF20240401
第一层–炼气
hint:
这是什么东西?
曰:玉魔命灵天观罗炁观神冥西道地真象茫华茫空吉清荡罗命色玉凶北莽人鬼乐量西北灵色净魂地魂莽玉凶阿人梵莽西量魄周界
天书解码:First_layer_simple
解压压缩包
png 宽高修改
XYCTF{T3e_c0mb1nation_
第二层–筑基
hint:
xihak-minoh-zusok-humak-zurok-gulyk-somul-nenel-dalek-nusyh-zumek-sysuk-zelil-fepak-tysok-senax
BubbleBabble 解码:The_second_layer_is_also_simple
ZmxhZzLvvJowZl9jcnlwdDBfYW5kXw==
base64 解码
flag2ï¼0f_crypt0_and_
第三层–结丹
hint:
不是夏多密码,看交点是摩斯。四个交点代表”-” 三个交点代表空格 两个交点代表”.”
得到:the_third
解压压缩包得到 flag.zip 010 文件尾发现:5a+G56CB57uZ5L2g5Y+I5oCO5qC377yaMTIzNDU2
base64 解码提示密码 123456
但本身压缩包就是损坏的应该是伪加密但不完全是其实是伪加密后真加密了,改一个地方就行如下图:
保存解压得到:MZWGCZZT566JU3LJONRV6MLTL5ZGKNTMNR4V6ZTVNYQSC===
base32 解码:
flag3ï¼misc_1s_re6lly_fun!!
第四层–元婴
hint:
都 2024 年了不会还有人解不出 U2FsdGVkX1+y2rlJZlJCMnvyDwHwzkgHvNsG2TF6sFlBlxBs0w4EmyXdDe6s7viL 吧
TripleDES 解码:The_fourth_floor_is_okay
解压发现两个文件 hint.txt 和 MSG0.db
hint.txt
wqk:1m813onn17o040358p772q37rm137qpnqppqpn38nr704m56n2m9q22po7r05r77
随波逐流凯撒解码得到:
key1 #12: key:1a813cbb17c040358d772e37fa137edbeddedb38bf704a56b2a9e22dc7f05f77
数据库文件搜索得知是微信聊天记录文件
搜索解密脚本
input_pass = '1a813cbb17c040358d772e37fa137edbeddedb38bf704a56b2a9e22dc7f05f77'
input_dir = r'文件夹路径。例如: C:\\xxx\\xxx\\xxx\\xxx\\xxx\\元婴\\第四层\\第四层'
import ctypes
import hashlib
import hmac
from pathlib import Path
from Crypto.Cipher import AES
SQLITE_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(input_pass.replace(' ', ''))
def decode_one(input_file):
input_file = Path(input_file)
with open(input_file, '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 ^ 58 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('Decryption Success')
else:
print('Password Error')
blist = [
blist[i:i + DEFAULT_PAGESIZE]
for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)
]
with open(input_file.parent / f'decoded_{input_file.name}', '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:])
if __name__ == '__main__':
input_dir = Path(input_dir)
for f in input_dir.glob('*.db'):
decode_one(f)
# 62914560
# Decryption Success
解开之后打开数据库文件
L1u_and_K1cky_Mu
第五层–化神
hint:
enc = ‘key{liu*****’
md5 = ‘87145027d8664fca1413e6a24ae2fbe7’
md5 爆破:
import hashlib
enc = 'key{liu'
md5 = '87145027d8664fca1413e6a24ae2fbe7'
for x in range(0,127):
for y in range(0,127):
for z in range(0,127):
for k in range(0,127):
temp1 = hashlib.md5(str(enc + chr(x) + chr(y) + chr(z) + chr(k) + "}").encode("utf-8"))
temp2 = temp1.hexdigest()
if(md5 == temp2):
print(enc + chr(x) + chr(y) + chr(z) + chr(k) + "}")
#key{liuyyds}
解压得到 flag.txt 和 serpent.txt
flag.txt无结果。看另一个txt文件名发现是serpent隐写。。密码就是 liuyyds
记事本打开此文件:
这是一个非常神奇的故事 ,至于它神奇在哪?嘿嘿 !我也不知道 。
一眼丁真,零宽隐写:
_3re_so_sm4rt!
第六层–炼虚
hint:
wszrdc
fgtrfvb
ghytgbn
rfctg
yhju
frtg
uyhbghj
6yhn
uyhjujmn
tgvvghb
yhnmghj
4rfv
derf
iujkikmn
键盘密码画图,根据每行字母走向刻画出密码为:keeponfighting
好多文件逐一分析发现 flag 都是假的。。还有一个 jpg,猜测可能是某种隐写,先试一波 steghide,密码是啥?
这里有个脑洞:观察上面的文件名是数字,密码可能就是顺序或者逆序排列的。
steghide extract -sf yuanshen.jpg
Enter passphrase: 98641
wrote extracted data to "flag.txt".
In_just_a_few_m1nutes_
第七层–合体
hint:
密文:Tig+AF8-viakubq+AF8-vphrz+AF8-xi+AF8-uayzdyrjs
听说维吉尼亚 key 大残
首先对密文进行 UTF-7 解码。熟悉此类编码的都懂(直接就看出来了。)
接下来的操作就挺新颖的。我们知道维吉尼亚 key 都是字母。因此大残即全选。之前做过 BUU 的 NewStar 的应该有印象,当时好像有个 misc 题是 R 通道大残。
这样一来我们解码即可:
The_seventh_level_is_difficult
接下来根据颜色找对应数字。
164 150 145 171 137 167 145 162 145 137 164 150 162 60 165 147 150 41
观察数字发现是八进制。随波逐流八进制转字符得到 flag:
they_were_thr0ugh!
第八层–大乘
hint8.py
from Crypto.Util.number import bytes_to_long, getPrime
flag=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
'''
普通的剪枝算法,exp:
from Crypto.Util.number import *
import gmpy2
import sys # 导入sys模块
sys.setrecursionlimit(3000) # 将默认的递归深度修改为3000
n = 22424440693845876425615937206198156323192795003070970628372481545586519202571910046980039629473774728476050491743579624370862986329470409383215065075468386728605063051384392059021805296376762048386684738577913496611584935475550170449080780985441748228151762285167935803792462411864086270975057853459586240221348062704390114311522517740143545536818552136953678289681001385078524272694492488102171313792451138757064749512439313085491407348218882642272660890999334401392575446781843989380319126813905093532399127420355004498205266928383926087604741654126388033455359539622294050073378816939934733818043482668348065680837
seed = 14488395911544314494659792279988617621083872597458677678553917360723653686158125387612368501147137292689124338045780574752580504090309537035378931155582239359121394194060934595413606438219407712650089234943575201545638736710994468670843068909623985863559465903999731253771522724352015712347585155359405585892
#seed即p^q
def findp(p, rp):
l = len(p)
if l == 1024:
rp.append(int(p, 2))
else:
pp = int(p, 2)
qq = (seed ^ pp) % 2 ** l
if pp * qq % 2 ** l == n % 2 ** l:
findp('1' + p, rp)
findp('0' + p, rp)
rp = []
findp('1', rp)
for i in rp:
if n%i==0 & isPrime(int(i)):
print(i)
#145805499551351837545170670839798336872366414383311042018386386595288060139791135454980413014693924866953972662266748526407954492877610429602886244372924035960962307198910659475639333945895922717307291255423855616274924584270570126180050363106535962473049107576556315461013755859097114552522187755171423621071
#153796947048270429510444756458855481287460639468563001213489907625132438953570738468181770925091867439727519074685449940618659583114338501872698220745473531199063071421852521618805765627999106188015431567625318850899895052130157037822960945909520973243793507740817436707504505709194025074527084803054107605547
p=145805499551351837545170670839798336872366414383311042018386386595288060139791135454980413014693924866953972662266748526407954492877610429602886244372924035960962307198910659475639333945895922717307291255423855616274924584270570126180050363106535962473049107576556315461013755859097114552522187755171423621071
q=n//p
c=1400352566791488780854702404852039753325619504473339742914805493533574607301173055448281490457563376553281260278100479121782031070315232001332230779334468566201536035181472803067591454149095220119515161298278124497692743905005479573688449824603383089039072209462765482969641079166139699160100136497464058040846052349544891194379290091798130028083276644655547583102199460785652743545251337786190066747533476942276409135056971294148569617631848420232571946187374514662386697268226357583074917784091311138900598559834589862248068547368710833454912188762107418000225680256109921244000920682515199518256094121217521229357
e=65537
phi = (p-1) * (q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
#password{pruning_algorithm}
解压得到 txt 文本,里面是 no 和 yes 组成的。想到 01 画图。no 代表 0,yes 代表 1
但要知道坐标才行,010 分析压缩包文件尾:
5rOi6YCQ5rWB5rSq5rWB5rOi5rOi5rSq5rWB5rOi6ZqP5rSq5rWB6YCQ6ZqP5rWq5rWB5rOi5rOi5rWB5rSq5rWB5rOi5rWB5rSq5rWB6ZqP6YCQ5rSq6YCQ6ZqP6ZqP5rWq5rOi6YCQ5rOi6YCQ5rWq5rOi6YCQ5rWB6ZqP5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi6YCQ5rOi5rWB5rSL5rOi6YCQ6YCQ6ZqP6ZqP5rWB5rWB6ZqP5rSL5rOi5rOi5rWB5rWB6ZqP6ZqP5rWB5rWB5rSL5rOi6ZqP5rWB5rWB6YCQ6ZqP6YCQ5rWB5rSL5rOi5rOi6YCQ5rOi6YCQ6ZqP6ZqP6YCQ5rSL5rWB5rWB5rWB5rWB6ZqP5rOi6YCQ6YCQ5rWq5rOi6ZqP6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOi5rSq5rWB6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi5rOi5rWB5rWB5rWq5rOi6YCQ6ZqP5rOi5rSq5rWB6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi5rOi5rWB5rWB5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi5rOi5rWB5rWB5rWq5rOi6YCQ6ZqP5rOi5rWq5rOi6YCQ6ZqP5rOiCg==
base64 解码得到:
波逐流洪流波波洪流波随洪流逐随浪流波波流洪流波流洪流随逐洪逐随随浪波逐波逐浪波逐流随浪波逐随波浪波逐波流洋波逐逐随随流流随洋波波流流随随流流洋波随流流逐随逐流洋波波逐波逐随随逐洋流流流流随波逐逐浪波随随波浪波逐随波洪流随波浪波逐随波浪波逐随波浪波波流流浪波逐随波洪流随波浪波逐随波浪波波流流浪波逐随波浪波逐随波浪波逐随波浪波波流流浪波逐随波浪波逐随波
随言随语密码,随波逐流解码即可:
548×72 flag 格式例如:Aa1aa_a1a_aaa_aa
坐标和 flag 格式都有了,接下来进行画图:
from PIL import Image
MAX1 = 548
MAX2=72
pic = Image.new("RGB",(MAX1, MAX2))
str = ""
i = 0
for y in range (0,MAX2):
for x in range (0,MAX1):
if(str[i] == '1'):
pic.putpixel([x,y],(0, 0, 0))
else:
pic.putpixel([x,y],(255,255,255))
i = i+1
pic.show()
pic.save("flag.png")
这是什么?好像是一种文字编码。百度一下发现是须弥沙漠文。
对照并根据 flag 格式可以得到:Sm3rt_y0u_can_do
第九层–渡劫
hint9.py
from Crypto.Util.number import *
from random import randint
p = 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 = }')
#n = 107803636687595025440095910573280948384697923215825513033516157995095253288310988256293799364485832711216571624134612864784507225218094554935994320702026646158448403364145094359869184307003058983513345331145072159626461394056174457238947423145341933245269070758238088257304595154590196901297344034819899810707
#c = 46049806990305232971805282370284531486321903483742293808967054648259532257631501152897799977808185874856877556594402112019213760718833619399554484154753952558768344177069029855164888168964855258336393700323750075374097545884636097653040887100646089615759824303775925046536172147174890161732423364823557122495
#list = [618066045261118017236724048165995810304806699407382457834629201971935031874166645665428046346008581253113148818423751222038794950891638828062215121477677796219952174556774639587782398862778383552199558783726207179240239699423569318, 837886528803727830369459274997823880355524566513794765789322773791217165398250857696201246137309238047085760918029291423500746473773732826702098327609006678602561582473375349618889789179195207461163372699768855398243724052333950197]
爆破 a 求 q (使用笛卡尔积)
我们知道
h1 = a1p + b1q
h2 = a2p + b2q
而其中的 a1 和 a2 很小,所以爆破一下可求
a2h1 – a1h2 = (a2b1 – a1b2) q
发现是 q 的倍数,然后和 n 进行 gcd 即可。
exp:
from Crypto.Util.number import *
from itertools import product
from math import gcd
import gmpy2
n = 107803636687595025440095910573280948384697923215825513033516157995095253288310988256293799364485832711216571624134612864784507225218094554935994320702026646158448403364145094359869184307003058983513345331145072159626461394056174457238947423145341933245269070758238088257304595154590196901297344034819899810707
c = 46049806990305232971805282370284531486321903483742293808967054648259532257631501152897799977808185874856877556594402112019213760718833619399554484154753952558768344177069029855164888168964855258336393700323750075374097545884636097653040887100646089615759824303775925046536172147174890161732423364823557122495
list = [618066045261118017236724048165995810304806699407382457834629201971935031874166645665428046346008581253113148818423751222038794950891638828062215121477677796219952174556774639587782398862778383552199558783726207179240239699423569318, 837886528803727830369459274997823880355524566513794765789322773791217165398250857696201246137309238047085760918029291423500746473773732826702098327609006678602561582473375349618889789179195207461163372699768855398243724052333950197]
h1, h2 = list
for a, b in product(range(2**8), repeat=2):
q = gcd(a * h1 - b * h2, n)
if q != 1 and q < n:
print(q, n)
break
q = 12951283811821084332224320465045864899191924765916891677355364529850728204537369439910942929239876470054661306841056350863576815710640615409980095344446711
p = n // q
e = 65537
d = pow(e, -1, (p - 1) * (q - 1))
m = pow(c, d, n)
print(long_to_bytes(m))
#game_over
解压得到:
你相信我吗.txt
压缩包里的图片真的有东西吗?不如看向外面
我们的小秘密嘿嘿.zip
看到提示说:压缩包里的图片真的有东西吗?不如看向外面
那应该是不让你分析图片,图片可能啥也没有。那就分析压缩包呗!尝试很多方法没什么思路,再看看文件名?我们的小秘密?oursecret? 试一下感觉是这个。密码是 game_over
分离得到 flag.txt:
_nine_turns?}
最终把九段 flag 拼接得到:
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?}
md5 加密上述结果,最终 flag 为:
XYCTF{b1bdc6cf06a28b97c91c1c12f0d3bc00}
又是个签到
题目描述
也许你能在QQ群里签上到
asrmorfe.txt
😸🙍👭🙅🙇👔🙊👙👺🙂👌👪😫🙈😰😳🙃🙃🙄🙊🙎👐😱🙆👮👡👚👷😵👫🙇👏🙊👲😶👤🙉👫😰😷👹🙇👨👸👓👏🙋🙋👲🙈👳😲🙎👭👨🙉😰👰👙🙇👑👸👦🙎🙊👹🙊👮👗👩🙁😹🙃👧👡👸🙁😱👤👩👣👷👕🙅👨👙👗🙄👵👐👡👢😫😸👔😳👤👬😵😯👦👱😵👭🙎🙂🙃👓😲👐👶👥😷👰😵😹😷👘👗👪👬👥👬👒👱👰😶👕👳😵😯🙇👺😳👹😱😰👵🙉🙁😽😽
签到.txt
HWXj+kI2pS+5pSJhDS0oAzlQmziosSr7gUvdXppjSt8BNUTz8oLfE57NkCrVwBBgGul5hHzCcKqyG7U5LWMOXYtzloMsVvdZdPbMZyb+EgYF17+W/S1oLDgQcjGmP6CSHWXj+kI2pS+5pSJhDS0oA3fVDcJt/sEYpz9U0yQTrgxTN0kF5G4xTJ5IKqYil2gK3Ml6usGZsucJXa6pCovoeaGSyZNq6T3aX1NOlb5Gt4gF17+W/S1oLDgQcjGmP6CSHWXj+kI2pS+5pSJhDS0oAzlQmziosSr7gUvdXppjSt8PPIU/UwIkvINgvGw+oQMCCaOmO7bDsiSxD/r9w3RKRQEfMm/fv+a/5v/NWgauEpoF17+W/S1oLDgQcjGmP6CSHWXj+kI2pS+5pSJhDS0oA2QV+Gu05V1J2eVrbGhHB487Ns8HTVNYrll8P/Xve17NCaOmO7bDsiSxD/r9w3RKRQEfMm/fv+a/5v/NWgauEpoF17+W/S1oLDgQcjGmP6CS1yISnL45ZHzPjs5BGSboyDJXscweSL6g0ptOqql5vhY7Ns8HTVNYrll8P/Xve17NlyvQj9HulYK3sIMIiNTVrv/QYgLgLF9uO3y6uH800Gy0VvmX5a5S5ZEDlkBSgVrDb/KxZEoU9d83Nbzm7yH80p9xX+50C/29uVc+H6gx1gOTPv9mT6A8qfJoby4BoCS3by65j7WFf6d/XZX0KskX4t1SAjnDpnC8qWVbU6l6Zs9zWhqP0E6UVZEUMUcRZB43hzoYB6fvcRSs8WPoArwl6dY0JrIccPz30xmtzuOLZRKpeJ5IPHFZw5l6Zo68xW/fiYggRz/KqtgFCLvPQ+Lj+6YY1X0zgl8a3xzz5EI9efUoZd30RstP6oPDy17QzTwoaA1OLHZfyIntyJiT9r3x0kLELrvwIFczyH339IGVYqE4qA/Xsd3t/I+jStXiGGCnKCWoqABdtqk7Z22cIzn0lPAiqi9i3hd/IIgrlkygiofpTmBc34UjLRWWFjQgmDQZ8em1hDlVfgd+/93D4BVIn36xgcg2RtYCx2GmXmg5JwRj5pxcBzyOVie5m0U4zHD6Rt0T8GAvCiCf9hhYkBi7lVHe4Sb7op9fpgfXrNunluSOwxS0NlaBKwa1gvE6/BNy2CI2Uv2y4jlPTdIuCNnWbCJsTSczfPJg5PVfyXykQtg4qA/Xsd3t/I+jStXiGGCnKCWoqABdtqk7Z22cIzn0lLw/priteJqeyg6psALOE5HEboNbEbOkupEDq1HXrfGn2CI2Uv2y4jlPTdIuCNnWbCJsTSczfPJg5PVfyXykQtg4qA/Xsd3t/I+jStXiGGCnctoLlIFVYoOgnQM/2Rz5g4eIxaKQoZ+9cRB51n5yxl/BJQA5860fCnVVFSyvS40JdaogrK4AcB+C0gsnUbXVyeX1Kq+MwIHo812Z/0GIAiR+HkJQwgmO7qkogz1vcP4+q7EHUnfXquRurKvZ5jMHz4eIxaKQoZ+9cRB51n5yxl9g/v4Djdoq+YadpY2vIGrZ2CI2Uv2y4jlPTdIuCNnWbDVfnXQwmbz3jY+JyZm4sKgHDLAxJSG/IIAKk2q5C0f6l6L6v86Nra6TiDC3FBOzBEMzapQz6v9XkJfLFhywMtFLbz4PXsEvXiaFbSooHN8xVDDfRmWQyINRSNJguwiY9ElfGZnb6gHT2U5ENwxhxpxW+5Jnwn3zMCBub7HDwqyOSl5l8hKoU5obcdof5SuB3A==
我的解答:
颜文字解密,密码为文件名逆过来看:65537
432000023200001320000211000003200004320000313000021100001130000113000034200003320000
可以看到上面的字符串基本都是后面4个0然后前面3位在变化,显然7个一组,类似ASCII,根据数字范围基本确定是五进制,计算一下
strs="432000023200001320000211000003200004320000313000021100001130000113000034200003320000"
for i in range(len(strs)//7):
num=strs[7*i:7*i+7]
n=0
for j in range(7):
# print(num[-j])
n=n+int(num[-(j+1)])*(5**j)
print(chr(n),end="")
得到了乱码,但是结果是有的,把密文逆一下试试
str="432000023200001320000211000003200004320000313000021100001130000113000034200003320000"
strs = str[::-1]
for i in range(len(strs)//7):
num=strs[7*i:7*i+7]
n=0
for j in range(7):
# print(num[-j])
n=n+int(num[-(j+1)])*(5**j)
print(chr(n),end="")
# DIQQ SEA BCE
已经可以看到结果了:ECB AES QQID
得知是AES(ECB模式加密),后面的QQID应该是key。结合题目描述可知QQID = 798794707
对附件密文签到.txt进行解密:
看到解密后末尾出现提示:Have you heard of Malbolge?
百度可找到此解密网址:https://malbolge.doleczek.pl/
XYCTF{It's_Easy!_Special_Signature}
Crypto
babyRSAMAX
题目
听说你们数学很好,我不信我不信;)
from Crypto.Util.number import *
from gmpy2 import *
from random import choice
flag = b'XYCTF{******}'
e = '?'
def getBabyPrime(nbits):
while True:
p = 1
while p.bit_length() <= nbits:
p *= choice(sieve_base)
if isPrime(p+1):
return p+1
p = getBabyPrime(512)
q = getBabyPrime(512)
n = p*q
gift1 = (pow(p,e,n)-pow(q,e,n)) % n
gift2 = pow(p+q,e,n)
t = 65537
x = bytes_to_long(e)
y = pow(x, t, n)
m = bytes_to_long(flag)
c = powmod(m, e, n)
print(f'n = {n}')
print(f'gift1 = {gift1}')
print(f'gift2 = {gift2}')
print(f'c = {c}')
print(f'y = {y}')
'''
n = 39332423872740210783246069030855946244104982381157166843977599780233911183158560901377359925435092326653303964261550158658551518626014048783435245471536959844874036516931542444719549997971482644905523459407775392702211086149279473784796202020281909706723380472571862792003687423791576530085747716706475220532321
gift1 = 4549402444746338327349007235818187793950285105091726167573552412678416759694660166956782755631447271662108564084382098562999950228708300902201571583419116299932264478381197034402338481872937576172197202519770782458343606060544694608852844228400457232100904217062914047342663534138668490328400022651816597367310
gift2 = 111061215998959709920736448050860427855012026815376672067601244053580566359594802604251992986382187891022583247997994146019970445247509119719411310760491983876636264003942870756402328634092146799825005835867245563420135253048223898334460067523975023732153230791136870324302259127159852763634051238811969161011462
c = 16938927825234407267026017561045490265698491840814929432152839745035946118743714566623315033802681009017695526374397370343984360997903165842591414203197184946588470355728984912522040744691974819630118163976259246941579063687857994193309554129816268931672391946592680578681270693589911021465752454315629283033043
y = 1813650001270967709841306491297716908969425248888510985109381881270362755031385564927869313112540534780853966341044526856705589020295048473305762088786992446350060024881117741041260391405962817182674421715239197211274668450947666394594121764333794138308442124114744892164155894256326961605137479286082964520217
'''
我的解答:
考点:p-1 光滑数、高次 Rabin、不互素问题 + 公式推导
首先,p-1 光滑攻击解 e
然后,高次 Rabin 解 flag,注意:gift1 和 gift2 不互素
exp:
from Crypto.Util.number import *
from gmpy2 import *
#part1: p-1光滑攻击解e
n = 39332423872740210783246069030855946244104982381157166843977599780233911183158560901377359925435092326653303964261550158658551518626014048783435245471536959844874036516931542444719549997971482644905523459407775392702211086149279473784796202020281909706723380472571862792003687423791576530085747716706475220532321
t = 65537
y = 1813650001270967709841306491297716908969425248888510985109381881270362755031385564927869313112540534780853966341044526856705589020295048473305762088786992446350060024881117741041260391405962817182674421715239197211274668450947666394594121764333794138308442124114744892164155894256326961605137479286082964520217
a = 2
m = 2
while True:
a = powmod(a, m, n)
p = gcd(a-1, n)
if p != 1 and p != n:
break
m += 1
q = n // p
phi = (p-1)*(q-1)
d = invert(t, phi)
e = powmod(y, d, n)
print(long_to_bytes(e))
#b'XYCTF{e==4096}'
#part2: 高次Rabin解flag,注意gift1和gift2不互素
from Crypto.Util.number import *
import gmpy2
gift1 = 4549402444746338327349007235818187793950285105091726167573552412678416759694660166956782755631447271662108564084382098562999950228708300902201571583419116299932264478381197034402338481872937576172197202519770782458343606060544694608852844228400457232100904217062914047342663534138668490328400022651816597367310
gift2 = 111061215998959709920736448050860427855012026815376672067601244053580566359594802604251992986382187891022583247997994146019970445247509119719411310760491983876636264003942870756402328634092146799825005835867245563420135253048223898334460067523975023732153230791136870324302259127159852763634051238811969161011462
n= 39332423872740210783246069030855946244104982381157166843977599780233911183158560901377359925435092326653303964261550158658551518626014048783435245471536959844874036516931542444719549997971482644905523459407775392702211086149279473784796202020281909706723380472571862792003687423791576530085747716706475220532321
c= 16938927825234407267026017561045490265698491840814929432152839745035946118743714566623315033802681009017695526374397370343984360997903165842591414203197184946588470355728984912522040744691974819630118163976259246941579063687857994193309554129816268931672391946592680578681270693589911021465752454315629283033043
e = 4096
p = gmpy2.gcd((gift1+gift2)//3,n)
q = n//p
print(p)
print(q)
p = 166353789373057352195268575168397750362643822201253508941052835945420624983216456266478176579651490080696973849607356408696043718492499993062863415424578199
q = 236438400477521597922950445153796265199072404577183190953114805170522875904551780358338769440558816351105253794964040981919231484098097671084895302287425479
pp = p%4
qq = q%4
print(pp)
print(qq)
#3
#3
n = p*q
def rabin(c):
mp = pow(c, (p + 1) // 4, p)
mq = pow(c, (q + 1) // 4, q)
yp = inverse(p,q)
yq = inverse(q,p)
r = (yp * p * mq + yq * q * mp) % n
r_ = n - r
s = (yp * p * mq - yq * q * mp) % n
s_ = n - s
return r,r_,s,s_
cs = [c] #把c放入列表里面
#[16938927825234407267026017561045490265698491840814929432152839745035946118743714566623315033802681009017695526374397370343984360997903165842591414203197184946588470355728984912522040744691974819630118163976259246941579063687857994193309554129816268931672391946592680578681270693589911021465752454315629283033043]
#循环12次罗宾算法
for i in range(12):
ps = [] #设置一个空列表用来存放最后结果
for c2 in cs:
r,r_,s,s_ = rabin(c2)
if r not in ps:
ps.append(r)
if r_ not in ps:
ps.append(r_)
if s not in ps:
ps.append(s)
if s_ not in ps:
ps.append(s_)
# print(ps)
cs = ps
for i in range(len(cs)):
print(long_to_bytes(cs[i]))
#XYCTF{Rabin_is_so_biggggg!}
fakeRSA
题目
无描述就是最好的描述,嘿嘿!
from Crypto.Util.number import *
flag = b'XYCTF{******}'
n = ZZ(bytes_to_long(flag))
p = getPrime(int(320))
print(p)
G = Zmod(p)
def function(X, Y, Z):
def part(a, b, c):
return vector([9 * a - 36 * c, 6 * a - 27 * c, b])
def parts(n):
Gx.<a, b, c> = G[]
if n == 0: return vector([a, b, c])
mid = parts(n // 2)
result = mid(*mid)
if n % 2 == 0: return result
else: return part(*result)
return parts(n)(X, Y, Z)
print(function(69, 48, 52))
#1849790472911267366045392456893126092698743308291512220657006129900961168811898822553602045875909
#(1431995965813617415860695748430644570118959991271395110995534704629241309597572003500157255135707, 1011565891130611736600822618382801465506651972373410962205810570075870804325974377971089090196019, 784497518859893244278116222363814433595961164446277297084989532659832474887622082585456138030246)
我的解答:
考点:矩阵相似对角化、jordan
题目给了一个 function ,输入的有 n 和三个常数 X Y Z 而 n 就是我们要的 flag。
part 函数对于三个输入 a,b,c 输出一个向量 [9a – 36c, 6a – 27c, b]。而且计算都是在 Fp 下运算的
parts 函数对于输入 n 使用 symbolic 的 a,b,c 做一些运算。仔细观察会发现这其实是一个很单纯的快速幂。
我们假设 part 代表一个未知的转换 T,mid = parts (n // 2) 计算 T[n/2] 然后 mid (*mid) 就是 ( T[n/2] )2
然后再看 n 的奇偶性考虑要不要再乘 T,因此 parts (n) 其实代表的就是 Tn(x)
而 part 代表的 T 本身其实很容易看出来是个矩阵乘法:
因此这道题简单来说就是给予 v = Anu 求 n,这有点像 discrete log。
要求矩阵的次方我们想到的第一件事是对角化看看,不过很容易就能发现,A 不可对角化。我们只能算 jordan form ,也就是求 A = PJP-1 其中 J 是一个上三角矩阵。
另外,我们知道:
因此 v = Anu 可以化成 v‘ = Jnu’ 其中 v‘ = P-1v 和 u’ = P-1u
而这道题的 J 我们可以算出来是:
上三角矩阵的次方很容易推出其通项公式,懒得手算了,直接用 WolframAlpha 来解吧
所以有:
其中的 a,b,c 和 a’,b’,c’分别是 u’,v’的三个维度,都是已知的值。由于 3n-2/2 未知,因此我们设成 k 方便处理。后面可以消掉。
两式相除得到
所以
exp:
from Crypto.Util.number import *
p = 1849790472911267366045392456893126092698743308291512220657006129900961168811898822553602045875909
G = Zmod(p)
A = matrix(G, [[9, 0, -36], [6, 0, -27], [0, 1, 0]])
u = vector(G, (69, 48, 52))
v = vector(
G,
(
1431995965813617415860695748430644570118959991271395110995534704629241309597572003500157255135707,
1011565891130611736600822618382801465506651972373410962205810570075870804325974377971089090196019,
784497518859893244278116222363814433595961164446277297084989532659832474887622082585456138030246,
),
)
J, P = A.jordan_form(transformation=True)
# A^n*v=u
# A=PJP^-1
# J^n*vv=uu
print(J)
vv = ~P * v
uu = ~P * u
a, b, c = uu
aa, bb, cc = vv
n = (18 * bb * c - 18 * b * cc) / (6 * c * cc)
print(n)
#11248090436223445352625693407089269386223255468324240386169564292825656540049141991068475773
print(long_to_bytes(int(n)))
#XYCTF{y0u_finally_f0und_t3h_s3cr3ts!!}
factor3
题目:
这个 e 咋比 n 还大啊 * 逆天!* 逆天!
from Crypto.Util.number import *
import random
flag = b'XYCTF{*****}'
m = bytes_to_long(flag)
def gainPrime():
while True:
x = random.getrandbits(256)
y = random.getrandbits(256)
if y % 2 == 0:
continue
p = x ** 3 + 3 * y ** 3
if p.bit_length() == 768 and p % 2 == 1 and isPrime(p):
return p
p, q = gainPrime(), gainPrime()
N = p * q
phi = (p ** 2 + p + 1) * (q ** 2 + q + 1)
d = getPrime(320)
e = inverse(d, phi)
c = d**2^m
print(f"N: {N}")
print(f"e: {e}")
print(f"c: {c}")
N: 913125842482770239379848062277162627509794409924607555622246822717218133091223291889541294440266178282194506242444509803611492259403578922020590849630191477864719052980160940803309686069818208833547621252544423652489179493083138385424424384165228024273745733240109761707533778691158938848158094054261174692601673435971526522219273943464877956131040249169850420336023942653021547841666224446678539579529590840999008107782784268926145671962239929431694391039559247
e: 494518390582436635999115147756676313570637682518235195828939117782099618734167908630788943568232122157772909140885391963441876427590731524706959546524212914108888799081844320513851526790475333924396837458796755678072486028072639014677580265244176441153444956871730684233063789931539669072735599696830757690822185323538738397827461580678488181113667710378657058297572328491762536595872579603698945272140918157163640403488075948987156585480146162739943419183496337465468187233821931312507662218106713861638334075899266373256620752680354704533272722692596941861606161634082613228896420520465402725359166156632884432690715903666803067996854084671477445131853993177110154928274312496230096270510089973592664248613332000290545537840595645944390047611474888693558676781309912289044962293014118087259307560444929227407113819165713213046898243995956550944640168932947118400215917515277554126694376415569909534496134700668701465649939
c: 4450931337369461482106945992542133557585962894030505065110870389112565329875502952762182372926117037373210509516570958483606566274369840551132381128665744266165792377925899683228751870742727716
我的解答:
考点:coppersmith-bounds、论文
我们有:
注意到 d 只有 320bits,非常小,所以说不定能透过以
去近似 phi,用 wiener attack 得到 k/d,不过实际上测试这个方法只有在 200 bits 的 d 才会成功。这样算不可举。
我们可以先推得
然后根据
得到:
设 s = p + q,然后 mod e 之后有:
这边的 k 和 d 都是同样大小 320bits, s = p + q 约 768-769bits 左右,一个容易被忽略的盲点是 phi 是 3072bits,所以 e 也是差不多的长度,所以 k,s 的大小符合 coppersmith 的 bounds,所以用 coppersmith 解出 s 后就能直接分解拿 d 了
exp:
from Crypto.Util.number import *
n = 913125842482770239379848062277162627509794409924607555622246822717218133091223291889541294440266178282194506242444509803611492259403578922020590849630191477864719052980160940803309686069818208833547621252544423652489179493083138385424424384165228024273745733240109761707533778691158938848158094054261174692601673435971526522219273943464877956131040249169850420336023942653021547841666224446678539579529590840999008107782784268926145671962239929431694391039559247
e = 494518390582436635999115147756676313570637682518235195828939117782099618734167908630788943568232122157772909140885391963441876427590731524706959546524212914108888799081844320513851526790475333924396837458796755678072486028072639014677580265244176441153444956871730684233063789931539669072735599696830757690822185323538738397827461580678488181113667710378657058297572328491762536595872579603698945272140918157163640403488075948987156585480146162739943419183496337465468187233821931312507662218106713861638334075899266373256620752680354704533272722692596941861606161634082613228896420520465402725359166156632884432690715903666803067996854084671477445131853993177110154928274312496230096270510089973592664248613332000290545537840595645944390047611474888693558676781309912289044962293014118087259307560444929227407113819165713213046898243995956550944640168932947118400215917515277554126694376415569909534496134700668701465649939
c = 4450931337369461482106945992542133557585962894030505065110870389112565329875502952762182372926117037373210509516570958483606566274369840551132381128665744266165792377925899683228751870742727716
P = PolynomialRing(Zmod(e), "k,s")
kk, ss = P.gens()
f = 1 + kk * (n ^ 2 + ss * (ss + n + 1) - n + 1)
load("coppersmith.sage")
k, s = small_roots(f, (2 ** 320, 2 ** 769), m=3, d=4)[0] # take ~1min
k, s = ZZ(k), ZZ(s)
print(k)
print(s)
sol = solve(x ^ 2 - s * x + n, (x,))
p = ZZ(sol[0].rhs())
q = ZZ(sol[1].rhs())
print(p)
print(q)
assert p * q == n
d = inverse_mod(e, (p ^ 2 + p + 1) * (q ^ 2 + q + 1))
print(d)
#k = 1251257306657373659654605739485817595695717202438149781637777849635371292306024253248630690054410
#s = 1925420229022578583406139554581551835655011964695773657501082158233633376833949737222087944109022904389943420455209060081354234597292378923627336957822763834975165642898757928184306157864510241547740313972548801708249946480791494352
#p = 1079692686288325812308630934214667048073665141240195252583556389192093937087035206847129125872559936616225942097278411602071282941911673739879515157769270737229378250560113256396308250699296075273110248314981762673299506406938725953
#q = 845727542734252771097508620366884787581346823455578404917525769041539439746914530374958818236462967773717478357930648479282951655380705183747821800053493097745787392338644671787997907165214166274630065657567039034950440073852768399
#d = 2109723047551375043305134722302342646596769444055829710618826161103186815230448177424794300667429
m = c^^d**2
print(long_to_bytes(m))
#b'XYCTF{I_love_to_read_the_crypto_paper_and_try_to_ak_them}'
coppersmith.sage
import itertools
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
if isinstance(f, Polynomial):
x, = polygens(f.base_ring(), f.variable_name(), 1)
f = f(x)
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m+1):
base = N^(m-i) * f^i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1/factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B*monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []