UofTCTF 2024 比赛记录

打印 上一主题 下一主题

主题 844|帖子 844|积分 2532

这次的题目挺有意思,难度适中,*开头的代表未做出,简单记录一下解题笔记。
Introduction

General Information

题目
The flag format for all challenges is UofTCTF{...}, case insensitive. If you are experiencing technical difficulties with challenges, support is on our Discord server: https://discord.gg/Un7avdkq7Z. The flag for this challenge is UofTCTF{600d_1uck}.
我的解答:
介绍题,没啥说的直接给了
UofTCTF{600d_1uck}
Cryptography

repeat

题目
I'm a known repeat offender when it comes to bad encryption habits. But the secrets module is secure, so you'll never be able to guess my key!
Author: SteakEnthusiast
gen.py
  1. import os
  2. import secrets
  3. flag = "REDACATED"
  4. xor_key = secrets.token_bytes(8)
  5. def xor(message, key):
  6.     return bytes([message[i] ^ key[i % len(key)] for i in range(len(message))])
  7. encrypted_flag = xor(flag.encode(), xor_key).hex()
  8. with open("flag.enc", "w") as f:
  9.     f.write("Flag: "+encrypted_flag)
复制代码
flag.enc
  1. Flag: 982a9290d6d4bf88957586bbdcda8681de33c796c691bb9fde1a83d582c886988375838aead0e8c7dc2bc3d7cd97a4
复制代码
我的解答:
标准的XOR加密,从题目可知,密钥长度为8个字节,这个是非常重要的。因为我们知道flag的前8个字节“uoftctf”
因此,由于XOR是个可逆函数,我们可以很容易得到flag
exp:
  1. from binascii import unhexlify
  2. from Crypto.Util.strxor import strxor
  3. ct = unhexlify("982a9290d6d4bf88957586bbdcda8681de33c796c691bb9fde1a83d582c886988375838aead0e8c7dc2bc3d7cd97a4")
  4. key = strxor(ct[:8], b'uoftctf{')
  5. def xor(message, key):
  6.     return bytes([message[i] ^ key[i % len(key)] for i in range(len(message))])
  7. flag = xor(ct, key)
  8. print(flag)
  9. #uoftctf{x0r_iz_r3v3rs1bl3_w17h_kn0wn_p141n73x7}
复制代码
Pianoman

题目
Windy, a piano prodigy, believes that RSA encryption may not provide sufficient security to safeguard his invaluable piano mastery secrets. So, he uses his musical talents to add another layer of security to the RSA encryption scheme. Now, no one will be able to figure out his secrets!
Note: The flag is UofTCTF{plaintext}.
Author: XiaoXiangjiao
Windy是一位钢琴神童,他认为RSA加密可能无法提供足够的安全性来保护他宝贵的钢琴掌握秘密。因此,他利用自己的音乐天赋为 RSA 加密方案增加了另一层安全性。现在,没有人能够弄清楚他的秘密!
注意:标志是 UofTCTF{plaintext}。
music_cipher.py
  1. # no secrets for you!
  2. flag = ...
  3. # Prime numbers
  4. p = 151974537061323957822386073908385085419559026351164685426097479266890291010147521691623222013307654711435195917538910433499461592808140930995554881397135856676650008657702221890681556382541341154333619026995004346614954741516470916984007797447848200982844325683748644670322174197570545222141895743221967042369
  5. q = 174984645401233071825665708002522121612485226530706132712010887487642973021704769474826989160974464933559818767568944237124745165979610355867977190192654030573049063822083356316183080709550520634370714336131664619311165756257899116089875225537979520325826655873483634761961805768588413832262117172840398661229
  6. n = p * q
  7. # a public exponent hidden away by Windy's musical talents
  8. e = ...
  9. # Converting the message to an integer
  10. m = int.from_bytes(message.encode(), 'big')
  11. # Encrypting the message: c = m^e mod n
  12. inc_m = pow(message_int, e, n)
  13. print(encrypted_message_int)
复制代码
musical_e.png

output.txt
  1. 13798492512038760070176175279601263544116956273815547670915057561532348462120753731852024424193899030774938204962799194756105401464136384387458651343975594539877218889319074841918281784494580079814736461158750759327630935335333130007375268812456855987866715978531148043248418247223808114476698088473278808360178546541128684643502788861786419871174570376835894025839847919827231356213726961581598139013383568524808876923469958771740011288404737208217659897319372970291073214528581692244433371304465252501970552162445326313782129351056851978201181794212716520630569898498364053054452320641433167009005762663177324539460
复制代码
我的解答:
看了一下题目发现我们只要找到e,这道题就解决了
给了一个图片显然可以找到e,属于Music Sheet Cipher密码

e = 7029307
exp:
  1. import gmpy2
  2. from Crypto.Util.number import *
  3. p = 151974537061323957822386073908385085419559026351164685426097479266890291010147521691623222013307654711435195917538910433499461592808140930995554881397135856676650008657702221890681556382541341154333619026995004346614954741516470916984007797447848200982844325683748644670322174197570545222141895743221967042369
  4. q = 174984645401233071825665708002522121612485226530706132712010887487642973021704769474826989160974464933559818767568944237124745165979610355867977190192654030573049063822083356316183080709550520634370714336131664619311165756257899116089875225537979520325826655873483634761961805768588413832262117172840398661229
  5. c= 13798492512038760070176175279601263544116956273815547670915057561532348462120753731852024424193899030774938204962799194756105401464136384387458651343975594539877218889319074841918281784494580079814736461158750759327630935335333130007375268812456855987866715978531148043248418247223808114476698088473278808360178546541128684643502788861786419871174570376835894025839847919827231356213726961581598139013383568524808876923469958771740011288404737208217659897319372970291073214528581692244433371304465252501970552162445326313782129351056851978201181794212716520630569898498364053054452320641433167009005762663177324539460
  6. e = 7029307
  7. n = p*q
  8. phi = (p-1) * (q-1)
  9. d = gmpy2.invert(e, phi)
  10. m = pow(c, d, n)
  11. print(long_to_bytes(m))
  12. #uoftctf{AT1d2jMCVs03xxalViU9zTyiiV1INNJY}
复制代码
Clever Thinking

题目
I think that Diffie-Hellman is better with some curves, maybe elliptic ones. Let's share a secret!
Wrap the secret (which is a point) in uoftctf{(x:y:z)}, where (x:y:z) are homogeneous coordinates.
Author: Phoenix
我认为 Diffie-Hellman 更适合一些曲线,也许是椭圆形曲线。让我们分享一个秘密!
将密钥(即一个点)包装在 uoftctf{(x:y:z)} 中,其中 (x:y:z) 是齐次坐标。
chal.sage
  1. m = 235322474717419
  2. F = GF(m)
  3. C = EllipticCurve(F, [0, 8856682])
  4. public_base = (185328074730054:87402695517612:1)
  5. Q1 = (184640716867876:45877854358580:1) # my public key
  6. Q2 = (157967230203538:128158547239620:1) # your public key
  7. secret = ...
  8. my_private_key = ...
  9. assert(my_private_key*public_base == Q1)
  10. assert(my_private_key*Q2 == secret)
复制代码
我的解答:
这是非常标准的椭圆加密。
基本上,我们的私钥乘以公钥的标量乘法将返回我们的公钥 Q1,而我们的私钥与其他人的公钥 Q2 的标量乘法将返回共享密钥。
我们可以用Smart攻击。本文对Smart的攻击进行了更深入的描述。然而,我们需要知道的是,当有限群的阶数等价于 p 时,它就会起作用,我们可以用 Sage 的 .order() 函数轻松检查。
解题脚本参考这个。剩下的就是用我们的参数替换参数,然后将其乘以 Q2 以获得共享密钥!
exp:
  1. def SmartAttack(P,Q,p):
  2.     E = P.curve()
  3.     Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + randint(0,p)*p for t in E.a_invariants() ])
  4.     P_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True)
  5.     for P_Qp in P_Qps:
  6.         if GF(p)(P_Qp.xy()[1]) == P.xy()[1]:
  7.             break
  8.     Q_Qps = Eqp.lift_x(ZZ(Q.xy()[0]), all=True)
  9.     for Q_Qp in Q_Qps:
  10.         if GF(p)(Q_Qp.xy()[1]) == Q.xy()[1]:
  11.             break
  12.     p_times_P = p*P_Qp
  13.     p_times_Q = p*Q_Qp
  14.     x_P,y_P = p_times_P.xy()
  15.     x_Q,y_Q = p_times_Q.xy()
  16.     phi_P = -(x_P/y_P)
  17.     phi_Q = -(x_Q/y_Q)
  18.     k = phi_Q/phi_P
  19.     return ZZ(k)
  20. # p = 235322474717419
  21. # E = EllipticCurve(GF(p), [0, 8856682])
  22. # P = E.point((185328074730054,87402695517612))
  23. # Q = E.point((184640716867876,45877854358580))
  24. # Curve parameters --> Replace the next three lines with given values
  25. p = 235322474717419
  26. a = 0
  27. b = 8856682
  28. # Define curve
  29. E = EllipticCurve(GF(p), [a, b])
  30. assert(E.order() == p)
  31. # Replace the next two lines with given values
  32. pub_base = E(185328074730054 , 87402695517612)
  33. Q1 = E(184640716867876 , 45877854358580)
  34. priv_key = SmartAttack(pub_base, Q1,p)
  35. print(priv_key)
  36. Q2 = E(157967230203538,128158547239620)
  37. print(priv_key * Q2)
  38. #uoftctf{(11278025017971:36226806176053:1)}
复制代码
Wheel Barrow

题目
A wheelbarrow ran over the flag. Can you fix it?
Please wrap the flag in uoftctf{}. Please keep the $ in the flag when submitting.
Author: notnotpuns
密文:hc0rhh3r3ylmsrwr___lsewt_03raf_rpetouin$_3tb0_t
我的解答:
根据题目名称查找相应密码发现 Burrows-Wheeler 变换
所有可能结果如下:

整合得到:burr0w_wh33ler_transform_is_pr3tty_c00l_eh$th3_
根据题目意思最终得到:
uoftctf{th3_burr0w_wh33ler_transform_is_pr3tty_c00l_eh$}
*Export Grade Cipher(不会!有时间再回顾吧!)

题目
This "state of the art"™ cipher can be exported to your enemies without restriction.
Author: nullptr
nc 0.cloud.chals.io 23753
chal.py
查看代码
  1.  import ast
  2. import threading
  3. from exportcipher import *
  4. try:
  5.     from flag import FLAG
  6. except:
  7.     FLAG = "test{FLAG}"
  8. MAX_COUNT = 100
  9. TIMEOUT = 120 # seconds
  10. def input_bytes(display_msg):
  11.     m = input(display_msg)
  12.     try:
  13.         m = ast.literal_eval(m)
  14.     except:
  15.         # might not be valid str or bytes literal but could still be valid input, so just encode it
  16.         pass
  17.     if isinstance(m, str):
  18.         m = m.encode()
  19.     assert isinstance(m, bytes)
  20.     return m
  21. def timeout_handler():
  22.     print("Time is up, you can throw out your work as the key changed.")
  23.     exit()
  24. if __name__ == "__main__":
  25.     print("Initializing Export Grade Cipher...")
  26.     key = int.from_bytes(os.urandom(5))
  27.     cipher = ExportGradeCipher(key)
  28.     print("You may choose up to {} plaintext messages to encrypt.".format(MAX_COUNT))
  29.     print("Recover the 40-bit key to get the flag.")
  30.     print("You have {} seconds.".format(TIMEOUT))
  31.     # enough time to crack a 40 bit key with the compute resources of a government
  32.     threading.Timer(TIMEOUT, timeout_handler).start()
  33.    
  34.     i = 0
  35.     while i < MAX_COUNT:
  36.         pt = input_bytes("[MSG {}] plaintext: ".format(i))
  37.         if not pt:
  38.             break
  39.         if len(pt) > 512:
  40.             # don't allow excessively long messages
  41.             print("Message Too Long!")
  42.             continue
  43.         nonce = os.urandom(256)
  44.         cipher.init_with_nonce(nonce)
  45.         ct = cipher.encrypt(pt)
  46.         print("[MSG {}] nonce: {}".format(i, nonce))
  47.         print("[MSG {}] ciphertext: {}".format(i, ct))
  48.         # sanity check decryption
  49.         cipher.init_with_nonce(nonce)
  50.         assert pt == cipher.decrypt(ct)
  51.         i += 1
  52.     recovered_key = ast.literal_eval(input("Recovered Key: "))
  53.     assert isinstance(recovered_key, int)
  54.     if recovered_key == key:
  55.         print("That is the key! Here is the flag: {}".format(FLAG))
  56.     else:
  57.         print("Wrong!")
复制代码
exportcipher.py
查看代码[code] import osclass LFSR:    def __init__(self, seed, taps, size):        assert seed != 0        assert (seed >> size) == 0        assert len(taps) > 0 and (size - 1) in taps        self.state = seed        self.taps = taps        self.mask = (1 > tap) & 1        self.state = ((self.state > 40) == 0        self.key = key        self.initialized = False        def init_with_nonce(self, nonce):        # 256 byte nonce, nonce size isnt export controlled so hopefully this will compensate for the short key size        assert len(nonce) == 256        self.lfsr17 = LFSR((self.key & 0xFFFF) | (1 > 16) | 0xAB
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

八卦阵

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表