# Secret Array
Author: [roerohan](https://github.com/roerohan)
# Requirements
- Python
# Source
```Randomness is a power ! You don't have a chance to face it.
nc twistwislittlestar.fword.wtf 4445
Author: Semah BA```
# Exploitation
The exploit is based on the Mersene Twister vulnerability, as the name suggests. For that, we need 624 consecutive primes.
```pyfrom pwn import remote r = remote('twistwislittlestar.fword.wtf', 4445)
arr = list(map(lambda x: x.split(': ')[1], list(filter(lambda x: 'Random Number is' in x, r.recvuntil('Your Prediction For the next one : ').decode().split('\n')))))print(arr)
for _ in range(624):    r.sendline('1')
    arr.append(r.recvuntil('Your Prediction For the next one : ').decode().split('was : ')[1].split('\n')[0])    print('running...')
arr += [str(i) for i in range(20)]
open('./data.txt','w').write('\n'.join(arr))r.interactive()```
In this, we have 627 consecutive random numbers followed by 1-20. Pass this `data.txt` to the following code (in stdin). It will predict the correct values for 1-20. You could enter them manually from here (since it's just 20 numbers).
```py#!/usr/bin/env python## Mersenne Twister predictor## Feed this program the output of any 32-bit MT19937 Mersenne Twister and# after seeing 624 values it will correctly predict the rest.## The values may come from any point in the sequence -- the program does not# need to see the first 624 values, just *any* 624 consecutive values.  The# seed used is also irrelevant, and it will work even if the generator was# seeded from /dev/random or any other high quality source.## The values should be in decimal, one per line, on standard input.## The program expects the actual unsigned 32 bit integer values taken directly# from the output of the Mersenne Twister.  It won't work if they've been# scaled or otherwise modified, such as by using modulo or# std::uniform_int_distribution to alter the distribution/range.  In principle# it would be possible to cope with such a scenario if you knew the exact# parameters used by such an algorithm, but this program does not have any# such knowledge.## For more information, refer to the original 1998 paper:##  "Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom#   number generator", Makoto Matsumoto, Takuji Nishimura, 1998##   http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.215.1141## This code is not written with speed or efficiency in mind, but to follow# as closely as possible to the terminology and naming in the paper.## License: CC0 http://creativecommons.org/publicdomain/zero/1.0/
from __future__ import print_functionimport sysimport collections
class Params:    # clearly a mathematician and not a programmer came up with these names    # because a dozen single-letter names would ordinarily be insane    w = 32              # word size    n = 624             # degree of recursion    m = 397             # middle term    r = 31              # separation point of one word    a = 0x9908b0df      # bottom row of matrix A    u = 11              # tempering shift    s = 7               # tempering shift    t = 15              # tempering shift    l = 18              # tempering shift    b = 0x9d2c5680      # tempering mask    c = 0xefc60000      # tempering mask
def undo_xor_rshift(x, shift):    ''' reverses the operation x ^= (x >> shift) '''    result = x    for shift_amount in range(shift, Params.w, shift):        result ^= (x >> shift_amount)    return result
def undo_xor_lshiftmask(x, shift, mask):    ''' reverses the operation x ^= ((x << shift) & mask) '''    window = (1 << shift) - 1    for _ in range(Params.w // shift):        x ^= (((window & x) << shift) & mask)        window <<= shift    return x
def temper(x):    ''' tempers the value to improve k-distribution properties '''    x ^= (x >> Params.u)    x ^= ((x << Params.s) & Params.b)    x ^= ((x << Params.t) & Params.c)    x ^= (x >> Params.l)    return x
def untemper(x):    ''' reverses the tempering operation '''    x = undo_xor_rshift(x, Params.l)    x = undo_xor_lshiftmask(x, Params.t, Params.c)    x = undo_xor_lshiftmask(x, Params.s, Params.b)    x = undo_xor_rshift(x, Params.u)    return x
def upper(x):    ''' return the upper (w - r) bits of x '''    return x & ((1 << Params.w) - (1 << Params.r))
def lower(x):    ''' return the lower r bits of x '''    return x & ((1 << Params.r) - 1)
def timesA(x):    ''' performs the equivalent of x*A '''    if x & 1:        return (x >> 1) ^ Params.a    else:        return (x >> 1)
seen = collections.deque(maxlen=Params.n)
print('waiting for {} previous inputs'.format(Params.n))for _ in range(Params.n):    val = untemper(int(sys.stdin.readline()))    seen.append(val)
num_correct = num_incorrect = 0print('ready to predict')
while True:    # The recurrence relation is:    #    #     x[k + n] = x[k + m] ^ timesA(upper(x[k]) | lower(x[k + 1]))    #    # Substituting j = k + n gives    #    #     x[j] = x[j - n + m] ^ timesA(upper(x[j - n]) | lower(x[j - n + 1]))    #    # The 'seen' deque holds the last 'n' seen values, where seen[-1] is the    # most recently seen, therefore letting j = 0 gives the equation for the    # next predicted value.
    next_val = seen[-Params.n + Params.m] ^ timesA(                        upper(seen[-Params.n]) | lower(seen[-Params.n + 1]))    seen.append(next_val)    predicted = temper(next_val)
    actual = sys.stdin.readline()    if not actual:        print('end of input -- {} predicted correctly, {} failures'.format(                    num_correct, num_incorrect))        sys.exit(0)
    actual = int(actual)    if predicted == actual:        status = 'CORRECT'        num_correct += 1    else:        status = 'FAIL'        num_incorrect += 1
    print('predicted {} got {} -- {}'.format(predicted, actual, status))```
Here's what you get as output (in this case, varies everytime):
```bash$ cat data.txt | python3 mer_twis.pywaiting for 624 previous inputsready to predictpredicted 2630305257 got 2630305257 -- CORRECTpredicted 2597663602 got 2597663602 -- CORRECTpredicted 1795123759 got 1795123759 -- CORRECTpredicted 306338802 got 0 -- FAILpredicted 2955851394 got 1 -- FAILpredicted 1106083444 got 2 -- FAILpredicted 1852587916 got 3 -- FAILpredicted 259036002 got 4 -- FAILpredicted 4098119175 got 5 -- FAILpredicted 1412275791 got 6 -- FAILpredicted 545371933 got 7 -- FAILpredicted 2098379118 got 8 -- FAILpredicted 2550571293 got 9 -- FAILpredicted 2691429539 got 10 -- FAILpredicted 470431618 got 11 -- FAILpredicted 1731687872 got 12 -- FAILpredicted 499518855 got 13 -- FAILpredicted 1368988182 got 14 -- FAILpredicted 767634446 got 15 -- FAILpredicted 1065878028 got 16 -- FAILpredicted 1428656079 got 17 -- FAILpredicted 3030198656 got 18 -- FAILpredicted 1804758619 got 19 -- FAILend of input -- 3 predicted correctly, 20 failures```
Now send the actual values to the netcat server and obtain the flag.
The flag is:
```FwordCTF{R4nd0m_isnT_R4nd0m_4ft3r_4LL_!_Everyhthing_is_predict4bl3_1f_y0u_kn0w_wh4t_Y0u_d01nGGGG}```