2026-1-31-pwn之栈溢出

2026-1-31-pwn之栈溢出

一月 31, 2026

PWN之栈溢出

本篇由题目stack overflow

https://www.ctfplus.cn/problem-detail/1975492228679733248/description

为原型,详细解释栈溢出的原理和过程。

基本原理

栈存在于虚拟内存,遵循LIFO原则

而其中存在

  • 函数返回地址
  • 寄存器
  • 局部变量
  • 栈保护字段:canary(下次做如何捕捉canary)

其中函数返回地址就是一般题目利用的点

例如,我们通过溢出覆盖函数的返回地址,使其跳转到system函数,既拿到了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
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
Disassembly of section .init:

0000000000401000 <_init>:
401000: f3 0f 1e fa endbr64
401004: 48 83 ec 08 sub $0x8,%rsp
401008: 48 8b 05 e9 2f 00 00 mov 0x2fe9(%rip),%rax # 403ff8 <__gmon_start__@Base>
40100f: 48 85 c0 test %rax,%rax
401012: 74 02 je 401016 <_init+0x16>
401014: ff d0 call *%rax
401016: 48 83 c4 08 add $0x8,%rsp
40101a: c3 ret

Disassembly of section .plt:

0000000000401020 <.plt>:
401020: ff 35 e2 2f 00 00 push 0x2fe2(%rip) # 404008 <_GLOBAL_OFFSET_TABLE_+0x8>
401026: f2 ff 25 e3 2f 00 00 bnd jmp *0x2fe3(%rip) # 404010 <_GLOBAL_OFFSET_TABLE_+0x10>
40102d: 0f 1f 00 nopl (%rax)
401030: f3 0f 1e fa endbr64
401034: 68 00 00 00 00 push $0x0
401039: f2 e9 e1 ff ff ff bnd jmp 401020 <_init+0x20>
40103f: 90 nop
401040: f3 0f 1e fa endbr64
401044: 68 01 00 00 00 push $0x1
401049: f2 e9 d1 ff ff ff bnd jmp 401020 <_init+0x20>
40104f: 90 nop
401050: f3 0f 1e fa endbr64
401054: 68 02 00 00 00 push $0x2
401059: f2 e9 c1 ff ff ff bnd jmp 401020 <_init+0x20>
40105f: 90 nop
401060: f3 0f 1e fa endbr64
401064: 68 03 00 00 00 push $0x3
401069: f2 e9 b1 ff ff ff bnd jmp 401020 <_init+0x20>
40106f: 90 nop
401070: f3 0f 1e fa endbr64
401074: 68 04 00 00 00 push $0x4
401079: f2 e9 a1 ff ff ff bnd jmp 401020 <_init+0x20>
40107f: 90 nop
401080: f3 0f 1e fa endbr64
401084: 68 05 00 00 00 push $0x5
401089: f2 e9 91 ff ff ff bnd jmp 401020 <_init+0x20>
40108f: 90 nop

Disassembly of section .plt.sec:

0000000000401090 <puts@plt>:
401090: f3 0f 1e fa endbr64
401094: f2 ff 25 7d 2f 00 00 bnd jmp *0x2f7d(%rip) # 404018 <puts@GLIBC_2.2.5>
40109b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

00000000004010a0 <system@plt>:
4010a0: f3 0f 1e fa endbr64
4010a4: f2 ff 25 75 2f 00 00 bnd jmp *0x2f75(%rip) # 404020 <system@GLIBC_2.2.5>
4010ab: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

00000000004010b0 <read@plt>:
4010b0: f3 0f 1e fa endbr64
4010b4: f2 ff 25 6d 2f 00 00 bnd jmp *0x2f6d(%rip) # 404028 <read@GLIBC_2.2.5>
4010bb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

00000000004010c0 <execve@plt>:
4010c0: f3 0f 1e fa endbr64
4010c4: f2 ff 25 65 2f 00 00 bnd jmp *0x2f65(%rip) # 404030 <execve@GLIBC_2.2.5>
4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

00000000004010d0 <setvbuf@plt>:
4010d0: f3 0f 1e fa endbr64
4010d4: f2 ff 25 5d 2f 00 00 bnd jmp *0x2f5d(%rip) # 404038 <setvbuf@GLIBC_2.2.5>
4010db: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

00000000004010e0 <exit@plt>:
4010e0: f3 0f 1e fa endbr64
4010e4: f2 ff 25 55 2f 00 00 bnd jmp *0x2f55(%rip) # 404040 <exit@GLIBC_2.2.5>
4010eb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

Disassembly of section .text:

00000000004010f0 <_start>:
4010f0: f3 0f 1e fa endbr64
4010f4: 31 ed xor %ebp,%ebp
4010f6: 49 89 d1 mov %rdx,%r9
4010f9: 5e pop %rsi
4010fa: 48 89 e2 mov %rsp,%rdx
4010fd: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
401101: 50 push %rax
401102: 54 push %rsp
401103: 45 31 c0 xor %r8d,%r8d
401106: 31 c9 xor %ecx,%ecx
401108: 48 c7 c7 2a 12 40 00 mov $0x40122a,%rdi
40110f: ff 15 db 2e 00 00 call *0x2edb(%rip) # 403ff0 <__libc_start_main@GLIBC_2.34>
401115: f4 hlt
401116: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
40111d: 00 00 00

0000000000401120 <_dl_relocate_static_pie>:
401120: f3 0f 1e fa endbr64
401124: c3 ret
401125: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
40112c: 00 00 00
40112f: 90 nop

0000000000401130 <deregister_tm_clones>:
401130: b8 58 40 40 00 mov $0x404058,%eax
401135: 48 3d 58 40 40 00 cmp $0x404058,%rax
40113b: 74 13 je 401150 <deregister_tm_clones+0x20>
40113d: b8 00 00 00 00 mov $0x0,%eax
401142: 48 85 c0 test %rax,%rax
401145: 74 09 je 401150 <deregister_tm_clones+0x20>
401147: bf 58 40 40 00 mov $0x404058,%edi
40114c: ff e0 jmp *%rax
40114e: 66 90 xchg %ax,%ax
401150: c3 ret
401151: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)
401158: 00 00 00 00
40115c: 0f 1f 40 00 nopl 0x0(%rax)

0000000000401160 <register_tm_clones>:
401160: be 58 40 40 00 mov $0x404058,%esi
401165: 48 81 ee 58 40 40 00 sub $0x404058,%rsi
40116c: 48 89 f0 mov %rsi,%rax
40116f: 48 c1 ee 3f shr $0x3f,%rsi
401173: 48 c1 f8 03 sar $0x3,%rax
401177: 48 01 c6 add %rax,%rsi
40117a: 48 d1 fe sar $1,%rsi
40117d: 74 11 je 401190 <register_tm_clones+0x30>
40117f: b8 00 00 00 00 mov $0x0,%eax
401184: 48 85 c0 test %rax,%rax
401187: 74 07 je 401190 <register_tm_clones+0x30>
401189: bf 58 40 40 00 mov $0x404058,%edi
40118e: ff e0 jmp *%rax
401190: c3 ret
401191: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)
401198: 00 00 00 00
40119c: 0f 1f 40 00 nopl 0x0(%rax)

00000000004011a0 <__do_global_dtors_aux>:
4011a0: f3 0f 1e fa endbr64
4011a4: 80 3d dd 2e 00 00 00 cmpb $0x0,0x2edd(%rip) # 404088 <completed.0>
4011ab: 75 13 jne 4011c0 <__do_global_dtors_aux+0x20>
4011ad: 55 push %rbp
4011ae: 48 89 e5 mov %rsp,%rbp
4011b1: e8 7a ff ff ff call 401130 <deregister_tm_clones>
4011b6: c6 05 cb 2e 00 00 01 movb $0x1,0x2ecb(%rip) # 404088 <completed.0>
4011bd: 5d pop %rbp
4011be: c3 ret
4011bf: 90 nop
4011c0: c3 ret
4011c1: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)
4011c8: 00 00 00 00
4011cc: 0f 1f 40 00 nopl 0x0(%rax)

00000000004011d0 <frame_dummy>:
4011d0: f3 0f 1e fa endbr64
4011d4: eb 8a jmp 401160 <register_tm_clones>

00000000004011d6 <backdoor>:
4011d6: f3 0f 1e fa endbr64
4011da: 55 push %rbp
4011db: 48 89 e5 mov %rsp,%rbp
4011de: 48 8d 05 1f 0e 00 00 lea 0xe1f(%rip),%rax # 402004 <_IO_stdin_used+0x4>
4011e5: 48 89 c7 mov %rax,%rdi
4011e8: e8 b3 fe ff ff call 4010a0 <system@plt>
4011ed: bf 00 00 00 00 mov $0x0,%edi
4011f2: e8 e9 fe ff ff call 4010e0 <exit@plt>

00000000004011f7 <whhhat>:
4011f7: f3 0f 1e fa endbr64
4011fb: 55 push %rbp
4011fc: 48 89 e5 mov %rsp,%rbp
4011ff: 48 8d 05 13 0e 00 00 lea 0xe13(%rip),%rax # 402019 <_IO_stdin_used+0x19>
401206: 48 89 c7 mov %rax,%rdi
401209: e8 82 fe ff ff call 401090 <puts@plt>
40120e: ba 00 00 00 00 mov $0x0,%edx
401213: be 00 00 00 00 mov $0x0,%esi
401218: 48 8d 05 05 0e 00 00 lea 0xe05(%rip),%rax # 402024 <_IO_stdin_used+0x24>
40121f: 48 89 c7 mov %rax,%rdi
401222: e8 99 fe ff ff call 4010c0 <execve@plt>
401227: 90 nop
401228: 5d pop %rbp
401229: c3 ret

000000000040122a <main>:
40122a: f3 0f 1e fa endbr64
40122e: 55 push %rbp
40122f: 48 89 e5 mov %rsp,%rbp
401232: 48 83 ec 30 sub $0x30,%rsp
401236: 48 8b 05 23 2e 00 00 mov 0x2e23(%rip),%rax # 404060 <stdout@GLIBC_2.2.5>
40123d: b9 00 00 00 00 mov $0x0,%ecx
401242: ba 02 00 00 00 mov $0x2,%edx
401247: be 00 00 00 00 mov $0x0,%esi
40124c: 48 89 c7 mov %rax,%rdi
40124f: e8 7c fe ff ff call 4010d0 <setvbuf@plt>
401254: 48 8b 05 15 2e 00 00 mov 0x2e15(%rip),%rax # 404070 <stdin@GLIBC_2.2.5>
40125b: b9 00 00 00 00 mov $0x0,%ecx
401260: ba 02 00 00 00 mov $0x2,%edx
401265: be 00 00 00 00 mov $0x0,%esi
40126a: 48 89 c7 mov %rax,%rdi
40126d: e8 5e fe ff ff call 4010d0 <setvbuf@plt>
401272: 48 8b 05 07 2e 00 00 mov 0x2e07(%rip),%rax # 404080 <stderr@GLIBC_2.2.5>
401279: b9 00 00 00 00 mov $0x0,%ecx
40127e: ba 02 00 00 00 mov $0x2,%edx
401283: be 00 00 00 00 mov $0x0,%esi
401288: 48 89 c7 mov %rax,%rdi
40128b: e8 40 fe ff ff call 4010d0 <setvbuf@plt>
401290: 48 8d 05 95 0d 00 00 lea 0xd95(%rip),%rax # 40202c <_IO_stdin_used+0x2c>
401297: 48 89 c7 mov %rax,%rdi
40129a: e8 f1 fd ff ff call 401090 <puts@plt>
40129f: 48 8d 45 d0 lea -0x30(%rbp),%rax
4012a3: ba 00 01 00 00 mov $0x100,%edx
4012a8: 48 89 c6 mov %rax,%rsi
4012ab: bf 00 00 00 00 mov $0x0,%edi
4012b0: e8 fb fd ff ff call 4010b0 <read@plt>
4012b5: b8 00 00 00 00 mov $0x0,%eax
4012ba: c9 leave
4012bb: c3 ret

Disassembly of section .fini:

00000000004012bc <_fini>:
4012bc: f3 0f 1e fa endbr64
4012c0: 48 83 ec 08 sub $0x8,%rsp
4012c4: 48 83 c4 08 add $0x8,%rsp
4012c8: c3 ret

我们通过 objdump拿到程序的反汇编,非常长和难以阅读,现在我们将其转写成伪C代码

第一部分是 init段 也就是初始化段

1
2
3
4
5
6
7
8
9
0000000000401000 <_init>:
401000: f3 0f 1e fa endbr64
401004: 48 83 ec 08 sub $0x8,%rsp
401008: 48 8b 05 e9 2f 00 00 mov 0x2fe9(%rip),%rax # 403ff8 <__gmon_start__@Base>
40100f: 48 85 c0 test %rax,%rax
401012: 74 02 je 401016 <_init+0x16>
401014: ff d0 call *%rax
401016: 48 83 c4 08 add $0x8,%rsp
40101a: c3 ret
1
2
3
4
5
6
7
void _init(void){ // 由于ret后无参数所以返回空
// endbr64 C层不体现
// sub $0x8,%rsp 函数序言



}

攻击流程