So what I am trying to do is to invoke a system command with system() function and then whatever its output is I would like to take it and send it over to the client (socket connection).
Client can send various messages. It can be ls but it might be even qwerty. I would like to take the ouput and place it in the write() function as a const void* buffer argument. I have seen this topic but I can get it done to work. So far I thought it could go somewhere of these lines but whatever I tried it did not work.
/* buffer is message from the client: ls, ls -l, whatever*/
system(buffer)
fp = popen(buffer, "r");
if(fp == NULL)
printf("Failed ot run command\n");
while(fgets(path, sizeof(path), fp) != NULL) {
//modify output here?
}
pclose(fp);
write(socket_fd, output, strlen(buffer));
You should only use popen() and not system() as it describes in the question you linked.
The path variable in the question you linked seems to be misnamed. It contains the output of the system call. You can rename it to output if you wish.
write() takes the length of the buffer you are sending it. In this case, that will be the length of output, not the length of buffer.
Putting this all together gives the following:
char output[1035];
fp = popen(buffer, "r");
if(fp == NULL)
printf("Failed ot run command\n");
while(fgets(output, sizeof(output), fp) != NULL) {
write(socket_fd, output, strlen(output));
}
pclose(fp);
Related
I am trying to redirect output from an exec()ed function into a buffer, so I though I would try and use open_memstream to handle the dynamic buffering
I put together this to test it out:
#include <stdio.h>
#include <unistd.h>
int main() {
char* buffer;
size_t buffer_len;
FILE* stream = open_memstream(&buffer, &buffer_len);
if(!stream) perror("Something went wrong with `open_memstream`!");
fflush(stream);
puts("Start");
if(dup2(fileno(stream), STDOUT_FILENO) == -1) perror("Something went wrong!");
puts("Internal");
fclose(stream);
FILE* f = fopen("out.txt", "w+");
fputs(buffer, f);
fclose(f);
}
But running it gives me the error bad file descriptor on dup2, which shouldn't be the case since open_memstream doesn't return NULL which it is supposed to do on error.
Is there something about the implementation of open_memstream that makes it nonviable to manipulate its underlying descriptor? Or am I just being dumb and using a function wrong?
Cheers in advance for any help given, and if this is impossible to do with open_memstream, is there a way to handle it with FILE* instead of using fds directly?
You should check return value (and subsequently errno) after every operation that can go wrong. Here, you are missing a check for fileno(stream) return value.
FILE* stream = open_memstream(&buffer, &buffer_len);
if(!stream) perror("Failed to open_memstream");
int fd = fileno(stream);
if (fd == -1) {
perror("Failed to get memstream fileno");
exit(1);
}
When you add the above, your program will fail with message
Failed to get memstream fileno: Bad file descriptor
The reason for this failure is already explained in comments on the question.
Have look at open with the O_TMPFILE parameter, or at memfd_create, which is similar to open_memstream but returns a file descriptor.
These approaches force you to forgo the convenience of having &buffer, &buffer_len. But nothing is actually lost. One can use lseek to learn the tmp file size and then mmap to access it as a memory buffer, getting all the conveniences back.
I have the following code as an executable that I want to exploit for a course in order to spawn a shell with elevated privileges. I am a user of levelX and the executable has setgid of levelX+1. I am not allowed to alter any of the code.
As I do not have root privileges, setguid(0) fails. I was not able to change the return address of the function or main function. Could anyone point to the right direction?
int main (int argc, char** argv)
{
if (exec(argv[1]) != 0)
{
fprintf(stderr, "Cannot execute your command\n");
return -1;
}
return 0;
}
int exec(char *command)
{
FILE *f = NULL;
char entry[64];
char line[256];
f = fopen("log", "a");
if (f == NULL)
{
fprintf(stderr, "Can't open file\n");
return -1;
}
snprintf(entry, 64, "%d: %s\n", getuid(), command);
fprintf(f, entry, NULL);
fclose(f);
f = fopen("sudoers", "r");
if (f == NULL)
{
fprintf(stderr, "Can't open\n");
return -1;
}
while(fgets(line, 256, f) != NULL)
{
if (atoi(line) == getuid())
{
if (setuid(0) == 0) {
system(command);
} else {
fprintf(stderr, "check permissions\n");
}
fclose(f);
return 0;
}
}
fprintf(stderr, "Error\n");
fclose(f);
return -1;
}
From the code you posted, it appears you are supposed to write your own sudoers file to any directory you have write access to, then run this program in that directory, so it reads your file.
So, simply write your own UID to this fake sudoers file, and then give a command parameter such as bash to get a shell. There's no need to do any buffer overflow exploitation.
Presumably the real exploitable program has suid bit set in the file permissions, so it can perform the setuid(0) call. I guess the purpose of the exercise is to demonstrate how all input needs to be sanitized when you are dealing with suid programs, including things like relative paths (which effectively take current working directory as input) like any user-supplied paths and other input.
But, since the program only has setgid bit (as said in comment), you need find something you do with just the group id. That something could be that log file write. You could create a symbolic link with file name log, pointing to whatever file you want to append to, which that group has write permissions for. Also, that file needs to have format such, that the log line format does not make the file corrupted. Remember, you can put newlines etc into command line arguments!
After all it was a format string exploit on fprintf(f, entry, NULL); inside int exec(char *command) where you overwrite the return address with %n format.
No matter what "cmd" string is passed in popen(), it is never FAILING for me
So fp is never NULL even for random "cmd" string.
FILE *fp;
char path[1035];
char cmd = "randomrandomrandom";
fp = popen(cmd, "r");
if (fp == NULL) {
//Handle Error
exit(1);
}
while (fgets(path, sizeof(path)-1, fp) != NULL) {
printf("%s", path);
}
pclose(fp);
popen runs an instance of the shell. Starting a shell normally succeeds. You need to determine if it has terminated successfully. popen itself cannot do that, but pclose can: it returns the status of the child process (or -1 if another error has occurred).
So in order to verify that the command has been executed successfully, one needs to check return values of both popen and pclose.
It seems to be behaving as expected:
http://pubs.opengroup.org/onlinepubs/009695399/functions/popen.html
As you can see, popen only fails when its internal pipe command fails--the stream cannot be opened. For example, all the file descriptors are in use
I wrote a program using c, which I use popen to open a pipe and execute a command line.
This program works fine in host, but when I run the program in vbox, ubuntu12.04, error:can not allocate memory displayed.
My code is:
FILE *fp;
char path[100];
/* Open the command for reading. */
fp = popen(pdpcall, "r");
if (fp == NULL) {
printf("Error opening pipe pdpcall: %s\n",strerror(errno));
pclose(fp);
exit(0);
}
/* Read the output a line at a time - output it. */
while (fgets(path, sizeof(path)-1, fp) != NULL) {
if(strncmp(decision,path,strlen(decision))==0)
{
pclose(fp);
return 1;
}
I also try a test program only have popen in VM, it works fine. But can not work within my program.
I guess the reason is that in my program, I use a lot of malloc, and might not free. The memory in Vbox is smaller than host, so there are memories errors.
But I change the vbox memory from 512m to 2G, it still the same errors.
Is there any other problems within VM. How to solve this problems.
Is there any analog of PHP's system in C?
man system says, that system return status of the command, but I need the output (like in PHP).
Of course, I can use pipes for this, but is there any standard way?
You can make use of popen and related function as:
// command to be run.
char *cmd = "date";
// open pipe stream.
FILE *fp = popen(cmd,"r");
int ch;
// error checking.
if(!fp) {
fprintf(stderr,"Error popen with %s\n",cmd);
exit(1);
}
// read from the process and print.
while((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
// close the stream.
pclose(fp);
Ideone link
If you need the output of the command, you'd use popen() on Unix (with "r" to indicate that you want to read from the command).
FILE *fp = popen("some -convoluted command", "r");
...check for validity...
...read data from command...
pclose(fp);