Crypto
拿到的是python脚本文件:
1 2 3 assert (len(open('flag.txt' , 'rb' ).read()) <= 50 )assert (str(int.from_bytes(open('flag.txt' , 'rb' ).read(), byteorder='big' ) << 10000 ).endswith('1002773875431658367671665822006771085816631054109509173556585546508965236428620487083647585179992085437922318783218149808537210712780660412301729655917441546549321914516504576' ))
从代码里可以看到,flag的长度小于等于50,将flag转换为int然后左移10000位,以指定的175位数字结尾。
首先左移10000位等同于乘以2**10000
然后结合endswith这里,要能想到使用模运算简化计算
计
c = 1002773875431658367671665822006771085816631054109509173556585546508965236428620487083647585179992085437922318783218149808537210712780660412301729655917441546549321914516504576 c = 1002773875431658367671665822006771085816631054109509173556585546508965236428620487083647585179992085437922318783218149808537210712780660412301729655917441546549321914516504576
c = 1 0 0 2 7 7 3 8 7 5 4 3 1 6 5 8 3 6 7 6 7 1 6 6 5 8 2 2 0 0 6 7 7 1 0 8 5 8 1 6 6 3 1 0 5 4 1 0 9 5 0 9 1 7 3 5 5 6 5 8 5 5 4 6 5 0 8 9 6 5 2 3 6 4 2 8 6 2 0 4 8 7 0 8 3 6 4 7 5 8 5 1 7 9 9 9 2 0 8 5 4 3 7 9 2 2 3 1 8 7 8 3 2 1 8 1 4 9 8 0 8 5 3 7 2 1 0 7 1 2 7 8 0 6 6 0 4 1 2 3 0 1 7 2 9 6 5 5 9 1 7 4 4 1 5 4 6 5 4 9 3 2 1 9 1 4 5 1 6 5 0 4 5 7 6
于是能得到下面的等式:
f l a g ∗ 2 10000 % 1 0 175 = c flag *2^{10000}\%10^{175}=c
f l a g ∗ 2 1 0 0 0 0 % 1 0 1 7 5 = c
f l a g = c ∗ ( 2 10000 ) − 1 % 1 0 175 flag =c*(2^{10000})^{-1}\%10^{175}
f l a g = c ∗ ( 2 1 0 0 0 0 ) − 1 % 1 0 1 7 5
但是这样就结束了吗,并不是,看一下模逆元的定义
可见,只有两个数互质才有模逆元存在,那看一下这两个数是不是互质的,使用扩展欧几里得算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def egcd (a, b) : if a == 0 : return (b, 0 , 1 ) else : g, x, y = egcd(b % a, a) return (g, y - (b // a) * x, x) if __name__ == '__main__' : a = 2 **10000 b = 10 **175 c = 5 **175 print(egcd(a,b)) print(egcd(a,c))
从执行结果里可以看到210000 和10175 并不是互质的,因为最大公约数并不是1
但是210000 和5175 却是互质的,于是有
f l a g ∗ 2 10000 % 1 0 175 = c flag * 2^{10000}\%10^{175} = c
f l a g ∗ 2 1 0 0 0 0 % 1 0 1 7 5 = c
f l a g ∗ 2 10000 % 1 0 175 % 5 175 = c % 5 175 flag * 2^{10000}\%10^{175}\%5^{175} = c \%5^{175}
f l a g ∗ 2 1 0 0 0 0 % 1 0 1 7 5 % 5 1 7 5 = c % 5 1 7 5
f l a g ∗ 2 10000 % 5 175 = c % 5 175 flag * 2^{10000}\%5^{175} = c \%5^{175}
f l a g ∗ 2 1 0 0 0 0 % 5 1 7 5 = c % 5 1 7 5
f l a g = c ∗ ( 2 10000 ) − 1 % 5 175 flag = c*(2^{10000})^{-1}\%5^{175}
f l a g = c ∗ ( 2 1 0 0 0 0 ) − 1 % 5 1 7 5
模逆可以用扩展欧几里得算法(可看https://ce-automne.github.io/2020/01/26/LCG%E5%92%8C%E6%A8%A1p%E5%B9%B3%E6%96%B9%E6%A0%B9%E7%BB%93%E5%90%88%E7%9A%84%E9%A2%98%E7%9B%AE/ ),也可以用欧拉定理求解,这里通过欧拉定理
f l a g = c ∗ ( 2 10000 ) φ ( 5 175 ) − 1 = c ∗ ( 2 10000 ) 5 175 − 5 174 − 1 flag = c* (2^{10000})^{φ(5^{175})-1}=c*(2^{10000})^{5^{175}-5^{174}-1}
f l a g = c ∗ ( 2 1 0 0 0 0 ) φ ( 5 1 7 5 ) − 1 = c ∗ ( 2 1 0 0 0 0 ) 5 1 7 5 − 5 1 7 4 − 1
最终的解题脚本:
1 2 3 4 5 6 7 c = 1002773875431658367671665822006771085816631054109509173556585546508965236428620487083647585179992085437922318783218149808537210712780660412301729655917441546549321914516504576 mod = 5 ** 175 phi = 5 ** 175 - 5 ** 174 inv = pow(pow(2 , 10000 , mod), phi - 1 , mod) print(((c * inv) % mod).to_bytes(50 , byteorder='big' ))
同样用sage也可以解,里面封装了模逆函数inverse_mod()
1 2 3 4 5 6 7 8 sage: a = 2**10000 sage: b = 5**175 sage: c = 1002773875431658367671665822006771085816631054109509173556585546508965236428620487083647585179992085437922318783218149808537210712780660412301729655917441546549321914516504576 sage: d = inverse_mod(a,b) sage: flag = pow(c*d,1,b) sage: from Crypto.Util.number import long_to_bytes sage: long_to_bytes(flag) 'TSGCTF{0K4y_Y0U_are_r3aDy_t0_Go_aNd_dO_M0r3_CryPt}'
参考链接:https://ctftime.org/writeup/22374