C:Program works fine but with gdb it crashes - c

I'm new in C and have some problem. Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int read_password(FILE *file, char *password, size_t n) {
fgets(password, n, file);
password[strcspn(password, "\n")] = '\0';
}
void elevated_shell(){
gid_t gid = getegid();
setresgid(gid,gid,gid);
fflush(stdout);
system("/bin/bash");
}
void regular_shell(){
gid_t gid = getgid();
setresgid(gid,gid,gid);
fflush(stdout);
system("/bin/bash");
}
int main(int argc, char **argv){
char flag[100];
char password[100];
FILE *file;
printf("Hi! Welcome to my secure shell software!\n");
// Read in the root password
file = fopen("flag.txt", "r");
if(file == NULL) {
printf("FAIL: Failed to open the password file\n");
return -3;
} else {
read_password(file, flag, sizeof(flag));
}
// Read in the user's password
printf("Please enter the password: ");
fflush(stdout);
read_password(stdin, password, sizeof(password));
if(strcmp(flag,password) == 0) {
printf("Correct! Here's an elevated shell :)\n");
elevated_shell();
} else {
printf("Incorrect! No elevated shell for you >:)\n");
regular_shell();
}
}
So, I've compiled this file and run. It works fine when I run it directly but whenever I try to examine memory with gdb it crashes. For example when breakpoint is set at main function and run program is run fopen function returns Null because program print out
FAIL: Failed to open the password file and quits. Hope you can help.

GDB uses the user privileges that runs the program (type whoami to get noticed) not by privileges that the program has.

Related

How can one overwrite the return address without buffers on on the stack?

In the below program, I have a few buffers, but they are global variables, not stored on the stack. Thus, I'm not seeing a viable way of overwriting the return address to execute a shellcode.
Is there a vulnerability in the below that I am missing? The path constructed in snprintf seems pretty solid - not seeing a way to redirect the execution path.
C program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
char buffer[256] = "";
char filename[256] = "";
int main(int argc, char *argv[])
{
setreuid(geteuid(), geteuid());
setregid(getegid(), getegid());
if (argv[1]) {
snprintf(filename, 255, "/var/smash/g6/%s", basename(argv[1]));
printf("Checking filename %s\n", filename);
if (access(filename, X_OK)) {
fprintf(stderr, "You do not have the permission to execute this file\n");
return 1;
}
}
else {
fprintf(stderr, "Please provide the program name. Currently available programs:\n");
system("/bin/ls /var/smash/v6");
return 2;
}
if (argv[2]) {
strcpy(buffer, argv[2]);
}
else {
printf("Provide the parameter(s):\n");
gets(buffer);
}
printf("Executing filename %s\n", filename);
execlp(filename, filename, buffer, (char *)0);
return 0;
}
Without trying it, it looks as if the vulnerability is that you provide a filename, which is checked to see that you have access, but then you read a string that isn't constrained to buffer but can overflow into filename such that your program will then execute the new filename without being constrained by the earlier checks.

How can I fork&exec bash shell in C?

Trying to create a new bash shell in C and bring it to the user, this is my code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
char* secretpass = "password";
char password[50];
printf("%s", "Password: ");
fgets(password, 50, stdin);
password[strcspn(password, "\n")] = 0;
if (!strcmp(password, secretpass)){
pid_t pid = fork();
if (pid == 0){
execl("/bin/bash", "bash", NULL);
}
}
return 0;
}
After running the code (ELF), i get a new bash shell in ps but it's not my shell because echo $$ brings the first shell, what can I do to get the new shell to screen? kernel module will help?
EDIT:
edited my code for more help, /dev/chardev is a char device that come up with the boot process, the driver is also 0666 (.rw.rw.rw.) writable for everyone, the system(cmd) says at there is no permission at console, even if I do the command myself after execve.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#define MAX 50
#define USERNAME 2
int main(int argc, char const *argv[])
{
// Declare variables.
const char* username = argv[USERNAME];
char* password = (char*)calloc(MAX, sizeof(char));
char* cmd = (char*)calloc(5 * MAX, sizeof(char));
char* secretpass = "password";
printf("%s", "Password: ");
fgets(password, MAX, stdin);
password[strcspn(password, "\n")] = 0;
if (!strcmp(password, secretpass)){
int err;
struct passwd* pw_user = getpwnam(username);
//printf("-%s-%s-%d-%d-%s-%s-%s-\n", pw_user->pw_name, pw_user->pw_passwd,
//pw_user->pw_uid, pw_user->pw_gid, pw_user->pw_gecos,
//pw_user->pw_dir, pw_user->pw_shell);
if ( (err = fchown(0, pw_user->pw_uid, pw_user->pw_gid) ) != 0)
printf("%s %d\n", "fchown error", err);
if ( (err = setpgid(0, 0) ) != 0)
printf("%s %d\n", "setpgid error", err);
if ( (err = tcsetpgrp(0, getpid()) ) != 0)
printf("%s %d\n", "tcsetpgrp error", err);
if ( (err = chdir(pw_user->pw_dir) ) != 0)
printf("%s %d\n", "chdir error", err);
if ( (err = setgid(pw_user->pw_gid) ) != 0)
printf("%s %d\n", "setgid error", err);
if ( (err = setuid(pw_user->pw_uid) ) != 0)
printf("%s %d\n", "setuid error", err);
sprintf(cmd, "%s \"%d %d %d\" %s", "echo", pw_user->pw_uid, pw_user->pw_gid, getpid(), "> /dev/chardev");
system(cmd);
const char *args[] = {"bash", "--rcfile", "/etc/bashrc", NULL};
char LOGNAME[MAX];
char HOME[MAX];
char USER[MAX];
sprintf(LOGNAME, "%s%s", "LOGNAME=", pw_user->pw_name);
sprintf(HOME, "%s%s", "HOME=",pw_user->pw_dir);
sprintf(USER, "%s%s", "USER=", pw_user->pw_name);
const char *env[] = {"SHELL=/bin/bash", LOGNAME, HOME, USER, "IFS= ","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin", "TTY=tty1", NULL}; /* need to generate these; TTY is passed to you */
execve("/bin/bash", args, env);
}
else
execl("/bin/login", "login", NULL);
return 0;
}
always setpgid error and if username isn't root there are also setuid and chdir errors.
From the comments: you're trying to write a login program.
Ok. That's a bit more, and you're going about this all the wrong way. We don't want to fork at all. Let init worry about waiting. Anyway, we get to write a long sequence here:
int targetuid = ... ; /* You need a strategy for getting this */
int targetgid = ... ; /* You need a strategy for getting this */
const char *homdir = ... ; /* You need a strategy for getting this */
if (!strcmp(password, secretpass)){
/* Start up the user's shell */
fchown(0, targetuid, targetgid);
setpgid(0, 0);
tcsetpgrp(0, getpid());
chdir(homedir);
setgid(targetgid);
setuid(targetuid);
const char *args[] = {"-bash", NULL};
const char *env[] = {"SHELL=/bin/bash", "LOGNAME=...", "HOME=...", "USER=...", IFS="...", PATH=/bin:/usr/bin", "TERM=...", NULL }; /* need to generate these; TERM is passed to you */
execve("/bin/bash", args, env);
}
This is very much involved and I actually don't recommend this unless you really have to. I learned a ton when I tried this but it took forever to get it working right.
Particular subpoints: 1) The tty device needs to be owned by the user after a successful login. Thus the fchown(0, ...) call to give ownership to the user. 2) The chdir() first is traditional; you could reverse the order if you wanted to but I don't see why. 3) Starting the shell with a leading - in argv0 tells the shell that it's a login shell. Check in ps -f and you can see this.
I picked up your new code; it actually looks pretty good. The only mistake I can spot is my own; the variable is TERM not TTY (now corrected in my sample above) and the best place to get its value is getenv(). On running your code I only had to make only one correction; that is putting the -bash back. The only error it spits out is the one about chardev; what is chardev?
I guess your failures aren't in this code at all but rather in your kernel.
Info from chat: OP has a custom kernel with a custom /dev/chardev; I can't explain the failures as the code works for me. There may or may not be other changes to the kernel.

My own program who work as "which" command in linux - dont work great

I would like to make my own program who will be work as which command in linux. Original which command works that (example for pwd):
$ which pwd
/bin/pwd
but my program works that:
$ ./prog1 pwd
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games pwd
Can You correct my program? Source code:
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char *systemPath, *path, *fileName;
struct stat statStruct;
if (argc < 2){
printf( "Nothing to do\n");
return -1;
}
if ((systemPath = getenv("PATH")) == NULL)
{
perror( "Not found PATH!\n ");
return -1;
}
fileName = argv[1];
printf("%s %s\n", systemPath, fileName);
while ((path = strsep(&systemPath, ":")) != NULL)
{
if ((stat(fileName, &statStruct) == 0) && S_ISREG(statStruct.st_mode) && (statStruct.st_mode & S_IRUSR))
{
printf("%s\n", fileName);
printf("%s\n", systemPath);
printf("%s\n", path);
}
}
return 0;
}
You find the candidate directory using strsep, storing it in path. But then you don't use this variable; the stat call just uses the base filename, which will therefore always be looked up in the current working directory.
You need to form the concatenation of path, a /, and the filename, and then stat that.
You will probably find snprintf useful.

Open function in POSIX C not working

I'm trying to get my open function to work with this program, it is reading the input correctly, as I can see if I printf the file name after I type it in, but my open function must be wrong, I can't seem to figure out what is wrong with it and it keeps returning -1 and exiting. I am trying to just open a file called tester.txt and I'm using a virtual machine running ubuntu. Any help is appreciated,thanks everyone.
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
int bytes_read = 1;
int nbytes = 32;
char buffer[32];
char s[] = "name";
printf("Welcome to File Copy by %s!\n", s);
char *inputFile = NULL;
puts("Enter the name of the source file: ");
bytes_read = getline(&inputFile, &nbytes, stdin);
//if fail exit
int inputOpen = open("inputFile", O_RDONLY);
//if fail exit
if (inputOpen == -1){
printf("file not found.\n");
return -1;
}
return 0;
}
No matter what is entered as the name of the file, you try to open a file called "inputFile". You need to add code to extract the filename from the line entered.
This would be one way:
char *eol;
bytes_read = getline(&inputFile, &nbytes, stdin);
eol = strchr(inputFile, '\n');
if (eol != NULL) // remove end of line
*eol = 0;
int inputOpen = open(inputFile, O_RDONLY);

howto Enter into chroot environment from C?

what i am try to do is to get my program to enter chroot environment and do some commands and then exit.
For Example
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define ChRoot "sudo chroot \"/\" /usr/bin/env -i HOME=/root TERM=\"$TERM\" PATH=/bin:/usr/bin:/sbin:/usr/sbin:/bin /bin/bash --login +h"
void func1(){
//enter the chroot environment
char line[130]; FILE *fp;
fp = popen(ChRoot, "r");
while(fgets( line, sizeof line, fp)){
printf ("%s\n",line);
}
pclose(fp);
}
void func2(){
//run a command in the chroot environment
char line[130]; FILE *fp;
fp = popen("ls", "r");
while(fgets( line, sizeof line, fp)){
printf ("%s\n",line);
}
pclose(fp);
}
int main() {
func1();
func2();
return 0;
}
the problem with this code is, it will get me in the chroot environment however it will not fire func2 until i exit form the chroot environment. What i need is to get my code to do func1 and then func2 in chroot environment and then exit.I know what i am doing in my code is horribly wrong, however, i hope i could get some directions .
Any help would be much appreciated.
If you're in C and you want to enter a chroot you can do so directly using the chroot() function:
#include <stdio.h>
#include <unistd.h>
int main(void) {
FILE *f;
/* chroot */
chdir("/tmp");
if (chroot("/tmp") != 0) {
perror("chroot /tmp");
return 1;
}
/* do something after chrooting */
f = fopen("/etc/passwd", "r");
if (f == NULL) {
perror("/etc/passwd");
return 1;
} else {
char buf[100];
while (fgets(buf, sizeof(buf), f)) {
printf("%s", buf);
}
}
return 0;
}
Note that if you don't set the current directory before chrooting it's possible to break out of the chroot.
There is a chroot system call that does what you want. In fact, the chroot command-line utility itself uses this first and then spawns a shell.

Resources