Recently a colleague sent me a .docx which triggered on our scanning engine. Being the optimist me, I personally view such incidents positively; it either proves the accuracy of our engine if it is a true positive, or offers an opportunity to improve the detection logic if it turns out to be a false positive. The .docx comes with an accompanying email:

Sir/Madam

I am Dario Roberto Santos, President MP DO Brazil Ltd. Sao Paulo, Brazil. We are top dealers of your product in the Brasilia market. One of your customers, who is in same line of business with us, recommended your company to me when I met him in trade fair some time ago and I have decided to give your company a trial.
Please for our order samples and all the requirements and specifications, kindly refer to the attachment and unzip or open the zipped folder/file for our order samples. After studying our samples and the specifications, kindly send quotation as listed. Also fill and sign our company’s contract agreement Form attached on the zipped file and send it back to us by fax or email. Most importantly, we will need your guarantee of speedy delivery of this order and again our representative will visit your company/factory for inspection before shipment and final payment.

Please kindly reply ASAP
Street Address, Alameda Santos.
211 salas 1001/1002.
Sao Paulo. Brazil.

The odd thing to me is that nothing specific is mentioned. For example, what kind of product am I selling, or which of my customers did the sender come in contact with. In a nutshell, all the sender wants is for me to open the poorly-named attachment, Doc1.docx. Okay, so I did:

 

 

Seemingly there’s a .pdf inserted, which opens only when Protected-Mode is disabled. Once opened, Winword drops the package, “new1 (2).exe”, into the local temp directory. So this is not a .pdf as expected, and is easily achieved: Insert->Object->Package->Choose any executable. The icon image and caption (in this case, “Please Double Click To Open”) can be chosen when “Display as Icon” is checked.
The next step is to reverse the (Visual-Basic) executable to determine if this is anything new. A dynamic run is always a good starting point because you get the unpacked code (if packed) almost instantaneously. Under a debugger, it crashes at this point:

It is obvious that this is a result of ESP having the value 0xFF because [EBP-1]==1 at text.0015E754. [EBP-1] is actually a Boolean flag that indicates whether the executable is being debugged, as shown in this manually-decompiled function:

DWORD dwProcessId;			//global 1909F4
CRITICAL_SECTION CriticalSection1;	//gloabl 18FF90
CRITICAL_SECTION CriticalSection2;	//global 190C60
BYTE*	large_buffer;               	//global 18FF68
HMODULE hModNtdll;			//global 1909FC
HMODULE hModKernel32;			//global 18FF64
HMODULE hModUser32;			//global 190A00
HMODULE hModWs2_32;			//global 190A04
HMODULE hModWininet;			//global 18FD4C
DWORD dwOsMachineInfo;			//global 190A08
DWORD dwMiscInfo;				//global 18FF70
DWORD dwIdentityInfo;			//global 18FF74
WCHAR szUserName[0x104];			//global 18FFA8
WCHAR szDefaultBrowser[0x104];		//global 18FD50
DWORD dwGames;				//global 1909F8
DWORD dwK32GetMappedFileNameW;		//global 1901CC
BYTE* impt_apps;				//global 19127C (malloc size 0x4452)

bool AntiDebug () {
	/*
	This function also gathers all sorts of information about the system, machine, installed applications, etc.
	*/

	bool bStatus = false;
	bool bIsDebugged = false;
	DWORD dwDebugPort = 0;
	DWORD dwReturnLength = 0;

	dwProcessId = GetCurrentProcessId();

	if ( sub_0015EFAF(ESI)) {
		InitializeCriticalSectionAndSpinCount ( &CriticalSection1, 0xFA0);

		if ((ZwQueryInformationProcess (0xFFFFFFFF, ProcessDebugPort, &dwDebugPort, 4, &dwReturnLength) == 0) &&
			(dwDebugPort != 0) )
		{
				bIsDebugged = true;
		}
		hModNtdll = GetModuleHandle ("ntdll.dll");
		hModKernel32 = GetModuleHandle ("kernel32.dll");
		hModUser32 = GetModuleHandle ("user32.dll");
		hModWs2_32 = GetModuleHandle ("ws2_32.dll");
		hModWininet = GetModuleHandle ("wininet.dll");

		GetSystemTime ((LPSYSTEMTIME)(large_buffer+0x1C2E));

		/*
		Updates dwOsMachineInfo as a bitmask:
		OS version (v5.1-v6.2, server/workstation), processor (x86/x64) and service pack
		*/
		sub_001568D7();

		SHGetFolderPath (NULL, CSIDL_FLAG_CREATE|CSIDL_APPDATA, NULL, NULL, (LPSTR)(large_buffer+0x37E));
		SHGetFolderPath (NULL, CSIDL_FLAG_CREATE|CSIDL_PROFILE, NULL, NULL, (LPSTR)(large_buffer+0x176));
		SHGetFolderPath (NULL, CSIDL_FLAG_CREATE|CSIDL_COMMON_APPDATA, NULL, NULL, (LPSTR)(large_buffer+0x586));

		/*
		Returns bitmask of:
		|= 0x2        (dotnet version >= 2)
		|= 0x4        (Registry "HKEY_CLASSES_ROOTjarfileshellopencommand" is present)
		|= 0x80       (Any of these is present: (HKCUSoftware{Sysinternals;mIRC;Hex-Rays;Immunity Inc;CodeBlocks;7-Zip;PrestoSoft;Nmap}, HKLMSoftwarePerl, HKCR{.vcproj;.5vw})
		|= 0x20       ((*(large_buffer+0x0A) == 0x20) and (OS != workstation5.1||5.2))
		|= 0x100      (SYSTEM_POWER_STATUS->BatteryFlag < 0x80 (High/Low/Critical/Charging)
		|= 0x20000200 ((workstation6.0||6.1||6.2||server6.1||6.2), and (ELEVATION_UAC_ENABLED == 1))
		|= 0x8        (Length of (REG_SZ) ValueData "HKEY_CURRENT_USERSoftwareValveSteamLanguage" > 1)
		|= 0x1        (Value of (REG_DWORD) ValueData of "HKEY_CURRENT_USERSoftwareClassesCLSID{E9157F45-692A-5640-B0F5-E52ADF2EED29}16560361CG1BIS" is 1)
		|= 0x40       ((MEMORYSTATUS.dwTotalPhys >= 0x1800) and (NumOfCPU >= 4))
		|= 0x400      (IP of most recent Remote Desktop connection is found: ValueData of "HKEY_CURRENT_USERSoftwareMicrosoftTerminal Server ClientDefaultMRU0")
		*/
		dwMiscInfo = sub_0015D8EB();

		/*
		|= 1 (if current executable name is "explorer.exe")
		|= 4 (sub_00160CAD())
		|= 2 (if GetModuleHandle("iexplore.exe"||"firefox.exe"||"chrome.exe"))
		|= 8 (if GetModuleHandle("mscoree.dll"))
		*/
		dwIdentityInfo = sub_0015DA78();

		/*
		Fill szUserName[] (GetUserNameEx()) and
		szDefaultBrowser[] ("HKEY_CLASSES_ROOTHTTPshellopencommand")
		*/
		sub_0015DCAC();

		if ((*(USHORT*)(large_buffer+4) & 1) == 1) {
			/*
			Returns bitmask of:
			|= 0x4		(Folder "%userprofile%jagexcache" is present)
			|= 0x8		(Folder "%appdata%.minecraft" is present)
			|= 0x40		(Folder "%programfiles%League of Legends" is present)
			|= 0x1		(Length of (REG_SZ) ValueData "HKEY_CURRENT_USERSoftwareValveSteamLanguage" > 1)
			|= 0x200	(Registry "HKEY_CLASSES_ROOTjarfileshellopencommand" is present)
			|= 0x2		(Registry "HKEY_LOCAL_MACHINESOFTWAREClassesorigin" is present)
			|= 0x10		(Registry "HKEY_CURRENT_USERSOFTWAREBlizzard Entertainment" is present)
			|= 0x400	(Registry "HKEY_CURRENT_USERSOFTWARESkype" is present)
			|= 0x800	(Registry "HKEY_CURRENT_USERSOFTWAREMicrosoftVisualStudio" is present)
			|= 0x1000	(Registry "HKEY_CURRENT_USERSOFTWAREVMware, Inc." is present)
			*/
			dwGames = sub_0015DAF2();
		}
		else {
			dwGames = 0;
		}

		dwK32GetMappedFileNameW = (DWORD)GetProcAddress(hModKernel32, "K32GetMappedFileNameW");
		if (!dwK32GetMappedFileNameW) {
			dwK32GetMappedFileNameW = (DWORD)GetProcAddress(LoadLibrary ("Psapi.dll"), "GetMappedFileNameW");
		}

		memset (&CriticalSection2, 0, 0x18);
		InitializeCriticalSectionAndSpinCount (&CriticalSection2, 0x3E8);

		/*
		Set or clear bit 10 (0x400) of *(large_buffer+0x0A)
		*/
		sub_0017B396();

		/*
		Fill impt_apps with this format:
		[USHORT 0x0212][UINT 0x0][UINT 0x2][WCHAR[0x104]="skype.exe"]
		[USHORT 0x0212][UINT 0x70][UINT 0xA][WCHAR[0x104]="origin.exe"]
		[USHORT 0x0212][UINT 0x70][UINT 0xA][WCHAR[0x104]="steam.exe"]
		[USHORT 0x0212][UINT 0x0][UINT 0x1][WCHAR[0x104]="winlogon.exe"]
		[USHORT 0x0212][UINT 0x0][UINT 0x1][WCHAR[0x104]="csrss.exe"]
		[USHORT 0x0212][UINT 0x0][UINT 0x1][WCHAR[0x104]="services.exe"]
		[USHORT 0x0212][UINT 0x0][UINT 0x1][WCHAR[0x104]="lsass.exe"]
		[USHORT 0x0212][UINT 0x0][UINT 0x1][WCHAR[0x104]="spoolsv.exe"]
		[USHORT 0x0212][UINT 0x70][UINT 0x1][WCHAR[0x104]="dwm.exe"]
		*/
		sub_0017128D();

		/*
		Fill (WCHAR*)(large_buffer+0x1746) with "%userprofile%Low_00FEC012"
		*/
		sub_0017981A();

		if ((*(USHORT*)(large_buffer+4) & 1) == 1) {
			/*
			Patch ntdll.DbgBreakPoint() with "NOP" instead of "INT 3"
			*/
			sub_00153796();
		}

		memset (large_buffer+0x1BF2, 0, 0x3C);

		if (ESI!=0 && [SI]==0x1C4A && [ESI+0x1BF6]!=0)
			memcpy ( large_buffer+0x1BF2, ESI+0x1BF2, 0x3C);
		else {
			/*
			Fills large_buffer+0x1BFA with ValueData (BINARY, raw) of "HKEY_CURRENT_USERSoftwareWin7zipUuid"
			Fills large_buffer+0x1C0A with ValueData (BINARY, hex) of "HKEY_CURRENT_USERSoftwareWin7zipUuid"
			*/
			sub_00160DF1 ();
		}

		if (bIsDebugged == true) {
			if (TEB->WOW32Reserved != NULL) {
				TEB->WOW32Reserved = [1901FC];
				bStatus = true;
			}
			else {
/* Suicide	*/
				__asm {
					MOV ESP,0xFF;
					MOV EBP,0xFF;
					XCHG EDX,ESI;
				}
			}
		}
		else
			bStatus = true;
	}
	return bStatus;
}

 

So “new1 (2).exe” uses the ZwQueryInformationProcess(…, ProcessInformationClass=ProcessDebugPort, …) technique for anti-debugging. There is another anti-debug attempt in sub_00153796() where it patches the ntdll.DbgBreakPoint(). The rest of this function collects a whole lot of information about the system, machine, installed applications, etc.

In the course of reversing, I also came across this function:

void BetaBot_Commands () {
	/*
	BetaBot functionalities: Reacts according to commandline
	*/
	WCHAR szCommand[0x208];
	WCHAR* szCommandline;
	WCHAR** argv;
	size_t dwCommandLen;
	int iNumArgs;

	memset (szCommand, 0, 0x410);
	szCommandline = GetCommandLineW ();

	dwCommandLen = wcslen(szCommandline);
	if (szCommandline &&  dwCommandLen >= 3) {

		lstrcpynW (szCommand, szCommandline, 0x207);
		CharLowerBuffW(szCommand, dwCommandLen);

		argv = CommandLineToArgvW (szCommand, &iNumArgs);
		if (iNumArgs > 0 && argv != NULL) {

			WCHAR* each_argv;
			WCHAR* next_argv;
			for (int idx=0; idx<iNumArgs; idx++) {
				each_argv = ++(argv[idx]);
				next_argv = argv[idx+1];
				if (lstrcmpiW (each_argv, L"cp")==0) {
					continue;
				}
				else if (lstrcmpiW (each_argv, L"testme")==0) {
					WCHAR* file_name = PathFindFileNameW((WCHAR*)(large_buffer+0x996));
					if (!file_name) {
						file_name = L"(unknown)";
					}
					sub_001536FD (L"Works! PID: %d, Name: %s", dwProcessId, file_name);	//OutputDebugString("[BETA] <args>")
					sub_001536FD (L"Betabot (c) 2012-2014, coded by Userbased");		//OutputDebugString("[BETA] <args>")
				}
				else if (lstrcmpiW (each_argv, L"ssp")==0) {
					continue;
				}
				else if (lstrcmpiW (each_argv, L"suac")==0) {
					...
					TerminateProcess((HANDLE)-1, 0);
				}
				else if ((lstrcmpiW (each_argv, L"uac")==0) ||
						 (lstrcmpiW (each_argv, L"puac")==0))
				{
					...
					TerminateProcess((HANDLE)-1, 0);
				}
				else if ((lstrcmpiW (each_argv, L"nuac")==0)) {
					...
					TerminateProcess((HANDLE)-1, 0);
				}
				else if ((lstrcmpiW (each_argv, L"usb")==0)) {
					...
				}
				else if ((lstrcmpiW (each_argv, L"ron")==0)) {
					...
				}
				else if ((lstrcmpiW (each_argv, L"task")==0)) {
					continue;
				}
				else if ((lstrcmpiW (each_argv, L"un")==0)) {
					continue;
				}
				else if ((lstrcmpiW (each_argv, L"dbg")==0)) {
					continue;
				}
				else if ((lstrcmpiW (each_argv, L"ins")==0)) {
					...
				}
				else if ((lstrcmpiW (each_argv, L"ext")==0)) {
					ExitProcess(0);
				}
				else if ((lstrcmpiW (each_argv, L"upd")==0)) {
					...
				}
			}
		}
	}
	return;
}

 

Many of these callees are interesting, and reveal the capabilities of “new1 (2).exe”. But I have gathered sufficient information from AntiDebug() and BetaBot_Commands() to achieve my aim: conclude that this is the Betabot malware. Since we already had detection for this malware in place, I didn’t reverse further (stolen files, communication encryption, C&C servers, etc).

Lastly, as with all applications, there are at least 2 bugs in Betabot:

bool CheckSoftware () {
	/* Returns true if any of these software (registry keys) is present
		- HKEY_CURRENT_USERSoftwareSysinternals
		- HKEY_CURRENT_USERSoftwaremIRC
		- HKEY_CURRENT_USERSoftwareHex-Rays
		- HKEY_CURRENT_USERSoftwareImmunity Inc
		- HKEY_CURRENT_USERSoftwareCodeBlocks
		- HKEY_CURRENT_USERSoftware7-Zip
		- HKEY_CURRENT_USERSoftwarePrestoSoft
		- HKEY_CURRENT_USERSoftwareNmap
		- HKEY_LOCAL_MACHINESoftwarePerl
		- HKEY_CLASSES_ROOT.vcproj
		- HKEY_CLASSES_ROOT.5vw
	*/
	...
	WCHAR* lpHKLMSoftware[] = {L"Perl"};
	...
	WCHAR lpSubKey[0x104];
	...
	for (int index = 0; index < 1; index++) {
		if (lpHKLMSoftware[index]) {
			memset (lpSubKey, 0, 0x104);
			//should be: wsprintf (lpSubKey, L"Software\%s", lpHKLMSoftware[index]);
			wsprintf (lpSubKey, L"Software\%s", &lpHKLMSoftware[index]);
			if (CheckRegistryKey (HKEY_LOCAL_MACHINE, lpSubKey)) {
				return true;
			}
		}
	}
	...
	return false;
}

 

void BetaBot_Commands () {
	/*
	BetaBot functionalities: Reacts according to commandline
	*/
	...
	int iNumArgs;

	...
	else if ((lstrcmpiW (each_argv, L"uac")==0) ||
		 (lstrcmpiW (each_argv, L"puac")==0))
	{
		...
		//should be: (iNumArgs > idx+1)
		if ((iNumArgs >= idx+1) && (*next_argv != NULL)) {
			...
}

That’s all, folks.

Update:
.docx md5: 73b14e96931b51048302784af0143945
“new1 (2).exe” md5: 2976af9b6550823b7786c2f66514902d

More from Threat Research

RansomExx Upgrades to Rust

IBM Security X-Force Threat Researchers have discovered a new variant of the RansomExx ransomware that has been rewritten in the Rust programming language, joining a growing trend of ransomware developers switching to the language. Malware written in Rust often benefits from lower AV detection rates (compared to those written in more common languages) and this may have been the primary reason to use the language. For example, the sample analyzed in this report was not detected as malicious in the…

Defending Education from Cyber Threat Attackers

Threat actors — and particularly ransomware attackers — have education institutions in their crosshairs. From Vice Society’s September attack on schools in California to Snach’s late October assault on schools in Wisconsin, threat actors are not holding back when it comes to preying on schools. K-12 schools are the most vulnerable within the education industry, with many having only small staffs and even smaller budgets for defending against attacks. In addition, attacks have trickle-down effects on school staff, students and…

What Hurricane Preparedness Can Teach Us About Ransomware

Each year between June and November, many parts of the U.S. become potential targets for hurricanes. In October 2022, we had Hurricane Ian devastate Florida. To prepare for natural disasters like hurricanes, organizations are encouraged to build out and test business continuity, disaster recovery, and crisis management plans to use in the response efforts. Millions of dollars each year are spent on natural disaster preparation, but natural disasters are not the only disruption businesses face. While we can’t equate the…

Charles Henderson’s Cybersecurity Awareness Month Content Roundup

In some parts of the world during October, we have Halloween, which conjures the specter of imagined monsters lurking in the dark. Simultaneously, October is Cybersecurity Awareness Month, which evokes the specter of threats lurking behind our screens. Bombarded with horror stories about data breaches, ransomware, and malware, everyone’s suddenly in the latest cybersecurity trends and data, and the intricacies of their organization’s incident response plan. What does all this fear and uncertainty stem from? It’s the unknowns. Who might…