3

I am trying to create a executor program for regular users on linux with SUID bit set so whatever commands, passed to the program as parameters, get executed with root permission. However when I try to implement this as a bash script, this does not work, where it works when implemented in C. I want to know what I am doing wrong for the shell script. The codes are below

Shell Script:

#! /bin/bash
if [ $# -lt 1 ]; then
echo "Usage: $0 <Command String>"
exit 1
fi
$@
#Also tried this, same result
#exec $@

Execution:

root#: chmod 755 exec.sh 
root#: chmod u+s exec.sh
root#: ll exec.sh
-rwsr-xr-x 1 root root 75 Sep 19 16:55 exec.sh

regular_user$: ./exec.sh whoami
regular_user

C Program:

#include <stdlib.h>
#include <stdio.h>
int main ( int argc, char *argv[] )
{
if ( argc < 2 ) {
    printf( "Usage: %s <Command String>\n", argv[0] );
    return 1;
}
else
{
    argv[argc]=NULL;
    //setuid(0);  //Works without these
    //setgid(0);
    int exit=execvp(argv[1], argv+1);
    return exit;
}
}

Execution:

root#: gcc exec.c -o exec.obj
root#: chmod 755 exec.obj
root#: chmod u+s exec.obj
root#: ll exec.obj
-rwsr-xr-x 1 root root 6979 Sep 19 17:03 exec.obj

regular_user$: ./exec.obj whoami
root

Both files have identical permissions

-rwsr-xr-x 1 root root 75 Sep 19 16:55 exec.sh
-rwsr-xr-x 1 root root 6979 Sep 19 17:03 exec.obj
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74

3 Answers3

3

It is documented in execve(2) :

Linux ignores the set-user-ID and set-group-ID bits on scripts.

IIRC, setuid scripts would be a significant security hole

See this question

You could configure sudo to avoid asking a password - see sudoers(5) (or use super)

You could also write a simple C program wrapping your shell script, and make it setuid.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

try

regular_user$: sudo "./exec.sh whoami"
iamsrijon
  • 76
  • 6
0

The reason is explain by RedHat at https://access.redhat.com/solutions/124693 :

When executing shell scripts that have the setuid bit (e.g., perms of rwsr-xr-x), the scripts run as the user that executes them, not as the user that owns them. This is contrary to how setuid is handled for binaries (e.g., /usr/bin/passwd), which run as the user that owns them, regardless of which user executes them.

In order to solve this issue I write a script utility which converts a script call to a native binary:

#!/bin/bash

# https://access.redhat.com/site/solutions/124693

if [ $# != 1 ]; then
    echo "Please, provide script file name." >&2
    exit 1
fi

if [ ${EUID} != 0 ]; then
    echo "Only root can run this script." >&2
    exit 1
fi

SCRIPT_FILE=$1

if [ ! -f "${SCRIPT_FILE}" ]; then
    echo "Script file not found." >&2
    exit 1
fi

SCRIPT_BASE_FILE=$(basename ${SCRIPT_FILE})

C_TEMPLATE=$(cat << DELIMITER
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    char *cwd;
    char exe_file[PATH_MAX];
    char script_file[PATH_MAX];

    readlink("/proc/self/exe", exe_file, PATH_MAX);
    cwd = dirname(exe_file);
    sprintf(script_file, "%s/${SCRIPT_BASE_FILE}", cwd);

    setuid(0);
    system(script_file);
    return 0;
}
DELIMITER
)

C_FILE="${SCRIPT_FILE}.c"
EXE_FILE="${SCRIPT_FILE}.x"

   echo "${C_TEMPLATE}" > "${C_FILE}" \
&& gcc "${C_FILE}" -o "${EXE_FILE}" \
&& chown root:root "${EXE_FILE}" \
&& chmod 4755 "${EXE_FILE}" \
&& rm "${C_FILE}" \
&& echo "Setuid script executable created as \"${EXE_FILE}\"."
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74