NSSCTF Crypto刷题速通记录,目的是查漏补缺,有疑问欢迎交流ξ( ✿>◡❛)
BASE 给了一个很长的十六进制文件,导入CyberChef开始解码。说实话,感觉出题人有点无聊了。 下面是解码顺序:
1 hex - base64 - base64 - hex - base64 - base32 - base32 - base32 - hex - base32 - base32 - base32 - base32 - base32 - hex - base32 - base32 - base64 - base32 - base64 - base64 - base32 - base32 - hex - base32 - base64 - base64 - hex - base64 - base64
你能看出这是什么加密吗 题目:
1 2 3 4 5 6 7 p=0x928fb6aa9d813b6c3270131818a7c54edb18e3806942b88670106c1821e0326364194a8c49392849432b37632f0abe3f3c52e909b939c91c50e41a7b8cd00c67d6743b4f q=0xec301417ccdffa679a8dcc4027dd0d75baf9d441625ed8930472165717f4732884c33f25d4ee6a6c9ae6c44aedad039b0b72cf42cab7f80d32b74061 e=0x10001 c=0x70c9133e1647e95c3cb99bd998a9028b5bf492929725a9e8e6d2e277fa0f37205580b196e5f121a2e83bc80a8204c99f5036a07c8cf6f96c420369b4161d2654a7eccbdaf583204b645e137b3bd15c5ce865298416fd5831cba0d947113ed5be5426b708b89451934d11f9aed9085b48b729449e461ff0863552149b965e22b6
解答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from Crypto.Util.number import * p=0x928fb6aa9d813b6c3270131818a7c54edb18e3806942b88670106c1821e0326364194a8c49392849432b37632f0abe3f3c52e909b939c91c50e41a7b8cd00c67d6743b4f q=0xec301417ccdffa679a8dcc4027dd0d75baf9d441625ed8930472165717f4732884c33f25d4ee6a6c9ae6c44aedad039b0b72cf42cab7f80d32b74061 e=0x10001 c=0x70c9133e1647e95c3cb99bd998a9028b5bf492929725a9e8e6d2e277fa0f37205580b196e5f121a2e83bc80a8204c99f5036a07c8cf6f96c420369b4161d2654a7eccbdaf583204b645e137b3bd15c5ce865298416fd5831cba0d947113ed5be5426b708b89451934d11f9aed9085b48b729449e461ff0863552149b965e22b6 phi = (p-1 )*(q-1 ) n = p*q d = inverse(e,phi) m = pow (c,d,n) ans = long_to_bytes(m)print (ans)
Vigenere 直接在线网站破解:https://www.guballa.de/vigenere-solver
Morse 摩斯电码解码 -> 十六进制数转字符
Single 观察代码发现是单表替换加密,直接quipquip在线解密即可: https://quipqiup.com/#google_vignette
可怜的RSA 题目:
分析: 在线解析公钥文件得到e和n 使用factordb分解n得到p和q 直接进行解密会发现不能出flag,这是因为加密过程中使用了OAEP填充解答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from Crypto.Util.number import *from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPfrom base64 import b64decode n = 79832181757332818552764610761349592984614744432279135328398999801627880283610900361281249973175805069916210179560506497075132524902086881120372213626641879468491936860976686933630869673826972619938321951599146744807653301076026577949579618331502776303983485566046485431039541708467141408260220098592761245010678592347501894176269580510459729633673468068467144199744563731826362102608811033400887813754780282628099443490170016087838606998017490456601315802448567772411623826281747245660954245413781519794295336197555688543537992197142258053220453757666537840276416475602759374950715283890232230741542737319569819793988431443 e = 65537 p = 3133337 q = 25478326064937419292200172136399497719081842914528228316455906211693118321971399936004729134841162974144246271486439695786036588117424611881955950996219646807378822278285638261582099108339438949573034101215141156156408742843820048066830863814362379885720395082318462850002901605689761876319151147352730090957556940842144299887394678743607766937828094478336401159449035878306853716216548374273462386508307367713112073004011383418967894930554067582453248981022011922883374442736848045920676341361871231787163441467533076890081721882179369168787287724769642665399992556052144845878600126283968890273067575342061776244939 c = b64decode(open ('可怜的RSA/flag.enc' , 'rb' ).read()) d = inverse(e, (p-1 )*(q-1 )) pk = RSA.construct((n,e,d,p,q)) cipher = PKCS1_OAEP.new(pk) m = cipher.decrypt(c)print (m)
One Secret, Two encryption 题目:
1 2 3 一份秘密发送给两个人不太好吧,那我各自加密一次好啦~~~ 素数生成好慢呀 偷个懒也……不会有问题的吧?
题目给了两组密文和公钥,解析后发现两组公钥的n不同,并结合题目所说,猜测两个n应该存在共同素数。解答:
1 2 3 4 5 6 7 8 9 10 11 from Crypto.Util.number import * n1 = 4850297138162223468826481623082440249579136876798312652735204698689613969008632545220976699170308454082390834742570718247804202060929493571642074679428565168405877110681518105667301785653517697684490982375078989886040451115082120928982588380914609273008153977907950532498605486225883973643141516024058315360572988744607134110254489421516026937249163493982681336628726033489124705657217768229058487155865265080427488028921879608338898933540825564889012166181346177276639828346376362168934208822467295673761876965864573164529336885250577357767314256581019474130651412100897839606491189424373959244023695669653213498329 n2 = 2367536768672000959668181171787295271898789288397672997134843418932405959946739637368044420319861797856771490573443003520137149324080217971836780570522258661419034481514883068092752166752967879497095564732505614751532330408675056285275354250157955321457579006360393218327164804951384290041956551855334492796719901818165788902547584563455747941517296875697241841177219635024461395596117584194226134777078874543699117761893699634303571421106917894215078938885999963580586824497040073241055890328794310025879014294051230590716562942538031883965317397728271589759718376073414632026801806560862906691989093298478752580277 e = 65537 p = GCD(n1, n2) q = n2 // p c2 = bytes_to_long(open ('One Secret, Two encryption/flag_encry2' , 'rb' ).read()) d = inverse(65537 , (p-1 )*(q-1 )) m = pow (c2, d, n2) ans = long_to_bytes(m)print (ans)
MagicNum 题目:
1 2 3 4 5 6 72065910510177138000000000000000.000000 71863209670811371000000.000000 18489682625412760000000000000000.000000 72723257588050687000000.000000 4674659167469766200000000.000000 19061698837499292000000000000000000000.000000
分析: 本题应该是MISC题,根据分析,题目应该是要转换成IEEE 754单精度浮点数小端序,然后再转换ASCII字符解答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import structfrom Crypto.Util.number import long_to_bytes nums = [72065910510177138000000000000000.000000 , 71863209670811371000000.000000 , 18489682625412760000000000000000.000000 , 72723257588050687000000.000000 , 4674659167469766200000000.000000 , 19061698837499292000000000000000000000.000000 ] a = '' for i in nums: i = float (i) a += struct.pack('<f' ,i).hex () print (a)print (long_to_bytes(int (a,16 )))
MyOwnCBC 题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from Crypto.Cipher import AESfrom Crypto.Random import randomfrom Crypto.Util.number import long_to_bytesdef MyOwnCBC (key, plain ): if len (key)!=32 : return "error!" cipher_txt = b"" cipher_arr = [] cipher = AES.new(key, AES.MODE_ECB, "" ) plain = [plain[i:i+32 ] for i in range (0 , len (plain), 32 )] print (plain) cipher_arr.append(cipher.encrypt(plain[0 ])) cipher_txt += cipher_arr[0 ] for i in range (1 , len (plain)): cipher = AES.new(cipher_arr[i-1 ], AES.MODE_ECB, "" ) cipher_arr.append(cipher.encrypt(plain[i])) cipher_txt += cipher_arr[i] return cipher_txt key = random.getrandbits(256 ) key = long_to_bytes(key) s = "" with open ("flag.txt" ,"r" ) as f: s = f.read() f.close()with open ("flag_cipher" ,"wb" ) as f: f.write(MyOwnCBC(key, s)) f.close()
分析: 根据代码分析,可以发现题目对明文进行了AES分组加密,但是只有第一组是使用随机生成的密钥加密的,后面其他组都是使用前一组的密文作为密钥进行加密的,也就是说,除了第一组,其他所有组的密钥我们都知道,可以求出除了第一组外的所有明文。解答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from Crypto.Cipher import AESwith open ("MyOwnCBC/flag_cipher" ,"rb" ) as f: c = f.read() f.close()def MyOwnCBC_decrypt (cipher_txt ): cipher_arr = [cipher_txt[i:i+32 ] for i in range (0 , len (cipher_txt), 32 )] plain_txt = b'' for i in range (len (cipher_arr)-1 ,1 ,-1 ): plain = AES.new(cipher_arr[i-1 ], AES.MODE_ECB) plain_txt = plain.decrypt(cipher_arr[i]) + plain_txt return plain_txt m = MyOwnCBC_decrypt(c)print (m)
Tiny LFSR 题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import sysfrom binascii import unhexlifyif (len (sys.argv)<4 ): print ("Usage: python Encrypt.py keyfile plaintext ciphername" ) exit(1 )def lfsr (R, mask ): output = (R << 1 ) & 0xffffffffffffffff i=(R&mask)&0xffffffffffffffff lastbit=0 while i!=0 : lastbit^=(i&1 ) i=i>>1 output^=lastbit return (output,lastbit) R = 0 key = "" with open (sys.argv[1 ],"r" ) as f: key = f.read() R = int (key,16 ) f.close mask = 0b1101100000000000000000000000000000000000000000000000000000000000 a = '' .join([chr (int (b, 16 )) for b in [key[i:i+2 ] for i in range (0 , len (key), 2 )]]) f=open (sys.argv[2 ],"r" ) ff = open (sys.argv[3 ],"wb" ) s = f.read() f.close() lent = len (s)for i in range (0 , len (a)): ff.write((ord (s[i])^ord (a[i])).to_bytes(1 , byteorder='big' ))for i in range (len (a), lent): tmp=0 for j in range (8 ): (R,out)=lfsr(R,mask) tmp=(tmp << 1 )^out ff.write((tmp^ord (s[i])).to_bytes(1 , byteorder='big' )) ff.close()
分析: 题目给出了一组对应的明密文文件,我们通过分析可以发现,通过明密文直接异或的前一部分便是key。 因此我们可以直接恢复出key,由于加解密都是异或操作,所以使用得到的密钥,结合题目文件的加密再对flag_encode.txt
进行一次加密即可得到明文。解答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 plaintext = open ("Tiny LFSR\\Plain.txt" , "rb" ).read() ciphertext = open ("Tiny LFSR\\cipher.txt" , "rb" ).read() key_bytes = []for i in range (min (len (plaintext), len (ciphertext))): key_bytes.append(plaintext[i] ^ ciphertext[i]) key = '' .join(['%02x' % b for b in key_bytes])print ("Recovered key:" , key)def lfsr (R, mask ): output = (R << 1 ) & 0xffffffffffffffff i=(R&mask)&0xffffffffffffffff lastbit=0 while i!=0 : lastbit^=(i&1 ) i=i>>1 output^=lastbit return (output,lastbit) R = int (key,16 ) mask = 0b1101100000000000000000000000000000000000000000000000000000000000 a = '' .join([chr (int (b, 16 )) for b in [key[i:i+2 ] for i in range (0 , len (key), 2 )]]) f=open ("Tiny LFSR\\flag_encode.txt" ,"rb" ) ff = open ("Tiny LFSR\\flag.txt" ,"wb" ) s = f.read() f.close() lent = len (s)for i in range (0 , len (a)): ff.write((s[i]^ord (a[i])).to_bytes(1 , byteorder='big' ))for i in range (len (a), lent): tmp=0 for j in range (8 ): (R,out)=lfsr(R,mask) tmp=(tmp << 1 )^out ff.write((tmp^s[i]).to_bytes(1 , byteorder='big' )) ff.close()
你听说过一次一密吗 貌似这题题目有些问题,而且之前在BUU上刷过,此次目的是查漏补缺,这里就不再多写了,直接上大佬讲解:Many-Time-Pad 攻击
花开藏宝地 题目附件有5个压缩包,根据提示分析,5个压缩包分别为数字爆破、小写字母爆破、大写字母爆破、伪加密、ntfs流隐写 最后获取到五组数据:
1 2 3 4 5 6 7 8 9 10 x1 = 305345133911395218573790903508296238659147802274031796643017539011648802808763162902335644195648525375518941848430114497150082025133000033835083076541927530829557051524161069423494451667848236452337271862085346869364976989047180532167560796470067549915390773271207901537847213882479997325575278672917648417868759077150999044891099206133296336190476413164240995177077671480352739572539631359 m1 = 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820813413 x2 = 152012681270682340051690627924586232702552460810030322267827401771304907469802591861912921281833890613186317787813611372838066924894691892444503039545946728621696590087591246339208248647926966446848123290344911662916758039134817404720512465817867255277476717353439505243247568126193361558042940352204093381260402400739429050280526212446967632582771424597203000629197487733610187359662268583 m2 = 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820818553 x3 = 40952412095267791829743119118333311932687870987919948671780408726886151430242690997238831410249436653299224291445012397813221016909468630372862610415470277301591535416193017906909638241212666990959976187895288689640250810487806568164431359887246760313154046201720715301307811951233077581047872827004824833876458687145628724339714212107812941785880896399800008924818580623979723496070665230 m3 = 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820819351 x4 = 100459779913520540098065407420629954816677926423356769524759072632219106155849450125185205557491138357760494272691949199099803239098119602186117878931534968435982565071570831032814288620974807498206233914826253433847572703407678712965098320122549759579566316372220959610814573945698083909575005303253205653244238542300266460559790606278310650849881421791081944960157781855164700773081375247 m4 = 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820820091 x5 = 230502064382947282343660159791611936696520807970361139469603458689311286041516767875903549263861950740778705012699983268093626403307298415066249636346303539570207577050391796770068203937723627361951969413683246596072925692670365490970847825269581004483964261491917680759091791653759514213188778401968676433284753781006738293752440186858616315727565803777032119737689210471541053061940547213 m5 = 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820822249
题目还给了一个数据:
1 80804238007977405688648566160504278593148666302626415149704905628622876270862865768337953835725801963142685182510812938072115996355782396318303927020705623120652014080032809421180400984242061592520733710243483947230962631945045134540159517488288781666622635328316972979183761952842010806304748313326215619695085380586052550443025074501971925005072999275628549710915357400946408857
原本没看懂是什么,后来搜了一下才知道是Asmuth-Bloom门限方案,参考:Secret Sharing - Web Encrypt 直接上脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import mathfrom Crypto.Util.number import long_to_bytes remainders = [305345133911395218573790903508296238659147802274031796643017539011648802808763162902335644195648525375518941848430114497150082025133000033835083076541927530829557051524161069423494451667848236452337271862085346869364976989047180532167560796470067549915390773271207901537847213882479997325575278672917648417868759077150999044891099206133296336190476413164240995177077671480352739572539631359 , 152012681270682340051690627924586232702552460810030322267827401771304907469802591861912921281833890613186317787813611372838066924894691892444503039545946728621696590087591246339208248647926966446848123290344911662916758039134817404720512465817867255277476717353439505243247568126193361558042940352204093381260402400739429050280526212446967632582771424597203000629197487733610187359662268583 , 40952412095267791829743119118333311932687870987919948671780408726886151430242690997238831410249436653299224291445012397813221016909468630372862610415470277301591535416193017906909638241212666990959976187895288689640250810487806568164431359887246760313154046201720715301307811951233077581047872827004824833876458687145628724339714212107812941785880896399800008924818580623979723496070665230 ] moduli = [347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820813413 , 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820818553 , 347051559622463144539669950096658163425646411435797691973701513725701575100810446175849424000000075855070430240507732735393411493866540572679626172742301366146501862670272443070970511943485865887494229487420503750457974262802053722093905126235340380261828593508455621667309946361705530667957484731929151875527489478449361198648310684702574627199321092927111137398333029697068474762820819351 ] P = 80804238007977405688648566160504278593148666302626415149704905628622876270862865768337953835725801963142685182510812938072115996355782396318303927020705623120652014080032809421180400984242061592520733710243483947230962631945045134540159517488288781666622635328316972979183761952842010806304748313326215619695085380586052550443025074501971925005072999275628549710915357400946408857 def crt (rs, ms ): total = 0 prod = math.prod(ms) for r, m in zip (rs, ms): p = prod // m total += r * pow (p, -1 , m) * p return total % prodprint (long_to_bytes(crt(remainders, moduli)%P))
一道有趣的题目 题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def encrypt (plainText ): space = 10 cipherText = "" for i in range (len (plainText)): if i + space < len (plainText) - 1 : cipherText += chr (ord (plainText[i]) ^ ord (plainText[i + space])) else : cipherText += chr (ord (plainText[i]) ^ ord (plainText[space])) if ord (plainText[i]) % 2 == 0 : space += 1 else : space -= 1 return cipherText
分析: 本题是一道算法逆向分析题,但是逆向求解时我们不知道space
的具体值,也就没办法确定对应的计算方程。 但是我们可以发现密文的字节长度只有28,因此我们可以尝试爆破每一位明文的最后一位bit(总共约$2^{28}$种可能的序列),这样我们便能求出正确的space
序列。 如何判断每个明文lastbit(即代码中的seq)
序列是否正确呢?由于加密算法使用的是异或,因此可以利用加密算法来单独对明文的lastbit
进行加密,再对比密文的lastbit
是否一一对应,若确实一一对应,那大概率是正确的lastbit
序列。 之后再通过我们已知的部分明文字节afctf{
,便可以逆向求解了。解答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 from tqdm import trange cipher = bytes .fromhex("15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206" )def get_lastbit (): space = 10 for x in trange(2 **28 ): seq = bin (x)[2 :].zfill(28 ) space = 10 f = 1 for i in range (28 ): if i + space < 28 - 1 : tx = int (seq[i]) ^ int (seq[i + space]) else : tx = int (seq[i]) ^ int (seq[space]) if tx != cipher[i] % 2 : f = 0 break if int (seq[i]) % 2 == 0 : space += 1 else : space -= 1 if f == 1 : print (seq) return seqdef decrypt (cipher_bytes, known_prefix=b'afctf{' ): plain = [0 ] * len (cipher_bytes) space = 10 seq = get_lastbit() print (seq) seq_bits = [int (b) for b in str (seq)] print (seq_bits) space_list = [] for i in range (len (seq_bits)): if seq_bits[i] % 2 == 0 : space += 1 else : space -= 1 space_list.append(space) print (space_list) for i in range (len (known_prefix)): plain[i] = known_prefix[i] for i in range (len (cipher_bytes)-1 ,0 ,-1 ): if i + space_list[i-1 ] < len (cipher_bytes): plain[i] = plain[i + space_list[i-1 ]] ^ cipher_bytes[i] else : plain[i] = plain[space_list[i-1 ]] ^ cipher_bytes[i] return bytes (plain) flag = decrypt(cipher)print (flag)