Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shellcode: pass arguments to execve in x86_64 assembly

I'm trying to write a shellcode that runs execve. The equivalent c program looks like this:

int main ()
{

  char *argv[3] = {"/bin/sh","-i", "/dev/tty", NULL};
  execve("/bin/sh", argv, NULL);

  return 0;
}

The c program runs fine. Then I tries to write my test program like this(revised to push null):

#include<stdio.h>
int main(){
    __asm__(
            "xor    %rdx,%rdx\n\t"   //rdx is the third argument for execve, null in this case.
            "push   %rdx\n\t"
            "mov    -8(%rbp),%rdx\n\t"
            "mov    $0x692d,%rdi\n\t" //$0x6924 is 'i-'
            "push   %rdi\n\t"         //push '-i' to the stack
            "lea    -16(%rbp),%rax\n\t"    //now rax points to '-i'
            "mov    $0x31b7f54a83,%rdi\n\t" //the address of /bin/sh
            "push   %rdi\n\t"                //push it to the stack              
            "push   %rdx\n\t"                //end the array with null
            "mov    $0x31b7e43bb3,%rdi\n\t"  //the address of "/bin/sh"
            "push   %rdi\n\t"              //push the address of "/dev/tty to the stack
            "push   %rax\n\t"              //push the address of '-i' to the stack
            "mov    $0x31b7f54a83,%rdi\n\t"
            "push   %rdi\n\t"              //push the address of /bin/sh again to the stack
            "mov    %rsp,%rsi\n\t"         //rsi now points to the beginning of the array
            "mov    -24(%rbp),%rdi\n\t"   //rdi now points to the addresss of "/bin/sh"
            "mov    $0x3b,%rax\n\t"               // syscall number = 59
            "syscall\n\t"
    );
    }

I have the addresses of the strings in the memory here and we can assume they won't change. But we don't have the address of string '-i'. So what I'm doing here is pushing the arguments into the stack like this:


Low                  ------------------------------------------------------------------             High

|addressof"/bin/sh"(rsi points to here)|addressof"-i"|addressof"/dev/ssh"|addressof"/bin/sh"(rdi points to here)|-i|

It didn't work. The program compiled ok but when I ran the program, nothing happened.

I'm not familiar with assembly and I have some concerns about the way arguments are passed, for example, how does the compiler know when the argv argument ends in the memory?

EDIT

Thanks to the suggestion below by Niklas B, I used trace to see if execve actually runs. And I got execve(0x31b7f54a83, [0x31b7f54a83, "-i", 0x31b7e43bb3, 0x31b7f54a83, 0x692d], [/* 0 vars */]) = -1 EFAULT (Bad address), which means the second argument is passed wrong. Everything that I pushed into the stack is considered part of the argv argument!

After I push nulls into the stack, the strace gives execve(0x31b7f54a83, [0x31b7f54a83, "-i", 0x31b7e43bb3], [/* 0 vars */]) = -1 EFAULT (Bad address). This is quite close to the right answer only if the addresses are strings...

Thanks to Brian, I now see where the problem lies now. The hardcoded addresses are in the share libary of another program. So this program shouldn't run until it's actually fed into that program. Thanks everyone, I'll update this as soon as I can. Id the problem's solved, I'll mark it as solved.

like image 339
Gnijuohz Avatar asked Oct 21 '13 19:10

Gnijuohz


1 Answers

As Kerrek SB and user9000 point out in the comments, the argv array needed to be a null-terminated array of strings.

Once that is fixed, running this program standalone still won't work, as the strings "/bin/sh" and "/dev/tty" presumably don't exist at that location in the program that you have just compiled, but rather exist at that location in the program that the shell code is designed to target. You need to actually inject it into that program so it will execute there, where those strings are at those addresses.

like image 115
Brian Campbell Avatar answered Sep 28 '22 04:09

Brian Campbell