5

If I run a sudo command it will ask me for a password, however in that Terminal session for the next few minutes it will allow me to run sudo commands without asking me for a password as it will cache that I am allowed.

This is good for convenience, and I find it rather convenient so I don't want to fix this by meaning it asks for a password every time instead of caching.

But what I have recently found has been something rather worrying, if I create a little script like this for instance:

#!/bin/bash

sudo rm -rf /

And I execute it as the normal user in Terminal before I have executed any sudo commands then all is well and works as expected, it prompts me for the sudo password. However if I am to run a sudo command before executing this script without sudo it will cache that sudo commands should not ask for a password for a few minutes in this session and then even though I did not give the script sudo privileges it will not prompt me for a password and the script will be allowed to execute whatever sudo commands it wants.

Now I'm not the sort to execute many scripts without knowing what's in them but sometimes I have to install stuff from a script which I got from a trusted location, but I don't know for sure if there isn't anything bad in the script so I would like the piece of mind that it's not going to just hijack the sudo ability that has been granted to my Terminal session.

So my questions is, is it possible to make it so that I can run sudo commands and it will cache it for me, but then if I run a script not with sudo for the script not to be able to just hijack that ability? I understand that me executing the script is basically the same as me just executing the commands in the script in the order they are in there, but is there not a way of doing something clever so that it runs in a slightly different way or so that sudo is restricted for scripts that I run?

Really anything though that I didn't run with sudo shouldn't be able to run things with sudo. Including commands. If they are only hijacking the cached ability that is...

I am running Ubuntu GNOME 15.10 with GNOME 3.18.

I have a suggestion for how this could be done but I don't know the practicalities of this: could I make it so that when I execute a command and it starts running it it logs that to a file (like is done with all Terminal commands though maybe a bit too late for this - with the history command) and then when sudo is run it checks if I executed that command in Terminal (through the use of the log that logs when I do) and if not then it is assumed that it's not by me so it prompts me for a password?

  • 2
    Well you could run sudo -k , before running any script . Man page : -k, --reset-timestamp: When used without a command, invalidates the user's cached credentials. In other words, the next time sudo is run a password will be required. Basically you ensure that you invalidate possibility of using cached credentials in advance – Sergiy Kolodyazhnyy Mar 17 '16 at 19:21
  • @Serg: I have come up with a suggestion though I don't know of the full practicalities of this, I have updated my question with it at the end. What do you think? –  Mar 17 '16 at 19:58
  • I suppose you could alias sudo to a script which would check the last item in the history and act accordingly. – Mark Smith Mar 17 '16 at 20:01
  • @MarkSmith: I'm not sure that it could just be the usual history though because that can be written to by anything and making it owned by root won't really solve anything, just make things worse in certain ways... So it will probably have to be a different history which is owned by root but doesn't mean that I exactly have to write to it as root, but maybe there should be a root daemon running which just checks the commands I run and then adds them to the history. –  Mar 17 '16 at 20:25
  • I'll try and write it shortly... – Mark Smith Mar 17 '16 at 20:31
  • I have it working - but, unbelievably, I can't write the solution because I can't work out how to put bash code into the text editor without it looking terrible...! – Mark Smith Mar 17 '16 at 21:53
  • @MarkSmith: I've fixed your formatting the best I can... –  Mar 17 '16 at 22:40

4 Answers4

6

You can run

sudo -k

before you run your script. It will clear the cached credentials and the next sudo will ask again for your password.

Here's a way to do what you want (I think).

  1. Move your sudo elsewhere:

    mv /usr/bin/sudo /usr/bin/sudo_real
    
  2. Put the following into usr/bin/sudo:

    #!/bin/bash -i
    # Allows 'sudo' to be run with cached credentials from the command line,
    # but clears the cache if run from within a script.
    # Get the last command executed manually from the history
    LAST_COMMAND=`history | tail -n 1 | cut -c 8-`
    
    if [[ "${LAST_COMMAND}" == "sudo "* ]]; then
        # The last command was 'sudo' - i.e. the user ran sudo 
        sudo_real "$@"
    else
        # The last command was NOT sudo - so this sudo was called from within a script.
        # Force the cached credentials to be cleared. 
        sudo_real -k "$@"
    fi
    
  3. Make the new /usr/bin/sudo executable:

    chmod a+x /usr/bin/sudo
    
  4. Alias sudo to update the bash history when you run it from a shell by putting this in your ~/.bashrc:

    alias sudo="history -a;sudo"
    

Now, when YOU run sudo ... it will put the sudo ... into the bash history and the script will find it and run sudo_real. But when another script runs sudo, it won't be in the history, and it'll call sudo_real -k.

I think this is incredibly hairy, and I'd just live with the risk or use a new shell for scripts I didn't trust, personally :-)

muru
  • 197,895
  • 55
  • 485
  • 740
Mark Smith
  • 1,283
  • 1
  • 11
  • 22
  • Is there a not easy more automatic way of doing this? –  Mar 17 '16 at 19:23
  • 1
    The script should not only check if sudo was in the last command but also make sure that the commands are the same because I could have just run the sudo apt-get update command, and then the script could be wanting to run sudo rm -rf /, and just because they both have sudo in them your script would allow them to run... –  Mar 17 '16 at 22:43
  • But this is a good answer, almost exactly what I want! I'll accept it after you fix that! ;-) –  Mar 17 '16 at 22:44
  • If YOU run the script with sudo, it can do stuff as root anyway, without having to do sudo itself. – Mark Smith Mar 17 '16 at 22:45
  • Ah yes, well I guess so... –  Mar 17 '16 at 22:47
  • Wait, what happens if a script that isn't run by me but another program runs sudo? Isn't that just going to break things? And it would depend on whether or not I happened to have run a sudo command just before that whether or not it would allow the program to do so... No? –  Mar 17 '16 at 22:56
  • Or maybe not actually, what does impact does the sudo -k command have on other programs? Any impact? –  Mar 17 '16 at 22:58
  • I think this should be OK: cached sudo creds are per terminal, so if some other thing, unrelated to your terminal, runs sudo it won't have cached creds anyway, even without the workaround described in my answer. – Mark Smith Mar 18 '16 at 07:13
  • Does history work without enabling in scripts? – muru Mar 18 '16 at 11:15
  • @muru It works in interactive scripts - ensured by the -i in the shebang line. – Mark Smith Mar 18 '16 at 11:28
  • Ah, nice abuse of that. :D Anyway, LAST_COMMAND could be obtained more cleanly using history -p '!!' or something like that. – muru Mar 18 '16 at 11:39
  • There are a few potential problems with the script currently I think actually... Because when I type history I have it configured to output more than just the commands but also other information: 997 18/03/16 21:52:10 man history, so won't that confuse it? And also what about if I run sudo apt-get update && sudo apt-get dist-upgrade, will it prompt me for both or will things just get confused? Or typed sudo apt-get update && ./exampleScript.sh, would the script allow things to run because the start of the command started with sudo even though it wasn't the same command? –  Mar 18 '16 at 22:07
  • You know you can just try these things out :-) Try typing the commands (the whole lines) and see what they do. For example, I pipe the output of history into tail -n 1 to get only the last line, and then into cut to get the part of the line I want. You're probably right about the last one. sudo apt-get blah && ./script.sh will probably break it. Solution: don't do it. – Mark Smith Mar 18 '16 at 22:10
4

My stance on this issue is this : if you are unsure whether or not you may or may not run an app with root privillege while your credentials still haven't timed out, then just disable the timeout at all, make it 0. Specifically you need this setting in your /etc/sudoers file:

Defaults    timestamp_timeout=0

Man page defines it like so:

 timestamp_timeout
                   Number of minutes that can elapse before sudo will ask
                   for a passwd again.  The timeout may include a frac‐
                   tional component if minute granularity is insufficient,
                   for example 2.5.  The default is 15.  Set this to 0 to
                   always prompt for a password.  If set to a value less
                   than 0 the user's time stamp will never expire.  This
                   can be used to allow users to create or delete their
                   own time stamps via “sudo -v” and “sudo -k” respec‐
                   tively.

However, if you intend to be prudent, you can define the following function in .bashrc

sudo_check()
{
  real_path="$( realpath $1 )"
  file "$real_path" | grep -q -i script
  if [ $? -eq 0 ]; then
     grep -q 'sudo' "$real_path"  && \
     { echo '>>> ALERT: Its a script that requests sudo';
       echo '    resetting sudo timestamp';
       echo 'please rerun with sudo appended ';
     }
     sudo -k
  else
     sudo "$@"
  fi

}

This function will check whether or not a script contains call to sudo and alert you of that. Bellow is example of me running that function on a script ( which is my login screen background changer by the way )

$ sudo_check sergrep/chgreeterbg.sh                            
>>> ALERT: Its a script that requests sudo
    resetting sudo timestamp
muru
  • 197,895
  • 55
  • 485
  • 740
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
  • 1
    Note that it won't detect a script which calls another script which runs sudo. – Mark Smith Mar 18 '16 at 22:15
  • Perhaps you should either link to this answer, or make it clear that the line you speak of does not already exist in that file. You should also specify that you should edit it with sudo visudo rather than just a normal text editor. –  Mar 26 '16 at 14:02
2

If you have at least version 1.8.21 of sudo, you will want to set timestamp_type to ppid instead of the default tty.
By default, sudo will 'cache credentials' per terminal. This setting will make sudo only reuse them if the invoking process is the same. Any scripts you run will have a PID different from your shell, and will not be able to use your authorization.

Specifically, the following line needs to be in your sudoers file:
Defaults timestamp_type=ppid

More details can be found in the manual.

citriqa
  • 21
2

How can you differentiate between a script and an executable binary command?

Of course you can think of defining a function named sudo that will have the sanity checks before running the actual binary but

  • As the script can have any name, what if a script has a name like ls? So checking for extensions like .sh won't help
  • Also reading shebang as the first line of the script won't help too because a script can run without having a shebang

I think, if you are too paranoid about it, you can think of disabling password caching altogether by creating an alias like:

alias sudo='sudo -k'

and put it in your ~/.bashrc.

heemayl
  • 91,753
  • Well that basically is the same as making sudo reset timestamp each time, Panda wants to just exclude scripts from being "cached" – Sergiy Kolodyazhnyy Mar 17 '16 at 19:26
  • @Serg I know..my first part includes answer to that.. – heemayl Mar 17 '16 at 19:27
  • Is there no way of making it so that just anything that I run with sudo is not allowed to run any sudo commands without my proper authentication? –  Mar 17 '16 at 19:38
  • I have come up with a suggestion though I don't know of the full practicalities of this, I have updated my question with it at the end. What do you think? –  Mar 17 '16 at 19:57
  • @heemayl i like the idea of a function though. It has precedence over command names , so function named sudo will run instead of actual sudo – Sergiy Kolodyazhnyy Mar 17 '16 at 20:00
  • @Serg Yes, but like I said I don't see any criteria to bound the function to..it's too broad and too vague.. – heemayl Mar 17 '16 at 20:04