linux x86 tcp bind shellcode (GAS syntax) bind() does not return zero

0

i'm trying to make a tcp bind shellcode on linux x86 architecture and i'm using GAS syntax. i could successfully call socketcall(SYS_SOCKET) and got a file descriptor (which is not NULL) now that im trying to use that fd and make a SYS_BIND call i seem to get a return value from bind which is not ZERO (which it should be) . i've already debugged it . everything is just on the stack but ...

here is the commented code :

.text

.globl _start

_start:

    xorl %eax, %eax
    xorl %ebx, %ebx
    movb $1, %bl
    subl $30, %esp
    movl %esp, %esi

# array of arguments for socketcall->SYS_SOCKET:

    movb $2, 8(%esi)
    movb $1, 12(%esi)
    movl %eax, 16(%esi)

# load the address of that array in ecx:

    leal 8(%esi), %ecx
    movb $102, %al

    int $0x80

    jz exit0 # exit(0) if eax(return value)==0
# ---------------------------------------------------------------------

bind:

    movl %eax, %edx       # save the file descriptor
    xorl %eax, %eax
    inc %bl               # bl == 2 -> bind

    movw $2, 8(%esi)      # sa_family == AF_INET
    movw $2222, 10(%esi)  # sin_port == 2222

    movl %eax, 12(%esi)   # INADDR_ANY
    movl %eax, 16(%esi)   # sin_zero
    movl %eax, 20(%esi)   # sin_zero

    addl $16, %eax        
    pushl %eax            # size of struct sockaddr(16) as the third argument of bind,pushed first
    leal 8(%esi), %ecx    # leal the address of argument array into ecx
    pushl %ecx            # push it onto the stack
    pushl %edx            # file descriptor (first argument)
    movb $102, %al        # socketcall

    int $0x80

    jnz exit1 # exit(1) if bind() return value is not zero (zero flag is not set)

# ---------------------------------------------------------------------------

exit0:
    xorl %eax, %eax
    inc %eax
    xorl %ebx, %ebx

    int $0x80

# --------------------------------------------------------------------------

exit1:
    xorl %eax, %eax
    inc %eax
    xorl %ebx, %ebx
    inc %ebx

    int $0x80 

compiled:

as -ggstabs -o sys_socket.o sys_socket.s

linked:

ld -o sys_socket sys_socket.o

STACK and Registers just before the last kernel interrupt (GDB) :

(gdb) x/8xw $esp
0xbffff5d6: 0x00000007  0xbffff5ea  0x00000010  0x00000000
0xbffff5e6: 0x00000000  0x08ae0002  0x00000000  0x00000000
(gdb) x/1xb 0xbffff5ea
0xbffff5ea: 0x02
(gdb) i r
eax            0xfffffff7   -9
ecx            0xbffff5ea   -1073744406
edx            0x7  7
ebx            0x2  2
esp            0xbffff5d6   0xbffff5d6
ebp            0x0  0x0
esi            0xbffff5e2   -1073744414
edi            0x0  0
eip            0x8048099    0x8048099 <bind+40>
eflags         0x202    [ IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x0  0
(gdb) 

so where is the problem and how to solve it exactly ?

thanks in advance.

linux
sockets
assembly
gnu-assembler
shellcode
asked on Stack Overflow Dec 23, 2014 by V1R4N64R

1 Answer

1

You assemble the argument array on the stack, but you need to pass the address for the system call to use. You should clean up your code a little, it's hard to follow what you are doing. As a quick hack, movl %esp, %ecx before int $0x80 seems to work, although not sure if you wanted this:

bind(3, {sa_family=AF_INET, sin_port=htons(44552), sin_addr=inet_addr("0.0.0.0")}, 16) = 0

Also note that jz and jnz do not compare eax to 0 automatically, that is you can't use them directly after int $0x80. They just test the zero flag. You have to add code to set it based on eax yourself, such as testl %eax, %eax.

Furthermore, you should really keep the stack pointer 4 bytes aligned. subl $30, %esp is a very bad idea.


For this call, you need 2 things in memory. One, the argument array. You need to pass a pointer to that in ecx. Two, the second argument itself has to be a pointer to a sockaddr struct.

You build the sockaddr in memory pointed to by esi+8. Your comment incorrectly says that's the argument array, but it isn't. You build the argument array by the 3 push instructions on the stack, subsequently. As such the address of the argument array is esp, and the value at esp+4 (the second argument) points to esi+8 which is your sockaddr. You misleadingly use esi+8 (the first 8 bytes are unused there), but at least it's consistent and you have enough memory allocated, so it happens to work.

Also note that the port number is expected to be in network (big endian) byte order, that's why your 2222 (=0x08AE) will be interpreted as 44552 (=0xAE08).

answered on Stack Overflow Dec 23, 2014 by Jester • edited Dec 23, 2014 by Jester

User contributions licensed under CC BY-SA 3.0