Rating:

### Brief description ###
On `chal.tuctf.com:30102` a server presents the audacious with a 10-level challenge (level 0 ~ level 9).
There is no "save" functionality. Therefore, each try always starts from level 0.

### Level 0 to Level 4 ###
The first 5 levels are essentially the same. The server asks for a string and returns its encoded form.
After that, it outputs for 50 times a random encoded word, asking to decode it.
Each error is not fatal and results in a retry request, although there is a time limit to provide the correct answer.
The encoding consists of a consistent mapping `{letter -> unique_string_of_symbols}`.
Both lowercase and uppercase letters are mapped to the same string of symbols (i.e., the system is case insensitive).
No numbers are included in valid decoded strings.

#### The strategy for Level 0 ~ Level 4 ####
Just send `qwertyuiopasdfghjklzxcvbnm`, retrieve the encoded string, derive the unique mappings, and save them somewhere.
Then, for 50 times, receive the string to decode, apply the inverse mappings, and send back the decoded string.
After 50 correct guesses, the level increases by 1, and the mappings change.
At the beginning of each level one can send `qwertyuiopasdfghjklzxcvbnm` to retrieve the new mappings.

### Level 5 ###
The 6th level is similar to the previous ones in that at the beginning you can send a string and receive its encoded form.
Then, the usual 50-times cycle of receive-decode-send applies.
However, the mappings approach changes for this level: each string of symbols is mapped to a different letter depending on its position.
In other words, the new inverse mappings for decoding the ciphertext are `{(unique_string_of_symbols, position) -> letter}`.
Furthermore, the positions are considered modulo 8.
For instance, the same string of symbols is mapped to the same letter in all the following positions: 0, 8, 16, etc.
The same applies, for example, to positions 3, 11, 19, etc.

#### The strategy for Level 5 ####
Send (python syntax) `"a"*8 + "b"*8 + ... + "z"*8`, retrieve the encoded string, derive the mappings, and save them somewhere.
Then, for 50 times, receive the string to decode, apply the inverse mappings, and send back the decoded string.

### Level 6 ###
The 7th level features again an oracle encoding a string of your choice, and a 50-times receive-decode-send cycle.
This time, the mappings are position independent like the first 5 level, but there is a catch.
The encoding consists of 2 commutative operations (i.e., the order does not matter).
Not only each letter is consistently mapped to a unique string of symbols, but then a scrambling happens.
For the sake of explainability, it is easier to consider the scrambling as the first operation (i.e., before the encoding).

#### Level 6: the scrambling ####
For strings whose length is less than 5 characters, the scrambling always returns the same string.
For longer strings, consider an unscrambled input and an output string to build:

1) The first character of the output string is always the first character of the input string. Let's call `i` the position of such character in the input string.
2) Each successive character of the output string is the character in position `i + 4` of the input string, if it exists. Otherwise, it is the first character of the input string which has not been "added" yet to the output string.

For instance, the string `qwertyuiopasdfghjklzxcvbnm` is scrambled to `qtodjxnwypfkcmeuaglvrishzb`.
I could not find an easy way to reverse the scrambling for strings of arbitrary length.
However, the scramble is cyclical: if you continue to apply it to each product of itself, it will at some point output the unscrambled string.

#### Level 6: the strategy ####
Send whatever string to the oracle and ignore the returned one (the mappings are fixed, and can be retrieved by not ignoring the oracle output during a test run with `qwertyuiopasdfghjklzxcvbnm`, just mind the scrambling).
Then, for the usual 50 times:

1) Apply the mappings to get a string of letters.
2) Then apply the scrambling procedure multiple times, keeping track of the very first input, the lastest input, and the output.
3) When the output matches the very first input, then the latest input is the unscrambled string we want.
4) Send the output of phase 3) to the server.

Note that steps 2) and 3) can be applied in any order.

### Level 7 ###
The 8th level behaves like any Level 0~4. The strategy for any of them works for Level 7.

### Level 8 ###
The 9th level behaves like Level 5 with a minor caveat.
This time the positions are considered modulo 7, rather than modulo 8.
Therefore, the string to send is (python syntax) `"a"*7 + "b"*7 + ... + "z"*7`.
If one wishes to reuse the code from Level 5, every modulo 8 operation must be changed to a modulo 7 operation.

### Level 9 ###
Once you reach the 10th level, you are being told that it is the last level.
Luckily, this level behaves exactly like Level 6. Its strategy works for Level 9.
Once you complete Level 9, you receive the flag.

### The Exploit ###
Check [this link](https://github.com/cloudstrife9999/tuctf-crypto-infinite/blob/master/exploit.py)

Original writeup (https://github.com/cloudstrife9999/tuctf-crypto-infinite/blob/master/exploit.py).
unblvrDec. 2, 2019, 11:57 a.m.

Level 6 and 9 were column transpositions with key length 4 (order 1,2,3,4). Just undo that operation and you can solve it as a normal mapping problem.