crypto581-easywork(网鼎杯2022)

LCG题,整理一下做法。
题目源码如下:

from Crypto.Util.number import *
from random import *
import hashlib
from pwn import *
p = getPrime(128)
seed = randint(2, p - 1)
c = 114514
e = int(2e8)
class prng:
    n = p
    a,b = [randint(2, p - 1) for _ in range(2)]
    def __init__(self,seed):
        self.state = seed
    def next(self):
        self.state = (self.state * self.a + self.b) % self.n
        return self.state
def test():
    gen = prng(seed)
    print(seed)
    print(gen.next())
    print(gen.next())
    print(gen.next())
    print(gen.next())
    print(gen.next())
    print(gen.next())
def m_func(i):
    if i == 0: return 1
    return a*c**i+b*m_func(i-1)+n
def encrypt_flag(sol):
    sol = sol % (10**10000)
    sol = str(sol)
    sol_md5 = hashlib.md5(sol.encode()).hexdigest()
    return  xor(sol_md5.encode(),flag)

if __name__ == "__main__":
    test()
    sol = m_func(e)
    print(encrypt_flag(sol))


'''
150532854791355748039117763516755705063
335246949167877025932432065299887980427
186623163520020374273300614035532913241
215621842477244010690624570814660992556
220694532805562822940506614120520015819
17868778653481346517880312348382129728
160572327041397126918110376968541265339
b'UUV\x04H\x01T\x01P\x03\t\x04\t\x1fW\x00T\x02LRSPT\x1d\x02\x02^\x01N[\\R\x02\tSV\x07\x06P\x01QK'
'''

基本的逻辑是已知LCG随机数种子和前6个随机数,要反推参数a,b和p
然后根据sol的算法解出flag。
LCG反推部分主要参考这篇文章:
CTF中LCG算法总结
lcg-5这种情况,推演一下设 t n = X n + 1 − X n = ( a X n + b ) − ( a X n − 1 + b ) m o d    p t_n=X_{n+1}-X_n=(aX_n+b)-(aX_{n-1}+b) \mod p tn=Xn+1Xn=(aXn+b)(aXn1+b)modp

t n = a t n − 1 m o d    p ⟹ t n + 1 t n − 1 − t n t n = ( a a t n − 1 t n − 1 − a t n − 1 a t n − 1 ) = 0 m o d    p t_n=at_{n-1} \mod p \Longrightarrow t_{n+1}t_{n-1}-t_nt_n=(aat_{n-1}t_{n-1}-at_{n-1}at_{n-1})=0 \mod p tn=atn1modptn+1tn1tntn=(aatn1tn1atn1atn1)=0modp
T n = t n + 1 t n − 1 − t n t n T_n=t_{n+1}t_{n-1}-t_nt_n Tn=tn+1tn1tntn p p p的倍数, p = g c d ( T n , T n − 1 ) p=gcd(T_n,T_{n-1}) p=gcd(Tn,Tn1)
再根据 X n + 2 − X n + 1 = a X n + 1 + b − a X n − b m o d    p = a ( X n + 1 − X n ) m o d    p X_{n+2}-X_{n+1}=aX_{n+1}+b-aX_{n}-b \mod p=a(X_{n+1}-X_n) \mod p Xn+2Xn+1=aXn+1+baXnbmodp=a(Xn+1Xn)modp
得到
a = ( X n + 2 − X n + 1 ) ( X n + 1 − X n ) − 1 m o d    p a=(X_{n+2}-X_{n+1})(X_{n+1}-X_n)^{-1} \mod p a=(Xn+2Xn+1)(Xn+1Xn)1modp
最后计算
b = X n + 1 − a X n m o d    p b=X_{n+1}-aX_{n} \mod p b=Xn+1aXnmodp

套脚本:

from math import gcd
from gmpy2 import invert

x = [150532854791355748039117763516755705063,
335246949167877025932432065299887980427,
186623163520020374273300614035532913241,
215621842477244010690624570814660992556,
220694532805562822940506614120520015819,
17868778653481346517880312348382129728,
160572327041397126918110376968541265339]

t = [x[i+1] - x[i] for i in range(len(x)-1)]

def f(i):
    return t[i]*t[i+2]-t[i+1]*t[i+1]

p = gcd(f(0), f(1))
print('p=',p)
a = invert(x[1]-x[0], p)
a = a * (x[2]-x[1]) % p
print('a=',a)
b = (x[1] - x[0] * a) % p
print('b=',b)

求出a,b,p后问题就变为解决my_func()函数递归时间复杂度的问题。
主要用到矩阵快速幂算法,参考
矩阵快速幂详解
写成 f ( i ) = a c i + b f ( i − 1 ) + p f(i)=ac^i+bf(i-1)+p f(i)=aci+bf(i1)+p
进一步构造转移矩阵:
[ f ( i ) c i p ] = [ b a c 1 0 c 0 0 0 1 ] ∗ [ f ( i − 1 ) c i − 1 p ] \left[\begin{array}{ccc} f(i)\\ c^i\\ p\\ \end{array}\right] =\left[\begin{array}{ccc} b & ac & 1 \\ 0 & c & 0 \\ 0 & 0 & 1 \\ \end{array}\right] *\left[\begin{array}{ccc} f(i-1) \\ c^{i-1} \\ p \\ \end{array}\right] f(i)cip = b00acc0101 f(i1)ci1p
右侧展开:
[ f ( i ) c i p ] = [ b a c 1 0 c 0 0 0 1 ] i ∗ [ f ( 0 ) c 0 p ] \left[\begin{array}{ccc} f(i)\\ c^i\\ p\\ \end{array}\right] =\left[\begin{array}{ccc} b & ac & 1 \\ 0 & c & 0 \\ 0 & 0 & 1 \\ \end{array}\right]^{i} *\left[\begin{array}{ccc} f(0) \\ c^{0} \\ p \\ \end{array}\right] f(i)cip = b00acc0101 i f(0)c0p

上exp:

from hashlib import md5
from Crypto.Util.strxor import *

p= 339088189917874808463944743121467561531
a= 259086495324961642923203668736965982268
b= 121870392737324465817476070178603827899
c = 114514
e = int(2e8)

mod=10 ** 10000

M=matrix(Zmod(mod),[[b,a*c,1],[0,c,0],[0,0,1]])
C=matrix(Zmod(mod),[[1,1,p]])
C=C.T #matrix transpose
s=(M^e)*C
sol = str(s[0])[1:10001] #注意去掉前后括号

enc=b'UUV\x04H\x01T\x01P\x03\t\x04\t\x1fW\x00T\x02LRSPT\x1d\x02\x02^\x01N[\\R\x02\tSV\x07\x06P\x01QK'
sol_md5 = md5(sol.encode()).hexdigest()

print(strxor((2*sol_md5.encode())[:42],enc))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值