CNSS_Recruit_2020_crypto

(baby) Crypto做题须知

Description

crypto 方向 flag 形式如下 cnss{这是flag格式}

flag = int(b"cnss".hex(), 16)
flag = "cnss{%s}" % (hex(pow(flag, 0x10001, 19260817)))

Solution

运行代码得到flag

cnss{0x2f06f3}

(Baby)BabyFib

Description

n = 1926081719260817

f = [0, 1, 1]

for i in range(3, n + 1):
    f.append( ( f[i - 1] + f[i - 2] ) % n )
    
flag = "cnss{" + hex(f[n])[2:] + "}"
print(flag)

solution

求斐波那契数第\(n\)\(\mod n\)

矩阵快速幂或者其他算法

cnss{4de158c740f0e}

Code

没存

(baby) 龙王的代码I

Description

“三年! 三年不准再用超算!隐忍!”

隐忍的戳戳龙王不能再用超算轻易拿到flag了,只能向你求助。

戳戳龙王的代码如下:

def g(x):
    if x <= 1:
        return False
    cnt = 0
    for i in range(1, x + 1):
        if x % i == 0:
            cnt += 1
    if cnt > 2:
        return False
    return True

ans = 0
for i in range(1000000):
    if g(i):
        ans += i * i
print("Flag is cnss{%d}" % (ans))

Solution

线性筛质数

cnss{24693298341834533}

Code

没存

(baby) 龙王的代码II

Description

“三年! 三年不准再用超算!隐忍!”

隐忍的戳戳龙王不能再用超算轻易拿到flag了,只能向你求助。

戳戳龙王的代码如下:

from Crypto.Util.number import long_to_bytes
from hashlib import md5

p = [312609034968489560095816917649428218927, 201093538614623911247134492490252725577, 298359341518180165381217901632470444187, 283779784104916354790175596793270218363]
a = [135563869850958998185249517440045295817, 78188242776496129424059232264784298435, 120640187605672057179209488273239034888, 75233765181335440789936728233620033742]

flag = ""

def check(cur):
    for i in range(4):
        if cur % p[i] != a[i]:
            return False
    return True

for i in range(2**384):
    if(check(i)):
        flag = "cnss{" + md5(long_to_bytes(i)).hexdigest() + "}"

# 在给定的条件内,必有一个i满足check

Solution

中国剩余定理

cnss{089969da277f7a7ccc19c483c42d58c4}

Code

\((easy) NotFib\)

(easy) 龙王的代码III

Description

“三年! 三年不准再用超算!隐忍!”

隐忍的戳戳龙王不能再用超算轻易拿到flag了,只能向你求助。

戳戳龙王的代码如下:

def find_Residue(x,p):
    for i in range(2,p):
        if pow(i,2,p) == x:
            return i
    return -1

print ("Flag is cnss{%d}" % (find_Residue(7705321458598879497,12979492918818656033)))

Solution

求二次剩余

可以使用cipolla算法

cnss{4380399041077346226}

Code

\((Boss)PRNG2\)

(easy) Feistel

Description

Do you know Feistel ?

import os

real_flag = 'cnss{....}'
fake_flag = 'cnss{c91cac1ae8106c3aa80d49bf60f1c8d8}'

def xor(a, b):
	return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b))

def str_to_hex(s):
    return s.encode().hex()

def swap(a):
    return a[16: ] + a[ :16]

def single(m, k):
	assert len(m) == 32
	l = m[: 16]
	r = m[16: ]
	nl, nr = r, xor(k, xor(l, r))
	return nl + nr

def encrypt(m, k):
	for i in k:
		m = single(m, i)
	return swap(m)

k = []
for i in range(0, 16):
	k.append(os.urandom(8).hex())


print(str_to_hex(encrypt(fake_flag[5: -1], k)))
print(str_to_hex(encrypt(real_flag[5: -1], k)))


# 6464686f66626639303668303a613f6937646d696c36356d3664356d30303463
# 535f3d6f34240607302510203a3d68322503383f2b76086d30260c25637d0f68

Solution

可以看见encrypt函数中

依次用\(16\)个随机串\(k_i\)操作\(32\)位原始串

\(l\)为前\(16\)

\(r\)为后\(16\)

\((l,r)\)\(k_i\)操作后变成\(r,l \oplus r \oplus k_i\)

其中\(\oplus\)表示异或运算

现在假装\(k_i\)全是\(0\)

\((l,r)\)的变化如下(应该大概可能也许没错吧)

\[(l,r) \\(r,l \oplus r) \\(l \oplus r,l) \\(l,r) \\... \\(l,r) \\(r,l)(最后交换l,r) \]

算上\(k_i\)后也就是\((K_1\oplus r,K_2 \oplus l)\)

其中\(K_1,K_2\)都是与\(\{k_n\}\)相关的常数

所以可以先利用fake_flag和结果算出\(K_1,K_2\)

再用\(K_1,K_2\)和结果算出real_flag

cnss{Fe15tel_cipher_1s_e2sy_f0r_y0u_3}

Code

晚自习手机写的

比较丑陋

import os 
real_flag = 'cnss{Fe15tel_cipher_1s_e2sy_f0r_y0u_3}' 
fake_flag = 'cnss{c91cac1ae8106c3aa80d49bf60f1c8d8}' 
def xor(a, b): 
    return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)) 

def str_to_hex(s):
    return s.encode().hex() 

def swap(a): 
    return a[16: ] + a[ :16] 

def single(m, k): 
    assert len(m) == 32 
    l = m[: 16] 
    r = m[16: ]     
    nl, nr = r, xor(k, xor(l, r))     
    return nl + nr 

def encrypt(m, k):     
    for i in k:
        m = single(m, i)     
    return swap(m)
#k = [] 
#for i in range(0, 16):     
#    k.append(os.urandom(8).hex()) 

#print(str_to_hex(encrypt(fake_flag[5: -1], k))) 
#print(str_to_hex(encrypt(real_flag[5: -1], k)))

fake=fake_flag[5: -1]

def hex_to_str(s):
    return s.decode('hex')

fake2=hex_to_str('6464686f66626639303668303a613f6937646d696c36356d3664356d30303463')
real2=hex_to_str('535f3d6f34240607302510203a3d68322503383f2b76086d30260c25637d0f68')

lfake = fake[: 16] 
rfake = fake[16: ] 

lfake2=fake2[: 16]
rfake2=fake2[16: ]

lreal2=real2[: 16]
rreal2=real2[16: ]

rreal=xor(rfake,xor(rfake2,rreal2))
lreal=xor(lfake,xor(lfake2,xor(rfake,xor(rreal,lreal2))))
real=lreal+rreal
print(real_flag)

(easy) Not Vigenere

Description

这看起来跟维吉尼亚密码很像 task.py

# -*- coding: utf-8 -*-
import base64
from itertools import *
from data import flag, plain

flag = "cnss{....}"
# plain是只有大小写字母(没有空格和其他符号)的英文文章

a = [chr(i) for i in range(32,127)]

key = flag.strip("cnss{").strip("}")
assert len(key) < 40
ki = cycle(key)

cipher = ''.join([a[(ord(p) + ord(next(ki))) % 95] for p in plain])

print(base64.b64encode(cipher.encode()))

# b'YGYxXT5sRy8mU1olPXpELz1oOD1ZbGQkUzJiOGZGKDVmXzVNejU7Q2IpMGloPSxaOGk3aUgwNWlXNDwsNTtDVjozZm1ieGY+ZjFtPiwiXmU2SzBCKEhdKUBoXFUmZjhhMXU5OS9TYjRHIzkqPWk5Mlk1ZnxrOGk5b0A2N1dtKkx+ODBBaDg3YGA9e2E3aDtvQz5paVcvTH45NEhkJz1hWVZ4VTQ9Nmk5My1WZTVAd0Q+OWEwOlloVjFZOGI1dDYsI2tdMEZ7Q2c6aSlAVWBgL1c/WTJmOTUuU2gzQXs0LUNnNzNqWWIsVy5iSWY1OTQ7YyI6KT8oOGItPFhZWC9hNlU+Sks2Nl5aL0x+MT05Yi08WFlYL1oqaDhmODAlU2ktRyU3KEc+LzxZa2InZjFdPmg1KTBnaipMXjU0SWg4OWJjayxaKmg4akcwL1hXNU13RDBDYzs9YmhgeGU9PTZpOTMtVWUuPXgxKj9jM0VZalkqaz1cOW87KiJgWCZLJD82SF0pMmNqWSpTN1g+cEM1JmlfLUQiPjZLVjJHaFxdJlkqVj92SDA1O2okQCA8MzlZMTNVYF0sZjVZRGk1O21kaXNMKTkqP2ElPFhnXCdnNVgyZjc2L1VbM0Z7ND49aSw1Y2dnIWIvY0JKODAlYGU1QyU/PkhdKTxcY2t+ZC5VRGJEKDNmXzRIIzFAOVktPGtjYXxgPGA5ZzkpOmZeJkcnOTU9ZDI9WmNoIFc7Z3h1SC8zYW00OSo4KDhkOz1aXWIrWzdXNXM9OzphbCZKKzgsPWcxPWdoWHxXOWBJZzkzNVdjMEwgPzVHPjhFVWdfJmFAYkdpOTkmRWozQXk7MzVjKEVVZ2csU0JdPmh7MDRiVzNMJTU5PWMlRF1jYHxgPWA1dUgsM2VbL0wrPy89aCYvYl9ceFY9VUVvSCwlWl8uTyBELzxeKDdiW1whZUBcNXM5KCNhazVLdz4rJ2k2N1dfYHhgLV0+YjdAL1tZIkR3Pis8ajE9aWZjLWU7WUBtTS8iVmowRHo4MEdlJUBoYlkqV0FVM3VAQDhaWzM9Kz8tPWMoNl1hPHxpKmcxcUQoM1dkNUQwPDBKXjI1XWJVJjo4aDVtfD0mYFs3PSk4LDVnKD1aXWgrUzJYfHNHeTVkXyRDIzE1ODc5QjpmWXtdN2NHdD07OFdiLSB7QyhNaC1CZ2pZKmsubEBmQjoqaFtzQHs2M0loLDNYWFUqXTVteGpBKChbZCY8KzgoSGgsM2dVayBXO1xFdDYoL1ZfL0srMTNAWig3YlVgLWo+ZjlwSTo0Z181PSY2OUNkMUFYXWIhYDBVRHBCLDRfVzNMKTU6SFY5QFViaHhYPVlCYkI2NVpbMzklNDo8WjQ3V2hpKlctXDl0OCg6ZWkxPSVEKEhnJTFZYVl8ZjJiN3Q1NSVaXzQ9LTU1PWMrQVVoaCBXOWAxenw7JFNkNT8mPzU1aSw3Z1VbfGUxWUNiPSthWGomSnc8MzxaNzRjZmgxOyxjRW04PC9WWzNLKzE1OF44N2JVbSdnN1s9YkIpNmY/NUAgPjI9aTc2Y2ZmIVQ1WTlvNTQiYGUnQCBDQDlWNkFrXWggVTFdPGVGLC9pXjA5KTU1OVY2Om1bZidpN2lAST06KVdXLUx+RzBAYTIzallmK2YqYjRqSGcvWVszSytCPDtcMDNYXWIgVztWQmY1OjVpXzVAJDk6OWc9IllgYCBbNmg4Ykg2NmReMEV7Mzk9Wjc9aWhaJ2QxXT1GSiwza2opQSU3MEdfOUFoaFx8ZSphNWJCKzpXaiZOe0JASF0tPFtdZ3tbL1o1czk1NTtZIkYrPDBKWjs3aFxjLWYxXT1KODowYWQmSiI5M0BiPUFZYFprUzVfRHA8MC5TWDBNK0QvOWUlQWhVYntTNWBHZkosKGFkJkx+QjZJXCxCY1tZLFouZidpNTsiXz81RyoxQEhkODZZV1whXi1mNW9LLyZgaik9MDE6P1szQFxdYV9bPGY/cEEwNFduIjsrPEA1aC1Ca1VnL1ouYjhmQCwnZl81IStDPjVeODdiW1onZDFdPVg5OSZTYi1Pdzk7PWMrNGNmXCFfdmNHdDwsNWFiJUV7NT81WDg6bWtceGZxZzhwSTMlZVc6K341LjVrKTtZWWB4VDhmMXU5KC9lbSZKKkQ2OWspQG1kYytlMlY8ZkMpNFdoNzkrOTZCZCo2XWdNJ2dAXTxtODYmaFszUSs4MEJcPT1pV1UmWDhmPWZHLyZlVyo8Jzk7PVs5OmBtSHxeNVw5bksvImZXNEx3RCx8Yi08PWdVL2YxVUR0PCw4W2kpPXo9LEhkJT5kWVUkZjhcOXRHQC5iVzVAIDU6Nm4pRFlmbSVXKmJDakI0OmJlOD0pIy85bCVBa1lZKFs3WzZzOSwtaz84OSo1P0hnJT1mWF0mUztdPHpINjZVXiY8XzYsQGktPFhdWyZTN2gxdSc7M1tZLER3PitHWDM6WFdmLVc1aEliQitpYmgwRSBDLDhpMzJjVWAkOyxjRW04OzBUaCpGfTgwQVclMV89VX5kLlk0dUMuMGFsJkomPjs8WjIzbGhYeGsraURwQiwiYFo1RypEKE1eMn1VZl0rZjJgPEo8KCVTWSlBe0YsOGgzO1loXCFgMEg4ZkIoNFtqODkqNzlDbC08W2BVLFcqYjR4OT4mZFsjRys4LExdJUNnaFl7VEJnP25JKilXYzBMID81fGEpNGhcWSo='

Solution

都说了看起来跟维吉尼亚密码很像

那就去学呗

维吉尼亚密码是升级版的凯撒密码

凯撒密码可以用频率统计破解

而维吉尼亚密码因为不同位置移位不同所以频率统计失效

那么我们可以先尝试找出key的长度\(l\)

因为每隔\(l\)的移位相同

就可以得到一堆凯撒密码

然后就可以破解了

既然要找\(l\)的长度

我们可以利用英语中存在的单词频率

频率表和英语相似的就是可能\(l\)长度的倍数

怎么判断是否相似?

参考资料

cnss{V1g3n@re_15_vUner4bl333}

Code

当时是C++Python换着写的

比较杂乱

而且也没存

(easy) LFSR

Description

task.py

mask  = 0xef6a61417539686431326b4a6166686b2131265e402a4a414c
limit = 0xffffffffffffffffffffffffffffffffffffffffffffffffff

def LFSR(input):
	output = (input << 1) & limit
	i = (input & mask) & limit
	lsb = 0
	while i != 0:
		lsb ^= (i & 1)
		i = i >> 1
	output |= lsb
	return (output, lsb)

flag = 'cnss{...}'
assert len(flag) == 32
R = int(flag[5: -1], 16)

tmp = 0
for i in range(200):
	(R, lsb) = LFSR(R)
	tmp = (tmp << 1) | lsb
print(hex(tmp))

#0xf3c166646bce88af4be9c2c22fc681f2ee6641d0334f635842

Solution

考虑每次操作

其实就是左移一位

去掉最高位

最后一位统计某些位(包括最高位)的异或和

最后输出这些最后一位

可以注意到最后操作完后\(tmp\)就是操作完的\(R\)

根据现在的最后一位\(lsb\)

可以恢复出最后一次操作前的\(R\)

依次回溯

可以求出原始的\(R\)

参考资料

cnss{6c416869730616960383964b4a}

Code

mask  = 0xef6a61417539686431326b4a6166686b2131265e402a4a414c
limit = 0xffffffffffffffffffffffffffffffffffffffffffffffffff

R = 0xf3c166646bce88af4be9c2c22fc681f2ee6641d0334f635842

for i in range(200):
    lsb = R & 1
    R >>= 1
    ret = lsb
    for j in range (199):
      if((mask >> j) & 1):
        ret ^= ((R >> j) & 1)
    R |= ret<<199

print(hex(R))

(easy)NotFib

Description

\(2020\)个数\(a_i\),\([2,10^3]\)\(1000\)个,\((10^3 ,10^6]\)\(1000\)个,\((10^{15} ,10^{17})\)\(20\)

定义数列\(F\)

\[F[0]=1\\ F[1]=1\\ F[n]=F[n-2]+F[n-1]+r(n-1) \]

\(r(n)\)表示\(n\)是这\(2020\)个数中的\(r(n)\)个的倍数

\(F(p)\mod p\)

Solution

一个显然的套路是先提出来一个\(Fib_n\)

然后对每个\(a_i\)枚举贡献

\[F[n]=Fib[n]+\sum_x^nFib[n-x]r(x) \\=Fib[n]+\sum_{a_i}\sum_k^{\lfloor\frac{n}{a_i}\rfloor}Fib[n-k*a_i] \]

斐波那契数列可以拆成两个等比数列求和

但是模数\(M=1926081719260817=17*5882353*19260817\)

所以求不出\(\sqrt5\)

所以手动实现复数类

再加个\(CRT\)

cnss{323c5ba9317e7}

Code

from json import load

def qpow(a, b, p):
    result = 1
    while b != 0:
        if (b&1) == 1:
            result = (result * a)%p
        b >>= 1
        a = (a*a) % p
    return result

def inv(x,p):
    return qpow(x%p,p-2,p)

p0=1926081719260817
p1=17
p2=5882353
p3=19260817
p12=p1*p2
p13=p1*p3
p23=p2*p3
p=p0
C1
C2
inv2=(p+1)//2
inv5=(7*p+1)//5

class Complex:
    def __init__(self,a=0,b=0):
        self.a=a%p
        self.b=b%p
    
    def __add__(self, comp):
    	if type(comp) is type(self):
        	return Complex((self.a+comp.a)%p,(self.b+comp.b)%p)
        else:
        	return Complex(self.a,(self.b+comp+p)%p)
        
    def __sub__(self, comp):
    	if type(comp) is type(self):
        	return Complex((self.a-comp.a)%p,(self.b-comp.b)%p)
        else:
        	return Complex(self.a,(self.b-comp+p)%p)
        
    def __mul__(self, comp):
        if type(comp) is type(self):
            return Complex((self.a*comp.b+self.b*comp.a)%p,(self.b*comp.b+5*self.a*comp.a)%p)
        else:
            return Complex(self.a*comp%p,self.b*comp%p)
    
    def __pow__(self,b):
        ret=Complex(0,1)
        a=self
        while b!=0:
            if (b&1)==1:
                ret=ret*a
            b>>=1
            a=a*a
        return ret
       
    def __div__(self,comp):
        return self*Complex(comp.a,-comp.b)*inv(5*comp.a**2-comp.b**2,p)

def matrix_multiplication(n, A, B):
    C = []
    for line in range(n):
        line_arr = []
        for column in range(n):
            item = 0
            for i in range(n):
                item += A[line][i] * B[column][i]%p
            line_arr.append(item%p)
        C.append(line_arr)
    return C

def fib(n):
    return (C1**n-C2**n).a


def SumGP(a,n,q):
	if(q.a==0 and q.b==1):
		return a*n
	return a*(q**n-1)/(q-1)

x1=p23*inv(p23,p1)
x2=p13*inv(p13,p2)
x3=p12*inv(p12,p3)

def CRT(a,b,c):
    return (a*x1+b*x2+c*x3)%p0

a = load(open("a", "r"))

N=p0

p=p1
C1=Complex( 1,1)*inv(2,p)
C2=Complex(-1,1)*inv(2,p)
ans1=fib(N)
for ai in a:
	start=N%ai
	cnt=N//ai
	ans1+=(SumGP(C1**start,cnt,C1**ai)-SumGP(C2**start,cnt,C2**ai)).a
ans1%=p

p=p2
C1=Complex( 1,1)*inv(2,p)
C2=Complex(-1,1)*inv(2,p)
ans2=fib(N)
for ai in a:
	start=N%ai
	cnt=N//ai
	ans2+=(SumGP(C1**start,cnt,C1**ai)-SumGP(C2**start,cnt,C2**ai)).a
ans2%=p

p=p3
C1=Complex( 1,1)*inv(2,p)
C2=Complex(-1,1)*inv(2,p)
ans3=fib(N)
for ai in a:
	start=N%ai
	cnt=N//ai
	ans3+=(SumGP(C1**start,cnt,C1**ai)-SumGP(C2**start,cnt,C2**ai)).a
ans3%=p

print(ans1)
print(ans2)
print(ans3)
ans=CRT(ans1,ans2,ans3)
print(ans)

flag = "cnss{" + hex(ans)[2:] + "}"
print(flag)

(medium) PRNG

Description

nc 101.37.175.115 10000

下面的代码是隐去了flag的后端代码,用于分析攻击方法,和提供的服务交互才能获取flag

import random
import signal
import socketserver
import string
from hashlib import sha256
from os import urandom

FLAG = b'cnss{...}'
LEAK_LIMIT = 6
TIME_LIMIT = 2
TOTAL = 20

BITS = 64
BANNER = b'''
   _ __     ___     _     _      __ _      
  |  _ \   | _ \   | \   | |   / _  | 
  |  __/   | '_'|  | | \ | |   \__| |   
  |_|__   _|_|\_|  |_|  \|_|    |___/  
'''

class PRNG1(object):
    def __init__(self, bits):
        self.n = random.getrandbits(bits)
        self.a = 0
        self.b = 0
        self.s = 0
        while not (self.a < self.n and self.gcd(self.a, self.n) == 1):
            self.a = random.getrandbits(bits)
        while not (self.b < self.n and self.gcd(self.b, self.n) == 1):
            self.b = random.getrandbits(bits)
        while not (self.s < self.n and self.gcd(self.s, self.n) == 1):
            self.s = random.getrandbits(bits)

    def gcd(self, a, b):
        while b:
            a, b = b, a % b
        return a

    def next(self):
        self.s = (self.a * self.s + self.b) % self.n
        return self.s


class Task(socketserver.BaseRequestHandler):
    def __init__(self, *args, **kargs):
        super().__init__(*args, **kargs)

    def proof_of_work(self):
        random.seed(urandom(8))
        proof = ''.join([random.choice(string.ascii_letters + string.digits) for _ in range(20)])
        digest = sha256(proof.encode()).hexdigest()
        self.dosend(str.encode(("sha256(XXXX + %s) == %s" % (proof[4: ], digest))))
        self.dosend(str.encode('Give me XXXX:'))
        x = self.request.recv(10)
        x = (x.strip()).decode("utf-8") 
        if len(x) != 4 or sha256((x + proof[4: ]).encode()).hexdigest() != digest: 
            return False
        return True

    def dosend(self, msg):
        try:
            self.request.sendall(msg + b'\n')
        except:
            pass

    def timeout_handler(self, signum, frame):
        raise TimeoutError

    def handle(self):
        try:
            signal.signal(signal.SIGALRM, self.timeout_handler)
            signal.alarm(60)
            if not self.proof_of_work():
                self.dosend(b'You must pass the PoW!')
                return
            self.dosend(BANNER)
            signal.alarm(3)
            
            prng = PRNG1(BITS)
            output = []
            for i in range(TOTAL):
                output.append(prng.next())
            known = output[: LEAK_LIMIT]
            hint = sha256(''.join(map(str, output)).encode()).hexdigest()
            self.dosend(str(known).encode())
            self.dosend(str(hint).encode())
            signal.alarm(TIME_LIMIT)
            for i in range(TOTAL):
                self.dosend(b'guess: ')
                guess = int(self.request.recv(1024).strip())
                if guess != output[i]:
                    self.dosend(b'Wrong!')
                    self.request.close()
                    return
            self.dosend(b'Congrats! Here is the flag: %s' % FLAG)
        except TimeoutError:
            self.dosend(b'Timeout!')
            self.request.close()
        except:
            self.dosend(b'What\' wrong???')
            self.request.close()

class ThreadedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 10000
    server = ThreadedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    server.serve_forever()

Solution

可以看到这是个伪随机数生成器

先来观察它是如何工作的

首先生成模数\(n\)

然后生成与\(n\)互质且小于的数\(a,b,s\)

每次更新随机种子\(s\)

\[s\equiv a*s+b \mod n \]

并输出\(s\)

输出了生成的连续\(6\)个伪随机数

要预测接下来的数

显然要算出\(a,b,n\)

如果知道\(n\)

\(a,b\)是很好算的

直接解方程就可以了

所以关键是求解\(n\)

那么现在已知的是一堆同余等式

\[S_1\equiv aS_0+b \mod n \\S_2\equiv aS_1+b \mod n \\S_3\equiv aS_2+b \mod n \\... \]

先作差干掉\(b\)

\[T_1\equiv aT_0 \mod n \\T_2\equiv aT_1\mod n \\T_3\equiv aT_2\mod n \\... \\(其中T_i=S_{i+1}-S_i) \]

那么\(T_1*T_3-T_2^2\equiv 0\mod n\)

所以我们可以构造出一堆\(n\)的倍数

然后求gcd

就有大概率得到\(n\)

有多大?

我也不知道

不是还有hint

错了大不了枚举因数再试或者重来嘛

离线会做了就在逆向做题大师的教导下去学了pwn

然后就可以做了

前面的proof_of_work直接暴力枚举即可

参考资料

cnss{L6G_1s_k1nd_0f_PRNG}

Code

好丑

import random
import signal
import string
from hashlib import sha256
import os
from libnum import *
from pwn import *

Shell = remote("101.37.175.115", 10000)

def part1(tmp):
	
	proof = tmp[14: 30]
	tmp.strip(proof)
	digest = tmp[35: -1]

	tmp = Shell.read().decode()
	print(tmp)
	print("Proof == " + proof)
	print("digest == " + digest)
	st = string.ascii_letters + string.digits
	l = len(st)
	for a in range(l):
		for b in range(l):
			for c in range(l):
				for d in range(l):
					x = st[a] + st[b] + st[c] + st[d]
					if(sha256((x + proof).encode()).hexdigest() == digest):
						print(x)
						Shell.sendline(x)
						return 

s = []
t = []
f = []
def part2():
	tmp = Shell.read().decode()
	# print(tmp)
	tmp = Shell.read().decode()
	# print(tmp)
	# tmp = Shell.read().decode()
	# print(tmp)
	tmp = tmp.strip('\n')
	x = 0
	flag = 0
	h = ''
	for c in tmp:
		if(flag == 1):
			h = h + c
		elif(c == ','):
			s.append(x)
			x = 0
		elif(ord('0')<=ord(c)<=ord('9')):
			x = x * 10 + (ord(c) - ord('0'))
		elif(c == ']' ):
			s.append(x)
			flag = 1

	h = h.strip('\n')
	print("h == " + h)

	# for a in s:
	# 	print(a)
	
	for i in range(5):
		t.append(s[i + 1] - s[i])
	f.append(t[0]*t[2]-t[1]*t[1])
	f.append(t[0]*t[3]-t[1]*t[2])
	f.append(t[0]*t[4]-t[1]*t[3])
	f.append(t[0]*t[4]-t[2]*t[2])
	f.append(t[1]*t[4]-t[2]*t[3])
	n = reduce(gcd, f)
	a = (s[2] - s[1]) * invmod(s[1] - s[0],n) % n
	b = (s[1] - a * s[0]) % n
	for i in range(6, 20):
		s.append((s[i - 1] * a + b) % n)
	print("sha == " + sha256(''.join(map(str, s)).encode()).hexdigest())
	for a in s:
		print(tmp)
		print(a)
		Shell.sendline(str(a))
		tmp = Shell.read()

	# tmp = Shell.read()
	print(tmp)
	# tmp = Shell.read()
	# print(tmp)

tmp = Shell.read().decode()
print(tmp.strip('\n'))
part1(tmp)
part2()

(medium) RSA1

Description

task.py

from Crypto.Util.number import *
from FLAG import flag

pad = 0xffffffffffffffff
e = 0x10001
p = getPrime(512)
q = getPrime(512)
n = p * q

p1 = p | (pad<<256)

m = bytes_to_long(flag)
c = pow(m,e,n)

print("N = " + str(n))
print("p1 = " + str(p1))
print("C = " + str(c))

'''
N = 86408538200832738441053630701690666311817036711977563149301775118732430273230358416737501485116387663917737556078719403747856822036528056282885059518192563451129578002341407051322036731121256653431134476455920858137005774303574215108317286768867700749149891191528196389188438844616918232526286820074438880377
p1 = 10998891917537143150459750921909883345610102724514190176534372768205070915213213609183031930454528272713963998587029669016588933905791773046497403754249185
C = 68292422038497943439892795905110150184125214037089941633605604063649686183640244152480155007814154909237215405202836115044035959593825361680613619772337201416261487191174080496578821167356754019320515793576314281432288552185973532924139246292664889586539023761898983279339564228515410405048163144083480125433
'''

Solution

RSA三个大字都写出来了就去学呗

一直到学会Coppersmith’s Theorem就可以做了

给定\(f(x)\)和模数\(n\)

Coppersmith’s Theorem可以求出\(f(x)\equiv 0 \mod p\)一定范围内的解

注意其中\(p\)\(n\)的约数

问题的关键在于恢复\(p\)

我们可以得到等式

\[p\equiv a+x*2^{256}+b \mod n \]

其中\(x\in[0,2^{64})\)

所以转化为模多项式求小根问题

Coppersmith’s Theorem解决

关于Coppersmith’s Theorem是怎么搞的

可以啃论文

Youtube上也有不错的资料

包括LLL算法

cnss{R5A_C0ppersm1th_Atta@k}

Code

去了学下sage

sage算出\(p\)

再求解明文

e = 0x10001
n = 86408538200832738441053630701690666311817036711977563149301775118732430273230358416737501485116387663917737556078719403747856822036528056282885059518192563451129578002341407051322036731121256653431134476455920858137005774303574215108317286768867700749149891191528196389188438844616918232526286820074438880377
p1 = 10998891917537143150459750921909883345610102724514190176534372768205070915213213609183031930454528272713963998587029669016588933905791773046497403754249185
c = 68292422038497943439892795905110150184125214037089941633605604063649686183640244152480155007814154909237215405202836115044035959593825361680613619772337201416261487191174080496578821167356754019320515793576314281432288552185973532924139246292664889586539023761898983279339564228515410405048163144083480125433
pbar1 = p1 >> (256 + 64) << (256 + 64)
pbar2 = p1 & ((1 << 256) - 1)
pbar1 = p1 >> (256 + 64) << (256 + 64)
pbar2 = p1 & ((1 << 256) - 1)
PR.<x> = PolynomialRing(Zmod(n))
f = pbar1 + x * (1<<256) + pbar2
f = f.monic()
x0 = f.small_roots(X=1 << 64, beta=0.4)[0]
p = pbar1 + (x0<<256) + pbar2
q = n // int(p)
d = inverse_mod(e, (p-1)*(q-1))
print(pow(c, d, n))

然后就算出flag

from Crypto.Util.number import *
m = 10471353773279109191869802738615216594859774076390846086058283658109
flag = long_to_bytes(m)
print(flag)

(hard) RSA2

Description

task.py

from Crypto.Util.number import *
from hashlib import md5
from secret import flag,hint

e = 3
p = getPrime(1024)
q = getPrime(1024)
n = p * q

M = flag + md5(flag).digest()
M1 = bytes_to_long(M)
M2 = bytes_to_long(M) + bytes_to_long(hint)

assert bytes_to_long(hint) < 2**128
assert M1 > 2 ** 750

C1 = pow(M1,e,n)
C2 = pow(M2,e,n)

print('N = ' + str(n))
print('C1 = ' + str(C1))
print('C2 = ' + str(C2))

'''
N = 22442678583519738983875074494058317598953875091381485783474848899214372205308945778540436851868967325137345091940740014862547580741174054236020501945339638133676732757133495830887497041331279332265032399268349620619422748303225015657848578372961589906126191164760331145308411163193010021299096283654647819117761621523991044525447078790761543558044629807481102852079854601589180527157241472560749235428267203317706008764197762224910936290211233190050894154304054543248357637956355524415421010219367399546414598977082870279393651857044046504401815969856110997577293409021960020445330447400985069841819725986288236543701
C1 = 19147099662825459227041634257418668407014448481717356392863005714107719802643476432685575627636406454330638759832978044091390574463466219122993780222077952262832269308108913374274251415574958300603681615816648933630844835751717352928657042039813937362010767143442769545486494013505993044882411304529342944297612523540079251411942845605182337671650483110470600570835440095355126274761833163079271088317898736354574831732581857563584088137991682489896458566996898248046835340206406439210543681370234885920237209167954859763216593186191293807656190085622699043088985125286358185593838708581646734922040978936799483220889
C2 = 19147099662825459227041634257418668407014448481717356392863005714107719802643476432685575627636406454330638761546709794100651628661069612340661829908007439389895784066487257952836656633203397756140944963394710464681422607718942814464489448913219074442566929743760347663583732333484696916984559261761469654688715758497928074380359617464521128237695604447249781882333998082996023427280464522991785582915073853201966590263116649792425067159866432049304534660986406166250165231516761376072183367940186293420444436213176479948121681559332107035970038715247095673923035162891624827353031815715581766590303811737166454804769
'''

Solution

已知

\[\left\{\begin{aligned}M^e \equiv C_1\mod n\\\\(M+hint)^e \equiv C_2\mod n\end{aligned}\right. \]

其中\(hint<2^{128}\)

所以我们考虑先利用Coppersmith’s Theorem解出\(hint\)

高次方程组的求解需要用到结式

结式的资料B站就有

属于抽象代数

学完后我们构造结式就可以解出\(hint\)

然后代回去

\(M\)是两个方程的公共根

所以\(M-x\)是两个多项式的公约数

求出即可

cnss{C@PPER_SM1TH-SHORT_P4D0ING_ATTACK-AND F4ANKL1N-RE1TER RELATED!ME55AGE_ATTACK}

Code

sage真好用啊

e = 3
n = 22442678583519738983875074494058317598953875091381485783474848899214372205308945778540436851868967325137345091940740014862547580741174054236020501945339638133676732757133495830887497041331279332265032399268349620619422748303225015657848578372961589906126191164760331145308411163193010021299096283654647819117761621523991044525447078790761543558044629807481102852079854601589180527157241472560749235428267203317706008764197762224910936290211233190050894154304054543248357637956355524415421010219367399546414598977082870279393651857044046504401815969856110997577293409021960020445330447400985069841819725986288236543701
c1 = 19147099662825459227041634257418668407014448481717356392863005714107719802643476432685575627636406454330638759832978044091390574463466219122993780222077952262832269308108913374274251415574958300603681615816648933630844835751717352928657042039813937362010767143442769545486494013505993044882411304529342944297612523540079251411942845605182337671650483110470600570835440095355126274761833163079271088317898736354574831732581857563584088137991682489896458566996898248046835340206406439210543681370234885920237209167954859763216593186191293807656190085622699043088985125286358185593838708581646734922040978936799483220889
c2 = 19147099662825459227041634257418668407014448481717356392863005714107719802643476432685575627636406454330638761546709794100651628661069612340661829908007439389895784066487257952836656633203397756140944963394710464681422607718942814464489448913219074442566929743760347663583732333484696916984559261761469654688715758497928074380359617464521128237695604447249781882333998082996023427280464522991785582915073853201966590263116649792425067159866432049304534660986406166250165231516761376072183367940186293420444436213176479948121681559332107035970038715247095673923035162891624827353031815715581766590303811737166454804769

PRxy.<x,y> = PolynomialRing(Zmod(n))
PRx.<x> = PolynomialRing(Zmod(n))
PRZZ.<xz,yz> = PolynomialRing(Zmod(n))

a1 = x^e - c1
a2 = (x+y)^e - c2

b1 = a1.change_ring(PRZZ)
b2 = a2.change_ring(PRZZ)

F = b2.resultant(b1)
F = F.univariate_polynomial()
F = F.change_ring(PRx).subs(y=x)
F = F.monic()

hint = F.small_roots(X=2^128, beta=0.4)[0]

PRxx.<x> = PolynomialRing(Zmod(n))
g1 = x^e - c1
g2 = (x+hint)^e - c2

while g2:
        g1, g2 = g2, g1 % g2
    
m = -g1.monic()[0]

print(m)
from Crypto.Util.number import *
m = 39518495677363217000696899942255667430680230135832350489449900327922613215783274707217952032432592698988785513737756293149854856875724183968562821411002675077248046343784651651857017469370733498843436949677296484917016545069883670639024
print(long_to_bytes(m))

(boss) PRNG2

Description

nc 101.37.175.115 10001

task.py 如下

import random
import signal
import socketserver
import string
from hashlib import sha256
from os import urandom

FLAG = b'cnss{...}'
LEAK_LIMIT = 8
TIME_LIMIT = 35
TOTAL = 20

BITS = 64
BANNER = b'''
   _ __     ___     _     _     ____      ___ ___   
  |  _ \   | _ \   | \   | |   / _  |     | | | |
  |  __/   | '_'|  | | \ | |   \__| |     | | | |
  |_|__   _|_|\_|  |_|  \|_|    |___/     |_| |_|
'''


class PRNG4(object):
    def __init__(self, bits):
        self.n = 2 ** bits
        self.truncated = 16
        self.N = 2 ** 256 - 2 ** 224 + 2 ** 192 + 2 ** 96 - 1
        self.A = -3
        self.B = 41058363725152142129326129780047268409114441015993725554835256314039467401291
        self.INF = (None, None)
        self.P = (48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109)
        self.Q = self.mul(random.getrandbits(bits // 2), self.P)
        self.a = random.getrandbits(bits)
        self.b = -1
        self.cnt = 256

    def inverse(self, a, p):
        return pow(a, p - 2, p)

    def add(self, p_a, p_b):
        x1, y1 = p_a
        x2, y2 = p_b
        if p_a == self.INF:
            return p_b
        if p_b == self.INF:
            return p_a
        if x1 == x2 and y1 == y2:
            l = (3 * x1 * x1 + self.A) * self.inverse(2 * y1, self.N) % self.N
        elif x1 == x2 and (y1 + y2) == self.N:
            return self.INF
        else:
            l = (y2 - y1) * self.inverse(x2 - x1, self.N) % self.N
        x3 = (l * l - x1 - x2) % self.N
        y3 = (l * (x1 - x3) - y1) % self.N
        return (x3, y3)

    def mul(self, a, p_a):
        t = p_a
        r = self.INF
        if t == r:
            return self.INF
        while a:
            if a & 1:
                r = self.add(r, t)
            t = self.add(t, t)
            a >>= 1
        return r

    def next(self):
        if self.b == -1:
            self.b = self.Q[0]
        else:
            self.b >>= self.n.bit_length() - 1
        if self.cnt - self.n.bit_length() + 1 < 0:
            self.a = self.mul(self.a, self.P)[0]
            self.b += (self.mul(self.a, self.Q)[0] >> self.truncated) << self.cnt
            self.cnt += 256 - self.truncated
        self.cnt -= self.n.bit_length() - 1 
        return self.b % self.n

class Task(socketserver.BaseRequestHandler):
    def __init__(self, *args, **kargs):
        super().__init__(*args, **kargs)

    def proof_of_work(self):
        random.seed(urandom(8))
        proof = ''.join([random.choice(string.ascii_letters + string.digits) for _ in range(20)])
        digest = sha256(proof.encode()).hexdigest()
        self.dosend(str.encode(("sha256(XXXX + %s) == %s" % (proof[4: ], digest))))
        self.dosend(str.encode('Give me XXXX:'))
        x = self.request.recv(10)
        x = (x.strip()).decode("utf-8") 
        if len(x) != 4 or sha256((x + proof[4: ]).encode()).hexdigest() != digest: 
            return False
        return True

    def dosend(self, msg):
        try:
            self.request.sendall(msg + b'\n')
        except:
            pass

    def timeout_handler(self, signum, frame):
        raise TimeoutError

    def handle(self):
        try:
            signal.signal(signal.SIGALRM, self.timeout_handler)
            signal.alarm(60)
            if not self.proof_of_work():
                self.dosend(b'You must pass the PoW!')
                return
            self.dosend(BANNER)
            signal.alarm(3)

            prng = PRNG4(BITS)
            output = []
            for i in range(TOTAL):
                output.append(prng.next())
            known = output[: LEAK_LIMIT]
            hint = sha256(''.join(map(str, output)).encode()).hexdigest()
            self.dosend(str(known).encode())
            self.dosend(str(hint).encode())
            signal.alarm(TIME_LIMIT)
            for i in range(TOTAL):
                self.dosend(b'guess: ')
                guess = int(self.request.recv(1024).strip())
                if guess != output[i]:
                    self.dosend(b'Wrong!')
                    self.request.close()
                    return
            self.dosend(b'Congrats! Here is the flag: %s' % FLAG)
        except TimeoutError:
            self.dosend(b'Timeout!')
            self.request.close()
        except:
            self.dosend(b'Wtf?')
            self.request.close()

class ThreadedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 10001
    server = ThreadedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    server.serve_forever()

Solution

又是伪随机数生成器

观察代码发现生成随机数的方式异常毒瘤

先上factordb查了下这些数

除了\(N\)是质数没什么特别的

于是继续观察

感觉关键在于add函数

不难猜出\(l\)是斜率之内的东西

但是算出的\(x_3,y_3\)又不在直线上

y3 = (l * (x1 - x3) - y1) % self.N

如果在直线上就该是这样才对

y3 = (y1 - l * (x1 - x3)) % self.N

莫名其妙

于是卡死了一段时间

突然发现参数\(B\)没有用

感觉有点东西

直接扔进Google

发现这是个椭圆曲线

而且参数都是一致的

Very nice

所以去学习了椭圆曲线

发现完全一致

然后开始想做法

显然现在给我的前\(4\)个随机数拼起来就是\(Q_x\)

\(cnt\)\(b\)的位数(不过我觉得这修改\(cnt\)的位置有点反人类)

然后\((a*Q)_x\)只有\(16\)位不知道

因为\(Q\)已知

只要知道\(a\)就可以确定随机数列

但是感觉不可做

这要是能做不就破解椭圆曲线了吗

突然意识到不一定要求一开始的\(a\)

可以求更新后的\(a\)

也就是\((a*P)_x\)

感觉这个思路是对的

列下式子

\[Q=k*P \\a*Q=a*k*P=k*a*P \]

如果我们枚举\((a*Q)_x\)未知的\(16\)

那么只需要逆过来找\(a*P\)就可以了

正常来说这还是不可做的

否则椭圆曲线后门不是随便找出来了

但是现在我们还知道\(k<2^{32}\)

感觉有机会搞

显然\(k\)也是有办法求的

直接上BSGS

那么现在只要求出椭圆曲线的阶\(order\)就可以了

因为这样就可以求出\(k\)对阶的逆元\(d\)

就可以用\(a*Q\)\(a*P\)

再次google

居然还真能求

而且sage还已经封装好了

所以直接上sage求出\(order\)

然后就写出来了

然后就T掉了

重新算下复杂度

感觉确实差点

卡了下常

还是跑不了

感觉没救了

后来又想到可以开个Hash表加快求逆

以及不管\((a*Q)_y\)正负不影响\((a*P)_x\)

改了之后快了不少

但还是跑不了

于是自闭了

过了两天发现这是个论文题

而且论文就是这么做的

感觉很离谱

跑去问了出题人

发现时限确实有问题

于是把flag送我了

cnss{ECCCCCCCCCCCCCCC}

Code

import random
import signal
import socketserver
import string
from hashlib import sha256
from os import urandom
from libnum import *
from pwn import *
import time

FLAG = b'cnss{...}'
LEAK_LIMIT = 8
TIME_LIMIT = 35
TOTAL = 20

BITS = 64
BANNER = b'''
   _ __     ___     _     _     ____      ___ ___   
  |  _ \   | _ \   | \   | |   / _  |     | | | |
  |  __/   | '_'|  | | \ | |   \__| |     | | | |
  |_|__   _|_|\_|  |_|  \|_|    |___/     |_| |_|
'''

class PRNG4(object):
    def __init__(self, bits):
        self.Hash = {1 : 1}
        self.n = 2 ** bits
        self.truncated = 16
        self.N = 2 ** 256 - 2 ** 224 + 2 ** 192 + 2 ** 96 - 1
        self.A = -3
        self.B = 41058363725152142129326129780047268409114441015993725554835256314039467401291
        self.INF = (None, None)
        self.P = (48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109)
        self.Q = self.mul(random.getrandbits(bits // 2), self.P)
        self.a = random.getrandbits(bits)
        self.b = -1
        self.cnt = 256

    def inverse(self, a, p):
        if not( a in self.Hash ):
            self.Hash[a]=pow(a, p - 2, p)
        return self.Hash[a]


    def add(self, p_a, p_b):
        x1, y1 = p_a
        x2, y2 = p_b
        if p_a == self.INF:
            return p_b
        if p_b == self.INF:
            return p_a
        if x1 == x2 and y1 == y2:
            l = (3 * x1 * x1 + self.A) * self.inverse(2 * y1, self.N) % self.N
        elif x1 == x2 and (y1 + y2) == self.N:
            return self.INF
        else:
            l = (y2 - y1) * self.inverse(x2 - x1, self.N) % self.N
        x3 = (l * l - x1 - x2) % self.N
        y3 = (l * (x1 - x3) - y1) % self.N
        return (x3, y3)

    def mul(self, a, p_a):
        t = p_a
        r = self.INF
        if t == r:
            return self.INF
        while a:
            if a & 1:
                r = self.add(r, t)
            t = self.add(t, t)
            a >>= 1
        return r

    def next(self):
        if self.b == -1:
            self.b = self.Q[0]
        else:
            self.b >>= self.n.bit_length() - 1
        if self.cnt - self.n.bit_length() + 1 < 0:
            self.a = self.mul(self.a, self.P)[0]
            self.b += (self.mul(self.a, self.Q)[0] >> self.truncated) << self.cnt
            self.cnt += 256 - self.truncated
        self.cnt -= self.n.bit_length() - 1 
        return self.b % self.n

Shell = remote("101.37.175.115", 10001)

def part1(tmp):
    
    proof = tmp[14: 30]
    tmp.strip(proof)
    digest = tmp[35: -1]

    tmp = Shell.read().decode()
    print(tmp)
    print("Proof == " + proof)
    print("digest == " + digest)
    st = string.ascii_letters + string.digits
    l = len(st)
    for a in range(l):
        for b in range(l):
            for c in range(l):
                for d in range(l):
                    x = st[a] + st[b] + st[c] + st[d]
                    if(sha256((x + proof).encode()).hexdigest() == digest):
                        print(x)
                        Shell.sendline(x)
                        return 


tmp = Shell.read().decode()
print(tmp.strip('\n'))
part1(tmp)

tmp = Shell.read().decode()
tmp = Shell.read().decode()
tmp = tmp.strip('\n')
x = 0
flag = 0
h = ''
known = []
print(tmp)
for c in tmp:
    if(flag == 1):
        h = h + c
    elif(c == ','):
        known.append(x)
        x = 0
    elif(ord('0')<=ord(c)<=ord('9')):
        x = x * 10 + (ord(c) - ord('0'))
    elif(c == ']' ):
        known.append(x)
        flag = 1

tmp = Shell.read().decode()
h = tmp.strip('\n')
print("h == " + h)

time_start=time.time()


prng = PRNG4(BITS)

Order = 115792089210356248762697446949407573529996955224135760342422259061068512044369

Q1 = 0
for i in range(4):
    Q1<<=64
    Q1 |= known[3-i]

Q2 = 0
for i in range(4,8):
    Q2<<=64
    Q2 |= known[11-i]

Q2<<=16
Q2%=(2**256)

def add(A, B):
    return prng.add(A, B)

def sub(A, B):
    x, y = B
    return prng.add(A, (x, (-y) % prng.N))

def mul(a, P):
    return prng.mul(a, P)

def bsgs(P, Q):
    N = 2 ** 16 
    T = Q
    S = {T : 0}
    for i in range(1,N):
        T = add(T, P)
        S[T] = i
    c = add(sub(T,Q),P)
    # assert(add(sub(T,Q),P) == mul(N,P))
    T = (None,None)
    for i in range(1,N+1):
        T = add(T,c)
        if T in S:
            return i * N - S[T]
    return -1

def check(x,p):
    if (pow(x,(p-1)//2,p)==p-1):
      return -1
    else :
      return 1;

def mul0(A,B,w,p):
    ar,ai=A
    br,bi=B
    return ((ar*br+ai*bi*w)%p,(ar*bi+ai*br)%p)

def qpow(a, b, p,w):
    result = 1,0
    while b != 0:
        if (b&1) == 1:
            result=mul0(result,a,w,p)
        b >>= 1
        a = mul0(a,a,w,p)
    x,y=result
    return x

def cipolla(x,p):
    if(check(x, p)== -1):
        return -1
    t=random.randint(0,p-1)
    w=(t*t-x)%p
    while check(w,p)==1:
        t=random.randint(0,p-1)
        w=(t*t-x)%p
    return qpow((t,1),(p+1)//2,p,w)%p;

def Y(x):
    return cipolla(x**3 + prng.A * x + prng.B, prng.N)

P = (48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109)
x = Q1
y = Y(x)
prng.Q = (x, y)
k = bsgs(P, prng.Q)
if k == -1:
    prng.Q = (x, (-y) % prng.N)
    k = bsgs(P, prng.Q)
assert k != -1
print(k)
d = pow(k, Order - 2, Order)
for i in range(2 ** 16):
    x = Q2 | i
    y = Y(x)
    if y == -1:
        continue
    rQ = (x, y)
    prng.a = mul(d, rQ)[0]
    prng.b = (Q2 >> 208)

    prng.cnt = 224
    prng.b |= (mul(prng.a, prng.Q)[0] >> 16 << 48)
    if(prng.b% prng.n == known[7]):
        for i in range(8,20):
            known.append(prng.next())
        break
print(known)

time_end=time.time()
print('time cost',time_end-time_start,'s')

print("sha == " + sha256(''.join(map(str, known)).encode()).hexdigest())
for a in known:
    print(tmp)
    print(a)
    Shell.sendline(str(a))
    tmp = Shell.read()

print(tmp)

写在最后

\[ ^{_{stO}^{stO}stO}_{_{stO}^{stO}stO}stO~su\_29029~Orz^{Orz^{Orz}_{Orz}}_{Orz^{Orz}_{Orz}} \]

posted @ 2020-10-28 23:27  NamelessOIer  阅读(87)  评论(0编辑  收藏  举报