# ddu du ddu du ddu du ddu du ddu du ddu du ddu du ddu du ddu du ddu du> nc  ec2-13-251-81-16.ap-southeast-1.compute.amazonaws.com 3333
TLDR: The server xors each byte with the previous byte and encodes the outputas base16 using uppercase letters A-P.
Full solver code on my [GitLab](https://gitlab.com/Askaholic/ctf-writeups/blob/master/Mates%202018/base16_solver.py)
--------------------------------------The description of this challenge gives us a server to connect to and nothingelse, so we have to connect to figure out what it's about.
```$ nc  ec2-13-251-81-16.ap-southeast-1.compute.amazonaws.com 3333Please select one of flowing options:1 - You send me any message then I will give you corresponding cipher text2 - I show you the challenge flag and you have 3 times to guess the plain textYour choice:```
So what we need to do is figure out how the server is encoding our messages andif we can decode arbitrary messages, then the server will just give us the flag.
So we start by giving the server some simple, and repeating input just in caseit will help us find any obvious patterns.
```Your choice: 1Your message: AAAAAAAAAAThe cipher text: T0VFQktGQUFPRUVCS0ZBQU9FRUJLRkFBT0VFQktGQUFPRUVCS0ZBQQ==```
The server responds with some base64 encoded data which after decoding lookslike this: (spaces added for clarity)```OEEBKFAAOEEBKFAAOEEBKFAAOEEBKFAAOEEBKFAAOEEBKFAA OEEBKFAA OEEBKFAA OEEBKFAA OEEBKFAA```
So we can already see that just like our input, the output follows a veryconsistent pattern. We also notice that the output is 4 times as long as ourinput. But what could it mean?
Lets take one step back for a second and notice another interesting fact. Thedata was given to us in base64 encoded format, but it only consists of uppercaseletters. Usually base64 is used when you want to transfer arbitrary data withascii printable characters only. Maybe our try with the A's just happened toproduce only uppercase letters. Lets see what the server gives us when we pickoption 2 for solving the cipher.
```nc  ec2-13-251-81-16.ap-southeast-1.compute.amazonaws.com 3333Please select one of flowing options:1 - You send me any message then I will give you corresponding cipher text2 - I show you the challenge flag and you have 3 times to guess the plain textYour choice: 2Nice! Your challenge message: OCEHJDDGNKHPJJDMNHHCLKBPOJEMLABFPNFIJODLNMHJLBBENDHGKAAFMOGLLPBKPBFEJFDAMMGJIECBONEIJLDOKPAKPHFCINCIOCEHJHDCMOGLKIANNMHJKEABMDGGPBFEJDDGMGGDIJCMMLGOKGADPHFCJFDAPLFOYour guess:```
Again, only uppercase letters. So why would the server be base64 encoding it?Maybe it's a subtle hint as to what the letters could mean. The way base64encoding works is by splitting the input into 6-bit chunks (yes 6bits is very awkward to work with) and translating the resulting integer byindexing into a 64 (2^6) character alphabet array (so `000000` becomes `a`, `000001`becomes `b`, etc).
So it's possible that this challenge is doing something similar, but with adifferent alphabet and probably fewer bits. If we look at the challenge messagefrom option 2, we notice that the "highest" letter which appears is `P`. And ifwe check at which position it is located in the English alphabet we find thatit is the 16th letter! So the text could be a sort of base16 encoding using thealphabet `ABCDEFGHIJKLMNOP` instead of the standard hex digits which we wouldexpect.
After testing a few of the letters manually and finding that some of them dodecode to the ascii text that we inputed, we write a simple decoder for turningthe letters into bytes.
```pythonimport stringALPHABET = string.ascii_uppercase[0:16]
def decode(cipher):    bits = ""    for c in cipher:        num = ALPHABET.find(c)        bits += int_to_bin(num)    return bits```
Now when we decode the cipher for our original 10 A's and print it out as asascii we get some sort of mess of unicode:```äA¥äA¥äA¥äA¥äA¥```
But we notice that in some places our original text is already visible. Thelength of this text is also a bit strange because it isn't a multiple of 10. Itturns out that's just because there were some null bytes in the string whichdidn't get printed.```'äA¥\x00äA¥\x00äA¥\x00äA¥\x00äA¥\x00'```
The actual length of the string is twice as long as our input, and when we askthe server to encode only a single A, we notice that it gives us back 2characters worth of data: `äA`. The first character doesnt seem to make muchsense, but the second character is simply our input. So we decide to ignore thefirst characters for now (in the end, these turned out not to matter at all).
Removing the first characters in the string gives us:```'A\x00A\x00A\x00A\x00A\x00'```
So half of our message is preserved, but the other half has turned into nullbytes. We can try some other input strings like `ABCD` and notice that the nullbytes only occur with repeating characters. Since this is a crypto challengethere is a good chance that this is a result of xoring characters together. Ifyou have experience with xor you will know that xoring something with it's selfalways results in 0. So the null bytes are probably the result of xoring two A'stogether. But which two A's?
When we try the string `ABCD` we notice that we now only see the `A` in ourdecoded text: `'A\x03@\x04'`. But since we expect that the cipher is using xor,and xor is it's own inverse (a ^ b ^ a = b), we can xor the second byte with`B` to get some hints about what's happening.
```python>>> ord('B')66>>> hex(66 ^ 3)'0x41'>>> chr(0x41)'A'```
And bingo! The second byte is simply xored with the first byte. We can try thiswith the other bytes too and notice that they are always xored with the previousbyte. We can write a simple function to undo this xor, and we should have aworking decoder.
```pythondef undo_mangle(binstr):    i = 0    resultstr = ""    prev_chunk = None    while i < len(binstr):        chunk = binstr[i+8:i+16]        if prev_chunk:            resultstr += xor(chunk, prev_chunk)        else:            resultstr += chunk
        prev_chunk = chunk        i += 16  # Skip two chars ahead because we always ignore the first one    return resultstr```
With our working decoder we can decode the challenge string we got earlier:`GqICNmSYMcBmbsnqNdYHiv4XzouYftxg2bUOBmQbn`. We send this back to the serverand get the flag.
```Your guess: GqICNmSYMcBmbsnqNdYHiv4XzouYftxg2bUOBmQbnAwesome! Here is the final flag: Good fun with bad crypto```