↓ Skip to main content
Background Image

Lockpick

·688 words·4 mins
HoXoN
Author
HoXoN
Table of Contents

Initial Analysis
#

.
├── lockpick1
│   ├── bescrypt3.2 //ransomware
│   ├── bescrypt.zip
│   ├── DANGER.txt
│   └── forela-criticaldata
│       ├── co2_London
│       ├── complaints.csv.24bes //encrypted file
│       ├── complaints.csv.24bes_note.txt
│       ├── customer-feedback.json.24bes
│       ├── customer-feedback.json.24bes_note.txt
│       ├── forela_uk_applicants.sql.24bes
│       ├── forela_uk_applicants.sql.24bes_note.txt
│       ├── it_assets.xml.24bes
│       ├── it_assets.xml.24bes_note.txt
│       ├── sales_forecast.xlsx.24bes
│       ├── sales_forecast.xlsx.24bes_note.txt
│       ├── trading-firebase_bkup.json.24bes
│       └── trading-firebase_bkup.json.24bes_note.txt
└── lockpick1.zip

bescrypt3.2
#

file bescrypt3.2
bescrypt3.2: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2b6eafade391d7be39a8aff0d2e3a60aa8b6a4c2, for GNU/Linux 3.2.0, not stripped
r2 -AA bescrypt3.2
[0x00001160]> afl
0x00001030    1      6 sym.imp.free
0x00001040    1      6 sym.imp.remove
0x00001050    1      6 sym.imp.fread
0x00001060    1      6 sym.imp.fclose
0x00001070    1      6 sym.imp.opendir
0x00001080    1      6 sym.imp.strlen
0x00001090    1      6 sym.imp.printf
0x000010a0    1      6 sym.imp.rewind
0x000010b0    1      6 sym.imp.snprintf
0x000010c0    1      6 sym.imp.closedir
0x000010d0    1      6 sym.imp.strcmp
0x000010e0    1      6 sym.imp.ftell
0x000010f0    1      6 sym.imp.readdir
0x00001100    1      6 sym.imp.malloc
0x00001110    1      6 sym.imp.fseek
0x00001120    1      6 sym.imp.fopen
0x00001130    1      6 sym.imp.fwrite
0x00001140    1      6 sym.imp.strstr
0x00001150    1      6 sym.imp.__cxa_finalize
0x00001160    1     33 entry0
0x00001190    4     34 sym.deregister_tm_clones
0x000011c0    4     51 sym.register_tm_clones
0x00001200    5     54 entry.fini0
0x00001240    1      9 entry.init0
0x00001780    1      9 sym._fini
0x00001746    1     56 main
0x000014d4   20    626 sym.process_directory
0x00001249   11    651 sym.encrypt_file
0x00001000    3     23 sym._init
  • Disassemble and analyze main: This function is essential for understanding the overall program flow and logic.
  • Review process_directory and encrypt_file functions: These appear to be central to the program’s core functionality and warrant detailed inspection.

main()
#

[0x00001160]> s main
[0x00001746]> pdf
            ; ICOD XREF from entry0 @ 0x1174(r)
┌ 56: int main (int argc, char **argv, char **envp);
│ afv: vars(2:sp[0x10..0x18])
│           0x00001746      55             push rbp
│           0x00001747      4889e5         mov rbp, rsp
│           0x0000174a      4883ec10       sub rsp, 0x10
│           0x0000174e      488d05280a..   lea rax, str.bhUlIshutrea98liOp ; 0x217d ; "bhUlIshutrea98liOp"
│           0x00001755      488945f8       mov qword [var_8h], rax
│           0x00001759      488d05300a..   lea rax, str._forela_criticaldata_ ; 0x2190 ; "/forela-criticaldata/"
│           0x00001760      488945f0       mov qword [var_10h], rax
│           0x00001764      488b55f8       mov rdx, qword [var_8h]
│           0x00001768      488b45f0       mov rax, qword [var_10h]
│           0x0000176c      4889d6         mov rsi, rdx                ; int64_t arg2
│           0x0000176f      4889c7         mov rdi, rax                ; char *arg1
│           0x00001772      e85dfdffff     call sym.process_directory
│           0x00001777      b800000000     mov eax, 0
│           0x0000177c      c9             leave
└           0x0000177d      c3             ret
[0x00001746]> 

The main function sets up two string variables:

  • bhUlIshutrea98liOp
  • /forela-criticaldata/

It then calls process_directory with these two strings as arguments.

process_directory()
#

alt text

  • Opens the given directory path using opendir. If it fails, prints an error message.
  • Iterates over each directory entry with readdir.
  • Skips the special entries "." and "..".
  • Constructs the full path of each entry.
  • Recurses into subdirectories (d_type == 4) by calling itself.
  • For regular files (d_type == 8), checks extensions:
    • .txt, .sql, .pdf, .docx, .xlsx, .csv, .json, .xml
  • If the file matches one of these extensions, prints a message and calls encrypt_file to encrypt the file.

encrypt_file()
#

alt text

  • Opens the target file in binary read mode; prints an error on failure.
  • Reads the entire file contents into memory.
  • Encrypts each byte by XORing it with a repeated key derived from the second parameter (param_2).
  • Writes the encrypted content to a new file with the .24bes extension.
  • Creates a ransom note file (<filename>.24bes_note.txt) with payment instructions referring to the “bes24 group” and providing an email contact.
  • Attempts to delete the original unencrypted file, printing an error if unsuccessful.

decrypt.py
#

import os
import glob

def xor_decrypt(data, key):
    """XOR decrypt data with repeating key"""
    key_bytes = key.encode()
    decrypted = bytearray()
    for i, byte in enumerate(data):
        decrypted.append(byte ^ key_bytes[i % len(key_bytes)])
    return bytes(decrypted)

# XOR key from the ransomware binary
key = 'bhUlIshutrea98liOp'

# Directory containing encrypted files
directory = 'forela-criticaldata'

# Find all .24bes files
encrypted_files = glob.glob(f'{directory}/*.24bes')

print(f"Found {len(encrypted_files)} encrypted files to decrypt\n")

# Decrypt each file
for encrypted_file in encrypted_files:
    try:
        # Read encrypted data
        with open(encrypted_file, 'rb') as f:
            encrypted_data = f.read()
        
        # Decrypt the data
        decrypted_data = xor_decrypt(encrypted_data, key)
        
        # Remove .24bes extension to get original filename
        original_filename = encrypted_file.replace('.24bes', '')
        
        # Save decrypted file
        with open(original_filename, 'wb') as f:
            f.write(decrypted_data)
        
        print(f"✓ Decrypted: {os.path.basename(encrypted_file)} -> {os.path.basename(original_filename)}")
        
    except Exception as e:
        print(f"✗ Error decrypting {encrypted_file}: {e}")

print(f"\nDecryption complete! All files restored.")

alt text