2024_ctfshow_西瓜杯复现 ctfshow西瓜杯wp
前言
整体来说,这次的西瓜杯的题目非常有意思,收获还是挺多的。大家可以去ctfshow上面复现复现
网址链接:ctf.show
官方wp:XGCTF(西瓜杯官方wp)
MISC
她说她想结婚
考点:文件分离,snow隐写,0kb文件隐写,oursecret隐写,base解码
先解压得到一张图片,常规放入010查看
发现后面有一些乱码字符和一个压缩包,先手动提取压缩包。提取后直接解压可能会出现问题,我当时就是卡在这了(悲),需要先修改伪加密,即将14000900全部替换为14000000,然后再解压。
看见flag文件,直接打开看看怎么个事
发现全是非中文字符,是编码问题,不麻烦可以直接拖到浏览器,后面面明显的SNOW隐写,那就要找密码了。可以看到文本似乎全是重复这一段话的,根据图片上的文字和提示可以知道密码是 你们耳朵是聋了吗
使用SNOW隐写工具得到前半段flag
根据iscc的经验还有文件明显特征,我们知道前面文件是时间戳隐写,使用脚本直接提取,脚本如下
import os
filename = "C:\\Users\\atlan\\Downloads\\1\\10.txt"
file_attr = os.stat(filename)#读取文件属性
alter_time = file_attr.st_mtime#获取修改时间
print(alter_time)
import os
for i in range(11):
filename = "C:\\Users\\atlan\\Downloads\\1\\{0}.txt".format(i)
file_attr = os.stat(filename)#读取文件属性
alter_time = str(file_attr.st_mtime)#获取修改时间
print(chr(int(alter_time[7:10])),end='')
运行得到 key:ctfSh0w
前面我们说到png文件尾和zip文件头之间还有一些乱码之类的东西,9E97BA2A,这个是oursecret的加密特征
根据上面得到的key,放入oursecret解密,得到base64编码,一直解密得到后半段flag:happy_time_pl4ying}
flag值:ctfshow{W1sh1ng_every0ne_4_happy_time_pl4ying}
你是我的眼
打开是一个jar文件,使用jadx反编译工具直接打开,查看源码
查看main类,代码意思是先将 Q1RGU2hvd3tURVNUX0JBU0U2NF9CSUFOTUF9Xw- 字符串使用customDecode()方法进行解码,再将解码后的“_”和“\u000f”替换为空
再看prompt类,是将空格替换为“_”
综上,先解码,再把下划线替换的位置换为空,还需要再换回来,所以直接解码就是flag
flag值:CTFShow{TEST_BASE64_BIANMA}
SignIn
一张图片,隐藏着三个二维码,直接使用Tokeii神的工具梭
直接放入我们得到第二段flag 2:QRc0de_,将预计二维码个数调高一点,得到剩余两段flag
flag:ctfshow{Ai_Art_QRc0de_iS_Amz!}
CRYPTO
奇怪的条形码
使用画图工具调整长宽像素大小,再经过base64解码得到flag
flag值:ctfshow{xigubei_misc_gram_here_flag}
简单密码
题目给出一串字符,像是十六进制字符,尝试直接解码失败
647669776d757e83817372816e707479707c888789757c92788d84838b878d9d
发现ctfshow的十六进制为63 74 66 73 68 6f 77,刚好是题目给出的十六进制两位转字符,第i个字符减去i得到的,根据此规律写脚本
str = "647669776d757e83817372816e707479707c888789757c92788d84838b878d9d"
str = bytes.fromhex(str)
flag = ''
for i in range(len(str)):
tmp = str[i] - i - 1
flag += chr(tmp)
print(flag)
# ctfshow{xiguabei_just_ez_signin}
flag值:ctfshow{xiguabei_just_ez_signin}
factor
from Crypto.Util.number import *
import gmpy2
import os
from enc import flag
hint = os.urandom(36)
tmp = bytes_to_long(hint)
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
d = getPrime(400)
phi = (p-1)*(q-1)
e = gmpy2.invert(d,phi)
n = p*q
c = pow(m,e,n)
leak1 = p^tmp
leak2 = q^tmp
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
print(f"leak1 = {leak1}")
print(f"leak2 = {leak2}")
'''
n = 145462084881728813723574366340552281785604069047381248513937024180816353963950721541845665931261230969450819680771925091152670386983240444354412170994932196142227905635227116456476835756039585419001941477905953429642459464112871080459522266599791339252614674500304621383776590313803782107531212756620796159703
e = 10463348796391625387419351013660920157452350067191419373870543363741187885528042168135531161031114295856009050029737547684735896660393845515549071092389128688718675573348847489182651631515852744312955427364280891600765444324519789452014742590962030936762237037273839906251320666705879080373711858513235704113
c = 60700608730139668338977678601901211800978306010063875269252006068222163102100346920465298044880066999492746508990629867396189713753873657197546664480233269806308415874191048149900822050054539774370134460339681949131037133783273410066318511508768512778132786573893529705068680583697574367357381635982316477364
leak1 = 13342820281239625174817085182586822673810894195223942279061039858850534510679297962596800315875604798047264337469828123370586584840078728059729121435462780
leak2 = 10901899434728393473569359914062349292412269512201554924835672710780580634465799069211035290729536290605761024818770843901501694556825737462457471235151530
'''
分析:tmp相当于一个随机数了,leak1 = p^tmp,leak2 = q^tmp,根据异或的性质可以知道leak1^leak2 = p^q,接下来直接使用p^q的脚本解题得到flag
import gmpy2
import libnum
n1 = 145462084881728813723574366340552281785604069047381248513937024180816353963950721541845665931261230969450819680771925091152670386983240444354412170994932196142227905635227116456476835756039585419001941477905953429642459464112871080459522266599791339252614674500304621383776590313803782107531212756620796159703
leak1 = 13342820281239625174817085182586822673810894195223942279061039858850534510679297962596800315875604798047264337469828123370586584840078728059729121435462780
leak2 = 10901899434728393473569359914062349292412269512201554924835672710780580634465799069211035290729536290605761024818770843901501694556825737462457471235151530
x1 = leak1 ^ leak2
x1 = bin(x1)[2:].zfill(512)
pre_sol = [(0, 0)]
for x in range(512 - 1, -1, -1):
cur_pow = pow(2, len(x1) - x - 1)
print(cur_pow)
cur_sol = []
for p, q in pre_sol:
for i in range(2):
for j in range(2):
if str((i + j) % 2) == x1[x]:
cur_p = p + i * cur_pow
cur_q = q + j * cur_pow
if cur_p * cur_q % pow(2, len(x1) - x) == n1 % pow(2, len(x1) - x):
cur_sol.append((cur_p, cur_q))
pre_sol = cur_sol
for p, q in pre_sol:
if p * q == n1:
print(p, q)
break
n=n1
e = 10463348796391625387419351013660920157452350067191419373870543363741187885528042168135531161031114295856009050029737547684735896660393845515549071092389128688718675573348847489182651631515852744312955427364280891600765444324519789452014742590962030936762237037273839906251320666705879080373711858513235704113
c = 60700608730139668338977678601901211800978306010063875269252006068222163102100346920465298044880066999492746508990629867396189713753873657197546664480233269806308415874191048149900822050054539774370134460339681949131037133783273410066318511508768512778132786573893529705068680583697574367357381635982316477364
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(libnum.n2s(int(m)))
# cftshow{do_you_know_what_is_xor_and_prune!!!}
混合密码体系
# 库
from Crypto.Util.number import bytes_to_long,getPrime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
# 对称加密
flag = b'ctfshow{***}' # 密文,隐藏
key = b'flag{***}' # 会话密钥,隐藏
iv = b'flag{1fake_flag}' # AES偏移向量,已知
# 对明文进行填充,使其长度符合AES加密的要求
padded_plaintext = pad(flag, AES.block_size)
# 创建AES加密对象
cipher = AES.new(key, AES.MODE_CBC, iv)
# 加密
ciphertext = cipher.encrypt(padded_plaintext)
# 加密后的文本通常是字节串,转成整数便于进行会话密钥的RSA加密
c1 = bytes_to_long(ciphertext)
print(f'c1 = {c1}')
# 非对称加密
m = bytes_to_long(key)
e = 0x10001
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m,e,n)
print(f'p = {p}')
print(f'q = {q}')
print(f'n = {n}')
print(f'c2 = {c}')
# print("hint:key需要转成字节流也就是b''")
'''
c1 = 10274623386006297478525964130173470046355982953419353351509177330015001060887455252482567718546651504491658563014875
p = 126682770761631193509957156425049279522830651950325320826580754739365086374362604934854454428815835196844469535588686149210573266628767888593088817059600076401582225549728184309047483547810100015820325082976781284679340880386138390518973395696206374336712856387090369022746536868747455939074262253452873845903
q = 99825079362327808334563489684167271427241139432727401182808888165552821217781929397837262324242177528386988701584385208395369790542025175917752058047649096340776854252623173162664426065810683048016574420043010318337693586527652970534982946701493024718805916479479658257730226388868060010370893747360166996939
n = 12646117645119414744807511144503229609414192869007113075368323921021672404219693075011763838210400633721060798765473421092201704833591315689681668160927426685183273670665030724394172000165517517884654100267567861284096827407481978978840602383267875832034344793848710383473014512122260278131503985961857107838296047172582364612603344429943715046318283653354068887129071531081918798285138812386418361474496678248683513378861801570673376726388110813411011818940310547686977359605296489433805717348250520973842927175837164120905300831792358190183785344002217291207378744610039145999012939983693891188308725179098958690917
c2 = 5211902378262010726785508340196935051860438587769647187076059600864676774592415052428465708887047312982844957691943180258845015420187239772414768121857728821510440178906193308448250067671679439841031484589864038401572589752057423667532898133171822921282769652197139455317095891357335645435094243006629469245881345449943250189771998449015275390517315432969774421721243965028796050948747282387052634211032729131656214346307483397410725129682422969273915759947596313513270946529649661334582775282060624547405060499311618257517792321792697831000977711752728887999320311631022598717946355057272761740061999974856808147244
'''
分析:本质上就是使用了RSA数据的AES解密题,已知p,q,e,c,可以用基础脚本直接得到key
import libnum
e = 65537
p = 126682770761631193509957156425049279522830651950325320826580754739365086374362604934854454428815835196844469535588686149210573266628767888593088817059600076401582225549728184309047483547810100015820325082976781284679340880386138390518973395696206374336712856387090369022746536868747455939074262253452873845903
q = 99825079362327808334563489684167271427241139432727401182808888165552821217781929397837262324242177528386988701584385208395369790542025175917752058047649096340776854252623173162664426065810683048016574420043010318337693586527652970534982946701493024718805916479479658257730226388868060010370893747360166996939
n = 12646117645119414744807511144503229609414192869007113075368323921021672404219693075011763838210400633721060798765473421092201704833591315689681668160927426685183273670665030724394172000165517517884654100267567861284096827407481978978840602383267875832034344793848710383473014512122260278131503985961857107838296047172582364612603344429943715046318283653354068887129071531081918798285138812386418361474496678248683513378861801570673376726388110813411011818940310547686977359605296489433805717348250520973842927175837164120905300831792358190183785344002217291207378744610039145999012939983693891188308725179098958690917
c = 5211902378262010726785508340196935051860438587769647187076059600864676774592415052428465708887047312982844957691943180258845015420187239772414768121857728821510440178906193308448250067671679439841031484589864038401572589752057423667532898133171822921282769652197139455317095891357335645435094243006629469245881345449943250189771998449015275390517315432969774421721243965028796050948747282387052634211032729131656214346307483397410725129682422969273915759947596313513270946529649661334582775282060624547405060499311618257517792321792697831000977711752728887999320311631022598717946355057272761740061999974856808147244
n=p*q
phi_n=(p-1)*(q-1)
#求逆元
d=libnum.invmod(e,phi_n)
m=pow(c,d,n)
print(m)
#数字转字节,转字符串
print(libnum.n2s(int(m)).decode())
# flag{**********}
得到key的值,有了key和iv,再写脚本将c1进行AES解密,得到flag
from Crypto.Util.number import bytes_to_long,getPrime,long_to_bytes
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import gmpy2
c1 = 10274623386006297478525964130173470046355982953419353351509177330015001060887455252482567718546651504491658563014875
iv = b'flag{1fake_flag}'
key = b'flag{**********}'
cipher = AES.new(key, AES.MODE_CBC, iv)
flag = cipher.decrypt(long_to_bytes(c1))
print(unpad(flag, AES.block_size))
# ctfshow{Hybrid_password_system_is_chaos}
flag值:ctfshow{Hybrid_password_system_is_chaos}
RE
pe
修复PE文件头,把ZM改成MZ,运行就能得到flag
flag值:CTFShow{i95f5417b37c5e8019372de8737fI}
探索进制转换的奥秘
先查壳,无壳,32位程序,直接用IDA打开
直接就能看到一串十六进制字符,解码就得到flag
flag值:CTFShow{Thank_CTFSHOW_Sky}
一个西瓜切两半你一半我一半
在线pyc反编译
分析一下脚本:先依次提取flag里的字符,将其ASCII码减去32,然后将其转换回字符,存到tmp里,再将tmp中每个字符ASCII码与key字符串中对应位置的字符的ASCII码相加,然后将其转换回字符,将字符添加到crypt字符串中。
接下来就直接写脚本
key = "一个西瓜切两半你一半我一半"
crypt = "乃乾觅甯剏乳厡侻丨厏扝乌博丿乜规甲剌乶厝侥丿卻扚丠厘丿乎覟瓬剤"
tmp = ""
for i in range(len(crypt)):
tmp += chr(ord(crypt[i]) - ord(key[i % len(key)]))
flag=''
for i in tmp:
flag += chr(ord(i) + 32)
print(flag)
# ctfshow{Hell0_Reverse_Qi@n_D@0}
flag值:ctfshow{Hell0_Reverse_Qi@n_D@0}
E
IDA打开,shift+f12快速查找字符串,看到一串base64编码的字符串,解码,得到flag
flag值:CTFSHOW{JIAMI_SHOW_YAN}
WEB
CodeInject
先闭合前面的括号,再把要执行的命令拼接上,后面直接注释掉
1=1);system('ls /');//
使用cat命令得到flag
1=1);system('cat /000f1ag.txt');//