Injecting shellcode into processes with Syringe

by Spencer McIntyre, SecureState -- A while ago, many security focused sites and mailing lists were abuzz with the release of a new tool called ShellCodeExec that boasts the ability to execute alpha numerically created shellcode (as commonly generated with the Metasploit Framework). I was particularly interested in how this new tool worked; and the author, Bernardo Damele, was kind enough to release it under an open source license allowing me to review the source. The source is all written in C and supports both Linux and Windows operating systems. I have never had the need to execute shell code to bypass antivirus on Linux, so I focused on the Windows portion.

The method that this tool uses is a simple one that opens a location in its address space with a call to VirtualAlloc with permissions of read, write, and execute. VirualAlloc is a Windows specific call that reserves a region of memory with the specified permissions. The read and write permissions are required because the alpha numeric shell code will change itself as it is being executed. ShellCodeExec then copies the user supplied shellcode string into the resulting memory buffer from VirtualAlloc. Finally, ShellCodeExec executes the shellcode via an Assembly stub that takes a pointer to the shell code as its only parameter before calling it. One of the very nice features of this tool is that the stub used to execute the shell code is wrapped in a Structured Exception Handler (SEH) block, allowing the program to execute gracefully, even if the shellcode encounters an error.

One feature that I believe would greatly complement ShellCodeExec is the ability to inject the shellcode into a process ID of the user’s choosing. This can be particularly useful when on a host that only permits certain processes to initiate outbound connections. With this goal in mind, I set out to implement these techniques in my own general purpose injection utility, which I have dubbed Syringe.

In order to inject the shellcode into a remote process, I chose to modify the popular DLL injection technique that utilizes a call to CreateRemoteThread. This popular technique makes a call to start a new thread with a pointer to “LoadLibraryA” as the function to execute with an argument of a pointer to a character array of the DLL to load. In order to modify the shellcode provided by the user, I followed this concept but instead wrote an assembly stub to the address space of the remote process, which will be tasked with executing the shellcode. The assembly stub takes a single argument, like LoadLibraryA, but instead of it representing a DLL to load it, points to the shellcode to execute in the same way as ShellCodeExec does.

To implement this technique, Syringe follows these steps:

1) Opens a handle to the remote process

2) Uses VirtualAllocEx to allocate memory in the remote process with the necessary permissions of read, write, and execute. Then uses WriteProcessMemory to copy the shellcode to the remote buffer.

3) Repeats step #2 with the assembly stub

4) Starts the assembly stub via a call to CreateRemoteThread, with a pointer to the assembly stub as the function to execute and a pointer to the remote shellcode as the argument.

When I initially used this technique, I was disappointed to discover a problem with the assembly stub. When the assembly stub is written, the SEH chain contains addresses from the injecting process (in this case, Syringe), which are not valid in the victim process. Because of this, when the SEH chain is created, the remote process will crash with an access violation. In order to get around this issue, I created an additional assembly stub within Syringe that does not contain the SEH chain specifically for injecting into remote processes.

Once the SEH chain was removed, the shellcode would inject and execute successfully; however, when the shellcode exited once again, the remote process would crash. After reviewing this behavior, I determined that the problem was that the shell code I was generating with the Metasploit Framework was using Thread as its exit method. With this being the case, it is necessary for the assembly stub to make a call to ExitThread before returning. The ExitThread function is called to clean up current thread's resources before returning. With the call to ExitThread in place, the remote process is not affected when the shellcode terminates.

The final code used to generate the assembly stub for injection into remote processes is:

DWORD WINAPI RemoteExecPayloadStub(LPVOID lpParameter) {

                __asm {

                                mov eax, [lpParameter]

                                call eax

                                push 0

                                call ExitThread

                }

                return 0;

}

Lines 3 and 4 move the pointer passed to the function as the argument into register EAX before calling it, just like ShellCodeExec does. Lines 5 and 6, push 0 (the argument) onto the stack, before making a call to ExitThread.

We can inject this modified version into the remote process and successfully execute shellcode in its context, interact with our shellcode and exit out of it, without damaging the remote process. A couple of things for users to keep in mind is that, when generating shellcode, to inject into the remote process the user must be sure to always select “Thread” as the exit function both when generating the shellcode and when setting up the handler for it when necessary.

Armed with this technique, Syringe provides users an easy way of injecting shellcode into 32-bit processes while bypassing most forms of Anti Virus.

The original ShellCodeExec source can be found here: https://github.com/inquisb/shellcodeexec

The Metasploit Framework can be found here: http://www.metasploit.com

The source code to Syringe can be found here http://www.securestate.com/Services/Profiling--Penetration/Pages/Recent%20Tools.aspx

See more security tips from SecureState:
Use OpenDLP to find valuable data before attackers do
How to set up a chroot jail
Why you're probably not ready for DLP software

From CIO: 8 Free Online Courses to Grow Your Tech Skills
Join the discussion
Be the first to comment on this article. Our Commenting Policies