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 exploit is here:http://www.iserver.sk/~stanojr/instant-rogue-exp.sh AUTHOR: stanojr@iserver.sk ps: sorry, i know, my english is very bad :] Fix: check netbsd sources, they fix it
Responsible Changed From-To: freebsd-bugs->markm markm is currently portyfing rogue
Hello, NetBSD people fixed that problem: http://cvsweb.netbsd.org/bsdweb.cgi/src/games/rogue/inventory.c.diff?r1=1.7&r2=1.8 http://cvsweb.netbsd.org/bsdweb.cgi/src/games/rogue/save.c.diff?r1=1.7&r2=1.7.8.1 http://cvsweb.netbsd.org/bsdweb.cgi/src/games/rogue/message.c.diff?r1=1.7&r2=1.7.10.1 http://cvsweb.netbsd.org/bsdweb.cgi/src/games/rogue/rogue.h.diff?r1=1.11&r2=1.11.8.1 They also fixed another issue (buffer overrun): http://cvsweb.netbsd.org/bsdweb.cgi/src/games/rogue/save.c.diff?r1=1.5&r2=1.6 If someone could fix our "beloved" rogue, it'd great :) then it could be added to ports/games/freebsd-games :) Marc
I committed patches to freebsd-games for this when I reenabled rogue there. They were simply the following patch against 4.x split into different patch files. The buffer overflow part of this patch was ported over from NetBSD. The patch also contains the spelling fix from PR 45701. Index: rogue/inventory.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/inventory.c,v retrieving revision 1.4 diff -u -r1.4 inventory.c --- rogue/inventory.c 30 Nov 1999 03:49:23 -0000 1.4 +++ rogue/inventory.c 21 Aug 2003 19:58:45 -0000 @@ -415,14 +415,14 @@ mix_colors() { short i, j, k; - char *t; + char t[MAX_ID_TITLE_LEN]; for (i = 0; i <= 32; i++) { j = get_rand(0, (POTIONS - 1)); k = get_rand(0, (POTIONS - 1)); - t = id_potions[j].title; - id_potions[j].title = id_potions[k].title; - id_potions[k].title = t; + memcpy(t, id_potions[j].title, MAX_ID_TITLE_LEN); + memcpy(id_potions[j].title, id_potions[k].title, MAX_ID_TITLE_LEN); + memcpy(id_potions[k].title, t, MAX_ID_TITLE_LEN); } } Index: rogue/message.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/message.c,v retrieving revision 1.7.2.1 diff -u -r1.7.2.1 message.c --- rogue/message.c 20 Jul 2000 10:35:07 -0000 1.7.2.1 +++ rogue/message.c 21 Aug 2003 19:58:51 -0000 @@ -60,7 +60,7 @@ char msgs[NMESSAGES][DCOLS] = {"", "", "", "", ""}; short msg_col = 0, imsg = -1; boolean msg_cleared = 1, rmsg = 0; -char hunger_str[8] = ""; +char hunger_str[HUNGER_STR_LEN] = ""; const char *more = "-more-"; extern boolean cant_int, did_int, interrupted, save_is_interactive, flush; Index: rogue/move.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/move.c,v retrieving revision 1.7 diff -u -r1.7 move.c --- rogue/move.c 30 Nov 1999 03:49:24 -0000 1.7 +++ rogue/move.c 21 Aug 2003 20:02:38 -0000 @@ -64,7 +64,6 @@ extern short cur_level, max_level; extern short bear_trap, haste_self, confused; extern short e_rings, regeneration, auto_search; -extern char hunger_str[]; extern boolean being_held, interrupted, r_teleport, passgo; one_move_rogue(dirch, pickup) Index: rogue/object.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/object.c,v retrieving revision 1.5 diff -u -r1.5 object.c --- rogue/object.c 30 Nov 1999 03:49:25 -0000 1.5 +++ rogue/object.c 21 Aug 2003 20:04:13 -0000 @@ -159,7 +159,6 @@ extern short cur_level, max_level; extern short party_room; -extern char *error_file; extern boolean is_wood[]; put_objects() Index: rogue/pack.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/pack.c,v retrieving revision 1.8 diff -u -r1.8 pack.c --- rogue/pack.c 30 Nov 1999 03:49:25 -0000 1.8 +++ rogue/pack.c 21 Aug 2003 20:07:28 -0000 @@ -342,7 +342,7 @@ char desc[DCOLS]; if (rogue.armor) { - message("your already wearing some", 0); + message("you're already wearing some", 0); return; } ch = pack_letter("wear what?", ARMOR); Index: rogue/rogue.h =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/rogue.h,v retrieving revision 1.3.2.1 diff -u -r1.3.2.1 rogue.h --- rogue/rogue.h 17 Dec 2001 12:43:23 -0000 1.3.2.1 +++ rogue/rogue.h 21 Aug 2003 21:11:28 -0000 @@ -194,9 +194,12 @@ #define MAX_OPT_LEN 40 +#define HUNGER_STR_LEN 8 + +#define MAX_ID_TITLE_LEN 64 struct id { short value; - char *title; + char title[MAX_ID_TITLE_LEN]; char *real; unsigned short id_status; }; @@ -472,3 +475,9 @@ short second; /* 0 - 59 */ }; +/* + * external variable declarations. + */ +extern char hunger_str[HUNGER_STR_LEN]; +extern char login_name[MAX_OPT_LEN]; +extern const char *error_file; Index: rogue/save.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/save.c,v retrieving revision 1.6 diff -u -r1.6 save.c --- rogue/save.c 30 Nov 1999 03:49:27 -0000 1.6 +++ rogue/save.c 21 Aug 2003 20:03:37 -0000 @@ -63,8 +63,6 @@ extern boolean detect_monster; extern short cur_level, max_level; -extern char hunger_str[]; -extern char login_name[]; extern short party_room; extern short foods; extern boolean is_wood[]; @@ -102,15 +100,23 @@ { FILE *fp; int file_id; - char name_buffer[80]; + char *name_buffer; + size_t len; char *hptr; struct rogue_time rt_buf; if (sfile[0] == '~') { if (hptr = md_getenv("HOME")) { - (void) strcpy(name_buffer, hptr); - (void) strcat(name_buffer, sfile+1); - sfile = name_buffer; + len = strlen(hptr) + strlen(sfile); + name_buffer = md_malloc(len); + if (name_buffer == NULL) { + message("out of memory for save file name", 0); + sfile = error_file; + } else { + (void) strcpy(name_buffer, hptr); + (void) strcat(name_buffer, sfile+1); + sfile = name_buffer; + } } } /* revoke */ @@ -199,10 +205,10 @@ r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); r_read(fp, (char *) &cur_level, sizeof(cur_level)); r_read(fp, (char *) &max_level, sizeof(max_level)); - read_string(hunger_str, fp); + read_string(hunger_str, fp, sizeof hunger_str); - (void) strcpy(tbuf, login_name); - read_string(login_name, fp); + (void) strlcpy(tbuf, login_name, sizeof tbuf); + read_string(login_name, fp, sizeof login_name); if (strcmp(tbuf, login_name)) { clean_up("you're not the original player"); } @@ -345,7 +351,7 @@ r_read(fp, (char *) &(id_table[i].value), sizeof(short)); r_read(fp, (char *) &(id_table[i].id_status), sizeof(unsigned short)); - read_string(id_table[i].title, fp); + read_string(id_table[i].title, fp, MAX_ID_TITLE_LEN); } } } @@ -362,13 +368,16 @@ r_write(fp, s, n); } -read_string(s, fp) +read_string(s, fp, len) char *s; FILE *fp; +size_t len; { short n; r_read(fp, (char *) &n, sizeof(short)); + if (n > len) + clean_up("read_string: corrupt game file"); r_read(fp, s, n); xxxx(s, n); } Index: rogue/score.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/score.c,v retrieving revision 1.4 diff -u -r1.4 score.c --- rogue/score.c 30 Nov 1999 03:49:27 -0000 1.4 +++ rogue/score.c 21 Aug 2003 20:03:30 -0000 @@ -58,7 +58,6 @@ #include "rogue.h" #include "pathnames.h" -extern char login_name[]; extern char *m_names[]; extern short max_level; extern boolean score_only, no_skull, msg_cleared; Index: rogue/use.c =================================================================== RCS file: /var/fcvs/src/games/rogue/Attic/use.c,v retrieving revision 1.4 diff -u -r1.4 use.c --- rogue/use.c 30 Nov 1999 03:49:29 -0000 1.4 +++ rogue/use.c 21 Aug 2003 20:06:00 -0000 @@ -68,7 +68,6 @@ const char *strange_feeling = "you have a strange feeling for a moment, then it passes"; extern short bear_trap; -extern char hunger_str[]; extern short cur_room; extern long level_points[]; extern boolean being_held; -- Greg Lewis Email : glewis@eyesbeyond.com Eyes Beyond Web : http://www.eyesbeyond.com Information Technology FreeBSD : glewis@FreeBSD.org
State Changed From-To: open->feedback Have these patches have been incorporated to the port, and if so, can this PR just be closed?
State Changed From-To: feedback->closed This patch is already present in the freebsd-games port. Thanks for your submission!