linux how to patch this code - c

#include <WhatHere?>
#include <WhatHere?>
#include <WhatHere?>
int main(int argc, char **argv) {
char command[50] = "echo ";
strcat(command,argv[1]); // concatenate the input so that the final command is "echo <input>"
system(command); // call the system() function to print the input
return 0; // denote that the program has finished executing successfully
}
Can we get a remote access by running this code ? I know it is possible but please help me patch it up.

Assuming that you're worried about the potential buffer overflow, you could fix it like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv) {
char *command;
if (argc != 2) {
fprintf (stderr, "Wrong number of arguments\n");
return 1;
}
if ((command = malloc (strlen (argv[1]) + 6)) == NULL) {
fprintf (stderr, "Could not allocate memory\n");
return 1;
}
strcpy (command, "echo ");
strcat(command,argv[1]);
system(command);
free (command);
return 0;
}
This makes enough room for "echo " (5), argv[1] (string length) and the null terminator (1).
It's still potentially dangerous allowing user-specified stuff to be run but at least you won't get buffer overflows any more.

Paxdiablo gave a good solution to your buffer overflow problem, but that's really the least of your problems here. Your big issue is that you are blindly using input from the user without inspecting it first.
For example, running your program like:
./your_app "\"goodbye data\" && rm -rf /"
would end in disaster, even if you program had no buffer overflow problems. An attacker could just as easily pass in an entire shell script that did all sorts of nasty things, all they would have to do is re-write it to fit in a single line.
You need to inspect incoming user input before you pass it to system() and make sure that it looks like what you are expecting. Better yet, avoid using system() with user input entirely and instead use safer methods to do what you need (in your example, you can replace your call to system("echo ...") with printf()). If you absolutely must pass user input to system(), consider running your app in a restricted environment like a chroot jail to at least make it more difficult to do anything nasty.

Related

Why does symlink() always print symlink failed?

My code always prints symlink failed even when it creates the symlink, why does this happen?
I am writting all the core utils I use myself as I want the experince and don't like the implementations that exist, I am working on ln and honestly may just do soft links and skip hard links. Right now the program works, but always prints my error and I can't figure out why.
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
short i;
for (i = 1; i < argc; i++) {
if (symlink(argv[1], argv[2]) == -1)
printf("symlink failed");
else
symlink(argv[1], argv[2]);
}
}
You're looping over each argument to the program, but attempting to create a symlink from argv[2] to argv[1] on every iteration. The first one might succeed, but any further attempts will always fail because the link already exists.
You'll want to think carefully about how ln should behave when passed more than two arguments. The behavior of ln -s is more complex than simply calling symlink(); notably, it behaves differently when the last argument is a directory.

Execlp with echo and md5sum

I am trying to write a program using execlp() to save the output of an md5sum of a string to the standard output. Basically, to simulate this:
echo "Hello!" | md5sum
Which gets this output:
31ebdfce8b77ac49d7f5506dd1495830 -
Here is what I tried first to figure this out:
char string[] = "Hello!";
execlp("md5sum", "md5sum", string, NULL);
Although, using execlp() in this way expects the argument to be a file, not a string. So then I tried this:
char string[] = "Hello!";
execlp("echo", "echo", string, "md5sum", NULL);
Although, this generates an output of Hello! md5sum. It recognizes the "md5sum" as a string, not the system call.
What can I do to make echo and md5sum cooperate together? Or what can I do to make md5sum work on a string, not a file? Maybe should I be using a different function than execlp() ?
Before I answer your question, some concerns.
And MD5 is long, long, long since broken. It's fairly trivial to create a file with a given MD5 sum. SHA1 is on its way out. Use SHA-256 or better. Doesn't matter if your application isn't about security, you and I aren't qualified to make decisions about attack surfaces, don't take the risk.
Have you considered doing the checksum in C? It will be faster, more portable, and more reliable. There's any number of checksum libraries. Gnome Lib provides checksums, and so much more.
#include <stdio.h>
#include <glib.h>
int main() {
char string[] = "Hello!";
printf("checksum for %s is %s\n",
string,
g_compute_checksum_for_string(G_CHECKSUM_SHA256, string, -1)
);
}
Ok, on to the question.
First problem is md5sum doesn't take a string, it takes a file. This has nothing to do with execlp, it's how the md5sum program works. You can make md5sum read from stdin, but that involves pipes and is more and I want to take on. Did I mention to use a library?
This leads to your second problem: error checking. I don't see any. Any error checking for an exec goes immediately after the exec; if it succeeded then the calling program will immediately exit.
Then problem is execlp is probably overkill unless you're changing the name of the program being run. Use execvp. I prefer it because it keeps all the program's arguments together in a nice list that can be used for error checking later.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main() {
char *args[] = { "md5um", "Hello!", NULL };
int exit_status = execvp(args[0], args);
fprintf(stderr, "executing %s ", args[0]);
for( int i = 1; args[i] != NULL; i++ ) {
fprintf(stderr, "%s ", args[i]);
}
fprintf(stderr, "exited with %d: %s\n", exit_status, strerror(errno));
}

Process returned -1 (0xFFFFFFFF)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)

u said still it will run something in background

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv) {
char *command;
if (argc != 2) {
fprintf (stderr, "Wrong number of arguments\n");
return 1;
}
if ((command = malloc (strlen (argv[1]) + 6)) == NULL) {
fprintf (stderr, "Could not allocate memory\n");
return 1;
}
strcpy (command, "echo ");
strcat(command,argv[1]);
system(command);
free (command);
return 0;
}
how to patch this code so there wont be any privelige given to user
the thing is by running this i can get acess as root user how to edit this so that this will not happen
Call seteuid(2) to drop root privileges before calling system(3).
Do you have to use system()? The easiest way to avoid security problems is to not feed user input into system(). In your example, what is your system() call doing that you can't do with a simple printf?
The program is limited to the permissions of the user account that runs the program. Run the program using a limited-access user account that doesn't have privileges to use sudo, su, etc. Create a "jail" using chroot and run the program inside that jail as a non-privileged user to limit the amount of your system that the program has access to.

Transfer files in C

How do I transfer files from one folder to another, where both folders are present in oracle home directory?
int main(int argc, char *argv[]){
char *home, *tmp2;
home = getenv("ORACLE_HOME");
temp2 = getenv("ORACLE_HOME");
strcat (home,"A");
strcat (tmp2,"B");
//transfer files from home to tmp2
}
strcat doesn't seem to work. Here, I see tmp2 pointer doesn't get updated correctly.
Edit: OS is a UNIX based machine. Code edited.
I require a binary file which does this copying, with the intention that the real code cannot be viewed. Hence I didn't consider using shell script as an option. The files in A are encrypted and then copied to B, decrypted in B and run. As the files are in perl, I intend to use system command to run them in the same C code.
Using the system(3) command is probably a good idea since you get the convenience of a shell interpreter to expand filenames (via *) but avoids the hassle of computing the exact length of buffer needed to print the command by using a fixed length buffer and ensuring it cannot overflow:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSZ 0xFFF
int main(void)
{
char * ohome = getenv("ORACLE_HOME"), cmd[BUFSZ];
char * fmt="/bin/mv %s/%s/* %s/%s";
int written = snprintf(cmd, BUFSZ, fmt, ohome, "A", ohome, "B"), ret;
if ((written < 0) || (written >= (BUFSZ-1))) {
/* ERROR: print error or ORACLE_HOME env var too long for BUFSZ. */
}
if ((ret = system(cmd)) == 0) {
/* OK, move succeeded. */
}
return 0;
}
As commenter Paul Kuliniewicz points out, unexpected results may ensue if your ORACLE_HOME contains spaces or other special characters which may be interpreted by the subshell in the "system" command. Using one of the execl or execv family will let you build the arguments without worrying about the shell interpreter doing it's own interpretation but at the expense of using wildcards.
First of all as pointed out before, this "security" of yours is completely useless. It is trivial to intercept the files being copied (there are plenty of tools to monitor file system changes and such), but that is another story.
This is how you could do it, for the first part. To do the actual copying, you'd have to either use system() or read the whole file and then write it again, which is kind of long for this kind of quick copy.
int main(int argc, char *argv[]){
char *home, *tmp2;
home = strdup(getenv("ORACLE_HOME"));
tmp2 = strdup(getenv("ORACLE_HOME"));
home = realloc(home, strlen(home)+strlen("A")+1);
tmp2 = realloc(tmp2, strlen(tmp2)+strlen("B")+1);
strcat (home,"A");
strcat (tmp2,"B");
}
By the way, if you could stand just moving the file, it would be much easier, you could just do:
rename(home,tmp2);
Not realted to what you are asking, but a comment on your code:
You probably won't be able to strcat to the results of a getenv, because getenv might (in some environments) return a pointer to read-only memory. Instead, make a new buffer and strcpy the results of the getenv into it, and then strcat the rest of the file name.
The quick-n-dirty way to do the transferring is to use the cp shell command to do the copying, but invoke it using the system command instead of using a shell script.
Or, have your C program create a shell script to do the copying, run the shell script, and then delete it.

Resources