不管怎么说还是打了这场,所以还是记录一下吧。
Ataa
题目描述:
1 | Cryptography challenges, like the Atta, require creativity and constructive thinking to unravel their complexities and secure sensitive information. |
题目:
1 | #!/usr/bin/env python3 |
连接上靶机后,靶机会提供一个128bit的p,要求给出u, v, w, x, y, z, k,使得他们满足:
u, v, w, x, y, z是128bit,k大于等于128bit
u, v, w, x, y, z互不相同
u, v, w, x, y, z, k均不是p的整数倍
u, v, w, x, y, z, k, p没有公因子
这一条算是送的,谁能和p有公因子
下面等式成立:
1
(pow(u, k, p) + v * w * x * y * z) % p + (pow(v, k, p) + u * w * x * y * z) % p + (pow(w, k, p) + v * u * x * y * z) % p + (pow(x, k, p) + v * w * u * y * z) % p + (pow(y, k, p) + v * w * x * u * z) % p + (pow(z, k, p) + v * w * x * y * u) % p == 0
这条也有点坑,下面说
然后就能拿到flag。
虽然题目似乎没有明说p是素数,但是实际上测下来p确实是素数,所以最自然的会想到指数k去构造一个p-1,就可以让指数部分都变成1,那么整个式子就会变成:
1 | f = v * w * x * y * z + u * w * x * y * z + v * u * x * y * z + v * w * u * y * z + v * w * x * u * z + v * w * x * y * u + 6 |
还剩六个变量,那么似乎随便取其中五个变量(只要满足128bit),然后在模p下解最后一个就可以了。
但是交互过去不太对,然后发现上面需满足条件的最后一个并没有在和的外层模p,也就是说其实我们需要满足的是:
1 | (pow(u, k, p) + v * w * x * y * z) % p == 0 |
由于是轮换对称的,所以就看第一个式子,如果需要满足这个式子的话就要:
右边五个并不是个常数,所以k取p-1应该是不行了,但是有指数肯定要利用费马,那不如就取k=p-2,此时就有:
也就是:
所以也就是说我们只要满足以下条件就可以满足题目:
- k=p-2
- uvwxyz乘积模p下为-1
所以仍然随机取另外五个,然后求解剩下一个就可以了。
exp:
1 | from pwn import * |
Avini
题目描述:
1 | The Avini challenge in cryptography involves doubling a point on elliptic curves (ECC); your task is to identify the vulnerability and capture the flag. |
题目:
1 | #!/usr/bin/env python3 |
连接上靶机后,靶机会随机生成一个私钥d,然后在NIST P-256上取dG得到点Q,并取无穷远点作为O,之后我们有一次交互机会,可以选择:
- 输入d,可以输入一个nbit的整数n,靶机会用这个整数n的二进制表示去做快速幂得到Q的n倍点。但是记n的二进制表示中1的个数为t,则:
- 若$t < \frac{nbit}{2} + 1$,则不成功
- 若$18(t + nbit) > 19nbit$,则无法计算完
- 输入b,可以输入一个长度为nbit的1、0、-1组成的序列,靶机会把这个序列当作二进制表示去做快速幂得到Q的n倍点。但是记序列中非0的个数为t,则:
- 若$71(t + nbit) > 72nbit$,则无法计算完
- 不管选择哪种,其实按题目的内容的话,都是只要能计算完快速幂就符合要求、拿到flag了。
上面这两种显然选d的话是没有符合要求的n的,所以只能选b。而选b又没看出什么障碍,只需要序列中非0项小于等于三个就行了,所以发:
1 | [1,0,0,...,0,0] |
就可以通过。
确实是很莫名其妙。。。不知道想考什么
exp:
1 | from pwn import * |
Heidi
题目描述:
1 | The Heidi challenge employs matrices over finite fields for message encryption, and we are unable to decrypt it. |
题目:
1 | #!/usr/bin/env sage |
output.txt:
1 | p = 11662551575461840475555573447888369258720609981894210736264777774264853865648625517657867646615246309976844738740514906726900361114740532559856817475566473 |
题目加密流程如下:
随机生成512bit的素数p以及一个16x16的可逆矩阵M
把flag分成前后两部分,转为整数m1、m2分别进行加密,下面以m1为例
分别生成两个长为8的随机向量u、v,并改变u的最后一个值使得向量u所有值的和为m1
用u、v按如下方式生成向量U:
1
U += [(v[i] * u[i]) % p, v[i]]
计算加密向量C:
给出p、M、C,要求还原flag
既然给了M,那只需要:
求出U:
用U求出v,进而求出u
求出u的和即为m
exp:
1 | M = Matrix(Zmod(p),M) |
处理这矩阵的时间都比做题的时间长TT
Clement
题目描述:
1 | Welcome to Clement Crypto Challenge, we have gained access to a very powerful supercomputer with high processing capabilities. Try to connect to the app running on this computer and find the flag. |
题目:
1 | #!/usr/bin/env python3 |
题目需要连续通过19轮挑战(降低过难度),每轮挑战流程是:
输入一个nbit的整数n,检验其满足:
提高nbit的值
由同余定理我们可以知道其实每轮需要满足的是:
而既然有阶乘,自然会想到威尔逊定理,比如对于第一条等式,在n+1为素数的时候有:
所以:
因此n+1为素数就满足一式。而如果n+1是合数的话有:
所以不满足。
同样的,对于第二个式子也要利用威尔逊定理,所以我们不妨把它写成:
也就是:
如果n+3是素数,那么有:
也就是:
所以自然满足。
而如果n+3是合数,那么有:
而由前面的推论,我们知道n+1一定是素数,所以他和n+3没有公因子。而n+2和n+3又肯定是互素的,所以上面的式子一定不成立。因此满足题目挑战的充要条件就是:
- n+1和n+3都是素数
所以其实就是简单爆一爆找twin primes而已。而由于有3s的timeout,所以用gmpy2的nextprime去找会比较快。
exp:
1 | from Crypto.Util.number import * |
Goliver
题目描述:
1 | Welcome to the Goliver World! You can play with ECC points on BTC curve. Your mission is to find the secret key and sweep wallets! |
题目:
1 | #!/usr/bin/env python3 |
题目基于Secp256k1曲线,大体是说靶机有一个私钥sk,我们可以交互最多十次,每次发送一个点H,靶机会计算sk倍的H之后返回。如果我们能在10此以内求出sk并提供给靶机就可以拿到flag。
而题目的这一部分简直是明示:
1 | try: |
这里的意思是说,靶机不会严格检查我们发送的点的坐标是不是在Secp256k1曲线上,而允许我们发送的点在:
只要其中7-b’在模p下小于15就行。
这就很简单了,我们取b’为0,发送的点就会在一条singular curve上:
由于singular curve有一个曲线加法群到模p加法群的映射:
所以简单求逆就可以拿到sk。
exp:
1 | from Crypto.Util.number import * |
当然也可以用其他b’去在低阶子群下crt得到sk,结合题目可以最多交互10次来看更像是预期解,但是显然比这个麻烦。
*Gasdeep
题目描述:
1 | The Gasdeep challenge utilizes finite fields for message encryption; your objective is to explore potential weaknesses in the system to find a way to break it. |
题目:
1 | #!/usr/bin/env sage |
输出太长就不放在这里了。
题目有点复杂,先理一下加密流程,为:
密钥生成:
有秘密参数u、k、d,用于生成密钥
从后面可以知道u小于等于2^64,k=100,d确实不知道
生成两个GF(2^8)下的k阶方阵A、B
随机生成度为d的多项式f,要求f不能是A的特征多项式的倍数
否则有$f(A) = O$
随机生成两个(2,u)之间的正整数m、n,并计算R:
公钥为$(A,B,R)$,私钥为$(f,m,n)$
生成完密钥后进行加密:
- 先把待加密消息m转为01串,并填充长度到8k^2,记为M
随机生成度为d的多项式h,同样要求h不能是A的特征多项式的倍数
随机生成两个(2,u)之间的正整数m’、n’,并计算C、S:
计算密文D:
给出A、B、R、C、D,要求还原flag。
先不管题目M2i之类的数据处理,就从密钥生成和加密这两个步骤出发,我们的目标是通过已知的几个矩阵A、B、R、C来求出S,之后自然就能解密出D了。
而S为:
我们不知道f、h,也不知道m’、m、n、n’,所以要从已知的信息直接求出S来。
一个很重要的信息在于,既然A自己的任意幂次都是可以交换的,那么所有关于A的多项式当然也都可交换,也就是下面的式子恒成立:
所以上面S的式子中的f、h也就可以交换,但这种交换越不过中间的B:
我们把R的式子变一下形:
记:
那么就有:
所以如果我们能求出来X、Y,我们就可以直接求出S了。
而X、Y都是k阶方阵,相当于我们一共有2k^2个变量,而上面的这个约束只有k^2条等式,显然不太够:
但是注意到我们还有很重要的约束没有用,那就是X、Y对于A的可交换性:
这样又多了2k^2条等式,所以显然可以解出X、Y来,因此就可以求出S来解flag了。
这其实就是这篇论文对于这种加密体制的攻击情形之一:
赛后factoreal在discord提供了这篇论文,但是他好像没意识到这题0 solve的核心问题不在于找不找得到论文XD
似乎到这里就结束了,然而我怎么解都解不出这样的X、Y来,而用自己的测试数据发现能做,丢个exp在这:
1 | from Crypto.Util.number import * |
所以应该是题目的数据处理函数出了问题。细看了一下发现:
1 | def h(a): |
这个函数对于输入0、1输出的都是0,所以没有办法通过M2i的输出正确的逆回去,得到原来的矩阵A、B、R、C,所以自然也就是0解。
昨年ASIS Quals我记得也有个做不出来的题目,这下优良传统了XD