what does this attempted trojan horse code do? - c

It looks like this just sends a ping, but whats the point of that when you can just use ping?
/* WARNING: this is someone's attempt at writing a malware trojan. Do not
compile and *definitely* don't install. I added an exit as the
first line to avoid mishaps - msw */
int main (int argc, char *argv[])
{
exit(1);
unsigned int pid = 0;
char buffer[2];
char *args[] = {
"/bin/ping",
"-c",
"5",
NULL,
NULL
};
if (argc != 2)
return 0;
args[3] = strdup(argv[1]);
for (;;)
{
gets(buffer); /* FTW */
if (buffer[0] == 0x6e)
break;
switch (pid = fork())
{
case -1:
printf("Error Forking\n");
exit(255);
case 0:
execvp(args[0], args);
exit(1);
default:
break;
}
}
return 255;
}

It's a hack - or an attempt at a hack - to get arbitrary code run in a privileged mode. Ping needs to run SUID root to get a raw socket for an ICMP_ECHO_REQUEST and the intentional buffer overrun in gets(buffer) is intended to pass junk to ping.
I don't see how this could work in practice, but you shouldn't compile and run it.

It makes sure that ping is called with the arguments -c 5. Which is stupid, because a shell script or alias would be easier to read and faster to write.

This program basically emulates a simple shell program. A shell program is going to take the arguments of another program as input and launch that specified program in a new process. The program you have above is just hard coded for one specific program (ping in this case) and is very simple.
A shell program makes working with the operating system more user friendly by providing an interface to boot up programs.

Related

I ran into a problem while creating my own shell

I'm making my own shell in C. The input window appears, but when I enter the command ls, it does not respond.
#define MAX 64
char buf[MAX];
void * get_next_command(void);
int main(int argc, char* argv[])
{
while(1){
char *cmd = get_next_command();
int child_pid = fork();
if(child_pid <0){
perror("error\n");
return -1;
}
else if(child_pid == 0){
execle(cmd,cmd,NULL);
exit(0);
}
else{
wait(NULL);
}
}
return 0;
}
void * get_next_command()
{
printf("Shell > ");
fgets(buf,MAX,stdin);
buf[strlen(buf)-1]='\n';
}
I wonder how to run commands in my own shell. Any reply will be thankful. Best regards.
While making a shell seems simple, you actually have to work a bit more on this to make it work. The thing is execle asks for the path of the file to execute. For example ls is actually /bin/ls so that's what you need to pass on as a first argument for your program to work. If you wanna go deeper into this and make a real custom shell, you have to get your environment through your main like this:
int main(int ac, char **av, char **env);
This will get your environment (you can type env in your terminal to see what it's like) then you'll be able to get the PATH variable to get all the paths separated by : for your binaries (like /bin which is used by /bin/ls).
As for execle, if you wanna pass on the arguments you have, you have to pass them like this:
For example if the command is ls -l -a
then you will run:
execle("/bin/ls", "ls", "-l", "-a", NULL);
But you can also do the same with execv which works with a char ** instead of strings for your arguments. AND if you go even deeper into this you can pass on your custom environment with execve (the third argument being your environment).
Here's how you should call your function (replacing the hardcoded values by variables of course):

Shell seems to recognize commands but doesn't execute them

I am trying to implement basic command execution in a shell program for the unix-like xv6 OS. The part of the shell code that I am editing is the runcmd function where I am using the execvp command to execute the commands used in the terminal. The program compiles without errors when I compile it but nothing happens when I try to type a command on the command line. I've read the man pages for the exec command, but I still don't really understand the proper way in which these arguments need to passed in the exec() command or when to use which version of exec() as I'm still very new to OS programming.
What haven't I implemented here that needs to be added in order for commands to be executed? I have the code for the runcmd function below:
EDIT:
I just added more exec statements with the paths to the binary for each command; however, only the first exec command works (which is cd in this case). When I use any other command, the command line executes it as if it is CD. How do I get it to work for multiple commands?
struct cmd {
int type; // ' ' (exec), | (pipe), '<' or '>' for redirection
};
struct
execcmd {
int type; // ' '
char *argv[MAXARGS]; // arguments to the command to be exec-ed
};
// Execute cmd. Never returns.
void
runcmd(struct cmd *cmd)
{
int p[2], r;
struct execcmd *ecmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
exit(0);
switch(cmd->type){
default:
fprintf(stderr, "unknown runcmd\n");
exit(-1);
case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0)
exit(0);
//fprintf(stderr, "exec not implemented\n");
execvp("/bin/cd" , ecmd->argv );
execvp("/bin/grep" , ecmd->argv );
execvp("/bin/echo" , ecmd->argv );
execvp("/bin/cat" , ecmd->argv );
execvp("/bin/ls" , ecmd->argv );
break;
case '>':
case '<':
rcmd = (struct redircmd*)cmd;
//fprintf(stderr, "redir not implemented\n");
execvp("/bin" , ecmd->argv );
runcmd(rcmd->cmd);
break;
case '|':
pcmd = (struct pipecmd*)cmd;
fprintf(stderr, "pipe not implemented\n");
int execl(const char *path, const char *arg, ...);
break;
}
exit(0);
}
It looks like you are trying to execute the "/bin" directory.
You should make the first argument to the exec call be the binary the user wants to run.
Using the perror function would also give you useful output when the command fails.
I think this is what you actually need:
case ' ':
ecmd = (struct execcmd*)cmd;
if (ecmd->argv[0] == 0)
_exit(0);
execvp(ecmd->argv[0], ecmd->argv);
/* if control reaches this point, execvp failed */
perror(ecmd->argv[0]);
_exit(127);
You may be wondering why execvp takes the executable to load as a separate argument from the argument vector, when you're just going to hand it argv[0]. This is legacy functionality; if I were designing this API from scratch today, I don't think I would include it. However, the idea is that a program might behave differently depending on what its argv[0] is. For instance, back in the day ex and vi were the same executable (two hard links to the same inode -- symlinks had not been invented yet), which decided what mode to start up in based on its argv[0]. And, since the dawn of Unix, login(1) has invoked shells with the first character of argv[0] set to '-'; there is no /bin/-sh, so it actually needs the ability to specify the program-to-invoke separately from the argument vector.
I can't presently think of a situation where a shell would use anything other than argv[0] as the first argument to execvp.
Notes on other changes to your code:
Never call exit on the child side of a fork, only _exit.
When a system call fails, always print out both the name of the offending file and strerror(errno), to stderr, not stdout. perror is a convenient shorthand for this operation.
For the perror call to be safe, you must have called fflush(0) in the parent, immediately before the fork, and your C library must implement line-buffering of stderr, correctly. I mention this because XV6 appears to be a teaching OS where you have to implement bits of it yourself, and I don't know whether stdio is your responsibility or not.

Fail to read command output using popen function

In Linux, I am finding pid of process by opening pipe with "pidof process_name" command and then reading it's output using fgets function. But it fails to find pid once in a while. Below is my code for finding pid of my process.
int FindPidByProcessName(char *pName)
{
int pid = -1;
char line[30] = { 0 };
char buf[64] = { 0 };
sprintf(buf, "pidof %s", pName);
//pipe stream to process
FILE *cmd = popen(buf, "r");
if (NULL != cmd)
{
//get line from pipe stream
fgets(line, 30, cmd);
//close pipe
pclose(cmd); cmd = NULL;
//convert string to unsigned LONG integer
pid = strtoul(line, NULL, 10);
}
return pid;
}
In output sometimes pid=0 comes even though process is available in "ps" command output.
So, I try to find root cause behind this issue and i found something like input/output buffer mechanism is may creating issue in my scenario.
So I try to use sync() function before opening popen() and strangely my function starts working with 100% accuracy.
Now sync() function is taking too much time(approximately 2min sometime) to complete its execution which is not desirable. So i try to use fflush(), fsync() and fdatasync() but these all are not working appropriately.
So please anyone tell me what was the exact root cause behind this issue And how to solve this issue appropriately?
Ok, the root cause of the error is stored in the errno variable (which btw you do not need to initialize). You can get an informative message using the fucntion
perror("Error: ");
If u use perror the variable errno is interpreted and you get a descriptive message.
Another way (the right way!) of finding the root cause is compiling your program with the -g flag and running the binary with gdb.
Edit: I strongly suggest the use of the gdb debugger so that you can look exactly what path does your code follow, so that you can explain the strange behaviour you described.
Second Edit: Errno stores the last error (return value). Instead of calling the functions as you do, you should write, and check errno immediately:
if ((<function>) <0) {
perror("<function>: ");
exit(1);
}

How to intercept SSH stdin and stdout? (not the password)

I realize this question is asked frequently, mainly by people who want to intercept the password-asking phase of SSH. This is not what I want. I'm after the post-login text.
I want to write a wrapper for ssh, that acts as an intermediary between SSH and the terminal. I want this configuration:
(typing on keyboard / stdin) ----> (wrapper) ----> (ssh client)
and the same for output coming from ssh:
(ssh client) -----> (wrapper) -----> stdout
I seem to be able to attain the effect I want for stdout by doing a standard trick I found online (simplified code):
pipe(fd)
if (!fork()) {
close(fd[READ_SIDE]);
close(STDOUT_FILENO); // close stdout ( fd #1 )
dup(fd[WRITE_SIDE]); // duplicate the writing side of my pipe ( to lowest # free pipe, 1 )
close(STDERR_FILENO);
dup(fd[WRITE_SIDE]);
execv(argv[1], argv + 1); // run ssh
} else {
close(fd[WRITE_SIDE]);
output = fdopen(fd[READ_SIDE], "r");
while ( (c = fgetc(output)) != EOF) {
printf("%c", c);
fflush(stdout);
}
}
Like I said, I think this works. However, I can't seem to do the opposite. I can't close(STDIN_FILENO) and dup the readside of a pipe. It seems that SSH detects this and prevents it. I've read I can use the "-t -t" option to force SSH to ignore the non-stdin nature of its input; but when I try this it still doesn't work.
Any hints?
Thanks very much!
Use popen (instead of execv) to execute the ssh cmd and be able to read and write to the session.
A pipe will not work if you want to allow any interactive use of ssh with the interceptor in place. In this case, you need to create a pseudo-tty. Look up the posix_openpt, ptsname, and grantpt functions. There's also a nonstandard but much-more-intuitive function called openpty, and a wrapper for it called forkpty, which make what you're trying to do extremely easy.
Python's Paramiko does all of this with SSH but it is in Python source code. However, for a C programmer, reading Python is a lot like reading pseudocode so go to the source and learn exactly what works.
Here's a working example that writes to ssh:
#include <unistd.h>
int main(int argc, char **argv)
{
int pid;
int fds[2];
if (pipe(fds))
return -1;
pid = fork();
if (!pid)
{
close(fds[1]);
close(STDERR_FILENO);
dup2(fds[0], STDIN_FILENO);
execvp(argv[1], argv + 1);
}
else
{
char buf[256];
int rc;
close(fds[0]);
while ((rc = read(STDIN_FILENO, buf, 256)) > 0)
{
write(fds[1], buf, rc);
}
}
wait(NULL);
return 0;
}
This line is probably wrong:
execv(argv[1], argv + 1); // run ssh
The array must be terminated by a NULL pointer, if you are using argv[] the parameter from main() I don't think there is any guarantee that this is the case. Edit: just checked the C99 standard and argv is NULL terminated.
execv() does not search the path for the file to execute, so if you are passing ssh as the parameter, it is equivalent to ./ssh which is probably not what you want. You could use execvp() but that is a security risk if a malicious program called ssh appears in $PATH before /bin/ssh. Better to use execv() and force the correct path.

Unable to use "execve()" successfully

The aim of the program is to fork a new child process and execute a process which also has command line arguments. If I enter /bin/ls --help, I get the error:
shadyabhi#shadyabhi-desktop:~/lab/200801076_lab3$ ./a.out
Enter the name of the executable(with full path)/bin/ls --help
Starting the executable as a new child process...
Binary file to be executed: /bin/ls
/bin/ls: unrecognized option '--help
'
Try `/bin/ls --help' for more information.
Status returned by Child process: 2
shadyabhi#shadyabhi-desktop:~/lab/200801076_lab3$
What would be the right argument to execve()?
#include<stdio.h>
#include<string.h> //strcpy() used
#include<malloc.h> //malloc() used
#include<unistd.h> //fork() used
#include<stdlib.h> //exit() function used
#include<sys/wait.h> //waitpid() used
int main(int argc, char **argv)
{
char command[256];
char **args=NULL;
char *arg;
int count=0;
char *binary;
pid_t pid;
printf("Enter the name of the executable(with full path)");
fgets(command,256,stdin);
binary=strtok(command," ");
args=malloc(sizeof(char*)*10);
args[0]=malloc(strlen(binary)+1);
strcpy(args[0],binary);
while ((arg=strtok(NULL," "))!=NULL)
{
if ( count%10 == 0) args=realloc(args,sizeof(char*)*10);
count++;
args[count]=malloc(strlen(arg));
strcpy(args[count],arg);
}
args[++count]=NULL;
if ((pid = fork()) == -1)
{
perror("Error forking...\n");
exit(1);
}
if (pid == 0)
{
printf("Starting the executable as a new child process...\n");
printf("Binary file to be executed: %s\n",binary);
execve(args[0],args,NULL);
}
else
{
int status;
waitpid(-1, &status, 0);
printf("Status returned by Child process: %d\n",WEXITSTATUS(status));
}
return 0;
}
The first entry in the args array should be the program name again. Your code calls /bin/ls with --help as the process name.
Please check to make sure args is not getting clobbered by the realloc call. See here on SO regarding realloc
Edit:
Also the loop looks funny....
You called strtok like this:
binary=strtok(command," ");
Change the loop construct to use binary instead as shown...
char *tmpPtr;
while (binary != NULL){
if ( count%10 == 0) tmpPtr=realloc(args,sizeof(char)*10);
if (tmpPtr != NULL) args = tmpPtr;
count++;
args[count-1]=malloc(strlen(binary)+1);
strcpy(args[count-1],binary);
binary = strtok(command, " ");
}
And use the binary for copying the string....
Hope this helps,
Best regards,
Tom.
Your program has some obvious errors. For instance, declaring char **args=NULL; and then args=realloc(args,sizeof(char)*10); (since it's char**, you should be alloc-ing to char*, no?..).
Since sizeof(char*) is usually 4 while sizeof(char) is usually 1, you end up with some serious memory management problems around there (you alloc less than you use, and you end up writing where you shouldn't). From there on, all hell breaks loose and you can't expect your program's behavior to make any sense.
I'd suggest that you run your program through an util such as Valgrind to figure out memory leaks and correct the program appropriately. Probably your execve problems will disappear as soon as the memory problems are corrected.

Resources