It is quite simple PRNG with the equation (t = 0xdeadbeef): $x_i = (k_1 - t) x_{i-1} + k_1 t x_{i-2} + k_2 (mod\ k_3)$

We can define $y_i$ as $y_i = x_i + t x_{i-1}$, then $y_i = k_1 y_{i-1} + k_2 (mod\ k_3)$. So, it’s just same as the normal LCG.

I used the method to break LCG described in this link, and the solver is here.

```from pwn import *

def xgcd(b, a):
x0, x1, y0, y1 = 1, 0, 0, 1
while a != 0:
q, b, a = b // a, a, b % a
x0, x1 = x1, x0 - q * x1
y0, y1 = y1, y0 - q * y1
return  b, x0, y0

def mulinv(b, n):
g, x, _ = xgcd(b, n)
if g == 1:
return x % n

r = remote('lcg.eatpwnnosleep.com', 12345)
inputs = []

for i in range(16):
r.sendline('1')
inputs.append( int(r.recvuntil('\n')) )

print(inputs)

arr = []

for i in range(15):
arr.append(inputs[i+1] + k*inputs[i])

# http://sandeepmore.com/blog/2012/03/23/breaking-linear-congruential-generator/
def d(i, j):
t1 = arr[i] - arr[0]
t2 = arr[i+1] - arr[1]
t3 = arr[j] - arr[0]
t4 = arr[j+1] - arr[1]

return t1 * t4 - t2 * t3

t = d(2, 3)
for i in range(3, 13):
t, _, _ = xgcd( t, d(i, i+1) )

k3 = t if t > 0 else -t

print("k3: ", k3)

g0_inv = mulinv( (arr[1] - arr[0]) % k3, k3)
k1 = ((arr[2] - arr[1]) * g0_inv) % k3
k2 = (inputs[2] - (k1 - k) * inputs[1] - k1 * k * inputs[0]) % k3

print("k1: ", k1)
print("k2: ", k2)

s0, s1 = inputs[-2], inputs[-1]

for i in range(16):
s0, s1 = s1, ( (k1 - k) * s1 + k1 * k * s0 + k2 ) % k3
r.sendline( str(s1) )

r.interactive()```

The flag is SCTF{LCG_is_too_simple_to_be_a_good_CSPRNG}.