BumbleBee

BumbleBee Operator executes Piece-by-Piece .PS1

 

Introduction

In this article I will be analyzing a recent Bumblebee campaign that impersonates DocuSign. The analysis will cover the execution chain, the PowerShell loader, and some Indicators of Compromise (IOCs).

The Sample

The lure is classic malvertising with a .zip and a password into a .img (not to be confused with an actual image extension like .jpg or .png)

Hovering over the “See The Document” link reveals the URL:

 

The de-horned URL is:

https://onedrive.live[.]com/download?cid=0F6CD861E2193F6E&resid=F6CD861E2193F6E%21118&authkey=ALbZV_c_Tn7O-OA

Instead of redirecting to the actual DocuSign site, the file is hosted on OneDrive, triggering an automatic download of an archive file upon clicking.

Threat Chain

 

The execution chain from the moment the phishing email is opened is depicted below:

 

Let’s quickly go through these steps:

  • The downloaded archive is opened by the user. To extract the IMG file, the user must enter the provided password: RD4432.

 

  • Once the IMG file is opened, the user sees only the LNK file (the .ps1 script is hidden).

 

  • The LNK file will execute the hidden .ps1 script

 

BumbleBee PowerShell .ps1

 

The focus now shifts to the script and the method used to extract the payload. The script contains approximately 42 base64 encoded strings (archives), each stored in a variable named elem{X}. For example:

 

 

The script replaces the first character in each encoded string with ‘H’ to match the .gz magic bytes: 1f 8b.

 

Here’s a Python script to extract, decode, and save these strings:

from base64 import b64decode
import re
import os

PS1_FILE_PATH = '/Users/igal/malwares/bumblebee/21-02-2023/documents.ps1'
OUTPUT_FOLDER = '/Users/igal/malwares/bumblebee/21-02-2023/archives/'

REG_PATTERN = '^\$elem.*\=\"(.*)\"$'

archiveIndex = 0

if not os.path.exists(OUTPUT_FOLDER):
    os.makedirs(OUTPUT_FOLDER)

ps1File = open(PS1_FILE_PATH, 'rb').readlines()
for line in ps1File:
    regMatch = re.findall(REG_PATTERN, line.replace(b'\x00',b'').decode('iso-8859-1'))
    if regMatch:
        varData = b64decode('H' + regMatch[0][1:])
        open(f'{OUTPUT_FOLDER}/archive{archiveIndex}.gz', 'wb').write(varData)
        print(f'[+] gz archive was created in:{OUTPUT_FOLDER}/archive{archiveIndex}.gz')
        archiveIndex += 1

This results in multiple .gz archives being created:
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive0.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive1.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive2.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive3.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive4.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive5.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive6.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive7.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive8.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive9.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive10.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive11.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive12.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive13.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive14.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive15.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive16.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive17.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive18.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive19.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive20.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive21.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive22.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive23.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive24.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive25.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive26.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive27.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive28.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive29.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive30.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive31.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive32.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive33.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive34.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive35.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive36.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive37.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive38.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive39.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive40.gz
[+] gz archive was created in:/Users/igal/malwares/bumblebee/21-02-2023/archives//archive41.gz

 

Extracting the Pieces of PowerShell script

Each archive contains parts of a larger PowerShell script. Here’s how to extract and concatenate them into a single script:

import gzip


ARCHIVES_FOLDER = '/Users/igal/malwares/bumblebee/21-02-2023/archives'
OUTPUT_FILE = '/Users/igal/malwares/bumblebee/21-02-2023/powershellCommand.txt'

countArchives = sum(1 for file in os.scandir(ARCHIVES_FOLDER))

finalString = ''

for x in range(0,countArchives):
    with gzip.open(f'{ARCHIVES_FOLDER}/archive{x}.gz', 'rb') as f:
        finalString += f.read().decode('utf-8')

open(OUTPUT_FILE, 'w').write(finalString)
2074441

The concatenated PowerShell script contains numerous base64 encoded strings, which, when decoded, form an executable. Here’s how to extract this executable:

 

ps1FileContent = open(OUTPUT_FILE, 'r').readlines()
REG_PATTERN = '^\$mbVar.*FromBase64String\(\"(.*)\"\)$'
OUTPUT_PAYLOAD = '/Users/igal/malwares/bumblebee/21-02-2023/payload.bin'
finalPayload = b''
for line in ps1FileContent:
    regMatch = re.findall(REG_PATTERN, line)
    if regMatch:
        finalPayload += b64decode(regMatch[0])

open(OUTPUT_PAYLOAD, 'wb').write(b'\x4d' + finalPayload[1:])
print(f'[+] Payload was extracted to the path:{OUTPUT_PAYLOAD}')
[+] Payload was extracted to the path:/Users/igal/malwares/bumblebee/21-02-2023/payload.bin

The extracted payload is a 64-bit DLL. Opening this DLL in IDA reveals that DLLMain executes sub_180001050, which contains an array variable with a pointer to an MZ blob and its size.

 

DLLMain will execute the function sub_180001050, which includes an intriguing array variable. This variable’s first value appears to be a pointer to an MZ blob, and the second value seems to represent the size of the blob.

 

I took the starting offset of the blob (0x180007320) and addded the possible length (0x169400) (wrote it in the IDA output window)

print(hex(0x180007320 + 0x169400))

And by double-clicking on the printed value it jumped to the offset which was the actual end of the blob data:

 

Investigating the Embedded Binary

Using x64Dbg, set a breakpoint at the array assignment of the blob and dump the embedded binary for further investigation.

 

Now we can investigate the embedded binary.

Bumblebee Payload

To triage the Bumblebee payload and extract encrypted configurations, upload the payload to Tria.ge, which confirms it as Bumblebee and reveals the botnet ID: 202lg.

 

 

RC4 Decryption

The loader function uses RC4 encryption with a hardcoded key to decrypt the blob of data. Here’s a script to decrypt it:

 

from Crypto.Cipher import ARC4
import binascii


KEY = "XNgHUGLrCD" BLOB_CONFIG_PORT = "0b002425baa537efd52cf61f683f8116bc994d01c892b9c140f4a29c3f8a0b823f5a65b8dc08bb73c1e7ec5f5cb40ca4a45ea741c5367ad2368ea826d4e90a4c2f986b4cfd78e1038028d261f872279b" BLOB_CONFIG_BOTNET = "0d042549dda537efd52cf61f683f8116bc994d01c892b9c140f4a29c3f8a0b823f5a65b8dc08bb73c1e7ec5f5cb40ca4a45ea741c5367ad2368ea826d4e90a4c2f986b4cfd78e1038028d261f872279b" BLOB_CONFIG_C2 = "0e00260b8b9306c1e418c531590cb72c8eae7f2dfaa38def77c38ca50ca439b30a60578eef248a43f5c9dd69649a3d9193709574f60c4ee605a2991fe2c7387e1bb6597ccd56d033ba1cea53d44012afc739f7fc6717d5691f8421ce19ceff182407a705418cd7b6ac92b685308988032dee724be6d2d897fdb031ca1fe74a115369eba75a7d1daa2cdab50ad2dc4920229b4a2d03204dff76d0787efee3b3f6129e23c56f0db2638f54548b8eeb0e33634b56f78e218b807a7d8088e19961165acaa738d226d897cdeb9ee1e1361a7f4eefbabbf8f3c4d4d23dc724df1db8b62a51edea15eaf11988094fc0d172e91da11c5121a0e663522d7a06e51ea6ddb531b4a89de69b8bb3a0622046d2bd26577e763a52bd55c9fc33855585a1cadd57f1167c3ce0a60068cc0aacfb5ddfa59baa6cae138f29e554ea51317e6f23f9a70339816c413b1b8501e2a1231b602666b3a561906f752cca682fd8c48c3256c148ccddb89e0199b2122fe3c06d8f23d727215431e8358692c59cf291d03eb57a92c0d031d604e79b10bd0c5231ccd940ab30ece0d0e33aa12062c0bc48bd49b223de7088768a9a3a890e1277bba2006b42eaedca10a57d85a306f8b3560b6f79a95e51732c109a26c47086f31ba8456cb182be49f2f2bf11d8fb1971e2b296495eb463a018612c4465ebbd0b097fd0c9566f75aa7c643926b4dd7966df75b5957445af826e48e0084efb68c73aaaed0dc2b47e7ef70673ee1d8c812bde7c77ba274b8348beceac7593dd444f513072ec832407173ccff8f46f1fa224bbe2f96990d41e837c37278688270e4c706085ec36c4802787c168637654543efccf22cd3a1b4561064c301d5fe5fa9add6281e396c7b6b6053a109a6e12cbb9b67b34559fb0cd8834136cec8ffca715cae19cf831d8f592ca87196008a89178522ccee395fbfbc1407843ddf216566a8cc35b05b548f09616aeb896757389e526744fb9f5a83e9f338d890418acb698fd882ea2acae9c82f5d943f579452ab185c2bb8f8a80eb294efd9b70636f0fadc1b8f5055e23dd9c6f5687e6f149797b71a95beeb6dc9f4dafa3a9d6cc8eb77557e87f09bf6f96f581dba6bf2f41c0641a43c065c992efd9df4b4a58ae807bbb46d3a83181705ebd3f95f3d869fb485ba7274526560dc2479a35c664fb55ae74612a767a5fc2b50c3034d5bab9092bccb4c9ad0bc5e654481e4e5b1f85f8a4fbe2cc26e1442a808bf6b5f90564733329b4a5a62d815175a15c8b4718f6c16d474957f014d2b930fd7eea94ce485d0a9ecbd36a0391205b4cecbe39b2e39ed4a7b1e2c3698b0a66ba9594fe35cd21abdb578c984bcbed482fce3f5bb209ed7f8e8009238656fd5eda5a5e2cfec507d065960a01d051f4f7af0378714c4fb8040a46fea6b74a6278f36cdac1867a7a429c4aff551a381df09492aeca2bfb3e0774a3160f21ad9b82a984590e7fa84b6bb01a0a59f882d316203c7d910a4c27a26d30babb8cbbf4997c47a5b3721c7fa578a0e458834bb27ffbe71d22ede304d8d89077e4d69dd7c215451cae24ebc9459d7e6ddbea97cd307fac9f9d8d0e4657528ce78054494b85f25b49bde3e691cfcd6c30015b241a782c9e78cd3c180db8a48625973490740b4fd3b435e1215339ae43ce15c984cf80d21666d46b55a99e51f676e12540074283c95ec682cdccf4e06c4336e03acd670123785bb42111d954737829a28170c52b9c8ce9c3a1df1547ae5fa63d8df26bc0262fb97be82adc1938fc19287d0704e36e7d41fcc86205bcc0d2dc4dfb4e1d304a44bc74e57346a5b92921c9828eac6612f2d0d7c7a2e168c4a77a0e4ef27928d201016c246a84af104396622d7d2cd59279aac6c35b50cfcb12990d323d8d03ca2d380d2058e00491ff410c478fda4eb77e59a1d611c8a2b12091c3515301d60ee95ce950aad32948924f87063860ea50820f4bffc88ceae22b403a7d13d8dd0644a68c6e1ce6fb13ed8381da44e2f1e263fba3440626de00a33808ceb4a4a548138ccab58f4e1b9fac1deab5e753fe3b851567d6f0c76f03d0461fbf64858abe8d59efe5175b28bc2c0c88eb16f8e7507ed16390f0a8161bf77db73b886907d266ad71666e166b084aa3e4be41bf4c86af2aea8d39c425fa76af5498bf4cf2a7c238ea34658302822e88ad5e807b1bbac59450ec7c3c0bd16fdc7220540148aaf1d9f11a8df7fae8131a1042c33541e396b875a3a7c05d0d3c485305feb036087d2d1115ae007c7133e3521e19c6a3fa885491d053cec36f979ae3c174082b19a33c4d0e3c0fe1cd7b76a1faaf2307180f7eb45e97390fb49a89ee2f05d36feac4862dee22df20aef615cc20c685b5052c681d402abbed1a528db0cae366ec8cd1ffa79920f55f3d7b51dd0f91fe339a0c2d94e179d26746d60311980b68782bda4b1dc9415a87bed64a97af03d2df234a73fa6e08e25c6d365c54c5b3223a7ed10d48713fa307fb9dced9e9fcb50050f60db52efd1c0affebddfd4f67ed9154a8607e3f4582a1bf45914e58953ad6d4d96201cc8633c05940a34de55d288eae99d3a7bb4a50621702e22816811a4ea8147f8dd6756462b21fd678e37b841d864c9033aab5a482398e23d643f42a1b11c866b69928e4478c89090e37c4f70bed141dfed9ea3df4c181de244452a185d76c715353ca0e33dcafb90fd9bb6642d5af89774e5fc8746ef8c68054bb392a90bd6d72967977554c39fbbaf9767295049c09c25bc82b1bb4f7fc3b83a02bf722b33a54332dfd0bae6aad5236db428e94eef3b76394e35aafab43a7ce376feced0b33c2a9d2d5fd77177745515df5d98124cde965e5177c4c064f94f92fe1b311c67aac88eaddc1bff648547d311c099b3560f40e244506d195aab67bf36b635ff7d30495a88b75864263f04004049d3580a41666a79f295acaebae1a0e4a916547e52287af8e0e7b49473918afff0f66cd4e19da9d043f8923aab8f4df541fc0e5a5409cf6a695039b52f1e1479fc20560e7a76dcf56dbd8c4e8c7864c5c48d3f777cd030ab40dd8e1935579c21552c2dd0bb05b71f8eeb9615dd969c860d273d3db1e02897d57485890d1970dcc1b5041ec40ed78849367d66d839c38f324e30211fd092fb54df386bd8b244e57fc233b3c970e9d387cce7cd4d1c807215ca1f9568be0a52767c2b98a0953ec514d52e4e5d8abef3c6d0940688e88b199833436048690dabb30bd602020edf380c7d997a39edc49909f0bf78da88e0e8d445c74bac96c5cd2e2d0aa14875a8b0c3c696ddbba8a3a9413427f8639219326eddc0c237f52c407d4dc5532e49577fddd20f949fdcc51e152231f0f1d6a4c4200286a74645d2b80782228abd2d19d56c3bb2d4a6bc370924c776ed1cefe2aa54dd7204fc6983eefaa523a9a40fbbc658fbc14f118e3464ca7a91de1b4c37c6299aee6c9921be8c13b4250ffe17b7225bf6c620c560333f0c7fbb1ca4438da82f1b200602c2c2b1a1f20b70f1a342df54c04acbada99b22e3211769c8ad317c4d70d86755868dbbbea185328539fa4082d27860bac3d96bc467958960ce9797c1c2989723e9f0c61c4da4fd2b4ef69e3538adf88dd8500f75c6f35691e9a7c8625b19d48ff9f13b5bbadf0a6c9cd913625f366bcf038be0fbde2bf68aa56b90e747e41c759ef200fae4ba87077f2c712091cd2b1d21cfc87125db90f61483985276e1abad88a36bb16336cad2ae5728300aa64527447c7445c99e1f64eb2fa6f3fd036fa684b1e116c0f2d88f809d641903a477e1e25abe2cb9a8497a27602295e55ce20257f83496b74d3897787ffb4a50f3f076f83017f5c4144841fa70b5e88697afb0e7a6b98b2a487d00de2eab366389682165fb20c27c0aaf14a03ab46b0a622c0ac3e90f58e505f1caed2738b69f2b992f8026e35ea5b594545dccdffa1d1c9c22e692ad4940c42821821aa0f28abf72010c4655bd46bf703cbc26fa83665df8b08bc144227d241f49877f38d424db6bfc64f61b8fd1edd4dcc353a38c60a8671fff32a39dec6c2cbafd5344d7393ded7faec3520d605d420bad79b8a1c7103d9a924c9ece97c77d6bd63b7318f8d903126cec0e24e9a13c3b935180e7b61d78d42e5dcdc9a5efce858bfd068ea9e2c5ec036eb29e5204084d496167822341375e1b45f9fb6e2a34f2a29fd217a748a6d2c469c28943b84cd9d7f7c711068d1da87e41d7e27bb395dbc5515d1a0f9d4eff78cbc4e7a66abf3bfacc073b35e98e4bacdd9e967d3e5db5fcb1ad9f69b67e0cebefe984b604a02f48f5d03cd5c3459f111514499679d4cbf3e245fdf6560b8d94ce998b186b0f31526ecdf9ca49c5c6dd3fc3084488d2140d0ffa2165a4e26f54a3de813bb01b42510898520aff1cc727a21430addec70dbf8b9b86ddc720017d6beb4f807bc2295d00108eb84bdd3c70f8c7320130781bb755fcf95afecaf4446edb59b800f6aee2bda11f237ee6540d09008713a31cf8bd3067f3dc0b71f2ba4b225799729f5987911308d6086f9ed1ea6344aaaea794cbb63f15197bc8df2957d775f9db43b6669cf7d128ebc4ee38d90ac32d1fa22f06ec595201c52469259cb054761b583cb8cf30856aaca94946f076d39fb8995e43733d311d51dafcaffaa42ecec44bf74749fa36d5b4bfd8f1229af37d6794d53f234ad1e434c3388fef13a4a1030c0aa5050ff46152f2d858cfc8f464cceb33887ed950a117589474a70eca2a0b419adfd8de8e492b65efd3f9da0fc31b69bd1808dc8108a598229d43e0e86c3bdfb3cb4e6ad7921b07a3c4f3918ab44d95424c2061ece4f5f5004500503924b88e4e9846a1194d3f70c690abc78b3ea894a3fd3a08785856e9056a36699c585eae0221eda810e32deaae3a44ccbfefb387c78096a650301eb6b5387501d554d0eba6e6ceef514d3a42050c0cf150658f4fe6dac85ef5b6d3440c88308a8137e92f5bf3025cce853f7bafce424232a6899a95060e401db71249a3d6d4f62ed64e30ab78149f4cfd32833d11798142ce1c80ba76ea9894d21247836ee9339754497e0253ed62016de1ef1ae91284cfe7c51d88141c4376c9b405cf1e927a1420a38b6c9ac15021810968c6406f9b41ec869421262c2efe0806b6ac2ff329a8cb688326bdbfcbdf123d88fece510c2f211e823fcbfb7e4160a486383320389a4bad5197eb50fdc04c5d2e2751e5a30aeef1a8af37b7e6b67e63ae22705dfbc78b19ed32e8d7cdbb1166b29f0428806f3b8e83440efd893525e7fefef10911cee4195f5bfa93f2b454112d47f436367a8e87f5e7780dc1ecbe202d52b398ec81eb51dd340b19992d45a0a2d6fae6538d3b6e68b9068d5af5037004c4175f291dea3aa35d172ad4bccee6858738011bae78f1a5ef4ee3de767996298a6278eea9d565b88f6f906f93ad80f0378be4f4d26f5eae0091f614add12fd7a96d531f2316a23af49b06b0363e88d2069aca3c335c8dc466cb281a55bfe7365e3755f3f93ba669c8350b7094764121bd5a6203dcb4fbcc75f1170a28fe35f03ddb000c72dca1e0024d61ea590f7067237f30fd997408230fac900755cda8e75a4492fb65d465df772ef0435d13084519abc405fc72a2e804b21361629643e1bbfbf8f232c389725c2cd7f7c8235a482ed4c328deb1e9149310fe4bad15cdf94019dca679f5f718d879c44a44c572f2bb9676086446ada3b67e5406d2aef8b6184b1e2a5bb6229158ee7bc4191e7bb4b7fdd54faf1892aa8b8" def toRaw(hexVal): return binascii.unhexlify(hexVal.encode()) def initCipher(): return ARC4.new(KEY.encode()) cipher = initCipher() plainPort = cipher.decrypt(toRaw(BLOB_CONFIG_PORT)).split(b'\x00\x00\x00\x00')[0].decode() cipher = initCipher() plainBotnet = cipher.decrypt(toRaw(BLOB_CONFIG_BOTNET)).split(b'\x00\x00\x00\x00')[0].decode() cipher = initCipher() plainC2List = cipher.decrypt(toRaw(BLOB_CONFIG_C2)).split(b'\x00\x00\x00\x00')[0].decode().split(',')

Indicators of Compromise (IOCs)

  • Email Subject: Your Invoice Is Ready For Payment
  • Email Content: Contains a link to download an archive from OneDrive
  • Archive Password: RD4432
  • Downloaded Archive: Contains an IMG file with hidden .ps1 script and visible LNK file
  • LNK File Execution: Executes a PowerShell loader script
  • PowerShell Loader: Contains multiple base64 encoded gzip archives

Conclusion

This detailed analysis of the Bumblebee campaign impersonating DocuSign highlights the sophisticated techniques employed by attackers to trick users into executing malicious scripts. By understanding and identifying these patterns, we can better protect against such phishing campaigns and mitigate the risks posed by similar malware loaders.

Posted in Write-Ups
Write a comment