# cup-of-tea
Details:
```For my friend a cup of Tea and a wonderful message: D0A4AE4DCC99E368BABD66996D67B88159ABE2D022B0AD78F1D69A6EB1E81CF3589B3EFE994005D6A9DE9DB2FD3C44B77628D2316AAC2229E938EC932BE42220DD6D1D914655820A43C09E2236993A8D
Flag: CTF{sha256(decrypt_message)}```
Given a binary [cup-of-tea](https://github.com/EvilBunnyWrote/Write-ups/blob/main/DefCamp_D-CTF-2021-22/cup-of-tea/cup-of-tea.zip)
Let's open in in IDA PRO and analyze.
The `main` function looks pretty straightforward:```cint __cdecl main(int argc, const char **argv, const char **envp){  int i; // [rsp+0h] [rbp-20A0h]  int v6; // [rsp+4h] [rbp-209Ch]  __int64 key[16]; // [rsp+10h] [rbp-2090h] BYREF  char s[80]; // [rsp+90h] [rbp-2010h] BYREF  char v9[4104]; // [rsp+1090h] [rbp-1010h] BYREF  unsigned __int64 v10; // [rsp+2098h] [rbp-8h]
  v10 = __readfsqword(0x28u);  key[0] = 'I';  key[1] = ' ';  key[2] = 'l';  key[3] = 'o';  key[4] = 'v';  key[5] = 'e';  key[6] = ' ';  key[7] = 'p';  key[8] = 'a';  key[9] = 'n';  key[10] = 'c';  key[11] = 'a';  key[12] = 'k';  key[13] = 'e';  key[14] = 's';  strcpy(s, "Betaflash_is_slow");  *(_WORD *)&s[18] = 0;  *(_DWORD *)&s[20] = 0;  *(_QWORD *)&s[24] = 0LL;  memset(&s[32], 0, 0xFE0uLL);  puts("We are under attack.");  puts("We need a group of hacker to decrypt this weird message.");  puts("And Betaflash is not slow :)).");  encrypt(s, 10LL, key);  v6 = strlen(s);  for ( i = 0; i < v6; ++i )    sprintf(&v9[2 * i], "%02X", (unsigned __int8)s[i]);  v9[2 * i] = 0;  printf("Decrypt me if you can: %s\n", v9);  return __readfsqword(0x28u) ^ v10;}```
I renamed the key variables to be more readable, so we can see the applicationdoes encryption of a string `"Betaflash_is_slow"` using the key `"I love pancakes"` and then it prints hex dump of the ciphertext to console.
Let's analyze the `encrypt` function.```c__int64 __fastcall encrypt(_QWORD *a1, __int64 a2, __int64 a3){  __int64 result; // rax  unsigned __int64 *v4; // rax  __int64 v5; // rcx  __int64 v6; // rax  unsigned __int64 v7; // [rsp+20h] [rbp-38h]  unsigned __int64 v8; // [rsp+28h] [rbp-30h]  __int64 i; // [rsp+30h] [rbp-28h]  __int64 v10; // [rsp+38h] [rbp-20h]  __int64 v11; // [rsp+50h] [rbp-8h]
  v7 = a1[a2 - 1];  v8 = 0LL;  result = 2654435769LL;  if ( a2 > 1 )  {    v10 = 52 / a2 + 6;    while ( 1 )    {      v6 = v10--;      if ( v6 <= 0 )        break;      v8 += 2654435769LL;      v11 = (v8 >> 2) & 3;      for ( i = 0LL; i < a2 - 1; ++i )      {        v4 = &a1[i];        *v4 += (((4LL * a1[i + 1]) ^ (v7 >> 5)) + ((a1[i + 1] >> 3) ^ (16 * v7))) ^ ((a1[i + 1] ^ v8)                                                                                   + (v7 ^ *(_QWORD *)(8 * (v11 ^ i & 3) + a3)));        v7 = *v4;      }      v5 = 8 * a2 - 8;      *(_QWORD *)((char *)a1 + v5) += (((4LL * *a1) ^ (v7 >> 5)) + ((*a1 >> 3) ^ (16 * v7))) ^ ((*a1 ^ v8)                                                                                              + (v7 ^ *(_QWORD *)(8 * (v11 ^ i & 3) + a3)));      v7 = *(_QWORD *)((char *)a1 + v5);    }    return 0LL;  }  return result;}```
I'm usually start analyzing the crypto algorithms with checking numeric constants like the following `result = 2654435769LL`. Quick grep using Google brought me to the [Tiny Encryption Algorithm or TEA WiKi](https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm). This corresponds the task name `cup-of-tea` so we in the right direction.
The algorithm in wiki has our constant `2654435769 or 0x9E3779B9` but the code example doesn't correspond our decompiled code at first glance.
Let's check the TEA algorithm successors:
| Algorithm | Standard Feistel network rounds number | Block size  | Key size        ||-----------|----------------------------------------|-------------|-----------------|| TEA       | 64                                     | 64 bits     | 128 bits        || XTEA      | 64                                     | 64 bits     | 128 bits        || XTEA-1    | 32                                     | 64 bits     | 128 bits        || XTEA-2    | 64                                     | 128 bits    | 128 bits        || XTEA-3    | 64                                     | 128 bits    | 256 bits        || XXTEA     | 52 + 12 * M                            | 64 * M bits | 128 bits        || RTEA      | 48 or 64                               | 64 bits     | 128 or 256 bits || Raiden    | 32                                     | 64 bits     | 128 bits        |
We can spot the similarity of XXTEA algorithm Feistel rounds number `52 + 12 * M` from the table above matches withthe code we have:
![rounds.png](https://github.com/EvilBunnyWrote/Write-ups/raw/main/DefCamp_D-CTF-2021-22/cup-of-tea/rounds.png)
Let's grab some existing XXTEA Python library and check its output having same input data and key.
I found two libraries:- [xxtea-py](https://github.com/xxtea/xxtea-python)- xxtea
Let's start from first one. The first goal is to make sure encoding works as expected, so let'sgrab the `./cup-of-tea` encoded hex values. Having input data and key same the encoded result has to be equalto what we grabbed.
Here is the first trial, what we have pay attention to ```pythonkey = b'I love pancakes\0'plain_test = b'Betaflash_is_slow'.rjust(80, b'\0')expect = bytes.fromhex('C7E4C81E20EBFB67A4977BA91C9C312FFF81669CA85798D475F0D9081DF7017CC8D009ADF02F67DD41D1F781EF561D0EF8EA2225502AF957D6844084CEE3BB7D2350DBF05DCD8B0AD33CD52C5E0171E4')enc = encrypt(plain_test, key)print(enc == expect)print(enc[:16].hex().upper())```
But the output is negative:```0AED8E4B82D7FBCF2D99AFB0762988C1False```
Lets compare original XXTEA with what we have in the binary. I opened the `xxtea-py` package source and I see that the core of this library is written in C, the `xxtea.c` is what we wanted to check. ```cstatic uint32_t * xxtea_uint_encrypt(uint32_t * data, size_t len, uint32_t * key) {    uint32_t n = (uint32_t)len - 1;    uint32_t z = data[n], y, p, q = 6 + 52 / (n + 1), sum = 0, e;
    if (n < 1) return data;
    while (0 < q--) {        sum += DELTA;        e = sum >> 2 & 3;
        for (p = 0; p < n; p++) {            y = data[p + 1];            z = data[p] += MX;        }
        y = data[0];        z = data[n] += MX;    }
    return data;}```
It looks very close to our algorithm except few differences:* `key` in the code is defined as `uint32_t *` a pointer to 4-byte long values array, but in the binary we see that key is passed as an array of `__int64` values. Also we knowThat the algorithm key length is 16-bytes long by definition.* `data` pointer in binary points to the `_QWORD` which is `uint64_t`, but in the algorithmit has type `uint32_t * `
Having all this in mind, lets make simple C++ application to do encryption/decryption. I used Visual Studio 2017 to create a simple Console Application in C++, copied `xxtea.{c,h}` to itand added to the project:
![project_structure](https://github.com/EvilBunnyWrote/Write-ups/raw/main/DefCamp_D-CTF-2021-22/cup-of-tea/project_structure.png)
**I selected 64-bit target in Visual Studio**
As we have `xxtea_uint_decrypt` and `xxtea_uint_encrypt` used 32-bit pointers, I create my own copies of them with the suffix `64` and 64-bit pointers:
In the xxtea.h:```cppuint64_t * xxtea_uint_encrypt64(uint64_t * data, size_t len, uint64_t * key);uint64_t * xxtea_uint_decrypt64(uint64_t * data, size_t len, uint64_t * key);```
In the xxtea.c:```cppuint64_t * xxtea_uint_encrypt64(uint64_t * data, size_t len, uint64_t * key) {	uint64_t n = (uint64_t)len - 1;	uint64_t z = data[n], y, p, q = 6 + 52 / (n + 1), sum = 0, e, first, second;
	if (n < 1) return data;
	while (0 < q--) {		sum += DELTA;		e = sum >> 2 & 3;
		for (p = 0; p < n; p++) {			y = data[p + 1];			first = (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)));			second = ((sum ^ y) + (key[(p & 3) ^ e] ^ z));			z = data[p] += first ^ second;		}
		y = data[0];		z = data[n] += MX;	}
	return data;}
uint64_t * xxtea_uint_decrypt64(uint64_t * data, size_t len, uint64_t * key) {	uint64_t n = (uint64_t)len - 1;	uint64_t z, y = data[0], p, q = 6 + 52 / (n + 1), sum = q * DELTA, e;
	if (n < 1) return data;
	while (sum != 0) {		e = sum >> 2 & 3;
		for (p = n; p > 0; p--) {			z = data[p - 1];			y = data[p] -= MX;		}
		z = data[n];		y = data[0] -= MX;		sum -= DELTA;	}
	return data;}```
Then running the following code I got match of expected encrypted output with what we receivedfrom the binary:```cpp#include <iostream>#include <iomanip>#include <stdio.h>#include "xxtea.h";
int main(){	static const char plainText[80] = "Betaflash_is_slow";	static const char key[] = "I\0\0\0\0\0\0\0 \0\0\0\0\0\0\0l\0\0\0\0\0\0\0o\0\0\0\0\0\0\0";	char buff[1024] = {};	memcpy(buff, plainText, strlen(plainText));	size_t out_len = 80;	const char* encrypted = (const char*)xxtea_uint_encrypt64((uint64_t*)buff, 80 / sizeof(uint64_t), (uint64_t*)key); 	printf("size %zu\n", out_len);	for (size_t i = 0; i < out_len; ++i) {		printf("%02X ", (unsigned int)encrypted[i] & 0xFF);		if ((i + 1) % 16 == 0) {			printf("\n");		}	}    printf("\n");}```
![encrypted](https://github.com/EvilBunnyWrote/Write-ups/raw/main/DefCamp_D-CTF-2021-22/cup-of-tea/encrypted.png)
Ok then now we can put our cipher text to the decryption function:```cppint main(){	static const char cipherText[80] = { 0xd0, 0xa4, 0xae, 0x4d, 0xcc, 0x99, 0xe3, 0x68, 0xba, 0xbd, 0x66, 0x99, 0x6d, 0x67, 0xb8, 0x81, 0x59, 0xab, 0xe2, 0xd0, 0x22, 0xb0, 0xad, 0x78, 0xf1, 0xd6, 0x9a, 0x6e, 0xb1, 0xe8, 0x1c, 0xf3, 0x58, 0x9b, 0x3e, 0xfe, 0x99, 0x40, 0x05, 0xd6, 0xa9, 0xde, 0x9d, 0xb2, 0xfd, 0x3c, 0x44, 0xb7, 0x76, 0x28, 0xd2, 0x31, 0x6a, 0xac, 0x22, 0x29, 0xe9, 0x38, 0xec, 0x93, 0x2b, 0xe4, 0x22, 0x20, 0xdd, 0x6d, 0x1d, 0x91, 0x46, 0x55, 0x82, 0x0a, 0x43, 0xc0, 0x9e, 0x22, 0x36, 0x99, 0x3a, 0x8d };	static const char key[] = "I\0\0\0\0\0\0\0 \0\0\0\0\0\0\0l\0\0\0\0\0\0\0o\0\0\0\0\0\0\0";	char buff[1024] = {};	memcpy(buff, cipherText, strlen(cipherText));	size_t out_len = 80; 	const char* decrypted = (const char*)xxtea_uint_decrypt64((uint64_t*)buff, 80 / sizeof(uint64_t), (uint64_t*)key);	printf("size %zu\n", out_len);	for (size_t i = 0; i < out_len; ++i) {		printf("%02X ", (unsigned int)decrypted[i] & 0xFF);		if ((i + 1) % 16 == 0) {			printf("\n");		}	}	printf("%s\n", decrypted);    printf("\n");}```
![decrypted](https://github.com/EvilBunnyWrote/Write-ups/raw/main/DefCamp_D-CTF-2021-22/cup-of-tea/decrypted.png)
Ok seems good output, now format the flag and thats it:```py>>> from hashlib import sha256>>> print(f'CTF{{{sha256(b"R3vErs3_1S_NoT_F0r_Ev3RYOn3").hexdigest()}}}')CTF{b98b74c78593c1238136a2d24d300ad2b1af82b137523adbdde2ba08b02a9cf0}```
