# Bumblebee DocuSign Campaign **[0xtoxin-labs.gitbook.io/malware-analysis/malware-analysis/bumblebee-docusign-campaign](https://0xtoxin-labs.gitbook.io/malware-analysis/malware-analysis/bumblebee-docusign-campaign)** In this blog post I will be going through a recent bumblebee campaign that impersonates DocuSign, I will be going through the execution chain, the powershell loader and some IOC extractions ## The Phish The email delivered to the user simply tells the user that an invoice is waiting to be paid and that a "unique HTML code" was created for him to download and view the invoice on the user's computer. Additionally a password was provided: RD4432 ----- Phishing Mail Hovering over the the "See The Document" can help us to see what is the click on action URL: ----- O e e bedded U The URL is: https://onedrive.live[.com/download?cid=0F6CD861E2193F6E&resid=F6CD861E2193F6E%21118&authkey=ALbZV_c_Tn7O-OA so instead of going to the actual DocuSign site, the file will be hosted on onedrive which once clicked will trigger an auto download of an archive file. ## Execution Chain Below you can see a diagram of the execution chain from the moment the phishing mail was opened: Execution Flow Lets go quickly through this chains: 1. 1. Downloaded archive is being opened by the user, in order to extract the IMG file the user will have to enter the given password: RD4432 Password Protected Archive ----- Once the IMG file is opened the user will see only the LNK file requested information (because the .ps1 is hidden) Hidden Powershell Script 3. 3. The LNK file will execute the hidden .ps1 script LNK Target Command ## Bumblebee Ps1 Loader I will be focusing now on what is going on in the script and what I've done to extract the payload out of it. So I know that there are about 42 base64 encoded strings (that are actually archives) each one of them stored in variable with the name elem{X}, for example: Broken B64 Variables The script then removes the first char in the encoded string and replace it with H to match the .gz magic bytes: 1f 8b. First Char Swap This script will extract each string variable, decode it and save in the selected folder 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 ​ [+] 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 ----- [ ] g a c e as c eated /Use s/ ga / a a es/bu b ebee/ 0 0 3/a c es//a c e g [+] 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 Each archive contains code parts of a bigger powershell script, I will extract the content of those archives and concatenate them to one big powershell 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 = '' ​ ----- o a ge(0,cou t c es) 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 Once again the script contains a huge amount of b64 encoded strings that once concatenated they create an executable. Broken B64 Strings 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 Investigating the extracted binary, I found out it's 64bit DLL, I've opened the DLL in IDA to see what is being executed from DLLMain: DllMain ----- a e ecute t e u ct o `sub_ 8000 050` c co ta s te est g a ay a ab e, c as t s st a ue a po te to b ob a d in the second value what seems like the size of the blob: MZ Blob I took the starting offset of the blob (0x180007320) and added 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: End Of Blob [I've opened the binary in x64Dbg and set a breakpoint at the array assign of the blob and dumped the embedded binary:](https://x64dbg.com/) ----- Payload Dumping Now we can investigate the embedded binary. ## BumbleBee Payload In this part I will going over a quick triage process of extracting encrypted configs located in the BumbleBee payload. [First of all by simply uploading the payload to Tria.ge we get a static incrimination that the payload is indeed BumbleBee payload:](https://tria.ge/dashboard) Tria.ge Incrimination Additionally Tria.ge shows us the botnet ID which is: 202lg. Going through what possibly can be the main function of the loader I saw pretty at the beginning of the function a call to a function which pass as an argument an hardcoded strange looking string: Rc4 Key The function contains inside of it RC4 encryptions routines that will use the hardcoded passed argument as a key and will pass alongside with it encrypted blob of data and the length of the data ----- Config Decryption Function So now that we know what the data is let's implement a quick decryption script: from Crypto.Cipher import ARC4 import binascii ​ KEY = "XNgHUGLrCD" BLOB_CONFIG_PORT = "0b002425baa537efd52cf61f683f8116bc994d01c892b9c140f4a29c3f8a0b823f5a65b8dc08bb73c1e7ec5f5cb40ca4a45ea741c5367ad2368ea826d BLOB_CONFIG_BOTNET = "0d042549dda537efd52cf61f683f8116bc994d01c892b9c140f4a29c3f8a0b823f5a65b8dc08bb73c1e7ec5f5cb40ca4a45ea741c5367ad2368ea826d BLOB_CONFIG_C2 = "0e00260b8b9306c1e418c531590cb72c8eae7f2dfaa38def77c38ca50ca439b30a60578eef248a43f5c9dd69649a3d9193709574f60c4ee605a2991f ​ 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(',') ​ print(f'[+] Botnet:{plainBotnet}') print(f'[+] Port:{plainPort}') ----- p t( [ ] C st ) for c2 in plainC2List: print(f'\t[*] {c2}') ​ [+] Botnet:202lg [+] Port:443 [+] C2 List: [*] 141.161.143.136:272 [*] 214.77.93.215:263 [*] 104.168.157.253:443 [*] 196.224.200.10:482 [*] 254.65.104.229:127 [*] 209.141.40.19:443 [*] 107.189.5.17:443 [*] 44.184.236.94:128 [*] 60.231.88.20:422 [*] 210.38.79.54:319 [*] 23.254.167.63:443 [*] 91.206.178.234:443 [*] 72.204.201.249:374 [*] 146.19.173.86:443 [*] 103.175.16.104:443 [*] 138.133.49.46:211 [*] 150.18.156.130:256 [*] 93.216.14.249:213 [*] 73.73.80.51:127 [*] 216.73.114.69:379 [*] 58.249.161.153:350 [*] 140.157.121.40:433 [*] 194.135.33.85:443 [*] 6.66.255.6:433 [*] 173.234.155.246:443 [*] 179.55.218.145:322 [*] 241.163.228.200:362 [*] 38.174.252.233:131 [*] 146.29.236.141:457 [*] 32.234.39.72:191 ----- [ ] 8 8 60 5 9 [*] 114.70.235.72:357 [*] 51.68.144.43:443 [*] 172.86.120.111:443 [*] 160.20.147.242:443 [*] 207.12.58.212:419 [*] 51.75.62.204:443 [*] 174.72.94.173:309 [*] 205.185.113.34:443 [*] 194.135.33.184:443 [*] 246.6.106.79:340 [*] 23.82.140.155:443 [*] 185.173.34.35:443 [*] 255.115.3.251:370 [*] 177.232.32.155:257 [*] 122.125.104.16:475 [*] 24.64.127.190:229 [The retrieved botnet ID is: 202lg which is fairly correlated with a recent tweet coming from k3dg3 regarding BumbleBee activity utilized by](https://twitter.com/k3dg3) TA579: K3dg3 Tweet ## Summary In this blogpost we went over a recent BumbleBee campaign that uses multi layered powershell script in order to load the BumbleBee loader. I've mainly focused on breaking down the powershell script part rather then focusing on the loader capabilities, if you want to learn more about the BumbleBee Loader, check this [blog written by](https://elis531989.medium.com/the-chronicles-of-bumblebee-the-hook-the-bee-and-the-trickbot-connection-686379311056) [Eli Salem​](https://twitter.com/elisalem9) ## Update 1 [During my writing i found yet another campaign with the botnet ID of lg0203 I've run my scripts on the hidden powershell script and managed](https://tria.ge/230303-kvklvsgc4x/behavioral2) to extract the DLL without any problem :) ## IOC's **Samples:** [requested_documents_714407544541.zip - d4a358c875ab55c811368eabe8fa33d09fe67f2d3beafa97b9504bf800a7a02d​](https://bazaar.abuse.ch/sample/d4a358c875ab55c811368eabe8fa33d09fe67f2d3beafa97b9504bf800a7a02d/) [8702268950347.img - a55979165779c3c4fc1bc80b066837df206d9621b0162685ed1a6f6a5203d8af​](https://bazaar.abuse.ch/sample/a55979165779c3c4fc1bc80b066837df206d9621b0162685ed1a6f6a5203d8af/) [requested information.lnk - 6fb690fbeb572f4f8f0810dd4d79cff1ca9dbd2caa051611e98d0047f3f2aa56​](https://bazaar.abuse.ch/sample/6fb690fbeb572f4f8f0810dd4d79cff1ca9dbd2caa051611e98d0047f3f2aa56/) documents.ps1 - [b6d05d8f7f1f946806cd70f18f8b6af1b033900cfaa4ab7b7361b19696be9259​](https://bazaar.abuse.ch/sample/b6d05d8f7f1f946806cd70f18f8b6af1b033900cfaa4ab7b7361b19696be9259/) [LoaderDLL.bin - 2d5c9b33ed298f5fb67ce869c74b2f2ec9179a924780da65fcbc1a0e0463c5d0​](https://bazaar.abuse.ch/sample/2d5c9b33ed298f5fb67ce869c74b2f2ec9179a924780da65fcbc1a0e0463c5d0/) BumbleBeeLoader.bin - [4a5d5e6537044cdbf8de9960d79c85b15997784ba1b74659dbfcb248ccc94f59​](https://bazaar.abuse.ch/sample/4a5d5e6537044cdbf8de9960d79c85b15997784ba1b74659dbfcb248ccc94f59/) -----