gdb exiting instead of spawning a shell - c

I am trying to exploit a SUID program.
The program is:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }
void print(unsigned char *buf, int len)
{
int i;
printf("[ ");
for(i=0; i < len; i++) printf("%x ", buf[i]);
printf(" ]\n");
}
int main()
{
unsigned char buf[512];
unsigned char *ptr = buf + (sizeof(buf)/2);
unsigned int x;
while((x = getchar()) != EOF) {
switch(x) {
case '\n': print(buf, sizeof(buf)); continue; break;
case '\\': ptr--; break;
default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
}
}
printf("All done\n");
}
We can easily see that if we somehow change ptr's contents to some address that starts with CA then a new shell will be spawned for us. And as ptr normally holds some address starting with FF the way to decrease it(ptr) is to enter \ character. So I make a file with 0x35000000 '\' characters, and finally 3 'a' at the end of the file
perl -e "print '\\\'x889192448" > file # decimal equivalent of 0x35000000
echo aaa > file # So that e() is called which actually spawns the shell
And finally in gdb,
run < file
However instead of spawning a shell gdb is saying
process <some number> is executing new program /bin/dash
inferior 1 exited normally
And then back to gdb prompt instead of getting a shell.
I have confirmed by setting breakpoints at appropriate locations that ptr is indeed starting with CA before setresuid() gets called.
Also if I pipe this outside of gdb, nothing happens.
./vulnProg < file
Bash prompt returns back.
Please tell me where am I making mistake.

You can see the problem by compiling a simpler test program
int main() { execlp("/bin/sed", "-e", "s/^/XXX:/", NULL); }
All this does is start a version of sed (rather than the shell) and converts input by prepending "XXX:".
If you run the resulting program, and type in the Terminal you get behaviour like this:
$./a.out
Hello
XXX:Hello
Test
XXX:Test
^D
Which is exactly as we'd expect.
Now if you feed it input from a file containing "Hello\nWorld" you get
$./a.out < file
XXX:Hello
XXX:World
$
And the application exits immediately, with the input stream to the application being closed when the input file has all been read.
If you want to provide additional input, you need to use a trick to not break the input stream.
{ cat file ; cat - ; } | ./a.out
This will put all the input from file into a running ./a.out and then
read from stdin and add that too.
$ { cat file ; cat - ; } | ./a.out
XXX:Hello
XXX:World
This is a Test
XXX:This is a Test

Related

Program displaying "port opened/closed"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char command[100];
char portrange[100];
printf("Enter portrange (e.g.,20-30)");
scanf("%s", portrange);
int i=0, range1, range2;
sscanf(portrange, "%d-%d", &range1, &range2);
for(i=range1;i<=range2;i++)
{
sprintf(command, "netstat -aont | grep \"`hostname -i`:%d \" ", i);
printf("command= %d \n", command); //printing the command for testing purpose only
system(command);
//here
//here
printf("%d\n",i);
}
return 0;
}
The program filters out the lines from netstat -aont | grep "hostname -i:%d " where %d is successively replaced by the entered range of ports.
I want to add a if statement to display "port#%d is open" if port %d is opened if the command is successful or "port#%d is closed" if the command fails.
How can I achieve this inside the for loop?
N.B.: I used %d inside the for loop in port range checking. I know it is wrong but when I use %s it crashes with a core dump. Let’s ignore that for the moment.
The exit code of the pipeline command is the exit code of the last command in the pipeline. In your example, this is the exit code of grep. If grep succeeds, it exits with the value 0 otherwise it is different than 0.
system() returns the status of the command line passed as parameter. So, you need to store the status in a variable:
int status;
...
status = system(...);
You need to check the content of status with the WIFEXIT() & WEXITSTATUS(). The latter macro will extract the exit code from the status:
if (WIFEXITED(status)) {
int exit_code = WEXITSTATUS(status);
printf("Exit code is %d\n", exit_code);
// If exit_code is 0 ==> The grep succeeded
}

How to: call a method every second impleting getchar() or if it's empty then continue

So I'm trying to do something like this: I have a function calling another one in which I am reading text line by line from a given file and I want it to execute what it reads(working atm), BUT it should only execute a line once every second so the user has time to write for example an S in stdin, meaning STOP (or something like that), else if the users didn't input anything then the program should continue to iterate the file. How can I do this ?
What I have been using to try this is signal and alarms(), testing out something like this:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<string.h>
volatile int breakflag = 2;
void handle(int sig){
if( getchar()=='a' ){
printf("it read something from input\n");
--breakflag;
}else{
printf("it didn't read anything from input\n");
--breakflag;
}
alarm(2);
}
int main(){
/*let's say this is part of the method that i call each iteration until I've read EOF.
now is the part that i should execute whatever i get into the stdin,
or if it's empty it should continue to next iteration...
*/
signal(SIGALRM, handle);
alarm(1);
while(breakflag){
sleep(1);
}
printf("done\n");
return 0;
}
Sorry for the long description. But I'm having a hard time trying to get anything that works out.
I have found a few answers that helped me throughout this problem but i can't seem to figure it out the way i need it....
You can use select with a timeout of 1 sec, for instance :
#include <stdio.h>
#include <sys/select.h>
int main()
{
struct timeval tv;
fd_set fd;
int i;
FD_ZERO(&fd);
for (i = 0; i != 10; ++i) {
FD_SET(0, &fd);
tv.tv_sec = 1;
tv.tv_usec = 0;
if (select(0 + 1, &fd, NULL, NULL, &tv) == -1) {
perror("error on select");
break;
}
if (FD_ISSET(0, &fd)) {
int c = getchar();
if (c == EOF) {
puts("EOF");
break;
}
printf("read char '%c'\n", c);
}
else
puts("nothing to read");
}
return 0;
}
Compilation and execution (under Linux) :
pi#raspberrypi:/tmp $ gcc -Wall c.c
pi#raspberrypi:/tmp $ (sleep 2 ; echo -n a ; sleep 3 ; echo -n z) | ./a.out
nothing to read
nothing to read
read char 'a'
nothing to read
nothing to read
nothing to read
read char 'z'
EOF
pi#raspberrypi:/tmp $ ./a.out

Force flush or read unflushed output

This is a frontend to the tool dc; the idea is to type an infix expression (2 + 3), map it to the corresponding postfix notation (2 3 +) and send it to dc. It's what bc does.
I'm doing this with pipes, but the frontend hangs waiting for output.
This is the code; I will continue commenting it below. The "h" command in my dc is unimplemented, hence is what I'm looking for as an end of output from dc.
TL;DR: the process hangs because stdout in dc is not flushed or that's what I think to have found. How can I read it regardless or force a flush after every write?
What I've found is commented below.
#define DC_EOF_RCV "dc: 'h' (0150) unimplemented"
#define DC_EOF_SND "h\n"
static FILE *sndfp, *rcvfp;
int dcinvoke() {
int pfdout[2], pfdin[2];
pid_t pid;
pipe(pfdout);
pipe(pfdin);
switch (pid = fork()) {
case -1: exit(1);
case 0:
dup2(pfdout[0], STDIN_FILENO);
dup2(pfdin[1], STDOUT_FILENO);
close(pfdout[0]);
close(pfdout[1]);
close(pfdin[0]);
close(pfdin[1]);
execlp("dc", "dc", "-", NULL);
}
close(pfdout[0]);
close(pfdin[1]);
sndfp = fdopen(pfdout[1], "w");
rcvfp = fdopen(pfdin[0], "r");
return 1;
}
void dcsnd(const char *s) {
fputs(s, sndfp);
fflush(sndfp);
}
void dcrcv(char *buf, size_t max) {
fgets(buf, max, rcvfp); // <<<<< HANGS HERE
}
int turnaround() {
dcsnd(DC_EOF_SND); fflush(sndfp);
}
int rcvall() {
char buf[256];
turnaround();
for (;;) {
dcrcv(buf, sizeof(buf));
if (! strcmp(buf, DC_EOF_RCV)) {
break;
}
printf("%s", buf);
}
return 1;
}
int prompt(const char *msg, char *res, size_t resmax, int *eofp) {
char *p;
printf("\n%s ", msg);
if (!fgets(res, resmax, stdin)) {
*eofp = 1;
} else {
if (p = strrchr(res, '\n')) {
*p = 0;
}
*eofp = 0;
}
return 1;
}
int main() {
char buf[128], line[128];
int eof;
dcinvoke();
dcsnd("2 3 +\n");
dcsnd(DC_EOF_SND);
rcvall();
for (;;) {
prompt("Expression", buf, sizeof(buf), &eof);
if (eof) {
break;
}
snprintf(line, sizeof(line), "%s\n", buf);
dcsnd(line);
rcvall();
}
dcsnd("q\n");
return 0;
}
I have removed the error checks for simplicity of this question.
The frontend hangs at the line:
fgets(buf, max, rcvfp);
As I really had no idea how to find the problem, I wrote my own dc which does nothing but responds correctly to an "h" command and outputs everything it gets to a file (so I can debug it; I am not aware of any other way). I can add it here if it's useful.
I've found that a call to fflush(stdout) in (my) dc resumes the frontend, as a call to fgets finally returns.
I cannot change dc itself. How can it not hang on fgets?
Some ideas I had:
Use another thread to flush rcvfp (stdout of dc)
Write it using pseudoterminal
I'm looking for suggestions or a simple way to avoid both of them.
I tried to:
Use read() to fileno(rcvfp)
Read this and this similar posts
Use setlinebuf() (man)
dc sends error messages to stderr, not stdout, so you'll never see them -- they go straight to the terminal (or whatever stderr is connected to in your environment). To be able to read them in your program, you also need to redirect stderr. Add
dup2(pfdin[1], STDERR_FILENO);
in the child fork code.
To make your code actually work, I had to also add a newline to the end of the DC_EOF_RCV string (to match what dc sends), and remove the extra dcsnd(DC_EOF_SND); call from main, since you never do a receive that matches it anywhere. Even with this, you can still get race conditions within dc between writing to stdout and stderr, which can cause the output lines to get mixed, resulting in a response that does not match your DC_EOF_RCV string. You can probably avoid those by adding a small sleep to your turnaround function.
An alternate option is using poll in your main loop to read from stdin and dc simultaneously. With this, you don't need the weird "send h command to trigger an error" mechanism to figure out when dc is done -- you just loop. Your main loop ends up looking like:
struct pollfd polling[2] = { { STDIN_FILENO, POLLIN, 0 }, { fileno(rcvfp), POLLIN, 0 } };
printf("Expression ");
for(;;) {
if (poll(polling, 2, -1) < 0) {
perror("poll");
exit(1); }
if (polling[0].revents) {
/* stdin is ready */
if (!fgets(buf, sizeof(buf), stdin))
break;
dcsnd(buf); }
if (polling[1].revents) {
/* dc has something for us */
printf("\r \r"); /* erase the previsouly printed prompt */
dcrcv(buf, sizeof(buf));
printf("%s\n", buf); }
printf("Expression "); /* new prompt */
}
There's more detail you can do here with managing error conditions (the revents might be POLLERR or POLLHUP for an error or hangup rather than POLLIN for normal input -- all of these are non-zero values, so testing just for nonzero is reasonable).
With the dc command provided by macOS 10.14.6 Mojave, sending 2 3 + to the program works fine; it just doesn't say anything because you've not asked it to.
$ dc
2 3 +
p
5
q
$
The p (print) command triggers the response 5. The q command quits.
Sending h gets a mixed response:
$ dc
h
dc: 'h' (0150) unimplemented
q
$
The response is mixed because the dc: (and space) goes to standard error and the message to standard output:
$ dc >/dev/null
h
dc:
q
$
$ dc 2>/dev/null
h
'h' (0150) unimplemented
q
$
Consequently, I think your primary problem is that you are waiting for a response that dc is not going to provide. If you want to ensure that you get a printed value, then you need to add a p command. That can be on the same line or on a different line as the 2 3 + expression.
$ dc
2 3 + p
5
2
3
+
p
5
q
$

Implementing Pipes in a C shell (Unix)

Basically I have created a shell using standard POSIX commands, I want to be able to Implement Piping as well. Right now it handles commands correctly, and can do background processing with &. But I need to be able to pipe using | and >> as well.
For example something like this:
cat file1 file2 >> file3
cat file1 file2 | more
more file1 | grep stuff
Here is the code I have currently. I also want to AVOID "SYSTEM" calls. I know U need to use dup2, but the way I did my code is a bit odd, so im hoping if someone can tell me if it is feasible to implement pipes in this code? thanks! I know dup2 is used, but also im def. confused at how to implement >> as WELL as |
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
void Execute(char* command[],bool BG)
{
//Int Status is Used Purely for the waitpid, fork() is set up like normal.
int status;
pid_t pid = fork();
switch(pid)
{
case 0:
execvp(command[0], command);
if(execvp(command[0], command) == -1)
{
cout << "Command Not Found" << endl;
exit(0);
}
default:
if(BG == 0)
{
waitpid(pid, &status, 0);
//Debug cout << "DEBUG:Child Finished" << endl;
}
}
}
bool ParseArg(char* prompt, char* command[], char Readin[],bool BG)
{
fprintf(stderr, "myshell>");
cin.getline(Readin,50);
prompt = strtok(Readin, " ");
int i = 0;
while(prompt != NULL)
{
command[i] = prompt;
if(strcmp(command[i], "&") == 0){
//Debug cout << "& found";
command[i] = NULL;
return true;
}
//Debug cout << command[i] << " ";
i++;
prompt = strtok(NULL, " ");
}
return false;
}
void Clean(char* command[])
{
//Clean Array
for(int a=0; a < 50; a++)
{
command[a] = NULL;
}
}
int main()
{
char* prompt;
char* command[50];
char Readin[50];
bool BG = false;
while(command[0] != NULL)
{
Clean(command);
BG = ParseArg(prompt, command, Readin, BG);
if(strcmp(command[0], "exit") == 0 || strcmp(command[0], "quit") == 0 )
{
break;
}
else
{
Execute(command,BG);
}
}
return 1;
}
Pipes and redirections are different, actually. To implement a redirection (such as >>) you have to use dup2 indeed. First, open the desired file with appropriate flags (for >> they'll be O_WRONLY|O_CREAT|O_APPEND). Second, using dup2, make stdout (file descriptor 1) a copy of this newly opened fd. Finally, close newly opened fd.
To create a pipe, you'll need a pipe syscall. Read its manpage, it contains example code. Then you'll also need dup2 to make file descriptors returned by pipe be stdin for one process and stdout for another, respectively.
You should be able to implement pipes and output redirection with your shell, but there are a few things I noticed:
Your code for reading input, parsing, and output are mixed together, you may want to separate this functionality.
strtok won't work very well as a parser for shell commands. It will work for very simple commands, but you may want to look into creating or finding a better parser. A command like echo "hello world" will be problematic with your current parsing method.
You may want to create a simple structure for holding your parsed commands.
Here is some pseudocode to get you started:
#define MAX_LINE 10000
#define MAX_COMMANDS 100
#define MAX_ARGS 100
// Struct to contain parsed input
struct command
{
// Change these with IO redirection
FILE *input; // Should default to STDIN
FILE *output; // Should default to STDOUT
int num_commands;
int num_args[MAX_COMMANDS]; // Number of args for each command
char* command_list[MAX_COMMANDS]; // Contains the programs to be run
char* args_list[MAX_COMMANDS][MAX_ARGS]; // The args for each command
boolean background_task;
boolean append;
}
int main()
{
char input[MAX_LINE];
while (1)
{
struct command cmd;
print_prompt();
read_input(input);
parse_input(input, &cmd);
execute(&cmd);
}
}
Good luck with this project!

C, pass AWK syntax as argument to execl

I want to run the following command from a C program to read the system's CPU and memory use:
ps aux|awk 'NR > 0 { cpu +=$3; ram+=$4 }; END {print cpu,ram}'
I am trying to pass it to the execl command and after that read its output:
execl("/bin/ps", "/bin/ps", "aux|awk", "'NR > 0 { cpu +=$3; ram+=$4 }; END {print cpu,ram}'",(char *) 0);
But in the terminal I am getting the following error:
ERROR: Unsupported option (BSD syntax)
I would like to know how to properly pass awk as argument to execl?
You can't do this here this way.
The problem is that you want to execute several commands. execl is for executing a single command. The statement you have is using shell syntax (notably the | )
You will have better luck combining it all up in a single string and using the system(3) call.
Instead of running awk and parsing awk's output, you can do the filtering and summation in C, which often can quickly become much more convenient. (It's about the same for the exact command you have here.)
#include <errno.h>
#include <stdio.h>
void ps_cpumem(FILE* f, double* cpu_total, double* mem_total) {
for (;;) {
char buf[2000];
if (!fgets(buf, sizeof buf, f)) {
return;
}
double cpu, mem;
if (sscanf(buf, "%*s %*s %lf %lf", &cpu, &mem) == 2) {
*cpu_total += cpu;
*mem_total += mem;
}
}
}
int main() {
errno = 0;
FILE* ps = popen("ps aux", "r");
if (!ps) {
if (errno == 0) puts("popen: memory allocation failed");
else perror("popen");
return 1;
}
double cpu = 0, mem = 0;
ps_cpumem(ps, &cpu, &mem);
int rc = pclose(ps);
if (rc == -1) return 1;
printf("%%cpu: %5.1f\n" "%%mem: %5.1f\n", cpu, mem);
return 0;
}
However, you can run the full command through popen, as it executes a shell:
FILE* output = popen("ps aux | awk 'NR > 0 { cpu +=$3; ram+=$4 }; END {print cpu,ram}'", "r");
// read from output to do with as you like
As Will suggested, popen() is what you want for capturing output for subsequent use inside your program. However, if you truly are wanting to do an exec operation, you can use the shell to do your bidding via execl():
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
printf("%s: execl returned unexpectedly: %d", argv[0],
execl("/bin/sh", "/bin/sh", "-c",
"ps aux | awk 'NR >0 { cpu += $3; ram+=$4}; END {print cpu, ram}'",
NULL));
exit(1);
}

Resources