Splatter Calc [reverse]

# splatter calc

Reverse this binary to determine the input number required to read the flag on the remote server.

• nc challenges.tamuctf.com 60032

## Linear congruential generator

Looks like a rust bin with LCG. Binary implements an LCG seeded with user input, it then applies a binary operation to the output of the LCG and a starting fixed point `0xcafebabe`.

It repeats this process 8 times in total, and every time it would use the next output from the LCG and the result of the previous binary operation. At the end of the routine it asserts that the output from the operation and the LCG each have a specific value.

Our goal is to get the initial seed that would lead to this state.

## Reversed code

```#include <stdio.h>
#include <stdlib.h>

unsigned long long transform(unsigned long long prev_trans, unsigned long long prev_lcg) {
int choice = (int)(prev_lcg & 0x7);
switch(choice) {
case 0:
return prev_trans;
case 1:
return prev_trans + prev_lcg;
case 2:
return prev_trans - prev_lcg;
case 3:
return prev_trans * prev_lcg;
case 4:
return (prev_trans * prev_trans);
case 5:
return (prev_trans << (prev_lcg & 0xFF));
case 6:
return (prev_trans >> (prev_lcg & 0xFF));
case 7:
return (prev_trans ^ prev_lcg);

}
return 0;
}

int main() {

unsigned long long seed;
scanf("%llu", &seed);
printf("Got seed: %llu\n", seed);
unsigned long long start = (long long)(seed & 7);
unsigned long long prev_trans = transform(0xcafebabe, seed);
unsigned long long prev_lcg = (seed * 0x83f66d0e3) + 0x24a452f8e;
for (int i = 0; i < 7; ++i) {
prev_trans = transform(prev_trans, prev_lcg);
prev_lcg = (prev_lcg * 0x83f66d0e3) + 0x24a452f8e;
}
if (prev_lcg == 0x471de8678ae30ba1 && prev_trans == 0xacdee2ed87a5d886) {
printf("%llu %llu\n", prev_trans, prev_lcg);
printf("YES");
return 0;
} else {
printf("%llu %llu\n", prev_trans, prev_lcg);
printf("NO");
return 1;
}
}
```

## Solution

```from gmpy2 import isqrt, mpz
from Crypto.Util.number import inverse
from sympy.ntheory.residue_ntheory import sqrt_mod

MAX = 2 ** 64

def unl(p):
return ((p - 0x24a452f8e) * inverse(0x83f66d0e3, MAX)) % MAX

def unt(t, p):
choice = p & 0x7
mapz = {
0: lambda x: x,
1: lambda x: x - x % MAX,
2: lambda x: x + x % MAX,
3: lambda x: (x * inverse(x, MAX)) % MAX,
4: lambda x: sqrt_mod(x, MAX),
5: lambda x: (x >> (x & 0xFF)) % MAX,
6: lambda x: (x << (x & 0xFF)) % MAX,
7: lambda x: (x ^ x)
}
return mapz[choice]((t, p)) % MAX

def rel(p):
return ((p * 0x83f66d0e3) + 0x24a452f8e) % MAX

def ret(t, p):
choice = p & 0x7
mapz = {
0: lambda x: x,
1: lambda x: x + x % MAX,
2: lambda x: x - x % MAX,
3: lambda x: (x * x) % MAX,
4: lambda x: (x ** 2) % MAX,
5: lambda x: (x << (x & 0xFF)) % MAX,
6: lambda x: (x >> (x & 0xFF)) % MAX,
7: lambda x: (x ^ x)
}
return mapz[choice]((t, p)) % MAX

prevl = 0x471de8678ae30ba1
prevt = 0xacdee2ed87a5d886

for i in range(8):
y = unl(prevl)
x = unt(prevt, y)
print(y, x)
assert rel(y) == prevl
assert ret(x, y) == prevt
print(i)
prevl = y
prevt = x

print(hex(prevl), hex(prevt))
print(prevl, prevt)
```

## Flag

```\$ python solve.py
7515707083221606161 4940936045942684021
0
17764897228028070113 5622782891624165524
1
4054891027388248273 1567891864235917251
2
16487616737524898849 3527019200420570018
3
269053440828241041 3257965759592328977
4
564860419845330273 2693105339746998704
5
2693104353610717777 986136280927
6
982730589345 3405691582
7
0xe4cf4ec4a1 0xcafebabe
982730589345 3405691582

\$ nc challenges.tamuctf.com 60032
Please enter an initial rng: 982730589345
gigem{00ps_ch3ck_y0ur_7upl35}
```

## Flag

`gigem{00ps_ch3ck_y0ur_7upl35}`