Rating:

## ASIS Finals: license

----------
## Challenge details
| Contest | Challenge | Category | Points |
|:---------------|:--------------|:----------|-------:|
| ASIS Finals | License | Reversing | 125 |

*Description*
> Find the flag in this file.

----------
## Write-up

### Format of Keyfile

We are given a binary file:

>```
>$ file license
>license: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=c81d4aad867bcf65380fef33fcab2ee2372c03a9, stripped
>```

On a first run:

>```
>$ ./license
>key file not found!
>```

Lets look at the disassembly in IDA, we find the filename it is looking for in the first three lines of *main*

>```asm
>mov esi, offset modes ; "rb"
>mov edi, offset filename ; "_a\nb\tc_"
>```

Since there are no other xrefs to the filename, I chose to patch the filename in the binary to something friendlier:

>```
>$ python -c 'import binascii; print binascii.hexlify("keyABCD")'
>6b657941424344
>```

![alt patch](1.png)

Continuing to follow the execution flow of the program when it can find the keyfile we get to the following pseudocode:

>```C
>fclose(v4);
>if ( -45235 * length_of_keyfile * length_of_keyfile * length_of_keyfile * length_of_keyfile
> + -1256 * length_of_keyfile * length_of_keyfile * length_of_keyfile
> + 14392 * length_of_keyfile * length_of_keyfile
> + -59762 * length_of_keyfile
> - 1949670109068LL
> + 44242 * length_of_keyfile * length_of_keyfile * length_of_keyfile * length_of_keyfile * length_of_keyfile )
>{
>LOBYTE(v5) = 0;
>LODWORD(v18) = std::operator<<<std::char_traits<char>>(6299840LL, 4198643LL);// invalid format
>std::endl<char,std::char_traits<char>>(v18);
>}
>else
>{....
>```

Which means our keylength needs to be a solution to the following inequality:

![alt eq1](2.png)

For which wolframalpha gives us the solution: 34

The next part, with the variables renamed:

>```C
>else
>{
> v34 = base_of_input;
> pos_in_file = base_of_input;
> newline_counter = 1;
> while ( length_of_keyfile > pos_in_file - base_of_input )
> {
> v13 = pos_in_file + 1;
> if ( *(_BYTE *)pos_in_file == '\n' )
> {
> v14 = newline_counter++;
> *(&v34 + v14) = v13;
> }
> pos_in_file = v13;
> }
> length_of_line = (length_of_keyfile - (newline_counter - 1)) / newline_counter;
> dword_6021E0 = length_of_line;
> if ( (unsigned __int64)(5 * (signed int)length_of_line) > 91 || (signed int)length_of_line <= 0 )
> {
> v5 = 32;
> LODWORD(v17) = std::operator<<<std::char_traits<char>>(6299840LL, 4198643LL);// invalid format
> std::endl<char,std::char_traits<char>>(v17);
> }
> else if ( newline_counter == 5 )
> {
>```

So to move on we need our keyfile to contain four newline characters, which means the length of each line is six (30 / 5), the last line must not end with a newline.

By now we know our keyfile is of the following form:

>```
>aaaaaa
>bbbbbb
>cccccc
>dddddd
>eeeeee
>```

### The Key

The next part of the binary will establish a relation between the five lines of the keyfile, there are 5 checks:

#### 1

>```C
> do
> {
> s1[index1] = *(line_1 + index1) ^ *(line_2 + index1);
> ++index1;
> }
> while ( length_of_line > index1 );
> if ( memcmp(
> s1,
> "iKWoZLVc4LTyGrCRedPhfEnihgyGxWrCGjvi37pnPGh2f1DJKEcQZMDlVvZpEHHzUfd4VvlMzRDINqBk;1srRfRvvUW",
> length_of_line) )
> goto fail;
>```

Giving the first relation:

![alt eq2](3.png)

#### 2

>```C
> do
> {
> s1[index2] = *(line_2 + index2) ^ *(line_4 + index2) ^ 0x23;
> ++index2;
> }
> while ( length_of_line > index2 );
> line_4_again = line_4;
> if ( memcmp(s1, &aIkwozlvc4ltygr[length_of_line], length_of_line) )
> goto fail;
>```

Giving the second relation:

![alt eq3](4.png)

#### 3

>```C
> do
> {
> s1[index3] = *(line_4_again + index3) ^ *(line_3 + index3);
> ++index3;
> }
> while ( length_of_line > index3 );
> if ( memcmp(s1, (2 * length_of_line + 0x401120LL), length_of_line) )
> goto fail;
>```

Giving the third relation:

![alt eq3](5.png)

#### 4 & 5

>```C
> do
> {
> s1[index4] = *(line_4_again + index4) ^ *(line_5 + index4) ^ 0x23;
> ++index4;
> }
> while ( length_of_line > index4 );
> v28 = 0LL;
> do
> {
> s1[v28] ^= *(line_3 + v28);
> ++v28;
> }
> while ( length_of_line > v28 );
> if ( !memcmp(s1, (3 * length_of_line + 0x401120LL), length_of_line)
> && (v5 = memcmp(line_4_again, (4 * length_of_line + 0x401120LL), length_of_line)) == 0 )
> {
> v29 = 0LL;
> do ...
>```

Giving the fourth and final relations:

![alt eq3](6.png)

Since we know the fourth line, we can deduce the other lines from that, as the following python code implements:

>```python
>#!/usr/bin/python
>
>from pwn import *
>
>answer = "iKWoZLVc4LTyGrCRedPhfEnihgyGxWrCGjvi37pnPGh2f1DJKEcQZMDlVvZpEHHzU"
>
>a4 = answer[24:30]
>a2 = xor(xor(a4, chr(0x23)*6), answer[6:12])
>a1 = xor(answer[0:6], a2)
>a3 = xor(answer[12:18], a4)
>a5 = xor(xor(xor(answer[18:24], a3), a4), chr(0x23)*6)
>
>with open("keyABCD", "w") as f:
> f.writelines((a1 + "\n", a2 + "\n", a3 + "\n", a4 + "\n", a5))
>```

After which the flag is revealed:

>```
>$ ./license
>program successfully registered to ASIS{8d2cc30143831881f94cb05dcf0b83e0}
>```

Original writeup (https://github.com/dqi/ctf_writeup/tree/master/2015/asis_finals/license).