Post Info: # Author: Flavio do Carmo Junior aka waKKu
# URL: Author’s Webpage
# Date: November 25, 2011
# Category: Assembly, Exploiting, Programming, Security
Hi folks… Long time no see, huh?
Yeah, Aussie life has kept me quite busy, however, if you live in Sydney you know that the weather has not been friendly lately…
Enough of BS, let’s see what matters.
I was following a thread in one of those maillists, and someone said that he was having difficult to see how Non-eXecutable Stack works properly, so I will try to illustrate it here.
First of all, we need to separate things. There are two things that are usually mistaken by the same.
Executable Space Protection: The PTE (Page Table Entry) is a set of control bits at the begining of each page (1 page = 4096 bytes), responsible to control things such as readable, writeable, user or supervisor, present or not, physical address, etc. At this moment, there was no eXecutable bit, therefore a readable page was also considered eXecutable. Those guys from PaX are always trying to make the world more secure and then they came with a solution to protect some memory areas from execution. However, the only alternative was a control by memory segment, what was cool but not perfect. This technique is based on highest address execution, where you can set the highest address which can be executable, but the start point is always the same. Therefore, if your application needs execution at 0xbeefdead address, it will need to mark everything from the 0×08048000 up to 0xbeefdead.
Hardware Bit: With the introduction of 64bits CPUs the word size doubled, allowing enough space to add a new bit, eXecutable bit, within the PTE. The 63rd bit (Most Significant Bit) was chosen to control eXectuable/Not eXecutable page. At this time, guys from PaX and other implementations (Red Hat Exec-Shield, for instance), improved their control to a page level in 64bits CPUs. The RH exec-shield patch was merged into the kernel 2.6.8 (IIRC) mainstream and now Linux has native Executable Space Protection for x86_64. Nevertheless,
Physical (memory) Address Extension: The PAE patch brought the HIGHMEM feature, which allows 32bits CPU address 4Gb+ of memory and, in the same vein, is able to emulate the NX Bit on x86 kernels.
To sum up, we have 3 ways to use Executable Space Protection:
1. – x86_64 CPU + Kernel > 2.6.8
2. – x86 CPU + Kernel > 2.6.8 with HIGHMEM
3. – x86 CPU + Patch to segment protection
Compatability:
Suddenly everything changed. How to make this change as seamless as possible for users.
The Exec Shield patch added a new kernel command line (or /proc) option:
/proc/sys/kernel/exec-shield, which allows to choose 4 states:
exec-shield=0 – always-disabled
exec-shield=1 – default disabled, except binaries that enable it
exec-shield=2 – default enabled, except binaries that disable it
exec-shield=3 – always-enabled
The default option is exec-shield=2, which allows a good level of security and almost no headaches for the majority of users.
This option is not present in every Linux distribution, but each one has its own way to control this behavior.
How this stuff works…
1. Examples
waKKu@0xcd80$ grep stack /proc/self/maps 7fff7246e000-7fff7248f000 rw-p 00000000 00:00 0 [stack] waKKu@0xcd80$ gcc -m32 -z execstack -o ryu ryu.c waKKu@0xcd80$ readelf -l ryu | grep STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 waKKu@0xcd80$ gcc -m32 -o ryu ryu.c waKKu@0xcd80$ readelf -l ryu | grep STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
As we can see, there are at least 2 ways to check which permissions a specific memory area was linked with.
- /proc/$PID/maps
- readelf
2. Our program
As our program, I did some modifications on that one from Linux Shellcodes 101 in order to ensure it will put the shellcode in the stack area.
#include
#include
// Linux x86 ShellCodes: 101 - exit(69)
int main(void)
{
char shellcode[10]; // Make room for our shellcode into the stack area
strncpy(shellcode, "\x31\xc0\x40\x31\xdb\xb3\x45\xcd\x80", 9); // write the exit shellcode
shellcode[9] = 0x00; // just precautions
int (*ret)() = (int(*)())shellcode; //function pointer = casting variavel -> function
ret(); // Once we have our pointer, we call it from the stack
}
- So far so good, right? Nothing new…
3. Tests
#include
#include
// Linux x86 ShellCodes: 101 - exit(69)
int main(void)
{
char shellcode[10]; // Make room for our shellcode into the stack area
strncpy(shellcode, "\x31\xc0\x40\x31\xdb\xb3\x45\xcd\x80", 9); // write the exit shellcode
shellcode[9] = 0x00; // just precautions
int (*ret)() = (int(*)())shellcode; //function pointer = casting variavel -> function
ret(); // Once we have our pointer, we call it from the stack
}
waKKu@0xcd80$ gcc -m32 -z execstack -o ryu ryu.c
waKKu@0xcd80$ readelf -l ryu | grep GNU_STACK
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
waKKu@0xcd80$ ./ryu
waKKu@0xcd80$ echo $?
69
waKKu@0xcd80$ # WORKS
waKKu@0xcd80$ gcc -m32 -z noexecstack -o ryu ryu.c
waKKu@0xcd80$ readelf -l ryu | grep GNU_STACK
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
waKKu@0xcd80$ ./ryu
Segmentation fault
waKKu@0xcd80$ echo $?
139
waKKu@0xcd80$ # DOESNT WORK - as expected
4. The Innards
a. Stack Execution Allowed:
waKKu@0xcd80$ gcc -ggdb -m32 -z execstack -o ryu ryu.c waKKu@0xcd80$ readelf -l ryu | grep GNU_STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 waKKu@0xcd80$ gdb -q ./ryu Reading symbols from /home/waKKu/0xcd80/posts/NX-Stack/ryu...done. (gdb) break main Breakpoint 1 at 0x804839d: file ryu.c, line 9. (gdb) r Starting program: /home/waKKu/0xcd80/ryu Breakpoint 1, main () at ryu.c:9 9 strncpy(shellcode, "\x31\xc0\x40\x31\xdb\xb3\x45\xcd\x80", 9); // write the exit shellcode Missing separate debuginfos, use: debuginfo-install glibc-2.14-5.i686 (gdb) shell pidof ryu 4204 (gdb) shell grep stack /proc/4204/maps fffdd000-ffffe000 rwxp 00000000 00:00 0 [stack] (gdb) # STACK AREA => from 0xfffdd000 upto 0xffffe000 (gdb) disass Dump of assembler code for function main: 0x08048394 : push %ebp 0x08048395 : mov %esp,%ebp 0x08048397 : and $0xfffffff0,%esp 0x0804839a : sub $0x10,%esp => 0x0804839d : mov $0x80484a8,%edx 0x080483a2 : lea 0x2(%esp),%eax 0x080483a6 : mov (%edx),%ecx 0x080483a8 : mov %ecx,(%eax) 0x080483aa : mov 0x4(%edx),%ecx 0x080483ad : mov %ecx,0x4(%eax) 0x080483b0 : movzbl 0x8(%edx),%edx 0x080483b4 : mov %dl,0x8(%eax) 0x080483b7 : movb $0x0,0xb(%esp) 0x080483bc : lea 0x2(%esp),%eax 0x080483c0 : mov %eax,0xc(%esp) 0x080483c4 : mov 0xc(%esp),%eax 0x080483c8 : call *%eax 0x080483ca : leave 0x080483cb : ret End of assembler dump. (gdb) # The most important line here is "037 (call *%eax)". It is where our execution flow is deviated to the stack. (gdb) # let's set a breakpoint nearby there... (gdb) break *main+48 Breakpoint 2 at 0x80483c4: file ryu.c, line 12. (gdb) continue Continuing. Breakpoint 2, main () at ryu.c:12 12 ret(); // Once we have our pointer, we call it from the stack (gdb) x/4i $eip => 0x80483c4 : mov 0xc(%esp),%eax 0x80483c8 : call *%eax 0x80483ca : leave 0x80483cb : ret (gdb) # is adjusting our %eax to point to the beginning of our shellcode (gdb) x/x $esp+0xc 0xffffd2cc: 0xffffd2c2 (gdb) i r eax eax 0xffffd2c2 -11582 (gdb) x/5i $eax 0xffffd2c2: xor %eax,%eax 0xffffd2c4: inc %eax 0xffffd2c5: xor %ebx,%ebx 0xffffd2c7: mov $0x45,%bl 0xffffd2c9: int $0x80 (gdb) # this is our exit(69) shellcode... (gdb) nexti 0x080483c8 12 ret(); // Once we have our pointer, we call it from the stack (gdb) x/3i $eip => 0x80483c8 : call *%eax 0x80483ca : leave 0x80483cb : ret (gdb) # at this time, call will replace the value on EIP with the value of EAX (our shellcode) (gdb) i r eax eip eax 0xffffd2c2 -11582 eip 0x80483c8 0x80483c8 (gdb) nexti 0xffffd2c2 in ?? () (gdb) i r eax eip eax 0xffffd2c2 -11582 eip 0xffffd2c2 0xffffd2c2 (gdb) x/5i $eip => 0xffffd2c2: xor %eax,%eax 0xffffd2c4: inc %eax 0xffffd2c5: xor %ebx,%ebx 0xffffd2c7: mov $0x45,%bl 0xffffd2c9: int $0x80 (gdb) # So, at this time EIP points to the stack, and is ready to execute instructions from it. Thus, allowing our stack-placed shellcode to execute. (gdb) i r eax eax 0xffffd2c2 -11582 (gdb) nexti 0xffffd2c4 in ?? () (gdb) i r eax eax 0x0 0 (gdb) # No problem to execute anything from the stack... (gdb) continue Continuing. [Inferior 1 (process 3167) exited with code 0105] (gdb) p /d 0105 $5 = 69 (gdb) # Shellcode executed successfully - from the stack... (gdb) quit
b. Stack Execution NOT Allowed:
waKKu@0xcd80$ gcc -ggdb -m32 -z noexecstack -o ryu ryu.c waKKu@0xcd80$ readelf -l ryu | grep GNU_STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 waKKu@0xcd80$ gdb -q ./ryu Reading symbols from /home/waKKu/0xcd80/ryu...done. (gdb) break main Breakpoint 1 at 0x804839d: file ryu.c, line 9. (gdb) run Starting program: /home/waKKu/0xcd80/ryu Breakpoint 1, main () at ryu.c:9 9 strncpy(shellcode, "\x31\xc0\x40\x31\xdb\xb3\x45\xcd\x80", 9); // write the exit shellcode Missing separate debuginfos, use: debuginfo-install glibc-2.14-5.i686 (gdb) disass Dump of assembler code for function main: 0x08048394 : push %ebp 0x08048395 : mov %esp,%ebp 0x08048397 : and $0xfffffff0,%esp 0x0804839a : sub $0x10,%esp => 0x0804839d : mov $0x80484a8,%edx 0x080483a2 : lea 0x2(%esp),%eax 0x080483a6 : mov (%edx),%ecx 0x080483a8 : mov %ecx,(%eax) 0x080483aa : mov 0x4(%edx),%ecx 0x080483ad : mov %ecx,0x4(%eax) 0x080483b0 : movzbl 0x8(%edx),%edx 0x080483b4 : mov %dl,0x8(%eax) 0x080483b7 : movb $0x0,0xb(%esp) 0x080483bc : lea 0x2(%esp),%eax 0x080483c0 : mov %eax,0xc(%esp) 0x080483c4 : mov 0xc(%esp),%eax 0x080483c8 : call *%eax 0x080483ca : leave 0x080483cb : ret End of assembler dump. (gdb) break *main+48 Breakpoint 2 at 0x80483c4: file ryu.c, line 12. (gdb) c Continuing. Breakpoint 2, main () at ryu.c:12 12 ret(); // Once we have our pointer, we call it from the stack (gdb) x/4i $eip => 0x80483c4 : mov 0xc(%esp),%eax 0x80483c8 : call *%eax 0x80483ca : leave 0x80483cb : ret (gdb) # All the same here... adjust EAX, calls it (gdb) x/x $esp+0xc 0xffffd2cc: 0xffffd2c2 (gdb) p &shellcode $1 = (char (*)[10]) 0xffffd2c2 (gdb) nexti 0x080483c8 12 ret(); // Once we have our pointer, we call it from the stack (gdb) i r eax eax 0xffffd2c2 -11582 (gdb) x/3i $eip => 0x80483c8 : call *%eax 0x80483ca : leave 0x80483cb : ret (gdb) i r eip eax eip 0x80483c8 0x80483c8 eax 0xffffd2c2 -11582 (gdb) nexti 0xffffd2c2 in ?? () (gdb) i r eip eax eip 0xffffd2c2 0xffffd2c2 eax 0xffffd2c2 -11582 (gdb) x/5i $eip => 0xffffd2c2: xor %eax,%eax 0xffffd2c4: inc %eax 0xffffd2c5: xor %ebx,%ebx 0xffffd2c7: mov $0x45,%bl 0xffffd2c9: int $0x80 (gdb) # Again, we are on the point to exec our shellcode - from the stack... (gdb) nexti Program received signal SIGSEGV, Segmentation fault. 0xffffd2c2 in ?? () (gdb) # No luck this time :( ... (gdb) quit waKKu@0xcd80$
5. Conclusion
Well, all this text just (trying) to show HOW and WHEN exactly the NX bit takes place to protect our programs…
That’s all folks, cya.
–waKKu


Is this prevent code execution on heap too?
Hey Coco,
Well, that depends.. HEAP has its own protection, it uses the same idea with a NX bit within PTE.
On Windows the heap protection is called DEP (Data Execution Prevention), on Linux it’s pretty much the same, we have PT_GNU_STACK and PT_GNU_HEAP as ELF headers and PaX has its own way to do this job.
i didn’t see any PT_GNU_HEAP header but if i make char shellcode[] to static (shellcode placed on heap) everything is worked like in previous situation.
Hey coco,
Well, this things I wrote are specific to stack, however, if you want to go deeper with this HEAP thing, I recommend you install the “ht” package, it is an editor which has some properties about ELF.
Install ht, open your binary there, press f6 (mode) and choose ELF section headers, choose a header and go over “details”.
There you can check all binary flags, writeable, readable, executable, etc.
On my Fedora 16, for a simple C code, heap and stack are non-exec by default. But I believe it may vary from distro to distro.
Let me know if you find something interesting. See you.
–
waKKu