I want to invoke a shell in C program by execve:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
main()
{
char* path = "/bin/sh";
int err = execve(path, &path, NULL);
printf("%d\n", err);
printf("%s\n", strerror(errno));
printf("%x, %x\n", path, &path);
}
However the output is:
-1
Bad address
80485c0, bf816f4c
Because you aren't sending a NULL terminated list of arguments.
You need:
char* path[2];
path[0] = "/bin/sh";
path[1] = NULL;
int err = execve(path[0], path, NULL);
The second argument to execve is defined as being a NULL-terminated list of strings, so you can't simply pass the address of path. It expects an array like this, with the final entry being NULL:
arg[0] = "/bin/ls"
arg[1] = "-l"
arg[2] = "/usr/include/std*"
arg[3] = NULL
The reason it was failing with a bad pointer is that execve would have been looking at each word following path to find the arguments, and treating each word as a pointer until it got to the first 0 word. Since path was alone on the stack, it would have been trying to interpret whatever garbage happened to be in memory after the stack beyond path as a string pointer.
The solution is simple: you need to construct an array of parameters and add a NULL terminator (since it is of variable length). The fixed example is below (with a few warnings taken care of):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main()
{
char* path[] = { "/bin/sh", NULL };
int err = execve(path[0], path, NULL);
printf("%d\n", err);
printf("%s\n", strerror(errno));
printf("%p, %p\n", path, &path);
return 0;
}
Try this instead:
execl(path, path, NULL)
The exec family of functions will automatically execute a shell if the program is a script rather than a process image file. So you might be able to replace "path" with the pathname of the script.
Related
I am currently tackling on an assignment, where I need to upload exploit.c and target.c onto a ubuntu server, and successfully achieve a buffer overflow attack with exploit onto target. I was provided a shellcode. Now, target.c is not to be altered, just exploit.c. I had to use GDB on exploit.c to force an external breakpoint on foo() from target.c, to figure out the return addresses using info frame.
I was provided with the working shellcode, and minimal instructions.
I am pretty sure I was able to successfully pull the return addresses, but my issue is that I cannot figure out what code to put into exploit.c to have it successfully perform a buffer overflow attack. I was also instructed that one of the return addresses must be input into the exploit code for it to function properly.
I understand that the exploit is trying to call back to the return address, to then push itself into the buffer, so I can obtain access to the shell.
Here is exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"
// replace this define environment to have the correct path of your own target code
#define TARGET "/*******************"
int main(void)
{
char *args[3];
char *env[2];
char *tmp = NULL;
// Creating an input buffer that can cause buffer overflow in strcpy function in the target.c executable code
int buffSize = 1000;
char buff[buffSize];
// Intialize buffer elements to 0x01
int i;
for (i=0; i < buffSize; i++) buff[i] = 0x01;
// write your code below to fill the 22 bytes shellcode into the buff variable, and
// at the correct location overwrite the return address correctly in order to achieve stack overflow
// Your own code starts here:
strcpy (buff[buffSize-22], shellcode);
// Your code ends here.
// prepare command line input to execute target code
args[0] = TARGET; // you must have already compiled and generated the target executable code first
args[1] = buff; // the first input parameter to the target code (artfully crafted buffer overflow string)
args[2] = NULL;
env[0] = "FOO=bar";
env[1] = NULL;
if (0 > execve(TARGET, args, env))
fprintf(stderr, "execve failed.\n");
return 0;
}
Here is the target.c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int foo(char* arg)
{
char localBuf[240];
short len = 240;
float var1=2.4;
int *ptr = NULL;
strcpy(localBuf, arg);
printf("foo() finishes normally.\n");
return 0;
}
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0; tv.tv_usec=0;
FD_ZERO(&read_fd); FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target: argc != 2\n");
exit(EXIT_FAILURE);
}
printf("Press any key to call foo function...\n");
while(!kbhit())
;
foo(argv[1]);
return 0;
}
I compiled both target and exploit. Then I ran GDB on exploit, and formed a breakpoint using "break target.c:10". Using Info Frame I was able to obtain the return addresses.
I used strcpy, because it is essentially the only line of code we were taught for this section involving overflow attacks, even though it clearly states in the document "Fill the shell executable code (in the string array shellcode[]) byte-by-
byte into the buff for your modified return address to execute, do not
use strcpy() because shellcode[] is not an ASCII string (and not
copying NULL byte, too)."
Exploit compiles fine, and it runs fine, but it does not give me access to a shell. I was instructed that I would know if it worked, if I was presented with two dollar signs ($$) instead of one ($).
I am a network engineer, and I am not entirely savvy with C, or attacking vulnerabilities in programs, any help would be appreciated. The entire lesson revolves around "stack overflow", but this assignment is called "buffer overflow attack".
I am trying to make a simple program that just writes your working directory to a file, and I cannot, for the life of me, figure out what I am doing wrong. No matter what I do, my buffer is storing null after my call to getcwd(). I suspect it may have to do with permissions, but allegedly, linux now did some wizardry to ensure that getcwd almost never has access problems (keyword, "almost"). Can anyone test it on their machines? Or is there an obvious bug I am missing?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("Error is with fopen if stops here\n");
FILE* out_file = fopen("dir_loc.sh","w+");
char* loc = malloc(sizeof(char)*10000);
size_t size = sizeof(loc);
printf("Error is with cwd if stops here\n");
loc = getcwd(loc,size);
printf("%s",loc);
fprintf(out_file,"cd %s",loc);
printf("Error is with fclose if stops here\n");
free(loc);
fclose(out_file);
return 0;
}
compiled with gcc main.c (the file is named "main.c")
EDIT: As was mentioned by different posters, sizeof(loc) was taking the size of a char pointer, and not the size of the amount of space allocated to that pointer. Changed it to malloc(sizeof(char)*1000) and it all works gravy.
Your problem is here:
size_t size = sizeof(loc);
You're getting the size of a char pointer, not the allocated memory for your char.
Change it to:
size_t size = sizeof(char) * 10000;
or even to
size_t size = 10000;
since sizeof(char) is guaranteed to be 1.
And since you're using size in your subsequent call to getcwd, you're obviously gonna have too little space to store most paths, so your result is unsurprising
If you don't want to go about changing multiple different numbers in the code every time you make a change, you can use #DEFINE text replacement to solve that.
Like this:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LOC_ARRAY_SIZE 10000 // Here you define the array size
int main(int argc, char *argv[])
{
printf("Error is with fopen if stops here\n");
FILE* out_file = fopen("dir_loc.sh","w+");
char* loc = malloc(sizeof(char)*LOC_ARRAY_SIZE); // sizeof(char) could be omitted
size_t size = sizeof(char)*LOC_ARRAY_SIZE;
printf("Error is with cwd if stops here\n");
loc = getcwd(loc,size);
printf("%s",loc);
fprintf(out_file,"cd %s",loc);
printf("Error is with fclose if stops here\n");
free(loc);
fclose(out_file);
return 0;
}
I've been giving the task of writing a simple shell, I've managed to get some really basic functionality however for one of the stages it's asking me to get and set the environment. This is the details of the task.
Stage 4: Getting and setting the path – 10 marks
Keep original path
The reason this is necessary is because we would like to restore the path to what was originally on exiting the shell. This is important because any changes you do to the shell’s environment (i.e. setenv() function above), does not only affect the shell itself but also any other program that will be executed from the same terminal afterwards. For this reason, it is a good idea to put things back the way they were on exit.
A single string will be enough to keep the original path.
Saving the path should be the first thing your shell does when it starts up.
Print and change the path – built-in commands
From a C program we can access the environment using the getenv() function and we can change the environment using the setenv() function. If you look at the manual pages for setenv(), you will find how it works (i.e. parameters needed and return values) as well as what you need to include to use it.
getpath – print system path & setpath – set system path
These two commands are about the environment parameter PATH. The first just gets and prints its value, while the second takes a path (string of colon separated list of directories) as a parameter and makes it the value of PATH. You can getenv() and setenv() respectively for this purpose.
Restore path
You just change the PATH environment parameter to its original value (i.e. the one you saved at the start up of the shell).
Restoring the path should the last thing your shell does before it exits.
Stage 4: Testing
First, make sure that all the tests you carried out for stage 3 still work. Be careful though, as we are now changing the path this will affect the execution of external programs.
To check the additional functionality, you should start by checking that the save and restore of the path work. A good idea here is to print the path when you save it at the beginning of the execution of the shell and then again when you exit at the end. In both cases the printed path should be exactly the same!
Following that you should check that when getpath is called you print the current path, which should be the same as the original one.
Then you should focus on testing setpath. First, setpath the path to a new value and test that getpath prints it, then try also to see how changing the path really affects the execution of external commands (e.g. set the path to only ‘.’ and try ‘ls’ or try the shell itself, etc).
This is my code:
/* S.NO:201148541 Simple Shell Example
Completed upto Stage 3 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define BUFFER_SIZE 1<<16
#define ARR_SIZE 1<<16
void parse_args(char *buffer, char** args,
size_t args_size, size_t *nargs)
{
char *buf_args[args_size];
char **cp;
char *wbuf;
size_t i, j;
wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;
for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}
for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}
*nargs=j;
args[j]=NULL;
}
int main(int argc, char *argv[], char *envp[]){
char buffer[BUFFER_SIZE];
char *args[ARR_SIZE];
int *ret_status;
size_t nargs;
pid_t pid;
char curDir[100];
while(1){
getcwd(curDir, 100);
printf("%s->", curDir);
fgets(buffer, BUFFER_SIZE, stdin);
parse_args(buffer, args, ARR_SIZE, &nargs);
if (nargs==0) continue;
if(strcmp(args[0], "cd") == 0){
chdir(args[1]);
}
else if (!strcmp(args[0], "exit" )) exit(0);
pid = fork();
if (pid){
pid = wait(ret_status);
printf("finished\n", pid);
}
else {
if( execvp(args[0], args)) {
puts(strerror(errno));
exit(127);
}
}
}
}
return 0;
}
I'm really at a loss and any guidance would be helpful.
Given that we don't know what your previous steps are, and going by the advice
Then you should focus on testing setpath. First, setpath the path to a
new value and test that getpath prints it, then try also to see how
changing the path really affects the execution of external commands
(e.g. set the path to only ‘.’ and try ‘ls’ or try the shell itself,
etc).
You can do like this...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *path, *old, *tobeSet;
path = malloc(1024);
path = getenv("PATH");
old = malloc(strlen(path));
tobeSet = malloc(10); // just to be safe
strcpy(tobeSet,".");
if(setenv("PATH",tobeSet,1)!=0)
{
printf("Couldn't set path\n");
return 0;
}
printf("\nPATH::\t%s\n",path);
printf("\n\nNewPath::\t%s\n",tobeSet);
if(setenv("PATH",path,1)!=0)
{
printf("Couldn't restore path\n");
return 0;
}
printf("\n\nOld path ::\t%s\n",path);
free(path);
free(old);
free(tobeSet);
return 0;
}
So, I've got a function that loads up a char** variable with some string data. My goal is to fork the process, and print some of that data in the child, and some from the parent. However, I'm unable to reference the pointer after the fork() call.
I thought that fork() made a copy of the entire address space of the parent process, which seems that it would include the various stack pointers...
Essentially, my code currently looks like this:
load_data(char **data);
char** data;
load_data(data);
printf("String 0: %s\n", data[0]);
fork();
printf("String 0 again: %s\n", data[0]); /* Segfaults Here! */
Anyone have any ideas what I'm doing wrong? I've done a bit of google searching on this, and it seems what I'm doing should work - but it doesn't. Thus, I'm misunderstanding something fundamental...
You're doing bad pointer operations and just getting lucky on the first call - here's what the code should look like:
load_data(char **data);
char* data = NULL;
load_data(&data);
printf("String 0: %s\n", data);
fork();
printf("String 0 again: %s\n", data); /* Doesn't Segfault Here! */
In your case, data doesn't point anywhere. Using an uninitialized variable is undefined behaviour. Even if it changed inside the load_data function, the change wouldn't be visible outside.
You need to either make data point to something valid, or pass the address of data to the function to have the changes "return", as in load_data(char ***data).
Your code, with minimal changes to make it a complete program, "works" for me
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int load_data(char **data);
int main(void) {
char **data;
data = malloc(2 * sizeof *data);
assert(data && "no memory");
load_data(data);
printf("String 0: %s\n", data[0]);
fork();
printf("String 0 again: %s\n", data[0]);
return 0;
}
int load_data(char **data) {
data[0] = "one";
data[1] = "two";
return 2;
}
And a sample run
$ ./a.out
String 0: one
String 0 again: one
String 0 again: one
I am currently trying to count the number of bytes consumed by files in a certain directory. It recursively goes through all the folders on the current directory and counts the bytes of the files.
When I recursively call the function rec_bytes, I print off "Go in"... but when it returns the value... It segfaults.
I labeled the problematic line in the code below.
I think the problem has to do with open/closing directories.
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
int rec_Bytes(char path[])
{
int bytesSum = 0;
printf("PathX %s\n", path);
DIR *mydir = opendir(path); // Look in current directory
struct dirent *entry = NULL;
while((entry = readdir(mydir))) /* If we get EOF, the expression is 0 and
* the loop stops. */
{
if (!isDir(entry->d_name)) // Check to see if the entry is a directory of a file
{
char tempPath[] = "";
strcat(tempPath, path);
strcat(tempPath,"/");
strcat(tempPath,entry->d_name);
int tempSum = fileSize(tempPath); // Get file size
bytesSum += tempSum; // Add to sum
printf("%s\t%d\n", entry->d_name, tempSum);
}
else // The current entry is a directory
{
if ((strcmp((entry->d_name),"..") != 0) && (strcmp((entry->d_name),".")) != 0)
{
printf("Directory%s\n", entry->d_name);
char tempPath[] = "";
strcat(tempPath, path);
strcat(tempPath,"/");
strcat(tempPath,entry->d_name);
printf("Go in\n");
int tempSum = rec_Bytes(tempPath); <<<<<< Get segmentation fault here.
printf("Come Out%d\n", tempSum);
bytesSum += tempSum;
printf("%s\t%d\n", entry->d_name, tempSum);
}
}
}
closedir(mydir);
printf("XXXX\t%s\t%d\n", path, bytesSum);
return bytesSum;
}
// Thanks to : http://cboard.cprogramming.com/cplusplus-programming/117431-how-tell-if-file-directory.html
int isDir(const char* target)
{
struct stat statbuf;
stat(target, &statbuf);
return S_ISDIR(statbuf.st_mode);
}
Your problem is with lines like this...
char tempPath[] = "";
This will allocate a buffer with one byte, that byte being a null character. There is no room in that buffer for any longer string.
Basically, C does not have dynamically resizable strings. It has null terminated strings that live within fixed-size arrays of characters. This creates an issue when you won't know the length of the string until you've finished building it, of course.
Try something like...
char tempPath[5000] = "";
as a quick fix. Also, look up strncat - it's less likely to segfault. There's a printf variant as well, but I use too much C++ these days.
EDIT
Actually, the segfault is probably due to those strcats and printfs corrupting the stack. The segfault is probably when a function tries to return. The basic issue is the too-small string buffers thing, though.
Whoops!
The real quick fix is...
char tempPath[5000];
tempPath [0] = 0;
Otherwise, it won't always get initialised to an empty string when you expect it to.