###### tags: `ctf` `writeup` `rev`
# WhiteHatPlay11 - RE
## re01-WhiteHatPlay11v1 - 128pts

Check file bằng DiE và mở bằng IDA32:


Input của mình sau khi nhập vào Buffer thì sẽ được đưa vào hàm `sub_4010A0()` xử lí:

Trong hàm này, mình đã đổi 0x55 thành 85 cho dễ nhìn, tới đây mình thấy nghi nghi, thử bấm vào `byte_40EFB0` xem nó là gì:

Rồi luôn, tới đây thì mình khá chắc là chương trình này dùng `base85`, mình thử kiếm `cipher` trong string và xref, mình thấy 2 đoạn này khá phù hợp:

Thử trên cyber chef và bùm:

Flag: WhiteHat{Whit3H4t11H4v34N1C3D4yR3VeRs31!}
## re02-WhiteHatPlay11v2 - 256pts
Lần này đề cho mình file dll, tiếp tục check và mở bằng IDA32 lên xem:

Trong IDA mình thấy 1 hàm tên là WhiteHat khá là khả nghi:
```c
char WhiteHat()
{
int v0; // edi
int v1; // esi
int v2; // kr04_4
char *v3; // eax
char *v4; // ecx
void *v5; // eax
void **v6; // eax
int v7; // eax
int i; // ecx
int v10; // [esp+0h] [ebp-4B4h]
int v11; // [esp+10h] [ebp-4A4h]
int v12[14]; // [esp+14h] [ebp-4A0h]
void *v13[4]; // [esp+4Ch] [ebp-468h] BYREF
int v14; // [esp+5Ch] [ebp-458h]
unsigned int v15; // [esp+60h] [ebp-454h]
void *v16; // [esp+64h] [ebp-450h]
int v17; // [esp+74h] [ebp-440h]
unsigned int v18; // [esp+78h] [ebp-43Ch]
char Str[264]; // [esp+7Ch] [ebp-438h] BYREF
char v20; // [esp+184h] [ebp-330h] BYREF
char v21[263]; // [esp+185h] [ebp-32Fh] BYREF
char Destination[264]; // [esp+28Ch] [ebp-228h] BYREF
char v23[268]; // [esp+394h] [ebp-120h] BYREF
int v24; // [esp+4B0h] [ebp-4h]
v11 = 1887667281;
v12[0] = 1882219565;
v12[1] = 743254827;
v12[2] = 762456936;
v12[3] = -2105317328;
v12[4] = 1865175935;
v12[5] = -2004341935;
v12[6] = 2139565390;
v12[7] = 1848467079;
v20 = 0;
memset(v21, 0, 0x103u);
memset(Str, 0, 260);
memset(Destination, 0, 260);
memset(v23, 0, 260);
v0 = 0;
v18 = 15;
v17 = 0;
LOBYTE(v16) = 0;
v24 = 1;
v15 = 15;
v14 = 0;
LOBYTE(v13[0]) = 0;
sub_10003997("___________________________________________________________________________\n");
sub_10003997(" __ \n");
sub_10003997(" _ _ _ _ _ _ _____ _ _____ _ | | ___ ___ \n");
sub_10003997("| | | | |_|_| |_ ___| | |___| |_ | _ | |___ _ _ | | |_ | |_ | \n");
sub_10003997("| | | | | | _| -_| | .'| _| | __| | .'| | | |__| _| |_ _| |_ \n");
sub_10003997("|_____|_|_|_|_| |___|__|__|__,|_| |__| |_|__,|_ | |__| |_____|_____|\n");
sub_10003997(" |___| \n");
sub_10003997("___________________________________________________________________________\n");
sub_10003997("\n********Let's Play!********\n");
sub_10003997("Try to guess the flag: ");
gets_s(Str, 0x104u);
v1 = strlen(Str);
if ( v1 < 40 )
{
while ( 1 )
{
sub_10003997("\nHmm, enter something more interesting: ");
gets_s(Str, 0x104u);
v2 = strlen(Str);
v1 = v2;
if ( v2 > 41 )
break;
if ( v2 >= 40 )
goto LABEL_6;
}
sub_10003997("Great! It may be the right flag :)\n");
}
LABEL_6:
sub_10003997("Checking...\n");
Sleep(0x3E8u);
strncpy_s(Destination, 0x104u, Str, 0x24u);
if ( !strstr(Str, "@") )
goto LABEL_41;
v3 = strrchr(Str, 64);
strncpy_s(v23, 0x104u, v3, 5u);
v4 = Str;
if ( dword_10018FD4 != 1 )
v4 = Destination;
sub_10001EC0(v4, &v20);
sub_100017A0("QDIwMjI=", 8u);
v5 = (void *)sub_10001430(v10);
sub_100023E0(v13, v5);
if ( v12[13] >= 0x10u )
j__free((void *)v12[8]);
v6 = v13;
if ( v15 >= 0x10 )
v6 = (void **)v13[0];
v7 = strcmp(v23, (const char *)v6);
if ( v7 )
v7 = v7 < 0 ? -1 : 1;
if ( v7 )
{
LABEL_41:
sub_10003997("Oh no! That is a wrong flag! Try again!!1\n");
}
else
{
sub_10003997("Great! Keep moving...\n");
Sleep(0x3E8u);
if ( FindWindowA("OllyDbg", 0) )
ExitProcess(0);
if ( FindWindowA("x32dbg", 0) || sub_10001DA0(L"OllyDbg.exe") || sub_10001DA0(L"x32dbg.exe") )
ExitProcess(0);
if ( dword_10018FD4 == 1 || v1 != 41 )
{
sub_10003997("\nOops! Did you forget anything?\n");
sub_10003997("That is a wrong flag! Try again!!1\n");
}
else
{
for ( i = 0; i < 36; i += 6 )
{
if ( v21[i - 1] == *((_BYTE *)&v12[-1] + i) )
++v0;
if ( v21[i] == *((_BYTE *)&v11 + i + 1) )
++v0;
if ( v21[i + 1] == *((_BYTE *)&v11 + i + 2) )
++v0;
if ( v21[i + 2] == *((_BYTE *)&v11 + i + 3) )
++v0;
if ( v21[i + 3] == *((_BYTE *)v12 + i) )
++v0;
if ( v21[i + 4] == *((_BYTE *)v12 + i + 1) )
++v0;
}
if ( v0 == 36 )
{
sub_10003997("\nGreat Flag!\n");
sub_10003997("Congratulations!\n");
}
}
}
sub_10003997("\n");
system("pause");
if ( v15 >= 0x10 )
j__free(v13[0]);
v15 = 15;
v14 = 0;
LOBYTE(v13[0]) = 0;
if ( v18 >= 0x10 )
j__free(v16);
return 1;
}
```
Đoạn này sẽ check len của input
```c
LABEL_6:
print("Checking...\n");
Sleep(0x3E8u);
strncpy_s(Destination, 0x104u, Str, 0x24u);
if ( !strstr(Str, "@") )
goto FAIl;
v3 = strrchr(Str, 64);
strncpy_s(v22, 0x104u, v3, 5u);
v4 = Str;
if ( dword_10018FD4 != 1 )
v4 = Destination;
sub_10001EC0(v4, &v19);
sub_100017A0(v16, "QDIwMjI=", 8u);
v5 = sub_10001430(v10);
sub_100023E0(v13, v5);
if ( v12[13] >= 0x10u )
j__free(v12[8]);
v6 = v13;
if ( v15 >= 0x10 )
v6 = v13[0];
v7 = strcmp(v22, v6);
if ( v7 )
v7 = v7 < 0 ? -1 : 1;
if ( v7 )
{
FAIl:
print("Oh no! That is a wrong flag! Try again!!1\n");
```
Đoạn check này chương trình sẽ lấy 36 kí tự đầu và lưu vào v4, còn 5 kí tự cuối, 5 kí tự cuối sẽ được `cmp` với b64decode của `QDIwMjI=`:

36 kí tự đầu sẽ được xử lí qua hàm `sub_10001EC0`:
```c
int __fastcall sub_10001EC0(const char *a1, _BYTE *a2)
{
unsigned int v4; // eax
_BYTE *v5; // edx
int v6; // esi
unsigned int v7; // ebx
v4 = strlen(a1);
if ( v4 )
{
v5 = a2;
v6 = a1 - a2;
v7 = v4;
do
{
*v5 = (v5[v6] ^ 0x11) + 11;
++v5;
--v4;
}
while ( v4 );
a2[v7] = 0;
return 1;
}
else
{
*a2 = 0;
return 1;
}
}
```
Cụ thể thì hàm này chỉ là `xor` từng kí tự input với lại 0x11 và cộng thêm 11
Tại dòng 119, ta sẽ thấy đoạn check 36 kí tự đầu:
```c
for ( i = 0; i < 36; i += 6 )
{
if ( v20[i - 1] == *(&v12[-1] + i) )
++v0;
if ( v20[i] == *(&v11 + i + 1) )
++v0;
if ( v20[i + 1] == *(&v11 + i + 2) )
++v0;
if ( v20[i + 2] == *(&v11 + i + 3) )
++v0;
if ( v20[i + 3] == *(v12 + i) )
++v0;
if ( v20[i + 4] == *(v12 + i + 1) )
++v0;
}
```
Sau khi mình xem trên stack thì mình `v11` nằm ngay trước `v12` nên là khi viết script mình sẽ gộp 2 bytes này chung:

```py
x= [0x70,0x83,0x84,0x51,0x70,0x30,0x64,0x2D,0x2C,0x4D,0x2B,0x2B,0x2D,0x72,0x2B,0x68,0x82,0x83,0x68,0x30,0x6F,0x2C,0x53,0x7F,0x88,0x88,0x2B,0x51,0x7F,0x87,0x2D,0x4E,0x6E,0x2D,0x5E,0x87]
for i in range(0,len(x),4):
t = x[i:i+4][::-1]
for c in t:
print(chr((c-11)^0x11),end = "") #Whit3H4t11S0L1v34LifeY0uW1llR3memB3r
```
Flag: `WhiteHat{Whit3H4t11S0L1v34LifeY0uW1llR3memB3r@2022}`
## re03-startr3 - 32pts
Bài này thì là bài free flag nên là, mở bằng ida64 thấy luôn flag:

Flag: `WhiteHat{start_r3_ez_game}`
## re04-Baby RE - 128pts
Đề cho mình 1 file exe như này:

Nhìn icon nên mìn chắc chắn là ông ra đề dùng pyinstaller luôn:)), ngay lập tức mình đi tìm tools để decompile ra:
Đầu tiên mình dùng [Pyinstxtractor](https://github.com/extremecoders-re/pyinstxtractor) để extract file này ra, sau khi extract nó sẽ trông như này:

Tiếp tục mình dùng [Uncompyle6](https://github.com/rocky/python-uncompyle6) để uncompyle file `quewridg.pyc` ra thành code python:
```py
import base64, os, time
str1 = []
str2 = []
k = None
h = None
def re():
global h
global k
s = 'VOhEdHV0YIRVVLF0S9'
x = '92Mp5GXI5XV79DMO1F'
for i in range(len(s)):
if i % 2 != 0:
str1.append(s[i])
str2.append(x[i])
else:
str1.append(x[i])
str2.append(s[i])
k = ''.join(str1)
h = ''.join(str2)
def write_1():
with open(os.environ['USERPROFILE'] + str(base64.b64decode('XEFwcERhdGFcTG9jYWxcVGVtcFw='), 'utf-8') + k + str(base64.b64decode('LnR4dA=='), 'utf-8'), 'w') as (f):
f.write('YmFuIGNvIHRoYXkgY29uIGJhY2ggdHVvYyBrZXUga2hvbmc=')
with open(os.environ['USERPROFILE'] + str(base64.b64decode('XEFwcERhdGFcUm9hbWluZ1w='), 'utf-8') + h + str(base64.b64decode('LnR4dA=='), 'utf-8'), 'w') as (f):
f.write('dGltIHRodSB4ZW0=')
def content():
banner = ".__ __. __ ______ ___ .___________.____ _ _ .___ ___. \n| \\ | | /_ | / | / _ \\ | |___ \\ | || | | \\/ | \n| \\| | | | | ,----'| | | | `---| |----` __) | | || |_ | \\ / | \n| . ` | | | | | | | | | | | |__ < |__ _| | |\\/| | \n| |\\ | | | | `----.| |_| | | | ___) | | | | | | | \n|__| \\__| |_| \\______| \\___/ |__| |____/ |_| |__| |__|"
print(banner)
print('=======================================================================================')
print(' https://www.youtube.com/shorts/t1u-h4rlNSY ')
print('=======================================================================================')
time.sleep(5)
if __name__ == '__main__':
content()
re()
write_1()
```
Sau khi chuyển base64 thành ascii, mình thấy là khi chạy file lên, nó sẽ tạo ra 2 tệp với nội 2 nội dung:
```
ban co thay con bach tuoc keu khong
tim thu xem
```
Và mình để ý là tên của 2 cái file kia cũng là base64:
```py
def re():
global h
global k
s = 'VOhEdHV0YIRVVLF0S9'
x = '92Mp5GXI5XV79DMO1F'
for i in range(len(s)):
if i % 2 != 0:
str1.append(s[i])
str2.append(x[i])
else:
str1.append(x[i])
str2.append(s[i])
k = ''.join(str1)
h = ''.join(str2)
print(base64.b64decode(h+k+"=").decode())
re() #WhiteHat{T1NH_N0NG_NHU_K3M}
```
Flag: `WhiteHat{T1NH_N0NG_NHU_K3M}`
Trong lúc làm bài này nóng thiệt=)), vì rating bài này 1* nên mình cũng không nói gì thêm, next thôi=))
## re05-Lucky Ticket - 64pts
```
Find the password of the mystery box
nc 164.92.81.231 9012
```

Sau khi mình chạy file thì nó dừng luôn, thử đưa vào IDA:

Ý của bài này là mình có 2 lựa chọn `1: Lucky Ticket`,`2: Mystery Box 600$`, Sau khi kiếm đủ 600$ bằng việc đoán chữ số thì mình sẽ được mở `Mystery Box`:
Đặt breakpoint tại đây và setup debug thôi:)

Tại đây sẽ có lệnh nhảy có điều kiện `jnz` (jump if not zero)

Mình muốn nhảy vào thì chỉnh lại `ZeroFlag = 0`:

Tới đây các bạn chọn option 2 luôn:


Còn đây sẽ là đoạn so sánh số tiền hiện tại với 599, nếu lớn hơn thì sẽ nhảy vào chổ mở box, muốn pass qua lệnh này, mình cần chỉnh `OF = SF`:


```c
__int64 __fastcall open(int a1)
{
__int64 result; // rax
_BOOL4 v2; // [rsp+14h] [rbp-9Ch]
int v3; // [rsp+18h] [rbp-98h]
int v4; // [rsp+1Ch] [rbp-94h]
int v5[34]; // [rsp+20h] [rbp-90h] BYREF
unsigned __int64 v6; // [rsp+A8h] [rbp-8h]
v6 = __readfsqword(0x28u);
v3 = 3 * a + 5;
for ( i = 0; i <= 9; ++i )
{
v5[i] = (int)(a * keypublic[i] + a1) % v3;
printf("%d\n", keypublic[i]);
}
puts("-----------------------------");
puts("\nYour key : ");
for ( i = 0; i <= 9; ++i )
{
__isoc99_scanf("%2d", &v5[i + 12]);
putchar(10);
}
v4 = module_reverse((unsigned int)a);
v2 = 0;
for ( i = 0; i <= 9; ++i )
v5[i + 24] = v4 * (v5[i + 12] - a1) % v3;
for ( i = 0; i <= 9; ++i )
v2 = v5[i + 24] == keypublic[i];
if ( v2 )
{
printf("\tCongratulate!!!!");
printf("\nYour password : ");
for ( i = 0; ; ++i )
{
result = (unsigned int)i;
if ( i > 9 )
break;
printf("%d", (unsigned int)v5[i]);
}
}
else
{
printf("Key not true");
return 0LL;
}
return result;
}
```
Hàm này trước khi in ra password thì cần bạn nhập key vào, phân tích 1 chút hàm này sẽ hoạt đông như sau:
9 kí tự đầu của `v5` sẽ lưu 1 dãy số gì đó:
```v5[i] = (int)(a * keypublic[i] + a1) % v3;```
9 kí tự ở giữa sẽ lưu key các bạn nhập vào:
```c
for ( i = 0; i <= 9; ++i )
{
__isoc99_scanf("%2d", &v5[i + 12]);
putchar(10);
}
```
9 kí tự ở cuối sẽ là nơi chứa key sau khi mã hóa, và được so sánh với public key có sẵn:
```c
for ( i = 0; i <= 9; ++i )
v5[i + 24] = v4 * (v5[i + 12] - a1) % v3;
for ( i = 0; i <= 9; ++i )
v2 = v5[i + 24] == keypublic[i];
```
Nếu đúng hết thì nó sẽ in password ra, mà password lại là 9 kí tự đầu của v5 =)))
Nên là khúc này mình chỉ cần chạy hết đoạn này, xong lấy pass ra thôi:))
```c
for ( i = 0; i <= 9; ++i )
{
v5[i] = (int)(a * keypublic[i] + a1) % v3;
printf("%d\n", keypublic[i]);
}
```

Lấy 9 số đầu chuyển thành decimal và nối lại thì mình được password: `76725167175623`
Lúc đầu mình nhập vào thì không đc, sau khi ib hỏi admin và thảo luận 1 hồi lâu thì admin mới sửa lại và có đc flag, rồi tới đây mìnht thấy cái netcat nó cứ sao sao, không biết nó giúp gì trong trường hợp này =))
Nhập pass và get flag:

Flag: `Whitehat{I_n33d_v1t4m1n_s34}`
## re07-flagcheck - 64pts

Sau khi mình enter thì nó mất tiêu luôn

```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
FILE *v3; // rax
char Buffer[48]; // [rsp+20h] [rbp-60h] BYREF
char cipher[44]; // [rsp+50h] [rbp-30h] BYREF
unsigned int i; // [rsp+7Ch] [rbp-4h]
_main();
qmemcpy(cipher, "Vjjp`Nf|roqSua}Ow}aKg%H{q{wpxpxE~mLTX", 37);
printf("Input flag: ");
v3 = __iob_func();
fgets(Buffer, 38, v3);
for ( i = 0; i <= 0x24; ++i )
Buffer[i] ^= (_BYTE)i + 1;
for ( i = 0; i <= 0x24; ++i )
{
if ( Buffer[i] != cipher[i] )
{
puts("Incorrect flag!");
return 0;
}
}
puts("\nCongratulation! You have flag.");
return 1;
}
```
Bài này khá cơ bản, sau khi nhập input thì nó sẽ lấy input của mình `xor` với lại index của kí tự đó + 1, tới đây thì không nói nhiều nữa viết script luôn:
```py
t = "Vjjp`Nf|roqSua}Ow}aKg%H{q{wpxpxE~mLTX"
for i in range(len(t)):
print(chr((i+1)^ord(t[i])),end = "") #WhiteHat{ez_xor_for_r3_challenge_Oop}
```
Flag: `WhiteHat{ez_xor_for_r3_challenge_Oop}`