# Interactive
Đề bài gồm 1 file release.exe

và 1 file output.txt
```
vYHAW7QX6DXGkNTRiDVlK8IGELPs/zyQ4124RObD6IqNCer8ipVSMipChgu/tVKcX/IB/Zz2XmS053UxuEiQLq==
```
Kiểm tra bằng DIE thì mình thấy nó đã bị packed bằng upx


Sau khi unpack thì mình chạy lại chương trình cho ra kết quả khác 2+2=5, có thể đây là một cảnh báo cho việc có thể một vài chỗ khác cũng sẽ bị unpack có vấn đề.

Load lại vào IDA và tìm tới hàm có đoạn in ra 2 + 2 = 5 thì có được đoạn code sau:
```c
__int64 sub_1400D4BE0()
{
unsigned int v0; // eax
_QWORD *v1; // rbx
__int64 v2; // rax
_BYTE *v3; // rsi
__int64 v4; // rdx
__int64 v5; // rax
__int64 v6; // rax
_BYTE *v7; // rbx
__int64 v8; // r8
char *v9; // r12
size_t v10; // rax
__int64 v11; // rbx
void *v12; // rax
const char *v13; // rsi
size_t v14; // rax
unsigned __int64 v15; // rdi
unsigned __int64 v16; // rsi
_QWORD *v17; // rbx
__int64 v18; // rax
_BYTE *v19; // rdi
__int64 v20; // rdx
__int64 v21; // rax
__int64 (__fastcall *v22)(); // rax
__int64 (__fastcall *v23)(); // rax
__int64 (__fastcall *v25)(); // rax
void *v26; // [rsp+40h] [rbp-3A8h]
void *v27; // [rsp+48h] [rbp-3A0h]
char v28[8]; // [rsp+78h] [rbp-370h] BYREF
char Str[16]; // [rsp+80h] [rbp-368h] BYREF
char v30; // [rsp+90h] [rbp-358h] BYREF
__int64 v31[2]; // [rsp+A0h] [rbp-348h] BYREF
char v32[16]; // [rsp+B0h] [rbp-338h] BYREF
const __m128i *v33[4]; // [rsp+C0h] [rbp-328h] BYREF
void *Src; // [rsp+E0h] [rbp-308h] BYREF
size_t Size; // [rsp+E8h] [rbp-300h]
char v36; // [rsp+F0h] [rbp-2F8h] BYREF
void *v37; // [rsp+100h] [rbp-2E8h] BYREF
unsigned __int64 v38; // [rsp+108h] [rbp-2E0h]
__int64 v39[2]; // [rsp+110h] [rbp-2D8h] BYREF
__int128 v40[2]; // [rsp+120h] [rbp-2C8h] BYREF
void *v41; // [rsp+140h] [rbp-2A8h] BYREF
unsigned __int64 v42; // [rsp+148h] [rbp-2A0h]
__int64 v43[2]; // [rsp+150h] [rbp-298h] BYREF
void *v44[2]; // [rsp+160h] [rbp-288h] BYREF
__int64 v45; // [rsp+170h] [rbp-278h] BYREF
void *Block; // [rsp+180h] [rbp-268h] BYREF
__int64 v47; // [rsp+188h] [rbp-260h]
_BYTE v48[16]; // [rsp+190h] [rbp-258h] BYREF
char v49[584]; // [rsp+1A0h] [rbp-248h] BYREF
sub_140010020();
v0 = time64(0i64);
srand(v0);
v31[0] = (__int64)v32;
strcpy(v32, "2 + 2 = 5");
v31[1] = 9i64;
v1 = (_QWORD *)sub_1400CD390(&unk_1400D9AC0, v32, 9i64);
v2 = *(_QWORD *)(*v1 - 24i64);
v3 = *(_BYTE **)((char *)v1 + v2 + 240);
if ( !v3 )
sub_1400D5620();
if ( v3[56] )
{
v4 = (unsigned int)(char)v3[67];
}
else
{
sub_14002DE90(*(_QWORD *)((char *)v1 + v2 + 240));
v4 = 10i64;
v25 = *(__int64 (__fastcall **)())(*(_QWORD *)v3 + 48i64);
if ( v25 != sub_14002E6B0 )
v4 = (unsigned int)((char (__fastcall *)(_BYTE *, __int64))v25)(v3, 10i64);
}
v5 = sub_140081560(v1, v4);
sub_140081780(v5);
sub_140005350(v33);
v36 = 0;
Src = &v36;
Size = 0i64;
while ( 1 )
{
sub_1400CD390(&unk_1400D9AC0, "> ", 2i64);
v6 = *(_QWORD *)(qword_1400D9760[0] - 24i64);
v7 = *(_BYTE **)((char *)&qword_1400D9760[30] + v6);
if ( !v7 )
sub_1400D5620();
if ( v7[56] )
{
v8 = (unsigned int)(char)v7[67];
}
else
{
sub_14002DE90(*(_QWORD *)((char *)&qword_1400D9760[30] + v6));
v8 = 10i64;
v22 = *(__int64 (__fastcall **)())(*(_QWORD *)v7 + 48i64);
if ( v22 != sub_14002E6B0 )
v8 = (unsigned int)((char (__fastcall *)(_BYTE *, __int64, __int64))v22)(v7, 10i64, 10i64);
}
sub_1400CEF40(qword_1400D9760, &Src, v8);
if ( Size > 0x64 )
{
sub_140005110("Input too long!!!\n");
exit(0);
}
if ( Size == 4 && *(_DWORD *)Src == 1953069157 )
break;
sub_1400020E0(v28, 2i64);
v9 = Str;
do
*v9++ = rand();
while ( v9 != &v30 );
v30 = 0;
v37 = v39;
v10 = strlen(Str);
sub_140005160(&v37, Str, &Str[v10]);
v11 = sub_140003950(Src, Size);
v12 = memcpy(v49, *(const void **)v11, *(_QWORD *)(v11 + 8));
v40[0] = (__int128)_mm_loadu_si128(v33[0]);
v40[1] = (__int128)_mm_loadu_si128(v33[0] + 1);
v13 = (const char *)sub_140002AD0(v28, v12, *(_QWORD *)(v11 + 8), v40, Str);
v13[*(unsigned int *)(v11 + 8)] = 0;
v41 = v43;
if ( !v13 )
sub_1400D56A0("basic_string: construction from null is not valid");
v14 = strlen(v13);
sub_140005160(&v41, v13, &v13[v14]);
v15 = v38;
v16 = v42;
Block = v48;
v26 = v37;
v48[0] = 0;
v27 = v41;
v47 = 0i64;
sub_1400B1E40(&Block, v38 + v42);
if ( 0x3FFFFFFFFFFFFFFFi64 - v47 < v15 )
sub_1400D5790("basic_string::append");
sub_1400B1F80(&Block, v26, v15);
if ( 0x3FFFFFFFFFFFFFFFi64 - v47 < v16 )
sub_1400D5790("basic_string::append");
sub_1400B1F80(&Block, v27, v16);
sub_1400043C0(v44, &Block, 0i64);
if ( Block != v48 )
j_j_free_3(Block);
v17 = (_QWORD *)sub_1400CD390(&unk_1400D9AC0, v44[0], v44[1]);
v18 = *(_QWORD *)(*v17 - 24i64);
v19 = *(_BYTE **)((char *)v17 + v18 + 240);
if ( !v19 )
sub_1400D5620();
if ( v19[56] )
{
v20 = (unsigned int)(char)v19[67];
}
else
{
sub_14002DE90(*(_QWORD *)((char *)v17 + v18 + 240));
v20 = 10i64;
v23 = *(__int64 (__fastcall **)())(*(_QWORD *)v19 + 48i64);
if ( v23 != sub_14002E6B0 )
v20 = (unsigned int)((char (__fastcall *)(_BYTE *, __int64))v23)(v19, 10i64);
}
v21 = sub_140081560(v17, v20);
sub_140081780(v21);
if ( v44[0] != &v45 )
j_j_free_3(v44[0]);
if ( v41 != v43 )
j_j_free_3(v41);
if ( v37 != v39 )
j_j_free_3(v37);
}
sub_1400AF470(&Src);
sub_1400AF470(v33);
sub_1400AF470(v31);
return 0i64;
}
```
sub_140005350(v33): hàm tạo ra key
Vòng lặp vô tận liên tục yêu cầu nhập vào một xâu Str:
* Nếu có độ dài > 0x64 (100) thì thoát
* Nếu là exit thì thoát
* sub_1400020E0(v28, 2i64): ...
* sub_140005160(&v37, Str, &Str[v10]): ...
* sub_140003950(Src, Size): thêm padding cho Src cho đủ độ dài với một block là Size.
* v13 = (const char *)sub_140002AD0(v28, v12, *(_QWORD *)(v11 + 8), v40, Str): đây là hàm mã hóa chính của chương trình, có thể là AES CBC:
* v28:
* v12 là input
* v11 + 8: độ dài + 8
* v40: key được sinh bởi hàm sub_140005350
* Str: IV
```c
__int64 __fastcall sub_140002AD0(__int64 a1, __int64 a2, unsigned int a3, __int64 a4, const __m128i *a5)
{
__int64 v9; // r12
void *v10; // rbp
unsigned int v11; // r15d
__m128i v12; // xmm0
const __m128i *v13; // rbx
__m128i v15[5]; // [rsp+20h] [rbp-58h] BYREF
sub_140002120(a1, a3);
v9 = sub_1400D41A0(a3);
v10 = (void *)sub_1400D41A0((unsigned int)(16 * (*(_DWORD *)(a1 + 4) + 1)));
sub_1400027C0(a1, a4, v10);
v15[0] = _mm_loadu_si128(a5);
if ( a3 )
{
v11 = 0;
do
{
v12 = _mm_loadu_si128((const __m128i *)(a2 + v11));
v13 = (const __m128i *)(v9 + v11);
v11 += 16;
v15[0] = _mm_xor_si128(v12, v15[0]);
((void (__fastcall *)(__int64, __m128i *, const __m128i *, void *))sub_1400023F0)(a1, v15, v13, v10);
v15[0] = _mm_loadu_si128(v13);
}
while ( v11 < a3 );
}
j_j_free_2(v10);
return v9;
}
```

16 byte đầu tiên của kết quả chính là IV. Các đoạn tiếp theo Ciper[i] sinh bởi encrypt của phép xor Plain[i] với đoạn trước đó Cipher[i-1].
Trở lại với hàm sinh key thì có vẻ như nó cố định
```c
__m128i **__fastcall sub_140005350(__m128i **a1)
{
__int16 v1; // dx
unsigned int v2; // eax
int v3; // r8d
char v5; // cl
char *v6; // r9
unsigned int v7; // eax
int v8; // edx
__int64 v9; // rcx
__int16 v10; // cx
unsigned int v11; // edx
int v12; // r8d
char v13; // r9
char *v14; // r9
int v15; // edx
__int64 v16; // rcx
__int16 v17; // cx
unsigned int v18; // edx
int v19; // r8d
char v20; // r9
char *v21; // r9
int v22; // edx
__int64 v23; // rcx
__m128i *v24; // rax
__int64 v25; // rdx
__m128i v26; // xmm0
__m128i v27; // xmm1
__m128i *v28; // rax
unsigned int v30; // [rsp+24h] [rbp-B4h] BYREF
__int64 v31; // [rsp+28h] [rbp-B0h] BYREF
__m128i v32; // [rsp+30h] [rbp-A8h] BYREF
__m128i v33; // [rsp+40h] [rbp-98h] BYREF
char v34[136]; // [rsp+50h] [rbp-88h] BYREF
v1 = 32;
v2 = 79764919;
v3 = 0;
do
{
v5 = v2;
v2 >>= 1;
v3 = v5 & 1 | (2 * v3);
--v1;
}
while ( v1 );
v6 = aPractice;
v7 = -1;
do
{
v8 = (unsigned __int8)*v6++;
v9 = 8i64;
v7 ^= v8;
do
{
v7 = v3 & -(v7 & 1) ^ (v7 >> 1);
--v9;
}
while ( v9 );
}
while ( v6 != &aPractice[8] );
v10 = 32;
v11 = 79764919;
v12 = 0;
do
{
v13 = v11;
v11 >>= 1;
v12 = v13 & 1 | (2 * v12);
--v10;
}
while ( v10 );
v14 = aMakes;
do
{
v15 = (unsigned __int8)*v14++;
v16 = 8i64;
v7 ^= v15;
do
{
v7 = v12 & -(v7 & 1) ^ (v7 >> 1);
--v16;
}
while ( v16 );
}
while ( v14 != &aMakes[5] );
v17 = 32;
v18 = 79764919;
v19 = 0;
do
{
v20 = v18;
v18 >>= 1;
v19 = v20 & 1 | (2 * v19);
--v17;
}
while ( v17 );
v21 = aPerfect;
do
{
v22 = (unsigned __int8)*v21++;
v23 = 8i64;
v7 ^= v22;
do
{
v7 = v19 & -(v7 & 1) ^ (v7 >> 1);
--v23;
}
while ( v23 );
}
while ( v21 != &aPerfect[7] );
v30 = ~v7;
sub_140001450(v34);
sub_140001940(v34, &v30, 4i64);
sub_140001AC0(&v32, v34);
*a1 = (__m128i *)(a1 + 2);
a1[1] = 0i64;
v31 = 32i64;
v24 = (__m128i *)sub_1400B2100(a1, &v31, 0i64);
v25 = v31;
v26 = _mm_loadu_si128(&v32);
v27 = _mm_loadu_si128(&v33);
*a1 = v24;
a1[2] = (__m128i *)v25;
*v24 = v26;
v24[1] = v27;
v28 = *a1;
a1[1] = (__m128i *)v25;
v28->m128i_i8[v25] = 0;
return a1;
}
```
Hàm khá phức tạp nên chắc sẽ phải debug để xem giá trị của a1 sau cùng luôn

Với key đó thì python đã có thể giải mãi AES CBC rồi
```python
import base64
from Crypto.Cipher import AES
key = [0xDF, 7, 0x38, 0x2F, 0x4A, 0xFC, 0x18, 3, 0x22, 0x89, 0x65, 0x90, 0xE0, 0xC4, 0x0E, 0x93, 0x10, 4, 0x31, 0xCE, 0x49, 0x57, 0x83, 0x79, 0xC4, 0x13, 0x29, 0x5A, 0x74, 0x26, 0x60, 0x99]
key = bytes(key)
with open('output.txt', 'rb') as f:
s = f.read()
s = base64.b64decode(s)
VI = s[:16]
cipher = AES.new(key, AES.MODE_CBC, VI)
print(cipher.decrypt(s))
```

Nhưng nó lại không ra flag ;-;
Trong lúc mò mẫn IDA bên text view để xem còn unpack được cái gì không thì có thấy một chỗ này:

Trong giải NMLT cũng có bài custom base64 như này nên mình đã tìm xem có hàm nào thay đổi cái này hay không vì cũng có khá nhiều thứ mình không rõ...


Những mà cũng chả hiểu gì cả ;-;
Đọc lại hint thì mình nghĩ vấn đề nằm ở đoạn unpack, vì thực tế là vụ 2 + 2 = 4 đã bị đổi thành 2 + 2 = 5 mình cũng chưa giải thích được nên giờ sẽ phải tìm cách unpack khác xem thử có bị vậy không.

https://kienmanowar.wordpress.com/2019/05/24/reversing-with-ida-from-scratch-p14/
Đây là lần đầu tiên tự unpack file nên hơi lằng nhằng ;-;
Thử đặt break point và làm theo các bước, dump file mới thì mình ra được như này:

Vậy là vấn đề đúng là ở unpack, mảng để custom base64 đã bị sai, nên giờ chỉ cần chỉnh lại xâu s về như cũ trước khi decode base64 là được
```python
import base64
from Crypto.Cipher import AES
key = [0xDF, 7, 0x38, 0x2F, 0x4A, 0xFC, 0x18, 3, 0x22, 0x89, 0x65, 0x90, 0xE0, 0xC4, 0x0E, 0x93, 0x10, 4, 0x31, 0xCE, 0x49, 0x57, 0x83, 0x79, 0xC4, 0x13, 0x29, 0x5A, 0x74, 0x26, 0x60, 0x99]
key = bytes(key)
with open('output.txt', 'rb') as f:
s = f.read()
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
custom = 'UbcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/'
for i in range(len(s)):
for j in range(len(base)):
if s[i] == custom[j].encode():
s = s[:i] + base[j].encode() + s[i+1:]
break
s = base64.b64decode(s)
VI = s[:16]
print(AES.new(key, AES.MODE_CBC, VI).decrypt(s))
```

Flag: W1{do_you_enjoy_it?_06f171f7399c}
# Incident

Bài này viết bằng Golang nên mình mất khá nhiều thời gian setup vì đây là lần đầu tiên gặp ;-;
Sau một hồi nổ lực thì IDA 7.7 của mình vẫn không nhận script python của gosym ;-; Vậy là mình chuyển sang ghidra thì may còn chạy được mà đọc cứ lú lú @.@
Đọc qua các hàm thì mình thấy chỗ tương tác chính ở đây vì nó có chứa các xâu giống như trong ảnh



...
Tiếp theo là rất nhiều những block kiểu như này


Phân tích đến hàm HasPrefix đó thì có vẻ như là nó kiểm tra một đoạn tiền tố 4 kí tự của cái xâu dài kia có khớp với input không. (diss, slap)

* Nếu khớp diss:

...

Có vẻ như đây là chỗ nó sẽ đi decryptAES cái tin nhắn của mình, nếu ppuVar3 mà bằng 0 thì sẽ in ra đống output DAT_... Trong ảnh thì mình cần chú ý đến 2 trường hợp nó không in kiểu vậy mà là một cipher text.
* Nếu khớp slap:

...

Vậy thì mình đoán là chỗ slap sẽ là base64 của keyAES
* Xem bên trong hàm EncryptAES với DecryptAES thì đoán là AES_CBC

Mình thử cả 2 cái output đó thì có 1 cái ra flag:
``` python
from Crypto.Cipher import AES
import base64
# slap
key = base64.b64decode(b'aIhFcSvcfhbElEGdOZvXllvxqTDnfNieUTjphBKYmjs=')
print(key)
# diss ra output
cipher = [
b'qzUzmR4gEA5NMMgueKoylxgjKp+sh2Q0Bsu0/6jQZmGTzpjoRLQl4i4wG1xZrT5eRhTG367Nvj1tSibv98zpkelFbJOrnTY1h/Ur5PK9iHbpDlTctubVpXJstc6jG5olk70iEpP/KO6klBjJ2M7BePgjBFSXsr8BJGF6bUJO5nFznHRGCy0AYWpj9cnq8P8R',
b'jGX2Rwz0vIv9jke+FnDZAN10341qgcRGmsAUPFMjTF3bmFAZIwCTwJk6YO4P9BlRUWccXXGNBAaIQ0JDKytj/w=='
]
for s in cipher:
print(AES.new(key, AES.MODE_CBC).decrypt(base64.b64decode(s)))
```

Flag: W1{lEaKeD_SuPeR_SeCrEt_rAp_bAtTlE!!!}