MT19937预测
Python中内置了一个random
库,用来产生随机数
其内置的算法为梅森算法(Mersenne Twister)
梅森旋转算法
可以产生高质量的伪随机数,并且效率高效,弥补了传统伪随机数生成器的不足,梅森旋转算法
的最长周期取自一个梅森素数: $2^{19937}-1$
由此命名为梅森旋转算法
,常见的两种为基于32
位的MT19937-32
和基于64
位的MT19937-64
我们注意到一个梅森素数为 $2^{19937}-1$ ,也就是说只要超过梅森素数,我们即可重新回到生成体系中来
说来也简单,我们已经知道随机数的范围(随机数表)就那么大,我们只需要找到随机数从哪儿来的,只要经过一个循环,必定能找到具体的位置,然后就能预测出来了
举个简单的例子:
已知字符串”12345678956789″,如果我们能够知道”34567895678912″,那我们必定能够知道这个循环是从”2
“开始的
思路清晰了,我们要解决的问题就是搞到一个梅森素数大小的随机数,然后交给程序分析,找到起始位置,然后预测即可
题目-1
- ! [HNCTF 2022 WEEK4]random
from randhlib import md5
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
f = open('output.txt','w')
for i in range(666):
f.write(f'{getrandbits(32)}\n')
f.close()
r = getrandbits(32)
key = bytes.fromhex(hex(r)[2:])
key = md5(key).digest()
cipher = AES.new(key,AES.MODE_CBC)
c = cipher.encrypt(pad(flag,16))
print(f'c = \'{cipher.iv.hex() + c.hex()}\'')
#c = '91fd1824ddc0a35e845e87f59e53a103334df418e6a65a7d7769699c3ca2119019361cd23a46a61d4e7f6cdff5f5200f586f90b66eabfd8ecff4ddf11ee444d37f80ada0bbe8af09e4fc32c1a51e3f29e2771b51c71d2ba4acb84fda61904b96'
数据
845373881
2159242406
1531293919
3964315133
682882434
2668803369
13690545
3981499016
3974056427
1756430420
3507595000
649025925
2011539976
3054216842
2408277213
2194875179
2219331383
1368267790
2299897386
2947093100
288939929
1390717726
2466870066
3981133397
1573182610
3944406571
3447362341
715844677
670102377
414837051
1461385271
86255566
862651440
3769031334
3510448355
3679246704
395832693
1690667809
335049267
1068876332
461302326
3079968516
704772851
4026446043
675737799
2098016213
3081713148
578922156
1865220366
2153819253
1119494132
1527596549
2433759308
1758723385
3419468731
3824135991
2037796430
3489010796
2174536167
3109459013
2784976042
2389811980
2519565555
552383195
550155790
3778576966
3086606118
20779154
852620009
1737473744
2324030530
3587565124
3279074958
3307125254
2613886260
357337677
2493280929
164468623
4198900523
1378956742
2068626325
306141631
3628905552
2416172592
1237310388
723828421
1319375168
1408139767
4140388257
324371920
1551895395
3022700120
1315260318
2903417744
275011670
2715397329
2242728739
3684051521
2787117426
1726619484
509657252
333913407
3699480685
3027004960
1190124267
3292764643
3526171378
470947647
2631929525
4041873288
3307949078
3779966106
3886871236
4137433527
371735479
2813106090
3849447265
1306594783
3677478558
1643637741
905045399
2563648523
3868428908
980871767
1244894272
3489381163
2910736282
3831492063
2117629846
4203753604
434050840
3301958648
4097030760
1548540893
2719713000
3125454206
509984247
1840457378
2272794878
2688325648
4021991831
4123848489
1504914491
2942632099
3401751519
3725239869
1145369298
1548494717
4233405103
572724830
3882760731
1117844008
898424646
608894989
899570255
224368496
498725477
3304388475
1835175535
1790171317
3365490927
86425881
2466489467
2604251789
2208460603
3582294281
291362440
4044759906
4125452657
2094240820
1511542801
3176198239
959137027
4262921869
2290966298
2757053104
1439376062
3992069391
789380592
3399543203
3521049603
1446197978
1300085842
2982744050
575836437
2626990957
3508693584
459102396
2369575000
2238871289
564297668
2896654205
2841999069
2630725266
2430180769
3253267051
77771590
4180077801
3009838601
1828273723
1114029369
3862184504
1557474633
2513633358
3146929290
1080036629
3700429834
591881184
1650647570
2497493691
4184505054
1282705289
3042445964
1487041652
1026861825
1730215708
4264420282
2139540396
623772722
3807689662
60864222
267290068
1924900272
1344942365
3219995634
1216897202
1003591267
2057984605
3541823553
545794247
537198932
1166002370
2907973882
1108207309
320286954
3809148239
3296594871
3795014167
1175153627
4241207248
2466668178
3898099355
2455749244
1120991477
2021280982
1241115209
141570885
745553880
1958190182
3185885638
4287840864
3091023414
3690798946
219264633
1616325338
2670690107
593487557
912001439
100298948
1049874064
2323017725
3079547868
264593054
2937135554
3862882010
2116180877
1448543227
2624027043
1945810301
1862902075
1879444176
3833274841
4086582330
3123539644
1994500245
2193152124
1112027927
3758000
3458793558
734003669
623004495
2692528135
3479253271
1493046974
476967577
1098623177
928039152
3689977857
2284459032
2232588813
1446558367
3851411026
1581039345
1631394861
1450688290
701050775
70463657
1398263612
2742662803
887806185
3664571376
4105010109
1230580397
2401433192
1499206328
1861204619
3885769952
3810200758
946968272
3427964957
4026323375
909966113
480323138
1599784218
876092077
3266364080
2305814575
1902257751
1752785961
3226641448
4133909268
2534322478
1282082468
2644838281
114089325
2988830223
702277312
1752631805
2513406759
1498131906
2300338668
1143959587
613505363
2819235623
990427703
1774660908
2115082027
485612723
940635161
729584864
1100940612
3405709800
2428503547
90671939
2473854176
3322307177
2631427737
518075871
3434817555
2251461963
3050380872
3829564674
1660881864
2883795340
539274849
106871781
3050978774
3486621816
3066995469
1845968092
692811959
4027734352
1429574511
329483193
693109476
810210917
619311686
3777319547
2811439521
3523018720
407478697
1825802809
155549681
1245405701
442727352
1027567968
187277591
1134529269
3261378274
2356312829
60387871
3042276410
1027591851
1640193836
2261077121
4001357890
3479870895
1280358583
1496629795
474076484
2980074148
1164449295
879912764
1565978563
422579284
1642195977
4011575842
3651154825
486752782
491864645
1282763631
2835457686
3307278947
3426228754
3782905174
2273618276
2460291772
105075043
3727115116
967542759
2716878533
756178413
3152680298
1843228694
36173193
3845628463
1181819802
3113532635
3772077173
4157802305
1728686943
2044684023
4246256525
4253099798
3083134888
4215375205
3837812777
3427977349
727715285
2729960342
3823071785
3785055152
893474046
1979636417
2171836875
3193977296
2537637097
614361602
525701025
1469762729
2129801823
1846955653
230310727
1176708428
668625482
69458985
321566938
3478050704
4135538212
3774030075
3827150006
2587131135
2736857677
2359843049
2739811984
2003102752
1060611805
2070786501
1512931
2313592699
4255063254
1395659591
3856741874
2611651325
1221579255
1237123257
165553468
4175557478
1172515527
637225359
1882554923
738661434
2529562154
2334890011
4150817613
34569919
2882206625
2093557022
2249835372
3198447718
1667580505
1500794162
1168893161
712666246
3696573060
4022632688
3458993518
187215652
2047831956
1808094223
664030929
965743590
813870858
2011573166
2682840763
1869369873
1783318514
3630077722
1368332520
2281244338
2416760293
1804732878
4081380631
529744139
3342165025
690176391
2377008277
2920331285
428748406
513185802
746073549
1541441458
4172058401
4123128833
1380748095
1159664356
774268753
2740324174
2999102631
2969822420
389506193
2549501834
4285762312
915230141
2584144394
1396829816
4075627630
2190168222
3840381124
1925048746
2984149265
165272117
3515646733
1932782742
1357475842
1547756909
664079088
867382671
436731505
4075827225
2360531460
304975629
126396860
3083593725
1211598254
241180288
1627679006
1465336912
3934911062
1573205331
2028880630
466882391
620349457
62441636
754776969
1193886719
74717240
78919637
1303658319
4281310491
402366481
711509704
3477678462
1220700462
3561122074
2764612997
342992613
673701722
132578891
3660349832
1973359798
1917695868
300429768
2419273987
4154779821
1207208059
3837206095
2011305059
2766208861
1394044874
451187908
614817596
629276326
1953525057
1696114059
3839410793
3782165553
628183599
1160510167
3095094532
330986568
1827753419
2052851375
2076256692
4039740492
1941283302
1488620127
477748304
2360465982
1401284193
2501234720
879716802
2509307852
2334624308
2465183772
3175978649
1158152431
579322737
732121519
3092326240
2174769151
3674175049
3520485705
4121535876
2563503894
2865731955
854047702
2393175183
2338977212
2668928998
3893657989
2425267190
2224708127
3879191472
2635310176
1381455381
2780248779
3035087644
1057084192
1741659539
1301626775
3317172232
1195760929
2544313067
2210779541
1011755271
4203997156
795311734
889277103
173208095
143217717
4064536366
2342012103
522573997
2024118916
2078437385
3525444663
867271488
1238041028
1213332002
2903333250
4246965531
3459390195
3528233595
3550600698
3232784029
3728051249
1642540216
4100940252
872711399
2888299766
3811147314
1933011308
258215124
1371662124
1655603567
解题思路
- @@ 找到循环点
由于Python中使用的梅森算法为MT19937
最为广泛使用Mersenne Twister的一种变体是MT19937
,可以产生32
位整数序列,具有以下的优点:
有的非常长的周期,在许多软件包中的短周期—232
随机数产生器在一个长周期中不能保证生成随机数的质量
在1≤k≤623
的维度之间都可以均等分布(参见定义)
除了在统计学意义上的不正确的随机数生成器以外,在所有伪随机数生成器法中是最快的(当时)
我们注意到,其生成的数据在624*32
后会达到循环(注:623*32=19936
)
由于每次随机产生了32
位的随机数,且623
次尚未达到2
的19937
次方的循环点,我们必须需要624
个32
位由梅森算法产生的随机数才能找到循环点,也就是如果我们能够找到624
个32
位随机数即可
进行预测
我们使用randcrack
的Python库进行预测
解答
from hashlib import md5
from Crypto.Cipher import AES
import binascii
from randcrack import RandCrack
from Crypto.Util.Padding import unpad
with open('D:\\AAACTF题目\\random\\output.txt','r') as f:
lines = [int(line) for line in f.readlines()]
f.close()
rc=RandCrack()
for i in range(len(lines)-624,666):
rc.submit(lines[i])
r=rc.predict_getrandbits(32)
key = bytes.fromhex(hex(r)[2:])
key = md5(key).digest()
c = binascii.unhexlify('91fd1824ddc0a35e845e87f59e53a103334df418e6a65a7d7769699c3ca2119019361cd23a46a61d4e7f6cdff5f5200f586f90b66eabfd8ecff4ddf11ee444d37f80ada0bbe8af09e4fc32c1a51e3f29e2771b51c71d2ba4acb84fda61904b96')
iv = c[:16]
c = c[16:]
aes = AES.new(key,AES.MODE_CBC,iv)
m = aes.decrypt(c)
print(unpad(m,16))
#NSSCTF{Every_Mersenne_prime_corresponds_2_exactly_1_perfect_number}
题目-2
- ! [SUCTF2019]MT
from Crypto.Util.number import bytes_to_long, long_to_bytes
from flag import flag
def convert(m):
m = m ^ m >> 13
m = m ^ m << 9 & 2029229568
m = m ^ m << 17 & 2245263360
m = m ^ m >> 19
return m
def transform(message):
assert len(message) % 4 == 0,
new_message = b''
for i in range(len(message) // 4):
block = message[i * 4 : i * 4 + 4]
block = bytes_to_long(block)
block = convert(block)
block = long_to_bytes(block, 4)
new_message += block
return new_message
transformed_flag = transform(bytes.fromhex(flag[5:-1])).hex()
print(f"transformed_flag: {transformed_flag}")
# transformed_flag: 641460a9e3953b1aaa21f3a2
解题思路
- @@ 法1
- 利用它的循环性:明文不断的加密,最终的还是明文
- @@ 法2
- 明文通过
convert()函数
获取随机数将flag加密,所以通过逆向extract_number函数
求解 - (这里的
convert
作为MT19937
中extract_number
的一部分,逆向convert
是有固定套路的)
class MT19937:
def __init__(self, seed):
self.index = 624
self.state = [0] * 624
self.state[0] = seed
for i in range(1, 624):
self.state[i] = (1812433253 * (self.state[i - 1] ^ (self.state[i - 1] >> 30)) + i) & 0xFFFFFFFF
def twist(self):
for i in range(624):
temp = (self.state[i] & 0x80000000) + (self.state[(i + 1) % 624] & 0x7FFFFFFF)
temp_shift = temp >> 1
if temp % 2:
temp_shift = temp_shift ^ 0x9908B0DF
self.state[i] = self.state[(i + 397) % 624] ^ temp_shift
self.index = 0
def extract_number(self):
if self.index >= 624:
self.twist()
y = self.state[self.index]
y = y ^ (y >> 11)
y = y ^ ((y << 7) & 0x9D2C5680)
y = y ^ ((y << 15) & 0xEFC60000)
y = y ^ (y >> 18)
self.index += 1
return y & 0xFFFFFFFF
# 示例使用
if __name__ == "__main__":
seed = 12345 # 初始种子
mt = MT19937(seed)
for _ in range(10):
print(mt.extract_number())
- @@ 法3
- 利用移位并与自身异或这一运算的特点,可以依次推出原数的二进制数,不过要注意的是
m = m ^ m << 9 & 2029229568
相当于m = m ^ ((m << 9) & 2029229568)
解答
- !! 法1
from Crypto.Util.number import bytes_to_long, long_to_bytes
def convert(m):
m = m ^ m >> 13
m = m ^ m << 9 & 2029229568
m = m ^ m << 17 & 2245263360
m = m ^ m >> 19
return m
def transform(message):
assert len(message) % 4 == 0
new_message = b''
for i in range(len(message) // 4):
block = message[i * 4 : i * 4 + 4]
block = bytes_to_long(block)
block = convert(block)
block = long_to_bytes(block, 4)
new_message += block
return new_message
def circle(m):
t = m
while True:
x = t
t = transform(t)
if t == m:
return x
transformed_flag = bytes.fromhex('641460a9e3953b1aaa21f3a2')
flag = circle(transformed_flag).hex()
print('transformed_flag:', flag)
#transformed_flag: 84b45f89af22ce7e67275bdc
def convert(m):
m = m ^ m >> 13
m = m ^ m << 9 & 2029229568
m = m ^ m << 17 & 2245263360
m = m ^ m >> 19
return m
c1 = 0x641460a9
c2 = 0xe3953b1a
c3 = 0xaa21f3a2
def decode(c):
x = c
while (x := convert(x)) != c:
xx = x
return hex(xx)[2:]
print(decode(c1)+decode(c2)+decode(c3))
#84b45f89af22ce7e67275bdc
- !! 法2
from Crypto.Util.number import bytes_to_long, long_to_bytes
# right shift inverse
def inverse_right(res, shift, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp >> shift
return tmp
# right shift with mask inverse
def inverse_right_mask(res, shift, mask, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp >> shift & mask
return tmp
# left shift inverse
def inverse_left(res, shift, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp << shift
return tmp
# left shift with mask inverse
def inverse_left_mask(res, shift, mask, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp << shift & mask
return tmp
def extract_number(y):
y = y ^ y >> 11
y = y ^ y << 7 & 2636928640
y = y ^ y << 15 & 4022730752
y = y ^ y >> 18
return y & 0xffffffff
def convert(y):
y = inverse_right(y, 19)
y = inverse_left_mask(y, 17, 2245263360)
y = inverse_left_mask(y, 9, 2029229568)
y = inverse_right(y, 13)
return y & 0xffffffff
def transform(message):
assert len(message) % 4 == 0
new_message = b''
for i in range(len(message) // 4):
block = message[i * 4 : i * 4 + 4]
block = bytes_to_long(block)
block = convert(block)
block = long_to_bytes(block, 4)
new_message += block
return new_message
transformed_flag = '641460a9e3953b1aaa21f3a2'
c = bytes.fromhex(transformed_flag)
flag = transform(c)
print(flag.hex())
#84b45f89af22ce7e67275bdc
- !! 法3
from Crypto.Util.number import *
def decrypt(c):
#4
c = c[:19] + bin(eval('0b' + c[19:]) ^ eval('0b' + c[:13]))[2:].zfill(13)
#3
f = bin(2245263360)[2:].zfill(32)
c1 = c[-17:]
c2 = bin(eval('0b' + c[:-17]) ^ (eval('0b' + c1[-15:]) & eval('0b' + f[:-17])))[2:].zfill(15)
c = c2 + c1
#2
f = bin(2029229568)[2:].zfill(32)
c1 = c[-9:]
f = f[:-9]
c2 = bin(eval('0b' + c[-18:-9]) ^ (eval('0b' + c1) & eval('0b' + f[-9:])))[2:].zfill(9)
f = f[:-9]
c3 = bin(eval('0b' + c[-27:-18]) ^ (eval('0b' + c2) & eval('0b' + f[-9:])))[2:].zfill(9)
f = f[:-9]
c4 = bin(eval('0b' + c[:5]) ^ (eval('0b' + c3[-5:]) & eval('0b' + f[-5:])))[2:].zfill(5)
c = c4 + c3 + c2 + c1
#1
c_1 = c[:13]
c_2 = bin(eval('0b' + c_1) ^ eval('0b' + c[13:26]))[2:].zfill(13)
c_3 = bin(eval('0b' + c_2[:6]) ^ eval('0b' + c[-6:]))[2:].zfill(6)
c = c_1 + c_2 + c_3
return c
message = '641460a9e3953b1aaa21f3a2'
m = ''
for i in range(0,len(message),8):
txt = bin(eval('0x' + message[i:i+8]))[2:].zfill(32)
m += decrypt(txt)
m = hex(eval('0b'+m))[2:]
print(m)
#84b45f89af22ce7e67275bdc