Passing Commands into a Binary that runs a shell using a bash script - linux

New to bash scripting so having a little teething problem and was wondering if someone could clear up some trouble I'm having, I have a simple C file called test that creates a shell as seen below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
execl("/bin/sh", "/bin/sh", (void *) NULL);
perror("exec");
return 1;
}
I want to create a bash script to execute this file which I have done below, but then on execution I then wish to send commands to the shell that the binary creates - is this possible I am trying the following to no avail:
#!bin/bash
/var/testfolder/test; # execute the test c file to spawn the shell
??? #don't know how to pass commands to the new shell created :(

Your compiled C binary has the SETUID permission i suppose? With the binary and arguments you can execute any shell like this with this binary permission:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( int argc, char ** argv )
{
execv("/bin/sh", argv );
perror("exec");
return 1;
}
Output of a test script to print arguments and current process:
$ ./test_execv ./test.sh foo bar
Executing $0: ./test.sh
Args $*: foo bar
process:
PID TTY TIME CMD
3300 pts/1 00:00:08 bash
3498 pts/1 00:00:00 sh
3499 pts/1 00:00:00 ps
Security issue
If you can execute a script to a root shell, anyone can do this. I think you just have to add some of your scripts (only those needed) with a sudo permission to be run as root from your the needed account.

Try this:
#!/bin/bash
/var/testfolder/test <<EOF
cmdtopass1
cmdtopass2
cmdtopass3
EOF

Related

How do I get the root directory of a process programmatically?

On Linux, every process has its own root directory. For most processes, this is /. However, chroot can change that. This information is exposed via /proc. However, how do I find out the root directory of a process programmatically? Is there a syscall, or, libc function for it?
I don't know whether there is another way, but lots of programs rely on the machine readable files in /proc to get additional information about processes and there's nothing inherently wrong with that.
Here's an example of a process finding its own root dir programmatically via /proc:
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
int main() {
char foo[PATH_MAX+1];
int count = readlink("/proc/self/root", foo, PATH_MAX);
if(count < 0) {
perror("Can't find root dir (is /proc mounted here?)");
} else {
foo[count]=0;
printf("My root dir is %s\n", foo);
}
}
Well there isn't. There exists a command to do this which is pwdx, here is its code https://elixir.bootlin.com/busybox/latest/source/procps/pwdx.c. It also reads root dir from /proc. You can get the pid of your process using getpid function.
One simple way is to just use a for loop. This is a one-liner that will print out the root directory of each of the processes you wish (proc1, proc2, proc3):
for i in $(ps -ef | grep -E 'proc1|proc2|proc3' | awk '{ print $2 }'); do ls -ld /proc/$i/root; done

How to get maximum number of child processes inside a Docker container?

I'm trying to run the following program inside a Docker container, which is started with --privileged:
root#1df00aaf673d:~# cat > sysconf_test.c
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
int main() {
long n = sysconf(_SC_CHILD_MAX);
printf("%ld %d\n", n, errno);
return 0;
}
root#1df00aaf673d:~# gcc sysconf_test.c ; ./a.out
-1 0
Going by the sysconf man page, "If name corresponds to a maximum or minimum limit, and that limit is indeterminate, -1 is returned and errno is not changed." Is there a way to make it determinate, perhaps by passing an option to the docker run command?
I'll answer my own question: it appears that sysconf returns -1L for "unlimited", although the man page doesn't spell it out:
[root#llg00amn ~]# ulimit -u
120996
[root#llg00amn ~]# docker run -ti debian /bin/bash
root#5668a7acb957:/# ulimit -u
unlimited
After setting the ulimit to an actual number, the program runs fine and returns the right result.

Linux effect of ptrace TRACEME call

I have the following code. It simply calls ptrace(PTRACE_TRACEME) before going into an infinite loop.
I have two issues:
After executing the binary, I can't attach with gdb even if I am root.
With ptrace(PTRACE_TRACEME), I can't terminate the process with Ctrl-C (SIGINT). it simply stops.
Can someone explain what's going on? Thank you in advance.
PS: I know that most debuggers fork a child which then calls ptrace(PTRACE_TRACEME) before execve. No need to remind me of this.
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv) {
printf("my pid : %d\n", getpid());
ptrace(PTRACE_TRACEME);
while(1){
printf("euid : %d\n", geteuid());
sleep(2);
}
return 0;
}
after executing this binary, I can't attach gdb even if I am root.
From man ptrace:
ERRORS
EPERM The specified process cannot be traced. This could be
because the parent has insufficient privileges (the required
capability is CAP_SYS_PTRACE); non-root processes cannot trace
processes that they cannot send signals to or those running
set-user-ID/set- group-ID programs, for obvious reasons.
Alternatively, the process may already be being traced, or be init(8) (PID 1).
with ptrace(PTRACE_TRACEME), I can't terminate the process with Ctrl-C (SIGINT). it simply stops.
From man ptrace:
DESCRIPTION
While being traced, the child will stop each time a signal is
delivered, even if the signal is being ignored. (The exception is
SIGKILL, which has its usual effect.) The parent will be notified at
its next wait(2) and may inspect and modify the child process
while it is stopped. The parent then causes the child to continue,
optionally ignoring the delivered signal (or even delivering a
different signal instead).

How to see the daemon process's output in Linux?

I wrote a test.c:
#include <unistd.h>
#include <stdio.h>
int main()
{
while(1)
{
sleep(1);
printf("====test====\r\n");
}
return 0;
}
then i compile it : gcc ./test.c -o ./test
and the i wrote a shell script:
#!/bin/sh
./test &
and then i made this script to be executed automatically on system boot.
then I login to the Linux system using secureCRT in SSH protocol.
using "ps aux | grep test" i can see the test process running,
but i just cannot see the test's output, some people told me because the test
output to tty, and i am using pts.
could anybody tell me the specific reason and how can i get the output?
thanks in advance!
It doesn't output anything because it got no terminal attached.
If you want your output to be visible to every terminal connected to the system, use wall
./test | wall
(it will be very annoying)
I suggest you to redirect the output to a log file.

Shell script password security of command-line parameters

If I use a password as a command-line parameter it's public on the system using ps.
But if I'm in a bash shell script and I do something like:
...
{ somecommand -p mypassword }
...
is this still going to show up in the process list? Or is this safe?
How about sub-processes: (...)? Unsafe right?
coprocess?
Command lines will always be visible (if only through /proc).
So the only real solution is: don't. You might supply it on stdin, or a dedicated fd:
./my_secured_process some parameters 3<<< "b#dP2ssword"
with a script like (simplicity first)
#!/bin/bash
cat 0<&3
(this sample would just dump a bad password to stdout)
Now all you need to be concerned with is:
MITM (spoofed scripts that eaves drop the password, e.g. by subverting PATH)
bash history retaining your password in the commandline (look at HISTIGNORE for bash, e.g.)
the security of the script that contains the password redirection
security of the tty's used; keyloggers; ... as you can see, we have now descended into 'general security principles'
How about using a file descriptor approach:
env -i bash --norc # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3 # cat /dev/stdin in mycommand
See:
Hiding secret from command line parameter on Unix
The called program can change its command line by simply overwriting argv like this:
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
int arglen = argv[argc-1]+strlen(argv[argc-1])+1 - argv[0];
memset(argv[0], arglen, 0);
strncpy(argv[0], "secret-program", arglen-1);
sleep(100);
}
Testing:
$ ./a.out mySuperPassword &
$ ps -f
UID PID PPID C STIME TTY TIME CMD
me 20398 18872 0 11:26 pts/3 00:00:00 bash
me 20633 20398 0 11:34 pts/3 00:00:00 secret-program
me 20645 20398 0 11:34 pts/3 00:00:00 ps -f
$
UPD: I know, it is not completely secure and may cause race conditions, but many programs that accept password from command line do this trick.
The only way to escape from being shown in the the process list is if you reimplement the entire functionality of the program you want to call in pure Bash functions. Function calls are not seperate processes. Usually this is not feasible, though.

Resources