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:
- Allocate a file description through
socket(2)
- Set up the structure defining the address family, address and port to connect to
- Initiate the connection to the remote host
- Print a password prompt and require the correct password to be entered
- 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:
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.
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.
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