I try to execute a perl script from my C program using a exec family function.
The first try with execv give me an infinite loop, so i check the man page for execv and see that all this function call execve which is more suitable for what i want to do.
Giving up to know why I have an infinite loop (yeah, that's not clever, i know), I intend to use execve, but this one fail too with "No such file or directory".
So i check again the man page, see that
[...]
filename must be either a binary executable, or a script starting with a line of the form:
#! interpreter [optional-arg]
For details of the latter case, see "Interpreter scripts" below.
[...]
ENOENT
The file filename or a script or ELF interpreter does not exist, or a
shared library needed for file or interpreter cannot be found.
So I write a code to check if both my perl scrip and the interpreter exist.
#define PERL_FILE "/home/path/script.pl"
int main(int argc, char *argv[], char *env[])
{
FILE *test;
char buffer[200];
/* Test if PERL_FILE exist */
if (!(test = fopen(PERL_FILE, "r"))) {
fprintf(stderr, "main : fopen("PERL_FILE") : %s\n", strerror(errno));
return (EXIT_FAILURE);
}
/* Retrieve the beginning of the PERL_FILE file */
if (fread(buffer, 1, sizeof(buffer), test) <= 0) {
fprintf(stderr, "main : fread : %s\n", strerror(errno));
return (EXIT_FAILURE);
}
fclose(test);
/* I want to check if the file in the shebang exist */
*strchr(buffer, '\r') = '\0';
printf("shebang = |%s|\n", buffer + 2);
if (!(test = fopen(buffer + 2, "r"))) {
fprintf(stderr, "main : fopen(%s) : %s\n", buffer + 2, strerror(errno));
return (EXIT_FAILURE);
}
fclose(test);
char *argv2[] = {PERL_FILE, NULL};
int i;
for (i = 0; env[i]; ++i) {
printf("%s\n", env[i]);
}
execve(PERL_FILE, argv2, env);
perror ("And so ... ");
return (EXIT_FAILURE);
}
Here the content of my perl script :
#!/usr/bin/perl
print "Hello world !\n";
and here the result of the code execution :
shebang = |/usr/bin/perl|
[...]
USER=root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
[...]
And so ... : No such file or directory
(I edited in order to clean my env).
So all this lead to my question : what I'm doing wrong ?
Can't I execute a Perl script with a exec function family ?
I added a space between the shebang and the interpreter (like "#! /usr/bin/perl") but that fail too.
I succed with "system", but i musn't use it.
Thank for your reading.
Related
I have code that looks like this:
char* buff = malloc(strlen(argv[1])+200);
if (!buff)
{
printf("%s\n", "Error allocating memory!");
return -1;
}
sprintf(buff, "%s%s%s%s", "gcc ", argv[1], " -o ", findChars(argv[1], '.'));
FILE* command = popen(buff, "r");
// NEED TO RETRIEVE OUTPUT OF POPEN
pclose(command);
And this works, but I need to save the output of the POPEN to a char* so I can read it.
(This is in C)
An open pipe is just a FILE*, so any function that can read from a FILE* can do this. For example:
fgets(some_buffer, sizeof(some_buffer), command);
Error handling, repeated reads in case the buffer is too small, all the usual stuff about reading files in C also applies here.
I want to use the "base64" script of linux to encode the data and get it in C.
When I try to compile
char a[200];
strcpy(a, "Hello");
printf("%s", a);
I get the output
Hello
Now whenever I try the code
char a[200];
strcpy(a, system("echo Hello | base64"));
printf("%s", a);
I get the output
aGVsbG8K
Segmentation fault
Even when I remove the "printf" statement, I get the same
aGVsbG8K
Segmentation fault
I want to save the value of the output of
system("echo Hello | base64")
in 'a' and not display it. Please help
If you read the documentation for system you'll discover that it doesn't return a string - it's defined as:
int system(const char *command);
The return value is the return status of the command or -1 if there's an error. You can't get the output using system - the output of the command(s) you run will go straight to stdout.
To get the output from another command you could use something like popen.
FILE *myfile;
char buffer[1024];
myfile=popen("echo Hello | base64","r");
if(myfile)
{
while(fgets(buffer,1024,myfile))
{
printf("%s",buffer);
}
pclose(myfile);
}
Here
strcpy(a, system("echo Hello | base64"));
system() doesn't stores it's result into array a as system() job is to execute the command provided in the argument & print it on console i.e stdout buffer. From the manual page of system
system() executes a command specified in command by calling
/bin/sh -c
command, and returns after the command has been completed.
There is one way to solve the problem i.e instead of printing system() output on stdout you can redirect its output to a file & then read that from file & print. For example
int main(void) {
close(1); /* stdout file descriptor is avilable now */
/* create the file if doesn't exist, if exist truncate the content to 0 length */
int fd = open("data.txt",O_CREAT|O_TRUNC|O_RDWR,0664); /* fd gets assigned with lowest
available fd i.e 1 i.e nowonwards stdout output
gets rediredcted to file */
if(fd == -1) {
/* #TODO error handling */
return 0;
}
system("echo Hello | base64"); /* system output gets stored in file */
int max_char = lseek(fd,0,2);/* make fd to point to end, get the max no of char */
char *a = malloc(max_char + 1); /* to avoid buffer overflow or
underflow, allocate memory only equal to the max no of char in file */
if(a == NULL) {
/* #TODO error handling if malloc fails */
return 0;
}
lseek(fd,0,0);/* from beginning of file */
int ret = read(fd,a,max_char);/* now read out put of system() from
file as array and print it */
if(ret == -1) {
/* #TODO error handling */
return 0;
}
a[ret] = '\0';/* \0 terminated array */
dup2(0,fd);/*fd 0 duplicated to file descriptor where fd points i.e */
printf("output : %s \n", a);
/* to avoid memory leak, free the dynamic memory */
free(a);
return 0;
}
My above suggestion is a temporary fix & I won't recommend this, instead use [popen] as suggested by #chris Turner (http://man7.org/linux/man-pages/man3/popen.3.html) which says
The popen() function opens a process by creating a pipe, forking,
and
invoking the shell. Since a pipe is by definition unidirectional, the
type argument may specify only reading or writing, not both; the
resulting stream is correspondingly read-only or write-only.
For example
int main(void) {
char buf[1024];
FILE *fp = popen("echo Hello | base64","r");
printf("%s\n",fgets(buf,sizeof(buf),fp));
return 0;
}
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.
So, I have this command line I want to execute in C:
ps -eo user,pid,ppid 2> log.txt | grep user 2>>log.txt | sort -nk2 > out.txt
And I need to figure out how I'd make the code... fd
What I understand is that I have the father ps... Which needs to redirect the output as an input to the grep, and it also needs to error output to log.txt...
The same with the grep... the output must be redirected to the sort, and the error must be saved in log.txt.
and I'd just output the sort to the file...
Something like this:
FATHER(ps) SON(grep) SON-SON? (sort)
0->must be closed ----> 0 ----> 0
/ /
1 ---------------/ 1 --------/ 1 -->out.txt
2 ---> log.txt 2 ---> log.txt 2 -->nowhere?
But I don't know how this would be coded...
I'd appreciate your help.
You can execute shell commands in C programs directly using sh -c
(How do I execute a Shell built-in command with a C function?)
Pipes can also be used in C programs directly using popen()
The following program example shows how to pipe the output of the ps -A command to the grep init command: ps -A | grep init
#include <stdio.h>
#include <stdlib.h>
int
main ()
{
FILE *ps_pipe;
FILE *grep_pipe;
int bytes_read;
int nbytes = 100;
char *my_string;
/* Open our two pipes */
ps_pipe = popen ("ps -A", "r");
grep_pipe = popen ("grep init", "w");
/* Check that pipes are non-null, therefore open */
if ((!ps_pipe) || (!grep_pipe))
{
fprintf (stderr,
"One or both pipes failed.\n");
return EXIT_FAILURE;
}
/* Read from ps_pipe until two newlines */
my_string = (char *) malloc (nbytes + 1);
bytes_read = getdelim (&my_string, &nbytes, "\n\n", ps_pipe);
/* Close ps_pipe, checking for errors */
if (pclose (ps_pipe) != 0)
{
fprintf (stderr,
"Could not run 'ps', or other error.\n");
}
/* Send output of 'ps -A' to 'grep init', with two newlines */
fprintf (grep_pipe, "%s\n\n", my_string);
/* Close grep_pipe, checking for errors */
if (pclose (grep_pipe) != 0)
{
fprintf (stderr,
"Could not run 'grep', or other error.\n");
}
/* Exit! */
return 0;
}
source: http://crasseux.com/books/ctutorial/Programming-with-pipes.html
else use named pipes (https://en.wikipedia.org/wiki/Named_pipe)
http://www.cs.fredonia.edu/zubairi/s2k2/csit431/more_pipes.html
See also this C program to perform a pipe on three commands (uses fork())
I'm using "system" API calls to run shell commands in my C program, now
there is case where I want to redirect the output generated by an executableto a buffer instead of a file (named recv.mail)
An example of how I write the output to the file:
cmd[] = "mda "/bin/sh -c 'cat > recv.mail'";
system (cmd);
Similarly I want to replace input taken from the file (send.mail) with input taken from a buffer.
An example of how I take input from a file:
cmd[] = "msmtp < cat send.mail";
system (cmd);
NOTE: The send.mail and recv.mail files have formatted data.
Are pipes a better replacement?
Can anyone suggest another alternative?
popen/pclose may do what you want:
FILE *f = popen("program to execute", "r");
if (NULL != f)
{
char buffer[128];
while (fgets(buffer, sizeof buffer, f)
{
printf("Read from program: '%s'\n", buffer);
}
pclose (f);
}
popen/pclose again:
FILE *f = popen("program to execute", "w");
...