[HNCTF]CRYPTO[Week1]littleprince.Writeup

题目详情

code:

from secret import flag
from Crypto.Util.number import *
from random import randint
def enc(a,b,c):
    return a>>b|(a&((1<<b)-1))<<(c-b)
def outp(x,h):
    p=randint(1<<h,1<<h+1)
    q=randint(1<<h,1<<h+1)
    c1,c2=x%p,x%q
    print(p,q,c1,c2)
m=bytes_to_long(flag)
m_len=m.bit_length()
d,h,st=32,16,32
r=m_len%d
assert(r>h)
while st<=m_len:
    x=enc(m,st,m_len)
    x>>=(m_len-d)
    outp(x,h)
    st+=d
m>>=(m_len-r)
outp(m,h)

 output:

58831 56263 46164 34042
55579 48157 2944 35950
35507 38933 1938 2559
63419 51803 24116 33843
40423 47237 20923 43307
33599 43441 4324 37076
43541 40771 42833 32799
54869 40031 21847 16617
48953 34841 36031 3788
34403 58271 12464 55665
33457 61463 3512 47396
53047 57283 185 38171
52583 59281 45851 38603
60727 58043 36261 37164

hint:When we generate two numbers, there may be a coincidence that they are coprime.

解题:

1.重点看循环加密过程中enc传入的三个参数,a为m,b为st,c为m的长度。

enc函数做的事情就是把m后st位拿出来,放到m的前面:a&((1<<b)-1)取出了后b位,再左移c-b就把后b位移到了最前面,a>>b取出前面c-b位,再做或运算就补上了后面。

2.循环加密中,st从32开始,每次增加32,输入到outp函数中的x每次都取前面32位,整个循环相当于是对m每个32位进行了一次加密。

3.再看outp的加密过程,根据提示,生成的两个整数可能互素,我们可以检查一下:

from Crypto.Util.number import *
from gmpy2 import *
L=[58831, 56263, 46164, 34042,
55579, 48157, 2944, 35950,
35507, 38933, 1938, 2559,
63419, 51803, 24116, 33843,
40423, 47237, 20923, 43307,
33599, 43441, 4324, 37076,
43541, 40771, 42833, 32799,
54869, 40031, 21847, 16617,
48953, 34841, 36031, 3788,
34403, 58271, 12464, 55665,
33457, 61463, 3512, 47396,
53047, 57283, 185, 38171,
52583, 59281, 45851, 38603,
60727, 58043, 36261, 37164]

def check():
    for i in range(14):
        if gcd(L[4*i],L[4*i+1])!=1:
            return False
    return True
print(check())

输出发现为True,说明每一次p,q都是互素的,后面在爆破的时候就可以用中国剩余定理了。

4.对m的每个32位写出中国剩余定理通解,深搜爆破。 仅仅用nssctf字段限定前面,你会发现输出的不合法解太多了,不好找flag,不过可以一段一段的找,不断缩小范围,最终找到flag。

还有一个更好的方法,将'\x'字符也排除了,可以直接得到flag。

在脚本运行的同一目录下创建一个名为log.txt的文件,先输出到文件中,在以字符串的形式一行一行读入,去含有除'\x'字段的串。

解题脚本

from Crypto.Util.number import *
from gmpy2 import *
L=[58831, 56263, 46164, 34042,
55579, 48157, 2944, 35950,
35507, 38933, 1938, 2559,
63419, 51803, 24116, 33843,
40423, 47237, 20923, 43307,
33599, 43441, 4324, 37076,
43541, 40771, 42833, 32799,
54869, 40031, 21847, 16617,
48953, 34841, 36031, 3788,
34403, 58271, 12464, 55665,
33457, 61463, 3512, 47396,
53047, 57283, 185, 38171,
52583, 59281, 45851, 38603,
60727, 58043, 36261, 37164]

def dfs(u,f):
    if u==14:
        f=long_to_bytes(f)
        if b'nssctf' in f:
            fp=open('log.txt','a')
            print(f,file=fp)
            fp.close()
        return
    p,q,c1,c2=L[u*4],L[u*4+1],L[u*4+2],L[u*4+3]
    m=p*q
    x=(c1*q*inverse(q,p)+c2*p*inverse(p,q))%m
    while x<(1<<32):
        dfs(u+1,f+(x<<(32*u)))
        x+=m
dfs(0,0)
fp='log.txt'
for line in open(fp):
    if '\\x' not in line:
        print(line)

输出:

b'nssctf{Y0u_kn0w_one_l0ves_the_sunset_when_0ne_is_so_sad}'

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值