0

I am new to asm and I am trying to execute a syscall to /bin/bash. However I am currently encountering the following problem:

My code works for any execve call whose 1st argument length is less than 8 bytes, i.e "/bin/sh" or "/bin/ls" :

.section .data

    name: .string "/bin/sh"

.section .text

.globl _start

_start:
    #third argument of execve, set to NULL
    xor %rdx, %rdx 

    #push nullbyte to the stack
    pushq %rdx 

    #push /bin/sh to the stack
    pushq name 

    #copy stack to rdi, 1st arg of execve
    mov %rsp, %rdi 

    #copy 59 to rax, defining syscall number for execve  
    movq $59, %rax 

    #3rd arg of execve set to NULL
    movq $0, %rsi 

    syscall

What puzzles me is that I cannot get it to work with

name: .string "/bin/bash"

I tried to split the string in parts, to pushq "/bash" then "/bin" to the stack, nothing seems to allows me to have it working and I get an "Illegal instruction" error every time. What am I doing wrong?

Non working code:

.section .data

    name: .string "/bin/bash"

.section .text

.globl _start

_start:
    #third argument of execve, set to NULL
    xor %rdx, %rdx 

    #push nullbyte to the stack
    pushq %rdx 

    #push /bin/sh to the stack
    pushq name 

    #copy stack to rdi, 1st arg of execve
    mov %rsp, %rdi 

    #copy 59 to rax, defining syscall number for execve  
    movq $59, %rax 

    #3rd arg of execve set to NULL
    movq $0, %rsi 

    syscall

Other non working code :

.section .data

.section .text

.globl _start

_start:
    #third argument of execve, set to NULL
    xor %rdx, %rdx 

    #push nullbyte to the stack
    pushq %rdx 

    #push /bin/bash to the stack
    pushq $0x68
    pushq $0x7361622f
    pushq $0x6e69622f

    #copy stack to rdi, 1st arg of execve
    mov %rsp, %rdi 

    #copy 59 to rax, defining syscall number for execve  
    movq $59, %rax 

    #3rd arg of execve set to NULL
    movq $0, %rsi 

    syscall
Goujon
  • 37
  • 1
  • 7
  • 1
    You forgot to show the **non-working** code. Also you forgot to use a debugger. You might have forgotten that stack works in reverse. And you probably forgot that `push` **always** writes 8 bytes. So you should split your string up into 8 byte parts with the exception of the last part (that you push first). – Jester Dec 20 '17 at 00:10
  • Obviously if you have a string in `.data` there is no need to copy it to the stack. You can just use its address directly and be done with it. – Jester Dec 20 '17 at 00:13
  • Have you looked at the X86_64 ABI calling convention for functions? That might help you figure out where things are going wrongly. – David Hoelzer Dec 20 '17 at 00:15
  • @Jester Thank you for the help. I actually did take into account the fact that stack works backward and ordered the pushes accordingly, the error stays the same. – Goujon Dec 20 '17 at 00:16
  • @MichaelPetch Thanks for the suggestion. This works for /bin/sh, as mentioned in my question. I have trouble to call /bin/bash, even if I split the string (cf edit). "/bin/bash" would be 0x687361622f6e69622f, and cannot fit in a 64-bit register. – Goujon Dec 20 '17 at 00:21

1 Answers1

5

You seem to be totally confused, too much to list all the errors. Nevertheless, here is an incomplete list:

  1. you set esi to zero meaning argv is NULL
  2. push nullbyte to the stack is actually a NULL pointer for terminating the argv array (it's a not a zero byte terminating a string).
  3. You need to put the address of the file name as argv[0]. You do not need to copy the string to the stack.

Here is a fixed version:

.section .data

    name: .string "/bin/bash"

.section .text

.globl _start

_start:
    # third argument of execve is envp, set to NULL
    xor %rdx, %rdx 

    # push NULL to the stack, argv terminator
    pushq %rdx 

    # first argument to execve is the file name
    leaq name, %rdi

    # also argv[0]
    push %rdi

    # second argument to execve is argv
    mov %rsp, %rsi

    #copy 59 to rax, defining syscall number for execve  
    movq $59, %rax 
    syscall

And a version that creates the string on the stack from code, without zero bytes:

.section .text

.globl _start

_start:
    # third argument of execve is envp, set to NULL
    xor %rdx, %rdx 

    # zero terminator
    push %rdx

    # space for string
    sub $16, %rsp

    # end is aligned to the zero terminator
    movb $0x2f, 7(%rsp)        # /
    movl $0x2f6e6962, 8(%rsp)  # bin/
    movl $0x68736162, 12(%rsp) # bash

    # first argument to execve is the file name
    leaq 7(%rsp), %rdi

    # push NULL to the stack, argv terminator
    pushq %rdx 

    # also argv[0]
    push %rdi

    # second argument to execve is argv
    mov %rsp, %rsi

    # copy 59 to rax, defining syscall number for execve
    # avoid zero byte
    xor %eax, %eax
    movb $59, %al 
    syscall
Jester
  • 56,577
  • 4
  • 81
  • 125
  • You are right, I am confused, as stated in my question I am totally new to ASM :). Anyway thanks a lot for your help and correcting my mistakes, it's working now. One more question, if I want to avoid the .data section, how should I proceed? – Goujon Dec 20 '17 at 00:38
  • @Goujon : You will need to push the string to the stack – Michael Petch Dec 20 '17 at 00:40
  • @Jester since this is destined for shell code I'd recommend against `movq $59, %rax` since it will introduce a 0x00 byte. Maybe preferable is `xor %eax, %eax` `mov $59, %al` ? – Michael Petch Dec 20 '17 at 00:42
  • @MichaelPetch Something like push $0x68 -- push $0x7361622f -- push $0x6e69622f -- mov %rsp, %rdi -- I assume, but it's not working (because I'm wrong :) ) – Goujon Dec 20 '17 at 00:43
  • 1
    Yes but remember, 8 bytes at a time! Unfortunately `push` doesn't take a 8 byte immediate, so go through a register. – Jester Dec 20 '17 at 00:44
  • 2
    No, not 32-bit values at a time. the 32-bit values get placed on the stack zero extended That results in extra zeros being placed on the stack which is why it fails doing it that way. – Michael Petch Dec 20 '17 at 00:45
  • 3
    That was why I recommended something using `movabsq` to a register and push a full 64-bit register. Just happened to be that what I posted as a comment was for the wrong string. If you are doing shell code you are going to have to avoid the inclusion of any 0x00 bytes in the stream so building the string on the stack is a bit more involved for the last byte and the NUL. I'm pretty sure what you are doing is to eventually encode this as a shell exploit so one tries to avoid 0x00 in the byte stream from the instructions encoded. – Michael Petch Dec 20 '17 at 00:48
  • That answer looks better, now I can upvote it. Since he didn't ask about the issue of introducing 0x00 into the stream of bytes for a shell exploit doesn't need an explanation in this case. – Michael Petch Dec 20 '17 at 00:55
  • @Jester Thanks a lot, really good answer. Thank you very much for taking the time to provide working code. I see I have a lot to learn in asm... I will read carefully your code, and will try as an a exercise to add parameters to the /bin/bash call (-p for instance). – Goujon Dec 20 '17 at 00:59
  • @MichaelPetch I indeed decided to start asm to produce shellcode. I really appreciate the effort to provide a nullbyte free solution. To be honest for now I just want to get a grasp on asm and be able to produce good code, nullbyte removal will be a second step :) – Goujon Dec 20 '17 at 01:02
  • What if I want to pass parameter? – K.Sopheak Jul 09 '19 at 08:26