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

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

import os
import secrets flag = "REDACATED"
xor_key = secrets.token_bytes(8) def xor(message, key):
return bytes([message[i] ^ key[i % len(key)] for i in range(len(message))]) encrypted_flag = xor(flag.encode(), xor_key).hex() with open("flag.enc", "w") as f:
f.write("Flag: "+encrypted_flag)

flag.enc

Flag: 982a9290d6d4bf88957586bbdcda8681de33c796c691bb9fde1a83d582c886988375838aead0e8c7dc2bc3d7cd97a4

我的解答:

标准的XOR加密,从题目可知,密钥长度为8个字节,这个是非常重要的。因为我们知道flag的前8个字节“uoftctf”

因此,由于XOR是个可逆函数,我们可以很容易得到flag

exp:

from binascii import unhexlify
from Crypto.Util.strxor import strxor ct = unhexlify("982a9290d6d4bf88957586bbdcda8681de33c796c691bb9fde1a83d582c886988375838aead0e8c7dc2bc3d7cd97a4")
key = strxor(ct[:8], b'uoftctf{') def xor(message, key):
return bytes([message[i] ^ key[i % len(key)] for i in range(len(message))]) flag = xor(ct, key)
print(flag)
#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

# no secrets for you!
flag = ... # Prime numbers
p = 151974537061323957822386073908385085419559026351164685426097479266890291010147521691623222013307654711435195917538910433499461592808140930995554881397135856676650008657702221890681556382541341154333619026995004346614954741516470916984007797447848200982844325683748644670322174197570545222141895743221967042369
q = 174984645401233071825665708002522121612485226530706132712010887487642973021704769474826989160974464933559818767568944237124745165979610355867977190192654030573049063822083356316183080709550520634370714336131664619311165756257899116089875225537979520325826655873483634761961805768588413832262117172840398661229
n = p * q # a public exponent hidden away by Windy's musical talents
e = ... # Converting the message to an integer
m = int.from_bytes(message.encode(), 'big') # Encrypting the message: c = m^e mod n
inc_m = pow(message_int, e, n) print(encrypted_message_int)

musical_e.png

output.txt

13798492512038760070176175279601263544116956273815547670915057561532348462120753731852024424193899030774938204962799194756105401464136384387458651343975594539877218889319074841918281784494580079814736461158750759327630935335333130007375268812456855987866715978531148043248418247223808114476698088473278808360178546541128684643502788861786419871174570376835894025839847919827231356213726961581598139013383568524808876923469958771740011288404737208217659897319372970291073214528581692244433371304465252501970552162445326313782129351056851978201181794212716520630569898498364053054452320641433167009005762663177324539460

我的解答:

看了一下题目发现我们只要找到e,这道题就解决了

给了一个图片显然可以找到e,属于Music Sheet Cipher密码

e = 7029307

exp:

import gmpy2
from Crypto.Util.number import *
p = 151974537061323957822386073908385085419559026351164685426097479266890291010147521691623222013307654711435195917538910433499461592808140930995554881397135856676650008657702221890681556382541341154333619026995004346614954741516470916984007797447848200982844325683748644670322174197570545222141895743221967042369
q = 174984645401233071825665708002522121612485226530706132712010887487642973021704769474826989160974464933559818767568944237124745165979610355867977190192654030573049063822083356316183080709550520634370714336131664619311165756257899116089875225537979520325826655873483634761961805768588413832262117172840398661229
c= 13798492512038760070176175279601263544116956273815547670915057561532348462120753731852024424193899030774938204962799194756105401464136384387458651343975594539877218889319074841918281784494580079814736461158750759327630935335333130007375268812456855987866715978531148043248418247223808114476698088473278808360178546541128684643502788861786419871174570376835894025839847919827231356213726961581598139013383568524808876923469958771740011288404737208217659897319372970291073214528581692244433371304465252501970552162445326313782129351056851978201181794212716520630569898498364053054452320641433167009005762663177324539460
e = 7029307
n = p*q
phi = (p-1) * (q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
#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

m = 235322474717419
F = GF(m)
C = EllipticCurve(F, [0, 8856682]) public_base = (185328074730054:87402695517612:1) Q1 = (184640716867876:45877854358580:1) # my public key
Q2 = (157967230203538:128158547239620:1) # your public key secret = ...
my_private_key = ...
assert(my_private_key*public_base == Q1)
assert(my_private_key*Q2 == secret)

我的解答:

这是非常标准的椭圆加密。

基本上,我们的私钥乘以公钥的标量乘法将返回我们的公钥 Q1,而我们的私钥与其他人的公钥 Q2 的标量乘法将返回共享密钥。

我们可以用Smart攻击。本文对Smart的攻击进行了更深入的描述。然而,我们需要知道的是,当有限群的阶数等价于 p 时,它就会起作用,我们可以用 Sage 的 .order() 函数轻松检查。

解题脚本参考这个。剩下的就是用我们的参数替换参数,然后将其乘以 Q2 以获得共享密钥!

exp:

def SmartAttack(P,Q,p):
E = P.curve()
Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + randint(0,p)*p for t in E.a_invariants() ]) P_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True)
for P_Qp in P_Qps:
if GF(p)(P_Qp.xy()[1]) == P.xy()[1]:
break Q_Qps = Eqp.lift_x(ZZ(Q.xy()[0]), all=True)
for Q_Qp in Q_Qps:
if GF(p)(Q_Qp.xy()[1]) == Q.xy()[1]:
break p_times_P = p*P_Qp
p_times_Q = p*Q_Qp x_P,y_P = p_times_P.xy()
x_Q,y_Q = p_times_Q.xy() phi_P = -(x_P/y_P)
phi_Q = -(x_Q/y_Q)
k = phi_Q/phi_P
return ZZ(k) # p = 235322474717419
# E = EllipticCurve(GF(p), [0, 8856682])
# P = E.point((185328074730054,87402695517612))
# Q = E.point((184640716867876,45877854358580)) # Curve parameters --> Replace the next three lines with given values
p = 235322474717419
a = 0
b = 8856682 # Define curve
E = EllipticCurve(GF(p), [a, b])
assert(E.order() == p) # Replace the next two lines with given values
pub_base = E(185328074730054 , 87402695517612)
Q1 = E(184640716867876 , 45877854358580) priv_key = SmartAttack(pub_base, Q1,p) print(priv_key) Q2 = E(157967230203538,128158547239620) print(priv_key * Q2) #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

查看代码
 import ast
import threading
from exportcipher import *
try:
from flag import FLAG
except:
FLAG = "test{FLAG}" MAX_COUNT = 100
TIMEOUT = 120 # seconds def input_bytes(display_msg):
m = input(display_msg)
try:
m = ast.literal_eval(m)
except:
# might not be valid str or bytes literal but could still be valid input, so just encode it
pass
if isinstance(m, str):
m = m.encode()
assert isinstance(m, bytes)
return m def timeout_handler():
print("Time is up, you can throw out your work as the key changed.")
exit() if __name__ == "__main__":
print("Initializing Export Grade Cipher...")
key = int.from_bytes(os.urandom(5))
cipher = ExportGradeCipher(key)
print("You may choose up to {} plaintext messages to encrypt.".format(MAX_COUNT))
print("Recover the 40-bit key to get the flag.")
print("You have {} seconds.".format(TIMEOUT))
# enough time to crack a 40 bit key with the compute resources of a government
threading.Timer(TIMEOUT, timeout_handler).start() i = 0
while i < MAX_COUNT:
pt = input_bytes("[MSG {}] plaintext: ".format(i))
if not pt:
break
if len(pt) > 512:
# don't allow excessively long messages
print("Message Too Long!")
continue
nonce = os.urandom(256)
cipher.init_with_nonce(nonce)
ct = cipher.encrypt(pt)
print("[MSG {}] nonce: {}".format(i, nonce))
print("[MSG {}] ciphertext: {}".format(i, ct))
# sanity check decryption
cipher.init_with_nonce(nonce)
assert pt == cipher.decrypt(ct)
i += 1
recovered_key = ast.literal_eval(input("Recovered Key: "))
assert isinstance(recovered_key, int)
if recovered_key == key:
print("That is the key! Here is the flag: {}".format(FLAG))
else:
print("Wrong!")

exportcipher.py

查看代码
 import os

class 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 << size) - 1 def _shift(self):
feedback = 0
for tap in self.taps:
feedback ^= (self.state >> tap) & 1
self.state = ((self.state << 1) | feedback) & self.mask def next_byte(self):
val = self.state & 0xFF
for _ in range(8):
self._shift()
return val class ExportGradeCipher:
def __init__(self, key):
# 40 bit key
assert (key >> 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), [2, 9, 10, 11, 14, 16], 17)
self.lfsr32 = LFSR(((self.key >> 16) | 0xAB << 24) & 0xFFFFFFFF, [1, 6, 16, 21, 23, 24, 25, 26, 30, 31], 32)
self.S = [i for i in range(256)]
# Fisher-Yates shuffle S-table
for i in range(255, 0, -1):
# generate j s.t. 0 <= j <= i, has modulo bias but good luck exploiting that
j = (self.lfsr17.next_byte() ^ self.lfsr32.next_byte()) % (i + 1)
self.S[i], self.S[j] = self.S[j], self.S[i]
j = 0
# use nonce to scramble S-table some more
for i in range(256):
j = (j + self.lfsr17.next_byte() ^ self.lfsr32.next_byte() + self.S[i] + nonce[i]) % 256
self.S[i], self.S[j] = self.S[j], self.S[i]
self.S_inv = [0 for _ in range(256)]
for i in range(256):
self.S_inv[self.S[i]] = i
self.initialized = True def _update(self, v):
i = self.lfsr17.next_byte() ^ self.lfsr32.next_byte()
self.S[v], self.S[i] = self.S[i], self.S[v]
self.S_inv[self.S[v]] = v
self.S_inv[self.S[i]] = i def encrypt(self, msg):
assert self.initialized
ct = bytes()
for v in msg:
ct += self.S[v].to_bytes()
self._update(v)
return ct def decrypt(self, ct):
assert self.initialized
msg = bytes()
for v in ct:
vo = self.S_inv[v]
msg += vo.to_bytes()
self._update(vo)
return msg if __name__ == "__main__":
cipher = ExportGradeCipher(int.from_bytes(os.urandom(5)))
nonce = os.urandom(256)
print("="*50)
print("Cipher Key: {}".format(cipher.key))
print("Nonce: {}".format(nonce))
msg = "ChatGPT: The Kerckhoffs' Principle, formulated by Auguste Kerckhoffs in the 19th century, is a fundamental concept in cryptography that states that the security of a cryptographic system should not rely on the secrecy of the algorithm, but rather on the secrecy of the key. In other words, a cryptosystem should remain secure even if all the details of the encryption algorithm, except for the key, are publicly known. This principle emphasizes the importance of key management in ensuring the confidentiality and integrity of encrypted data and promotes the development of encryption algorithms that can be openly analyzed and tested by the cryptographic community, making them more robust and trustworthy."
print("="*50)
print("Plaintext: {}".format(msg))
cipher.init_with_nonce(nonce)
ct = cipher.encrypt(msg.encode())
print("="*50)
print("Ciphertext: {}".format(ct))
cipher.init_with_nonce(nonce)
dec = cipher.decrypt(ct)
print("="*50)
try:
print("Decrypted: {}".format(dec))
assert msg.encode() == dec
except:
print("Decryption failed")

Miscellaneous(只会一个)

Out of the Bucket

题目

Check out my flag website!

Author: windex

我的解答:

题目给出了一个网站,访问会发现两张图,lsb隐写?也不是。其他方式也试了不行。。。。

修改下url试试,最终在

https://storage.googleapis.com/out-of-the-bucket

里发现啦一些东西。以 XML 格式列出该站点的文档树如下:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ListBucketResult>
<Name>out-of-the-bucket</Name>
<Prefix/>
<Marker/>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>secret/</Key>
<Generation>1703868492595821</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:48:12.634Z</LastModified>
<ETag>"d41d8cd98f00b204e9800998ecf8427e"</ETag>
<Size>0</Size>
</Contents>
<Contents>
<Key>secret/dont_show</Key>
<Generation>1703868647771911</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:50:47.809Z</LastModified>
<ETag>"737eb19c7265186a2fab89b5c9757049"</ETag>
<Size>29</Size>
</Contents>
<Contents>
<Key>secret/funny.json</Key>
<Generation>1705174300570372</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2024-01-13T19:31:40.607Z</LastModified>
<ETag>"d1987ade72e435073728c0b6947a7aee"</ETag>
<Size>2369</Size>
</Contents>
<Contents>
<Key>src/</Key>
<Generation>1703867253127898</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:27:33.166Z</LastModified>
<ETag>"d41d8cd98f00b204e9800998ecf8427e"</ETag>
<Size>0</Size>
</Contents>
<Contents>
<Key>src/index.html</Key>
<Generation>1703867956175503</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:39:16.214Z</LastModified>
<ETag>"dc63d7225477ead6f340f3057263643f"</ETag>
<Size>1134</Size>
</Contents>
<Contents>
<Key>src/static/antwerp.jpg</Key>
<Generation>1703867372975107</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:29:33.022Z</LastModified>
<ETag>"cef4e40eacdf7616f046cc44cc55affc"</ETag>
<Size>45443</Size>
</Contents>
<Contents>
<Key>src/static/guam.jpg</Key>
<Generation>1703867372954729</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:29:32.993Z</LastModified>
<ETag>"f6350c93168c2955ceee030ca01b8edd"</ETag>
<Size>48805</Size>
</Contents>
<Contents>
<Key>src/static/style.css</Key>
<Generation>1703867372917610</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2023-12-29T16:29:32.972Z</LastModified>
<ETag>"0c12d00cc93c2b64eb4cccb3d36df8fd"</ETag>
<Size>76559</Size>
</Contents>
</ListBucketResult>

显然有一些可疑的URL,尝试访问发现 secret/dont_show 里面有flag

uoftctf{allUsers_is_not_safe}

UofTCTF 2024 比赛记录的更多相关文章

  1. 【arc101】比赛记录

    这场还好切出了D,rt应该能涨,然而这场的题有点毒瘤,700分的D没多少人切,更别说EF了.(暴打出题人)既然这样,干脆就水一篇博客,做个简单的比赛记录. C - Candles 这题是一道一眼题,花 ...

  2. 【cf比赛记录】Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

    比赛传送门 只能说当晚状态不佳吧,有点头疼感冒的症状.也跟脑子没转过来有关系,A题最后一步爆搜没能立即想出来,B题搜索没有用好STL,C题也因为前面两题弄崩了心态,最后,果然掉分了. A:简单数学 B ...

  3. 【cf比赛记录】Codeforces Round #605 (Div. 3)

    比赛传送门 Div3真的是暴力杯,比div2还暴力吧(这不是明摆的嘛),所以对我这种一根筋的挺麻烦的,比如A题就自己没转过头来浪费了很久,后来才醒悟过来了.然后这次竟然还上分了...... A题:爆搜 ...

  4. 【cf比赛记录】Educational Codeforces Round 78 (Rated for Div. 2)

    比赛传送门 A. Shuffle Hashing 题意:加密字符串.可以把字符串的字母打乱后再从前面以及后面接上字符串.问加密后的字符串是否符合加密规则. 题解:字符串的长度很短,直接暴力搜索所有情况 ...

  5. 【cf比赛记录】Codeforces Round #601 (Div. 2)

    Codeforces Round #601 (Div. 2) ---- 比赛传送门 周二晚因为身体不适鸽了,补题补题 A // http://codeforces.com/contest/1255/p ...

  6. 【cf比赛记录】Codeforces Round #600 (Div. 2)

    Codeforces Round #600 (Div. 2) ---- 比赛传送门 昨晚成绩还好,AC A,B题,还能上分(到底有多菜) 补了C.D题,因为昨晚对C.D题已经有想法了,所以补起题来也快 ...

  7. BestCoder Round #92 比赛记录

    上午考完试后看到了晚上的BestCoder比赛,全机房都来参加 感觉压力好大啊QAQ,要被虐了. 7:00 比赛开始了,迅速点进了T1 大呼这好水啊!告诉了同桌怎么看中文题面 然后就开始码码码,4分1 ...

  8. [Codeforces 872]比赛记录

    强行打了$cf$上的第一场比赛,现在感觉自己的$rating$会炸飞= = A  这是练习输入输出吗QAQ,竟然$WA$了两遍QAQ,我$WA$的一声就哭了出来啊QAQ B  好像很水的乱扫就好了,m ...

  9. 【cf比赛记录】Codeforces Round #604 (Div. 2)

    比赛传送门 感觉这场是最近以来做过的最顺手的一场,持续上分,开心w A了 前三题,然后第四题其实还有半个多小时,但怕身体撑不住,就先退了,其实第四题也很简单 自己认为的算法标签: ​ A.暴力模拟.字 ...

  10. 【cf比赛记录】Educational Codeforces Round 77 (Rated for Div. 2)

    比赛传送门 这场题目前三题看得挺舒服的,没有臃肿的题目,对于我这种英语渣渣就非常友好,但因为太急了,wa了两发A后才意识到用模拟(可以删了,博主真的是个菜鸟),结果导致心态大崩 ---- 而且也跟最近 ...

随机推荐

  1. 【GIT-精讲】从零玩转Git-基础理论

    关于版本控制 一.什么是版本控制 版本控制(Version Control Systems)版本控制(Revision control)是一种软件工程技巧 在开发的过程中,确保由不同人所编辑的同一档案 ...

  2. Not on FX application thread(八)

    Not on FX application thread(八) JavaFX 从入门到入土系列 当你不在主线程中操作UI时会出现以下异常: Not on FX application thread 可 ...

  3. Prometheus配置Basic Auth进行安全防护,实现登录控制

    本文分享自华为云社区<Prometheus配置Basic Auth进行安全防护,实现登录控制>,作者:可以交个朋友. 一.Prometheus Basic Auth 使用背景 在日常pro ...

  4. 【技术总结】从Hash索引到LSM树

    摘要:本文将从实现最简单的Key-Value数据库讲起,然后针对实现过程中遇到的一些瓶颈,采用上述的索引技术,对数据库进行优化,以此达到对数据库的索引技术有一个较为深刻的理解. 前言 数据库算是软件应 ...

  5. 10个安全问题带你了解OWASP 定义的大模型应用

    摘要:OWASP 的一群研究人员,总结目前大模型中可能存在的TOP10安全风险,很好的揭示了我们在大模型应用中需要防护的目标,以及如何采取相应的防护措施. 本文分享自华为云社区<OWASP 定义 ...

  6. 云小课|GaussDB如何进行性能调优

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:GaussDB性能 ...

  7. 简化业务代码开发:看Lambda表达式如何将代码封装为数据

    摘要:在云服务业务开发中,善于使用代码新特性,往往能让开发效率大大提升,这里简单介绍下lambad表达式及函数式接口特性. 1.Lambda 表达式 Lambda表达式也被称为箭头函数.匿名函数.闭包 ...

  8. OLAP分析型应用场景中,数仓中vacuum为何对列存表无效

    摘要:对列存表执行vacuum为什么是无效的呢?其实这与列存表的存储结构以及数据写入方式有关. 本文分享自华为云社区<GaussDB(DWS)中vacuum为何对列存表无效?[这次高斯不是数学家 ...

  9. 如何在跨平台的环境中创建可以跨平台的后台服务,它就是 Worker Service。

    一.简介 最近,有一个项目要使用 Windows 服务,来做为一个软件项目的载体.我想了想,都已经到了跨平台的时代了,会不会有替换 Windows 服务的技术出现呢?于是,在网络上疯狂的搜索了一番,真 ...

  10. 对话 BitSail Contributor | 姚泽宇:新生火焰,未来亦可燎原

    2022 年 10 月,字节跳动 BitSail 数据引擎正式开源.同期,社区推出 Contributor 激励计划第一期,目前已有 12 位开发者为 BitSail 社区做出贡献,成为了首批 Bit ...